Sign in to follow this  
Followers 0
KaFu

_WinGetPosEx()

7 posts in this topic

#1 ·  Posted (edited)

Hiho,

after running into the problem that WinGetPos() did not return correct values on Win7 if the Aero effect is enabled, and after reading this topic by Zedna I scripted this little function to work around that problem.

_WinGetPosEx_Example()

; #FUNCTION# =======================================================
; Name...........:  _WinGetPosEx
; Description ...:  Retrieves Window size and position similar to WinGetPos() but regards possible Aero effects on Vista and Win7
; Syntax.........:  _WinGetPosEx($hWnd)
; Parameters ....:  $hWnd - Handle to Window to measure
; Return values .:  Success:    Returns a 4-element array containing the following information:
;                               $array[0] = X position
;                               $array[1] = Y position
;                               $array[2] = Width
;                               $array[3] = Height
;                       Sets @extended  = 0 for Aero effect is OFF for $hWnd
;                                       = 1 for Aero effect is ON for $hWnd
;
;                   Failure:    Returns 0 and sets @error to 1 if windows is not found.
; Author ........: KaFu
; Link ..........; http://msdn.microsoft.com/en-us/library/aa969515%28VS.85%29.aspx
; Example .......; Yes
; ==================================================================
Func _WinGetPosEx($hWnd)
    If Not IsHWnd($hWnd) Then Return SetError(1, 0, 0)
    Local $aPos[4], $tRect = DllStructCreate("int Left;int Top;int Right;int Bottom")
    Local Const $DWMWA_EXTENDED_FRAME_BOUNDS = 9
    DllCall("dwmapi.dll", "hwnd", "DwmGetWindowAttribute", "hwnd", WinGetHandle($hWnd), "dword", $DWMWA_EXTENDED_FRAME_BOUNDS, "ptr", DllStructGetPtr($tRect), "dword", DllStructGetSize($tRect))
    If @error Then Return SetError(0, 0, WinGetPos($hWnd))
    Local $iRectLeft = DllStructGetData($tRect, "Left")
    Local $iRectTop = DllStructGetData($tRect, "Top")
    Local $iRectRight = DllStructGetData($tRect, "Right")
    Local $iRectBottom = DllStructGetData($tRect, "Bottom")
    If Abs($iRectLeft) + Abs($iRectTop) + Abs($iRectRight) + Abs($iRectBottom) > 0 Then
        $aPos[0] = $iRectLeft
        $aPos[1] = $iRectTop
        $aPos[2] = $iRectRight - $iRectLeft
        $aPos[3] = $iRectBottom - $iRectTop
        Return SetError(0, 1, $aPos)
    EndIf
    Return SetError(0, 0, WinGetPos($hWnd))
EndFunc   ;==>_WinGetPosEx




Func _WinGetPosEx_Example()
    $hGui = GUICreate("My GUI")
    GUISetState(@SW_SHOW)
    ConsoleWrite(@CRLF)

    $aPos = _WinGetPosEx($hGui)
    $sPos = $aPos[0] & "," & $aPos[1] & @TAB & $aPos[2] & "x" & $aPos[3] & @TAB & @extended
    ConsoleWrite("Aero On   " & @TAB & "WinGetPosEx(): " & $sPos & @crlf)
    MsgBox(0, "", "Aero On   " & @TAB & "WinGetPosEx(): " & $sPos)

    Toggle_AERO_Style_On(True)

    Sleep(3000)

    $aPos = _WinGetPosEx($hGui)
    $sPos = $aPos[0] & "," & $aPos[1] & @TAB & $aPos[2] & "x" & $aPos[3] & @TAB & @extended
    ConsoleWrite("Aero Off  " & @TAB & "WinGetPosEx(): " & $sPos & @crlf)
    MsgBox(0, "", "Aero Off   " & @TAB & "WinGetPosEx(): " & $sPos)

    GUIDelete()
    ConsoleWrite(@CRLF)
EndFunc   ;==>Example

Func Toggle_AERO_Style_On($toggle = True)
    ; Disable AERO effect on Vista and Win7 => MPlayer requires this
    ; http://msdn.microsoft.com/en-us/library/aa969510%28VS.85%29.aspx
    Local Const $DWM_EC_DISABLECOMPOSITION = 0
    Local Const $DWM_EC_ENABLECOMPOSITION = 1
    If $toggle = True Then
        DllCall("dwmapi.dll", "hwnd", "DwmEnableComposition", "uint", $DWM_EC_DISABLECOMPOSITION)
    Else
        DllCall("dwmapi.dll", "hwnd", "DwmEnableComposition", "uint", $DWM_EC_ENABLECOMPOSITION)
    EndIf
