Jump to content
Sign in to follow this  

SPI_SETWORKAREA Updates Windows If Reduced, But Not Increased

Recommended Posts


Hello one and all.

I am creating a toolbar which reserves 40 pixels of the right-hand side of the screen by updating the "Desktop Work Area" via _WinAPI_SystemParametersInfo, so windows maximize up to it, much like the old Office Toolbar.  All worked great, new windows would maximize up to the new border, but existing maximized windows were a problem.

Initially I created a slightly noddy function utilising a combination of WinList and WinMove to find any visible maximized windows and adjust them accordingly.  While this worked ok, I didn't like it as it felt a bit, well, noddy.

I then discovered the 4th parameter of _WinAPI_SystemParametersInfo to send a WM_SETTINGCHANGE message after updating the work area which caused all maximized windows to instantly jump to their new position - great!  The Windows API was working for me - I could do away with my noddy function.

The trouble I face, however, is that on exit, while I set the work area back to the full width of the desktop, maximized windows aren't taking up the new larger area, unless manually restored down and maximized again.  With a bit of experimenting, I've discovered that using this method, maximized windows only respond to the message if the work area is reduced, not increased.

I created a little GUI which plays around with this very phenomenon;

#include <GUIConstantsEx.au3>
#include <GuiListView.au3>
#include <StaticConstants.au3>
#include <StructureConstants.au3>
#include <WinAPI.au3>

Global $iLeft, $iTop, $iRight, $iBottom

; Create the GUI
GUICreate("WorkArea", 210, 200)
GUICtrlCreateLabel("Pixel Amount:", 10, 10, 90, 20, $SS_RIGHT)
$Input = GUICtrlCreateInput("40", 110, 8, 90, 20)
$Reduce = GUICtrlCreateButton("Reduce", 10, 40, 90, 30)
$Increase = GUICtrlCreateButton("Increase", 110, 40, 90, 30)
$Reset = GUICtrlCreateButton("Reset", 10, 80, 190, 30)
$ListView = GUICtrlCreateListView("Left|Top|Right|Bottom", 10, 120, 190, 50)
$WorkArea = GUICtrlCreateListViewItem("", $ListView)
_GUICtrlListView_SetColumnWidth($ListView, 0, 33)
_GUICtrlListView_SetColumnWidth($ListView, 1, 33)
_GUICtrlListView_SetColumnWidth($ListView, 2, 60)
_GUICtrlListView_SetColumnWidth($ListView, 3, 60)
_GetDesktopWorkArea($iLeft, $iTop, $iRight, $iBottom)

; Loop until message received
While 1
    $msg = GUIGetMsg()
        Case $msg = $GUI_EVENT_CLOSE ; Reset the work area to Desktop Width then close
            _SetDesktopWorkArea($iLeft, $iTop, @DesktopWidth, $iBottom)
        Case $msg = $Reduce ; Reduce the work area width by the amount in input box
            $Pixels = GUICtrlRead($Input)
            _SetDesktopWorkArea($iLeft, $iTop, $iRight-$Pixels, $iBottom)
            _GetDesktopWorkArea($iLeft, $iTop, $iRight, $iBottom)
        Case $msg = $Increase ; Increase the work area width by the amount in input box
            $Pixels = GUICtrlRead($Input)
            _SetDesktopWorkArea($iLeft, $iTop, $iRight+$Pixels, $iBottom)
            _GetDesktopWorkArea($iLeft, $iTop, $iRight, $iBottom)
        Case $msg = $Reset ; Reset the work area to Desktop Width
            _SetDesktopWorkArea($iLeft, $iTop, @DesktopWidth, $iBottom)
            _GetDesktopWorkArea($iLeft, $iTop, $iRight, $iBottom)

Func _GetDesktopWorkArea(ByRef $iLeft, ByRef $iTop, ByRef $iRight, ByRef $iBottom)
    Local Const $SPI_GETWORKAREA = 48
    Local $tStruct = DllStructCreate($tagRECT)
    If _WinAPI_SystemParametersInfo($SPI_GETWORKAREA, 0, DllStructGetPtr($tStruct)) Then
        $iLeft = DllStructGetData($tStruct, "Left")
        $iRight = DllStructGetData($tStruct, "Right")
        $iTop = DllStructGetData($tStruct, "Top")
        $iBottom = DllStructGetData($tStruct, "Bottom")
        GUICtrlSetData($WorkArea, $iLeft&"|"&$iTop&"|"&$iRight&"|"&$iBottom)
        Return True
    Return False
EndFunc   ;==>_GetDesktopWorkArea

