Sign in to follow this  
Followers 0
PsaltyDS

_WinAPI_GetWindowPlacement()

10 posts in this topic

#1 ·  Posted (edited)

With some help understanding the DLL struct required from Siao and SmOke_N, I coded _WinAPI_GetWindowPlacement() in this topic: window restored position without actually restoring

The primary advantage to this method is getting where the window will go, vice where it is. For example determining where the window will restore to, while it remains minimized.

I am considering putting it in for consideration as an addition to WinAPI.au3 UDF, but need more people to try it first.

Here's the function, with a demo: <snip>

Also, I guess we need the matching _WinAPI_SetWindowPlacement() to go with it. I will take a look at that too.

Comments requested...

:)

Edit: Reformatted for submission to UDF, including both _WinAPI_GetWindowPlacement() and _WinAPI_SetWindowPlacement():

Here are the functions, to be included in WinAPI.au3:

; #FUNCTION# ====================================================================================
;
; Name...........: _WinAPI_GetWindowPlacement
; Description ...: Retrieves the placement of the window for Min, Max, and normal positions
; Syntax.........: _WinAPI_GetWindowPlacement($hWnd)
; Parameters ....: $hWnd        - Handle of the window
; Return values .: Success    - returns $tagWINDOWPLACEMENT structure with the placement coordinates
;                 Failure     - returns 0, @error = 1, @extended = _WinAPI_GetLastError()
; Author ........: PsaltyDS, with help from Siao and SmOke_N, at www.autoitscript.com/forum
; Modified.......:
; Remarks .......:
; Related .......: _WinAPI_SetWindowPlacement, $tagWINDOWPLACEMENT
; Link ..........; @@MsdnLink@@ GetWindowPlacement
; Example .......; Yes
;
; =============================================================================================
Func _WinAPI_GetWindowPlacement($hWnd)
; Create struct to receive data
    Local $tWindowPlacement = DllStructCreate($tagWINDOWPLACEMENT)
    DllStructSetData($tWindowPlacement, "length", DllStructGetSize($tWindowPlacement))
; Get pointer to struct
    Local $pWindowPlacement = DllStructGetPtr($tWindowPlacement)
; Make DLL call
    Local $avRET = DllCall("user32.dll", "int", "GetWindowPlacement", "hwnd", $hWnd, "ptr", $pWindowPlacement)
; Return results
    If $avRET[0] Then
        Return $tWindowPlacement
    Else
        Return SetError(1, _WinAPI_GetLastError(), 0)
    EndIf
EndFunc ;==>_WinAPI_GetWindowPlacement



; #FUNCTION# =====================================================================================
;
; Name...........: _WinAPI_SetWindowPlacement
; Description ...: Sets the placement of the window for Min, Max, and normal positions
; Syntax.........: _WinAPI_SetWindowPlacement($hWnd, $pWindowPlacement)
; Parameters ....: $hWnd        - Handle of the window
;                 $pWindowPlacement - pointer to $tagWINDOWPLACEMENT structure
; Return values .: Success    - Returns non-zero
;                 Failure     - Returns 0, @error = 1, @extended = _WinAPI_GetLastError()
; Author ........: PsaltyDS at www.autoitscript.com/forum
; Modified.......:
; Remarks .......:
; Related .......: _WinAPI_GetWindowPlacement, $tagWINDOWPLACEMENT
; Link ..........; @@MsdnLink@@ SetWindowPlacement
; Example .......; Yes
;
; ===============================================================================================
Func _WinAPI_SetWindowPlacement($hWnd, $pWindowPlacement)
; Make DLL call
    Local $avRET = DllCall("user32.dll", "int", "SetWindowPlacement", "hwnd", $hWnd, "ptr", $pWindowPlacement)
; Return results
    If $avRET[0] Then
        Return $avRET[0]
    Else
        Return SetError(1, _WinAPI_GetLastError(), 0)
    EndIf
EndFunc ;==>_WinAPI_SetWindowPlacement

...and here is the demo, which includes the required $tagWINDOWPLACEMENT definition:

; _WinAPI_GetWindowPlacement.au3 and _WinAPI_SetWindowPlacement.au3
#AutoIt3Wrapper_Au3Check_Parameters= -d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6