EndFunc   ;==>Toggle_AERO_Style_On

Tested on Win7-64bit and Virtual Windows XP.

Here's some more (unsorted) reading for those interessted:

DwmGetWindowAttribute Function

http://msdn.microsoft.com/en-us/library/aa969515%28VS.85%29.aspx

Referring to the reference for the DWMWINDOWATTRIBUTE enum:

http://msdn.microsoft.com/en-us/library/aa969530(VS.85).aspx

HRESULT DwmGetWindowAttribute(

HWND hwnd,

DWORD dwAttribute,

PVOID pvAttribute,

DWORD cbAttribute

);

public const uint DWMWA_NCRENDERING_ENABLED = 1; // [get] Is non-client rendering enabled/disabled

public const uint DWMWA_NCRENDERING_POLICY = 2; // [set] Non-client rendering policy

public const uint DWMWA_TRANSITIONS_FORCEDISABLED = 3; // [set] Potentially enable/forcibly disable transitions

public const uint DWMWA_ALLOW_NCPAINT = 4; // [set] Allow contents rendered in the non-client area to be visible on the DWM-drawn frame.

public const uint DWMWA_CAPTION_BUTTON_BOUNDS = 5; // [get] Bounds of the caption button area in window-relative space.

public const uint DWMWA_NONCLIENT_RTL_LAYOUT = 6; // [set] Is non-client content RTL mirrored

public const uint DWMWA_FORCE_ICONIC_REPRESENTATION = 7; // [set] Force this window to display iconic thumbnails.

public const uint DWMWA_FLIP3D_POLICY = 8; // [set] Designates how Flip3D will treat the window.

public const uint DWMWA_EXTENDED_FRAME_BOUNDS = 9; // [get] Gets the extended frame bounds rectangle in screen space

public const uint DWMWA_LAST = 10;

public const uint DWMNCRP_USEWINDOWSTYLE = 0;

public const uint DWMNCRP_DISABLED = 1;

public const uint DWMNCRP_ENABLED = 2;

public const uint DWMNCRP_LAST = 3;

Edited by KaFu

Share this post


Link to post
Share on other sites



Nice, but what is wrong with _WinAPI_GetWindowPlacement()?

Didn't check ;) ... wouldn't _WinAPI_GetWindowRect() be the better solution? But from my current experience with Aero I doubt that these functions take the extract Aero pixles into consideration.

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

_WinAPI_GetWindowRect() works even for minimized windows.

Like I assumed... it reports the same (wrong) values as WinGetPos() if Aero is enabled.

#include <WinAPI.au3>

_WinGetPosEx_Example()

; #FUNCTION# =======================================================
; Name...........:  _WinGetPosEx
; Description ...:  Retrieves Window size and position similar to WinGetPos() but regards possible Aero effects on Vista and Win7
; Syntax.........:  _WinGetPosEx($hWnd)
; Parameters ....:  $hWnd - Handle to Window to measure
; Return values .:  Success:    Returns a 4-element array containing the following information:
;                               $array[0] = X position
;                               $array[1] = Y position
;                               $array[2] = Width
;                               $array[3] = Height
;                       Sets @extended  = 0 for Aero effect is OFF for $hWnd
;                                       = 1 for Aero effect is ON for $hWnd
;
;                   Failure:    Returns 0 and sets @error to 1 if windows is not found.
; Author ........: KaFu
; Link ..........; http://msdn.microsoft.com/en-us/library/aa969515%28VS.85%29.aspx
; Example .......; Yes
; ==================================================================
Func _WinGetPosEx($hWnd)
    If Not IsHWnd($hWnd) Then Return SetError(1, 0, 0)
    Local $aPos[4], $tRect = DllStructCreate("int Left;int Top;int Right;int Bottom")
    Local Const $DWMWA_EXTENDED_FRAME_BOUNDS = 9
    DllCall("dwmapi.dll", "hwnd", "DwmGetWindowAttribute", "hwnd", WinGetHandle($hWnd), "dword", $DWMWA_EXTENDED_FRAME_BOUNDS, "ptr", DllStructGetPtr($tRect), "dword", DllStructGetSize($tRect))
    If @error Then Return SetError(0, 0, WinGetPos($hWnd))
    Local $iRectLeft = DllStructGetData($tRect, "Left")
    Local $iRectTop = DllStructGetData($tRect, "Top")
    Local $iRectRight = DllStructGetData($tRect, "Right")
    Local $iRectBottom = DllStructGetData($tRect, "Bottom")
    If Abs($iRectLeft) + Abs($iRectTop) + Abs($iRectRight) + Abs($iRectBottom) > 0 Then
        $aPos[0] = $iRectLeft
        $aPos[1] = $iRectTop
        $aPos[2] = $iRectRight - $iRectLeft
        $aPos[3] = $iRectBottom - $iRectTop
        Return SetError(0, 1, $aPos)
    EndIf
    Return SetError(0, 0, WinGetPos($hWnd))