Func _SetDesktopWorkArea($iLeft, $iTop, $iRight, $iBottom)
    Local Const $SPI_SETWORKAREA = 47
    Local Const $SPIF_SENDWININICHANGE  = 0x2
    Local $tStruct = DllStructCreate($tagRECT)
    DllStructSetData($tStruct, "Left", $iLeft)
    DllStructSetData($tStruct, "Right", $iRight)
    DllStructSetData($tStruct, "Top", $iTop)
    DllStructSetData($tStruct, "Bottom", $iBottom)
    If _WinAPI_SystemParametersInfo($SPI_SETWORKAREA, 0, DllStructGetPtr($tStruct), $SPIF_SENDWININICHANGE) Then
        Return True
    Return False
EndFunc   ;==>_SetDesktopWorkArea

Would anyone know why this might be, and indeed if it's possible with another API call to have maximized windows respond in the same way regardless of work area reduction or enlargement?  I'm loathe to go back to the noddy function!

Many thanks in advance.



Share this post

Link to post
Share on other sites

OK, so I think I've been taking the wrong approach.  After finding >Franks Gadgets I can see he's not using SPI_SETWORKAREA at all, but rather sending an SHAppBarMessage to the system to both register and unregister his AppBar window.  Interestingly, this is something I considered using >back in 2006 but I was put off this idea by Excalibur who suggested it only reported the "start bar" (taskbar) position and size.  Wish I hadn't listened!  As you can see I've had this idea on the back burner for some time...!

So I'm going to rework my script using this same approach, as it absolutely works.  If I ever get around to finishing it, I'll post the solution here :)

Share this post

Link to post
Share on other sites

Finally, using snippets of code borrowed from the aforementioned >Franks Gadgets, I have managed to come up with a basic GUI script which registers itself as a toolbar.

Disclaimer: This is a proof of concept only, kept as short as possible for this example, which makes lots of assumptions (such as taskbar position & size).

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>

Const $ABE_RIGHT = 2, $ABM_NEW = 0, $ABM_REMOVE = 1, $ABM_SETPOS = 3

; Create the GUI
$title = StringTrimRight(@ScriptName, 4)
$toolbarWidth = 40
$height = @DesktopHeight-40
$left = @DesktopWidth-$toolbarWidth
$top = 0
$right = @DesktopWidth
$bottom = $height
$hwnd = GUICreate($title, $toolbarWidth, $height, $left, $top, $WS_POPUPWINDOW, $WS_EX_TOOLWINDOW)

; Register the AppBar
$AppBarData = DllStructCreate("dword;int;uint;uint;int;int;int;int;int")
DllStructSetData($AppBarData, 1, DllStructGetSize($AppBarData))
DllStructSetData($AppBarData, 2, $hwnd)
DllStructSetData($AppBarData, 4, $ABE_RIGHT)
DllStructSetData($AppBarData, 5, $left)
DllStructSetData($AppBarData, 6, $top)
DllStructSetData($AppBarData, 7, $right)
DllStructSetData($AppBarData, 8, $bottom)
_SHAppBarMessage($ABM_NEW, $AppBarData)
_SHAppBarMessage($ABM_SETPOS, $AppbarData)

; Idle around
While 1
    Local $msg = GUIGetMsg()
        Case $msg = $GUI_EVENT_CLOSE

; Unregister the AppBar
_SHAppBarMessage($ABM_REMOVE, $AppBarData)

; Delete the GUI

; Exit

Func _ShAppBarMessage($dwMessage, ByRef $AppBarData)
    DllCall("shell32.dll", "int", "SHAppBarMessage", "int", $dwMessage, "ptr", DllStructGetPtr($AppBarData))

It only took me 8 years...


Share this post

Link to post
Share on other sites

Nice sample code, I suggest you to post it in the AutoIt Snippets thread or create a new one ;)


OS : Win XP SP2 (32 bits) / Win 7 SP1 (64 bits) / Win 8 (64 bits) | Autoit version: latest stable / beta.
Hardware : Intel(R) Core(TM) i5-2400 CPU @ 3.10Ghz / 8 GiB RAM DDR3.

My UDFs : Skype UDF | TrayIconEx UDF | GUI Panel UDF | Excel XML UDF | Is_Pressed_UDF

My Projects : YouTube Multi-downloader | FTP Easy-UP | Lock'n | WinKill | AVICapture | Skype TM | Tap Maker | ShellNew | Scriptner | Const Replacer | FT_Pocket | Chrome theme maker

My Examples : Capture toolIP Camera | Crosshair | Draw Captured Region | Picture Screensaver | Jscreenfix | Drivetemp | Picture viewer

My Snippets : Basic TCP | Systray_GetIconIndex | Intercept End task | Winpcap various | Advanced HotKeySet | Transparent Edit control


Share this post

Link to post
Share on other sites

hi im trying to display the appbar on top of the screen this is what i used but it doesn't worked so far


$toolbarWidth =@DesktopWidth
$height = 40
$left =0
$top = 0
$right = @DesktopWidth
$bottom = 40