; Placed here only until included in appropriate Constants include file:
; ------------------------------------------------------------------------------
; $tagWINDOWPLACEMENT
; -----------------------------------
; This structure defines the data for User32.dll functions GetWindowPlacement and SetWindowPlacement.
; Includes the X/Y coord of the window when minimized and maximized, and the rectangle coord when
; normalized.
; Parameters:
;        length = size of struct
;        flags = sum of WPF_ASYNCWINDOWPLACEMENT, WPF_RESTORETOMAXIMIZED, and WPF_SETMINPOSITION
;        showCmd = show state, i.e. SW_Show or SW_Minimize
;        ptMinPosition = X/Y coord of upper left corner when minimized
;        ptMaxPosition = X/Y coord of upper left corner when maximized
;        rcNormalPosition = left/top/right/bottom coord when normalized
; ------------------------------------------------------------------------------
Global Const $tagWINDOWPLACEMENT = "UINT length; UINT flags; UINT showCmd; " & _
        "int ptMinPosition[2]; int ptMaxPosition[2]; int rcNormalPosition[4]"

#include <WinAPI.au3>

Global $hWindow, $stRET, $sMsg, $pStruct, $iRET
; Create an instance of notepad to play with
Run("notepad.exe")
WinWait("Untitled - Notepad")
$hWindow = WinGetHandle("Untitled - Notepad")
WinMove($hWindow, "", 256, 256, 400, 400)
Sleep(1000)

; Minimize and then check the placement values returned by _WinAPI_GetWindowPlacement()
WinSetState($hWindow, "", @SW_MINIMIZE)
$stRET = _WinAPI_GetWindowPlacement($hWindow)
If @error = 0 Then
    $sMsg = "$stWindowPlacement:" & @CRLF & @CRLF
    $sMsg &= @TAB & "length = " & DllStructGetData($stRET, "length") & @CRLF
    $sMsg &= @TAB & "flags = " & DllStructGetData($stRET, "flags") & @CRLF
    $sMsg &= @TAB & "showCmd = " & DllStructGetData($stRET, "showCmd") & @CRLF & @CRLF
    $sMsg &= "ptMinPosition:" & @CRLF
    $sMsg &= @TAB & "MinX = " & DllStructGetData($stRET, "ptMinPosition", 1) & @CRLF
    $sMsg &= @TAB & "MinY = " & DllStructGetData($stRET, "ptMinPosition", 2) & @CRLF & @CRLF
    $sMsg &= "ptMaxPosition:" & @CRLF
    $sMsg &= @TAB & "MaxX = " & DllStructGetData($stRET, "ptMaxPosition", 1) & @CRLF
    $sMsg &= @TAB & "MaxY = " & DllStructGetData($stRET, "ptMaxPosition", 2) & @CRLF & @CRLF
    $sMsg &= "rcNormalPosition:" & @CRLF
    $sMsg &= @TAB & "left = " & DllStructGetData($stRET, "rcNormalPosition", 1) & @CRLF
    $sMsg &= @TAB & "top = " & DllStructGetData($stRET, "rcNormalPosition", 2) & @CRLF
    $sMsg &= @TAB & "right = " & DllStructGetData($stRET, "rcNormalPosition", 3) & @CRLF
    $sMsg &= @TAB & "bottom = " & DllStructGetData($stRET, "rcNormalPosition", 4)
    MsgBox(64, "Success", $sMsg)

; Change the normalized rectangle with _WinAPI_SetWindowPlacement() and then restore
    DllStructSetData($stRET, "rcNormalPosition", 128, 1); left
    DllStructSetData($stRET, "rcNormalPosition", 128, 2); top
    DllStructSetData($stRET, "rcNormalPosition", @DesktopWidth - 128, 3); right
    DllStructSetData($stRET, "rcNormalPosition", @DesktopHeight - 128, 4); bottom
    $pStruct = DllStructGetPtr($stRET); Get pointer to the modified struct
    $iRET = _WinAPI_SetWindowPlacement($hWindow, $pStruct)
    If @error = 0 Then
        WinSetState($hWindow, "", @SW_RESTORE)
        ControlSetText($hWindow, "", "Edit1", "_WinAPI_SetWindowPlacement() succeeded!")
    Else
        MsgBox(16, "Error", "_WinAPI_SetWindowPlacement() failed!" & @CRLF & _
                "$iRET = " & $iRET & @CRLF & _
                "@error = " & @error & @CRLF & _
                "@extended = " & @extended)
    EndIf
Else
    MsgBox(16, "Error", "_WinAPI_GetWindowPlacement() failed!" & @CRLF & _
            "$stRET = " & $stRET & @CRLF & _
            "@error = " & @error & @CRLF & _
            "@extended = " & @extended)