EndFunc   ;==>_WinGetPosEx




Func _WinGetPosEx_Example()
    $hGui = GUICreate("My GUI")
    GUISetState(@SW_SHOW)
    ConsoleWrite(@CRLF)

    $aPos = _WinGetPosEx($hGui)
    $sPos = $aPos[0] & "," & $aPos[1] & @TAB & $aPos[2] & "x" & $aPos[3] & @TAB & @extended
    ConsoleWrite("Aero On   " & @TAB & "WinGetPosEx(): " & $sPos & @crlf)
    ;MsgBox(0, "", "Aero On   " & @TAB & "WinGetPosEx(): " & $sPos)

    $stRET = _WinAPI_GetWindowPlacement($hGui)
    If @error = 0 Then
        $sPos = DllStructGetData($stRET, "rcNormalPosition", 1) & "," & DllStructGetData($stRET, "rcNormalPosition", 2) & @TAB & DllStructGetData($stRET, "rcNormalPosition", 3)-DllStructGetData($stRET, "rcNormalPosition", 1) & "x" & DllStructGetData($stRET, "rcNormalPosition", 4)-DllStructGetData($stRET, "rcNormalPosition", 2) & @TAB & @extended
        ConsoleWrite("Aero On   " & @TAB & "_WinAPI_GetWindowPlacement(): " & $sPos & @crlf)
    endif

    Sleep(1000)

    Toggle_AERO_Style_On(True)

    Sleep(1000)

    $aPos = _WinGetPosEx($hGui)
    $sPos = $aPos[0] & "," & $aPos[1] & @TAB & $aPos[2] & "x" & $aPos[3] & @TAB & @extended
    ConsoleWrite("Aero Off  " & @TAB & "WinGetPosEx(): " & $sPos & @crlf)
    ;MsgBox(0, "", "Aero Off   " & @TAB & "WinGetPosEx(): " & $sPos)

    $stRET = _WinAPI_GetWindowPlacement($hGui)
    If @error = 0 Then
        $sPos = DllStructGetData($stRET, "rcNormalPosition", 1) & "," & DllStructGetData($stRET, "rcNormalPosition", 2) & @TAB & DllStructGetData($stRET, "rcNormalPosition", 3)-DllStructGetData($stRET, "rcNormalPosition", 1) & "x" & DllStructGetData($stRET, "rcNormalPosition", 4)-DllStructGetData($stRET, "rcNormalPosition", 2) & @TAB & @extended
        ConsoleWrite("Aero Off   " & @TAB & "_WinAPI_GetWindowPlacement(): " & $sPos & @crlf)
    endif

    GUIDelete()
    ConsoleWrite(@CRLF)
EndFunc   ;==>Example

Func Toggle_AERO_Style_On($toggle = True)
    ; Disable AERO effect on Vista and Win7 => MPlayer requires this
    ; http://msdn.microsoft.com/en-us/library/aa969510%28VS.85%29.aspx
    Local Const $DWM_EC_DISABLECOMPOSITION = 0
    Local Const $DWM_EC_ENABLECOMPOSITION = 1
    If $toggle = True Then
        DllCall("dwmapi.dll", "hwnd", "DwmEnableComposition", "uint", $DWM_EC_DISABLECOMPOSITION)
    Else
        DllCall("dwmapi.dll", "hwnd", "DwmEnableComposition", "uint", $DWM_EC_ENABLECOMPOSITION)
    EndIf
EndFunc   ;==>Toggle_AERO_Style_On
Edited by KaFu

Share this post


Link to post
Share on other sites

Good.

Just tip:

at start of Func _WinGetPosEx($hWnd) I would add something like this:

(pseudo code only!)

Func _WinGetPosEx($hWnd)

If @OSType < WIN_VISTA Then Return WinGetPos($hWnd)

If Not _IsAeroEnabled() Then Return WinGetPos($hWnd)

...

Share this post


Link to post
Share on other sites

at start of Func _WinGetPosEx($hWnd) I would add something like this:

Thought about that first too. But then realized (and tested on XP Virtual Machine), that the dllcall will return an error if not successful (like e.g. on XP where the dll does not exist) and then return standard:

If @error Then Return SetError(0, 0, WinGetPos($hWnd))

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