this is what i have for position, any ideas how to fix it, thanks


found the problem changed this and now is working     $ABE_TOP =  1

Edited by leogianguajor

Share this post

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Similar Content

    • KaFu
      By KaFu
      ICU - Icon Configuration Utility

      Current Version: v6 (2018-Sep-16)
      Restore your desktop when the icons get "rearranged".
      Melba23 and I found we were working on very similar ideas to restore the Desktop icons to their normal place if they became "rearranged" (
      ). Vista seems to like this doing on occasion just for fun - but we all know some apps and games which change the display resolution or move icons around. This annoys "tidy" people who like their desktops arranged "just so" - I am particularly thinking of this desktop when I say that!
      We combined efforts and here is the result of our labors.
      Operation is easy - press "Save" to store a particular configuration and "Restore" to reset the icons to the saved positions in the selected configuration file. "Delete" allows you to remove unwanted configuration files from the list. There is a command line option so that the restoration can be run via HotKeys if required (that is why the script warns that it should be compiled for full functionality). You can decide what to do with any icons that have been added since you last saved the configuration file - the default is to put them in the top-left corner, but you can also banish them way off-screen or, more sensibly, specify a location for them.
      A new feature as of ICU v3.4 is the optional Desktop Contextmenu Integration (DCI) for Win7 (Win7 only because Microsoft implemented an easy way to do this through the registry as of this release).
      Version 3.3 should fix the empty save file bug
      Version 3.4 Win7: Admin rights no longer needed for DCI
      Version 5.0 Win8 compatibility for DCI
      The source and executable can be downloaded from my site: http://www.funk.eu
      Kudos to Ascend4nt, Melba23, Prog@ndy, & Valik for parts of the code.
      Please let me know if you found some piece of code in the source for which I forgot to mention a credit.
      Enjoy, let me know what you think of ICU and with Best Regards
    • copyleft
      By copyleft
      I am trying to create a script to clean up users' desktops by moving all desktop folders and files (except the two hidden "desktop.ini" files and a MyDesktop.lnk shortcut) to a different folder. The script below will move files but not folders. The other issue with the script is that it doesn't seem to execute from a location other than the user's desktop. I would appreciate any suggestions.
      #include <File.au3> MsgBox(64, "Desktop", "Cleaning up Desktop. This box will close in 4 seconds.", 4) $Files = _FileListToArray(@DesktopDir,"*",1) For $Index = 1 To $Files[0] If StringRight($Files[$Index],4) <> ".ini, MyDesktop.lnk" Then FileMove($Files[$Index],'F:\HOME\Desktop') EndIf Next  
    • BrewManNH
      By BrewManNH
      I was looking for a toolbar modification for SciTE and I was checking various versions of SciTE that were available on the internet. They all had some problems for how I wanted to use the editor, so I looked here to see if there were any toolbar modifications for Scite. I found one very old script by YogiBear (Volly) from 2006 that looked promising, though there were issues with it. I decided to see what I could do to modify this script, and make some improvements to it if possible. This script is the result of that work.

      It's not perfect and definitely could use some tweaking, but I thought that it had matured enough, and was mostly stable enough to release the updated version.

      Version 2.0.1
      Minor update to remove all the old Obfuscator directives and replaced them with #Au3Stripper directives instead. I also corrected a minor bug that only showed up for me on one computer I tried this on, and caused the tool bar to crash for others as well.
      SciTE toolbar version 2.0
      Changed the settings values to use constants instead of 'magic numbers' The icons on the toolbar weren't lining up with the separator characters or with the toolbar GUI because they weren't set with the resize setting for the icons, only for the separators. Changed to using arrays for everything, it makes it a lot easier to loop through the controls Added a line to use an alternate path to the SciTE program, so you can start it using, for example, the portable version instead of installed version for those that don't install AutoIt and/or SciTE4AutoIt3. It will accept a commmand line parameter that points to the SciTE executable. Removed a lot of Global variables by moving the GUI creation and monitoring to the Main function and passing variables from it. I embedded the icon files into the script so that there isn't a separate download of the icon files used here. Saves download time and makes the package smaller. Modification of tools is easier because the icon names, tooltip text, and SciTE command codes are saved in the INI file upon first start up. These can be modified after the script has been run once, even after it's been compiled, by changing the ini file information, you can modify this script to automate it, or you can change it manually in any text editor. The icon files are now using, in just my opinion, better looking icons, after all it's been 7 years and icon files have matured. I have included a file with all of the constants that SciTE uses for its menu commands which comes from the SciTE source file "scite.h", so you can use this file to help you modify the commands that the toolbar works with, by figuring out what each of these values represent in SciTE. The core of the script is pretty much the same, I've just fixed a couple of issues that it had, tweaked a few things, added some new functionality and "prettied" it up a bit.

      If anyone has any suggestions as to improvements, bugs/bugfixes, etc. please let me know.

    • Bitpicker
      By Bitpicker
      Not the most eloquent nor efficient, to be sure, but with the following functionality:
      MULTI_BAR Features: ----------------------------------------------------------------
          * Floating MULTIBAR Toolbar with four(4) Docking Positions
          * Drag MULTI bar to Dock at any Edge  position
          * Drag Edge bar to screen center to Float as a MULTI bar
          * All 4 EDGE BARS and MULTI BAR can exist and execute at one time
          * All Toolbars use common INI file format
          * Any Toolbar  can be displayed by any positional Service EXE
          * All ToolBars have common Controls
              Return to calling BAR [ORIGIN}
              Manual Edit the INI file [INIEDIT]
              Create and place a NEW Toolbar on a button [NEWBAR]
              Search Icon Initiator - search for a Toolbar or a Button Function
              Set AUTO mode for EDGE bar show/fade on cursor or click, [AUTOSW]
              Set AUTO mode for FLOAT bar to close or stay open on button click [AUTOSW]
              Rotate thru 3 button sizes, small, medium and large w/label [B-SIZE]
              EXIT this bar [EXIT]
          * User specifies Number of BUTTONS and Number of ROWS
          * Change Dynamically Number of BUTTONS or ROWS
              via NEWBAR Function Specifying SAME BARNAME with Changed BUTTONS & ROWS
          * Three(3) Button sizes - User can change on demand
          * Shrink to Fit - Will Auto reduce Button size on DOCKING if Bar too long    
          * Buttons can be any File OPEN function, web link, or Open another TOOLBAR_BAR
          * ToolBars can be cascaded down(DRILL DOWN - Button points to another ToolBar) to additional Toolbars
              with Return to previous Toolbar via Origin Function
          * 2 BAR TYPES:
              ACTION(Buttons do TOOLBAR, FILE or URL OPENS)
                  User drops a Link on Button
              DROP(Buttons are Folder Targets)dropped files are sorted to destination
                  MOVE or COPY: FILE, FILE(s) or FOLDERS(DIRs) to Button target
                  Recycle Bin(a Shortcut) is supported as a DROP target for FILE, FILE(s) or FOLDERs
          * Button Context functions
              DELETE the current function - empty the button
              EDIT the TOOLTIP for this Button
              EDIT the LABEL displayed on Large Button
              PLUCK this Button for move to new location on this bar -or-
                  ANY other Bar (in this TOOLBOX)  
              PLACE any PLUCKED Button, or PLACE any NEW TOOL_BAR
              OPEN file location of Button file
      UNZIP the attached to a folder which will be the folder for all toolbar definitions
          and executables. THIS FOLDER IS YOUR TOOLBOX.
          TOOLBOX\MULTIBAR\]README.doc or ]README.pdf provides detail on functions and implementing.
      Appreciate all the SILENT help from the AUTOIT community for this and my many projects. Thanks to all menbers who have provided the best self help book on applied AutoIt.
      Please advise on errors or suggestions. MULTIBAR was developed on Windows 10. Other targets or themes may present errors.For your personal use. Accept no responsibility for its functionality. Enjoy, olbitpicker
    • SteveJM
      By SteveJM
      I have a working program currently driven largely through menu selections. I would like to add a toolbar where most of the tollbar button actions are basically the same as menu items, but quicker to access. I have been wading around in toolbar examples, MSDN pages etc, it's clearly going to be a bit of a slog to get everything right, including tooltips etc. I thought I would start with something simple to prove the principle.
      Using bits from the help file examples I have a small program that successfully displays a toolbar. However, what seemed like the most elegant way to deal with the button commands does not seem to work. My understanding was that a toolbar button fires a WM_COMMAND message, with the command Id set by the second parameter in the call to
      _GUICtrlToolbar_AddButton ( $hWnd, $iID, $iImage)
      so I though it would be a good idea to set this Id to the same value as my menu item Id; then it would run the same task which is what I wanted. This did not work. I am using message loop mode and would like to stick with this because some of my scripts run hardware at the same time as the gui; it is easier if I don't have to worry about code being interrupted with the hardware in an unknown state . So I added a handler for WM_COMMAND, with some cribbed display code to try and see why. The toolbar button defintely fired a WM_COMMAND message and the Id looked the same, so no explanation there.
      I guess the issue is with GUIGetMsg() which may be constructed to ignore all but a limited number of control handles, i.e. those made with the GuiCtrlCreate... commands; this is speculation.
      I would dearly love to find a tidy way to get around this. Having some controls handled in the message loop and some in a WM_COMMAND handler, performing the same task, feels ugly. I would be very grateful for further insight from someone experienced with handling a toolbar. Perhaps I should be trying to fire the menu item. I have attached a code snippet to try and illustrate the issue.