EndIf
Edited by PsaltyDS

Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

Very useful function.

I will add this function in WinAPI.au3 UDF.

Thanks PsaltyDS. :)

Edited by Andreik

When the words fail... music speaks

Share this post


Link to post
Share on other sites

Very useful function.

I will add this function in WinAPI.au3 UDF.

Thanks PsaltyDS. :)

You're welcome, but monitor for changes.

As I look into _WinAPI_SetWindowPlacement(), I see a major change possible. That the $tagWINDOWPLACEMENT should be declared Global Const, rather than local to the function. The _WinAPI_GetWindowPlacement() function will return the structure, and the Set version will take the structure as an input parameter. So the tag should be global to be used in both cases for setting/reading data.

:)


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites

#4 ·  Posted (edited)

Here are _WinAPI_GetWindowPlacement() and _WinAPI_SetWindowPlacement() cleaned up per the UDF Standards, with a demo script. Note the new Global Const variable, which is declared in the demo but would presumably be included in the WinAPI.au3 UDF if these functions are accepted. I also added some error detection:

#AutoIt3Wrapper_Au3Check_Parameters= -d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6

#include <WinAPI.au3>

; ------------------------------------------------------------------------------
; Placed here until included in WinAPI.au3:
;
; $tagWINDOWPLACEMENT
; -----------------------------------
; This structure defines the data for User32.dll functions GetWindowPlacement and SetWindowPlacement.
; Includes the X/Y coord of the window when minimized and maximized, and the rectangle coord when
; normalized.
; Parameters:
;       length = size of struct
;       flags = sum of WPF_ASYNCWINDOWPLACEMENT, WPF_RESTORETOMAXIMIZED, and WPF_SETMINPOSITION
;       showCmd = show state, i.e. SW_Show or SW_Minimize
;       ptMinPosition = X/Y coord of upper left corner when minimized
;       ptMaxPosition = X/Y coord of upper left corner when maximized
;       rcNormalPosition = left/top/right/bottom coord when normalized
; ------------------------------------------------------------------------------
Global Const $tagWINDOWPLACEMENT = "UINT length; UINT flags; UINT showCmd; " & _
        "int ptMinPosition[2]; int ptMaxPosition[2]; int rcNormalPosition[4]"


; #Demo Script# ====================================================================================
Global $hWindow, $stRET, $sMsg, $pStruct, $iRET
; Create an instance of notepad to play with
Run("notepad.exe")
WinWait("Untitled - Notepad")
$hWindow = WinGetHandle("Untitled - Notepad")
WinMove($hWindow, "", 256, 256, 400, 400)
Sleep(1000)

; Minimize and then check the placement values returned by _WinAPI_GetWindowPlacement()
WinSetState($hWindow, "", @SW_MINIMIZE)
$stRET = _WinAPI_GetWindowPlacement($hWindow)
If @error = 0 Then
    $sMsg = "$stWindowPlacement:" & @CRLF & @CRLF
    $sMsg &= @TAB & "length = " & DllStructGetData($stRET, "length") & @CRLF
    $sMsg &= @TAB & "flags = " & DllStructGetData($stRET, "flags") & @CRLF
    $sMsg &= @TAB & "showCmd = " & DllStructGetData($stRET, "showCmd") & @CRLF & @CRLF
    $sMsg &= "ptMinPosition:" & @CRLF
    $sMsg &= @TAB & "MinX = " & DllStructGetData($stRET, "ptMinPosition", 1) & @CRLF
    $sMsg &= @TAB & "MinY = " & DllStructGetData($stRET, "ptMinPosition", 2) & @CRLF & @CRLF
    $sMsg &= "ptMaxPosition:" & @CRLF
    $sMsg &= @TAB & "MaxX = " & DllStructGetData($stRET, "ptMaxPosition", 1) & @CRLF
    $sMsg &= @TAB & "MaxY = " & DllStructGetData($stRET, "ptMaxPosition", 2) & @CRLF & @CRLF
    $sMsg &= "rcNormalPosition:" & @CRLF
    $sMsg &= @TAB & "left = " & DllStructGetData($stRET, "rcNormalPosition", 1) & @CRLF
    $sMsg &= @TAB & "top = " & DllStructGetData($stRET, "rcNormalPosition", 2) & @CRLF
    $sMsg &= @TAB & "right = " & DllStructGetData($stRET, "rcNormalPosition", 3) & @CRLF
    $sMsg &= @TAB & "bottom = " & DllStructGetData($stRET, "rcNormalPosition", 4)
    MsgBox(64, "Success", $sMsg)

; Change the normalized rectangle with _WinAPI_SetWindowPlacement() and then restore
    DllStructSetData($stRET, "rcNormalPosition", 128, 1); left
    DllStructSetData($stRET, "rcNormalPosition", 128, 2); top
    DllStructSetData($stRET, "rcNormalPosition", @DesktopWidth - 128, 3); right
    DllStructSetData($stRET, "rcNormalPosition", @DesktopHeight - 128, 4); bottom
    $pStruct = DllStructGetPtr($stRET); Get pointer to the modified struct
    $iRET = _WinAPI_SetWindowPlacement($hWindow, $pStruct)
    If @error = 0 Then
        WinSetState($hWindow, "", @SW_RESTORE)
        ControlSetText($hWindow, "", "Edit1", "_WinAPI_SetWindowPlacement() succeeded!")
    Else
        MsgBox(16, "Error", "_WinAPI_SetWindowPlacement() failed!" & @CRLF & _
                "$iRET = " & $iRET & @CRLF & _
                "@error = " & @error & @CRLF & _
                "@extended = " & @extended)
    EndIf
Else
    MsgBox(16, "Error", "_WinAPI_GetWindowPlacement() failed!" & @CRLF & _
            "$stRET = " & $stRET & @CRLF & _
            "@error = " & @error & @CRLF & _
            "@extended = " & @extended)
EndIf
; #End Demo Script# ================================================================================



; #FUNCTION# ====================================================================================
; Name...........: _WinAPI_GetWindowPlacement
; Description ...: Retrieves the placement of the window for Min, Max, and normal positions
; Syntax.........: _WinAPI_GetWindowPlacement($hWnd)
; Parameters ....: $hWnd        - Handle of the window
; Return values .: Success    - returns $tagWINDOWPLACEMENT structure with the placement coordinates
;                 Failure     - returns 0, @error = 1, @extended = _WinAPI_GetLastError()
; Author ........: PsaltyDS, with help from Siao and SmOke_N, at www.autoitscript.com/forum
; Modified.......:
; Remarks .......:
; Related .......: _WinAPI_SetWindowPlacement, $tagWINDOWPLACEMENT
; Link ..........; @@MsdnLink@@ GetWindowPlacement
; Example .......; Yes
; =============================================================================================
Func _WinAPI_GetWindowPlacement($hWnd)
; Create struct to receive data
    Local $stWindowPlacement = DllStructCreate($tagWINDOWPLACEMENT)
    DllStructSetData($stWindowPlacement, "length", DllStructGetSize($stWindowPlacement))
; Get pointer to struct
    Local $pWindowPlacement = DllStructGetPtr($stWindowPlacement)
; Make DLL call
    Local $avRET = DllCall("user32.dll", "int", "GetWindowPlacement", "hwnd", $hWnd, "ptr", $pWindowPlacement)
; Return results
    If $avRET[0] Then
        Return $stWindowPlacement
    Else
        Return SetError(1, _WinAPI_GetLastError(), 0)
    EndIf
EndFunc;==>_WinAPI_GetWindowPlacement



; #FUNCTION# =====================================================================================
; Name...........: _WinAPI_SetWindowPlacement
; Description ...: Sets the placement of the window for Min, Max, and normal positions
; Syntax.........: _WinAPI_SetWindowPlacement($hWnd, $pWindowPlacement)
; Parameters ....: $hWnd        - Handle of the window
;                 $pWindowPlacement - pointer to $tagWINDOWPLACEMENT structure
; Return values .: Success    - Returns non-zero
;                 Failure     - Returns 0, @error = 1, @extended = _WinAPI_GetLastError()
; Author ........: PsaltyDS at www.autoitscript.com/forum
; Modified.......:
; Remarks .......:
; Related .......: _WinAPI_GetWindowPlacement, $tagWINDOWPLACEMENT
; Link ..........; @@MsdnLink@@ SetWindowPlacement
; Example .......; Yes
; ===============================================================================================
Func _WinAPI_SetWindowPlacement($hWnd, $pWindowPlacement)
; Make DLL call
    Local $avRET = DllCall("user32.dll", "int", "SetWindowPlacement", "hwnd", $hWnd, "ptr", $pWindowPlacement)
; Return results
    If $avRET[0] Then
        Return $avRET[0]
    Else
        Return SetError(1, _WinAPI_GetLastError(), 0)
    EndIf
EndFunc;==>_WinAPI_SetWindowPlacement

Testing and comment requested.

:)

Edit: Minor typo, fixed line-wrap in header because SmOke_N is watching... :)

Edited by PsaltyDS

Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites

Another Useful function, Thanks.

Here is how I am using this (earlier I would restore a Min or Max 'ed window to achieve it):

Presumptions, _WinAPI_GetWindowPlacement is in an include as also <WinAPI.au3>, $IniFile is defined/set, Global Const $_Comma = ",", and $GUIMain is the Main Window defined elsewhere.

Func SaveSettings()
Local $App_Coords[4], $WinPlacement

    If FileExists($IniFile) Then; The App. does not save settings if this file does NOT already exist - Comment out to Force save
       $WinState = WinGetState($ActiveWindowTitle, "")
         If NOT BitAnd($WinState, 16) AND NOT BitAnd($WinState, 32) Then; NOT Minimized or Maximized
                $App_Coords = WinGetPos($GUIMain); Or $App_Coords = WinGetPos("[active]", "")
                WinSetState($GUIMain, "", @SW_MINIMIZE)
         Else
              $WinPlacement = _WinAPI_GetWindowPlacement($GUIMain)
              $App_Coords[0] = DllStructGetData($WinPlacement, "rcNormalPosition", 1); Left
              $App_Coords[1] = DllStructGetData($WinPlacement, "rcNormalPosition", 2); Top
              $App_Coords[2] = DllStructGetData($WinPlacement, "rcNormalPosition", 3); Right
              $App_Coords[3] = DllStructGetData($WinPlacement, "rcNormalPosition", 4); Bottom
              $App_Coords[2] = $App_Coords[2] - $App_Coords[0]; Discount Left from Right to Get Width
              $App_Coords[3] = $App_Coords[3] - $App_Coords[1]; Discount Top from Bottom to Get Height
         EndIf
         If UBound($App_Coords) = 4 Then; $App_Coords[0] = Left, 1 = Top, 2 = Width, 3 = Height
             IniWrite($IniFile, @UserName, "WinPos", $App_Coords[0] & $_Comma & $App_Coords[1] & $_Comma & $App_Coords[2] & $_Comma & $App_Coords[3])
         EndIf
      ; Other IniWrite Values....
    EndIf; FileExists($IniFile)
EndFunc;SaveSettings()

Share this post


Link to post
Share on other sites

Testing and comment requested.

:)

If this is prepared for standard UDFs then you should make example "language neutral" according to BugTrack post I have seen some days ago.

Original code:

Run("notepad.exe")
WinWait("Untitled - Notepad")

On my Czech Windows:

Run("notepad.exe")
WinWait("Bez názvu - Poznámkový blok")

Here is result from MessageBox on my WIN98SE (Success):

$stWindowPlacement:

length = 44

flags = 0

showCmd = 2

ptMinPosition:

MinX = 3000

MinY = 3000

ptMaxPosition:

MaxX = -1

MaxY = -1

rcNormalPosition:

left = 256

top = 256

right = 656

bottom = 656

Are the ptMinPosition and ptMaxPosition values right?

Share this post


Link to post
Share on other sites

#7 ·  Posted (edited)

If this is prepared for standard UDFs then you should make example "language neutral" according to BugTrack post I have seen some days ago.

Original code:

Run("notepad.exe")
WinWait("Untitled - Notepad")

On my Czech Windows:

Run("notepad.exe")
WinWait("Bez názvu - Poznámkový blok")
I haven't seen that Bug Trac yet, and the UDF Standards don't say anything about it. What do you think would be the easiest change to the demo script for that? I only went with Notepad because it's easy and familiar, and already used in many example scripts in the help file. I am submitting them as is, but could certainly submit an update if you have a good alternative. (See update post #1.)

Here is result from MessageBox on my WIN98SE (Success):

Are the ptMinPosition and ptMaxPosition values right?

Thanks. I get -32000 on XP for MinX and MinY. The numbers are just what the API returns from the DLL call.

:)

Edited by PsaltyDS

Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites

The WinAPI.au3 UDF includes _WinAPI_GetWindowPlacement() and _WinAPI_SetWindowPlacement() as of Beta 3.2.13.3 dated 6/22/08.

:)


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

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  
Followers 0