[Function] WinGetPosEx v0.1 (Preview) - Get the real position and size of a window

Post your working scripts, libraries and tools for AHK v1.1 and older
Skrell
Posts: 302
Joined: 23 Jan 2014, 12:05

Re: [Function] WinGetPosEx v0.0.2 - Get the real size of win

30 May 2014, 08:29

Drugwash wrote:Having just read the comments without looking at the code, I was wondering if for Skrell's situation on XP a call to GetWindowRgnBox() might help in getting the correct width and height of a window. Top-left corner should be calculated separately though, since the API returns region coordinates relative to upper-left corner of the window, not relative to the screen. If only width and height are required, this can be simply done as below:

Code: Select all

VarSetCapacity(RECT, 16, 0)
DllCall("GetWindowRgnBox", Ptr, hwnd, Ptr, &RECT)
w := NumGet(RECT, 8, "Int")-NumGet(RECT, 0, "Int"), h := NumGet(RECT, 12, "Int")-NumGet(RECT, 4, "Int")
Where is the WinGetPosEx code would i put this code? I'd love to try it !! :)
User avatar
Drugwash
Posts: 850
Joined: 29 May 2014, 21:07
Location: Ploieşti, Romania
Contact:

Re: [Function] WinGetPosEx v0.0.2 - Get the real size of win

30 May 2014, 10:06

I suppose it could go in place of GetWindowRect(), somewhere. I've just quickly glanced at the code, after posting the above, to make sure I didn't say something redundant, so can't pinpoint the exact location.
But you could easily try it standalone; just get the window handle (such as hwnd := WinExist() or whatever) and pass it to the code above - if you get the correct results, then you can tinker with the main script in the topic.
Part of my AHK work can be found here.
Skrell
Posts: 302
Joined: 23 Jan 2014, 12:05

Re: [Function] WinGetPosEx v0.0.2 - Get the real size of win

31 May 2014, 18:09

Drugwash wrote:I suppose it could go in place of GetWindowRect(), somewhere. I've just quickly glanced at the code, after posting the above, to make sure I didn't say something redundant, so can't pinpoint the exact location.
But you could easily try it standalone; just get the window handle (such as hwnd := WinExist() or whatever) and pass it to the code above - if you get the correct results, then you can tinker with the main script in the topic.
How is your code different than line 89 in the WinGetPosEx function?

Code: Select all

  if (DWMRC<>S_OK)
        if ErrorLevel in -3,-4  ;-- Dll or function not found (older than Vista)
            DllCall("GetWindowRect",PtrType,hWindow,PtrType,&RECTPlus)
         else
I did notice that there was no VarSetCapacity(RECT, 16, 0) in the original function. Could this make that much of a difference?
User avatar
Drugwash
Posts: 850
Joined: 29 May 2014, 21:07
Location: Ploieşti, Romania
Contact:

Re: [Function] WinGetPosEx v0.0.2 - Get the real size of win

31 May 2014, 18:20

GetWindowRgnBox() retrieves the bounding rectangle of the visible part of a window, while GetWindowRect() retrieves the coordinates for the entire window.

Since you have invisible parts of the window hidden through 'magic pink' (or any other method such as setting a custom window region), you should get different results and those retrieved by GetWindowRgnBox() should be accurate, at least theoretically.
Please note I have not tested this with such windows, it's only theory so you may performs some separate tests and if results are correct then you may modify the main script.

As for VarSetCapacity, the original script uses RectPlus to retrieve coordinates so you may use the same variable and omit setting capacity for a new RECT. The code I posted should be able to run as standalone, if you provide it with a window handle.
Part of my AHK work can be found here.
Skrell
Posts: 302
Joined: 23 Jan 2014, 12:05

Re: [Function] WinGetPosEx v0.0.2 - Get the real size of win

31 May 2014, 18:40

Drugwash wrote:GetWindowRgnBox() retrieves the bounding rectangle of the visible part of a window, while GetWindowRect() retrieves the coordinates for the entire window.

Since you have invisible parts of the window hidden through 'magic pink' (or any other method such as setting a custom window region), you should get different results and those retrieved by GetWindowRgnBox() should be accurate, at least theoretically.
Please note I have not tested this with such windows, it's only theory so you may performs some separate tests and if results are correct then you may modify the main script.

As for VarSetCapacity, the original script uses RectPlus to retrieve coordinates so you may use the same variable and omit setting capacity for a new RECT. The code I posted should be able to run as standalone, if you provide it with a window handle.
OK just tried it and the window dimensions are in fact more accurate!!! The BAD news is that it doesn't seem to give me accurate values for the x and y of a window...i'm wondering if the values it returns are from point 0,0 on the screen? If you can fix this it will be perfect!
User avatar
Drugwash
Posts: 850
Joined: 29 May 2014, 21:07
Location: Ploieşti, Romania
Contact:

Re: [Function] WinGetPosEx v0.0.2 - Get the real size of win

31 May 2014, 19:29

If you read carefully my first post here, you'll see I already mentioned the top-left corner coordinates retrieved by this function are relative to the top-left corner of the entire window, not relative to the screen. This is how it's been designed by MS.
To get the actual coordinates of the top-left corner you'll have to use something like ClientToScreen():

Code: Select all

VarSetCapacity(RECT, 16, 0)
DllCall("GetWindowRgnBox", Ptr, hwnd, Ptr, &RECT)
w := NumGet(RECT, 8, "Int")-NumGet(RECT, 0, "Int"), h := NumGet(RECT, 12, "Int")-NumGet(RECT, 4, "Int")
DllCall("ClientToScreen", Ptr, hwnd, Ptr, &RECT)
x := NumGet(RECT, 0, "Int"), y := NumGet(RECT, 4, "Int")
Theoretically this should be it. Please test.
Part of my AHK work can be found here.
Skrell
Posts: 302
Joined: 23 Jan 2014, 12:05

Re: [Function] WinGetPosEx v0.0.2 - Get the real size of win

01 Jun 2014, 10:53

jballi,
with Drugwash's help i've made some changes to your v0.2 release that i think would make it better for xp users while still being functional for Vista++ . Here is my code, please consider adding this for v0.3. Note that the offset values take on a different meaning for XP users and basically give the user the values for how many pixels of a window are considered the transparent "pink" region. The user can than uses these offsets however they want in their functions.

Code: Select all

;------------------------------
;
; Function: WinGetPosEx
;
; Description:
;
;   Gets the position, size, and offset of a window. See the *Remarks* section
;   for more information.
;
; Parameters:
;
;   hWindow - Handle to the window.
;
;   X, Y, Width, Height - Output variables. [Optional]  If defined, these
;       variables contain the coordinates of the window relative to the
;       upper-left corner of the screen (X and Y), and the Width and Height of
;       the window.
;
;   Offset_X, Offset_Y - Output variables. [Optional] [Vista++]Offset, in pixels, of the
;       actual position of the window versus the position of the window as
;       reported by GetWindowRect.  If moving the window to specific
;       coordinates, add these offset values to the appropriate coordinate
;       (X and/or Y) to reflect the true size of the window.
;       [XP] the offset values take on a different meaning for XP users and basically give 
;       the user the values for how many pixels of a window are considered the transparent 
;       "pink" region.  The user can than uses these offsets however they want in their functions.
;
; Returns:
;
;   If successful, the address of a RECTPlus structure is returned.  The first
;   16 bytes contains a RECT structure that contains the dimensions of the
;   bounding rectangle of the specified window.  The dimensions are given in
;   screen coordinates that are relative to the upper-left corner of the screen.
;   The next 8 bytes contain of X and Y offsets (4-byte integer for X and 4-byte
;   integer for Y).
;
;   Also if successful (and if defined), the output variables (X, Y, Width,
;   Height, Offset_X, and Offset_Y) are updated.  See the *Parameters* section
;   for more more information.
;
;   If not successful, FALSE is returned.
;
; Requirement:
;
;   Windows 2000+
;
; Remarks:
;
; * Starting with Windows Vista, Microsoft includes the Desktop Window Manager
;   (DWM) along with Aero-based themes that use DWM.  Aero themes provide new
;   features like a translucent glass design with subtle window animations.
;   Unfortunately, DWM doesn't always conform to the OS rules for size and
;   positioning of windows. If using an Aero theme, many of the windows are
;   actually larger than reported by Windows when using standard commands (Ex:
;   WinGetPos, GetWindowRect, etc.) and because of that, are not positioned
;   correctly when using standard commands (Ex: gui Show, WinMove, etc.)
;
;   This function was created to 1) identify the true position and size of all
;   windows regardless of the window attributes, desktop theme, or version of
;   Windows and to 2) identify the appropriate offset that is needed to position
;   the window if the window is a different size than reported.
;
; * The true size, position, and offset of a window cannot be determined until
;   the window has been rendered.  See the example script for an example of how
;   to use this function to position a new window.
;
; Credit:
;
;   Idea and some code from *KaFu* (AutoIt forum)
;
;-------------------------------------------------------------------------------
WinGetPosEx(hWindow,ByRef X="",ByRef Y="",ByRef Width="",ByRef Height="",ByRef Offset_X="",ByRef Offset_Y="")
    {
    Static Dummy5693
          ,RECTPlus
          ,S_OK:=0x0
          ,DWMWA_EXTENDED_FRAME_BOUNDS:=9

    ;-- Workaround for AutoHotkey Basic
    PtrType:=(A_PtrSize=8) ? "Ptr":"UInt"

    ;-- Get the window's dimensions
    ;   Note: Only the first 16 bytes of the RECTPlus structure are used by the
    ;   DwmGetWindowAttribute and the GetWindowRect functions.
    VarSetCapacity(RECTPlus,24,0)
    DWMRC:=DllCall("dwmapi\DwmGetWindowAttribute"
        ,PtrType,hWindow                                ;-- hwnd
        ,"UInt",DWMWA_EXTENDED_FRAME_BOUNDS             ;-- dwAttribute
        ,PtrType,&RECTPlus                              ;-- pvAttribute
        ,"UInt",16)                                     ;-- cbAttribute

    if (DWMRC<>S_OK)
        if ErrorLevel in -3,-4  ;-- Dll or function not found (older than Vista)
        {
            VarSetCapacity(RECT,16,0)
            DllCall("GetWindowRgnBox",PtrType,hWindow,PtrType,&RECT)
            DllCall("GetWindowRect",PtrType,hWindow,PtrType,&RECTPlus)
        } 
         else
            {
            outputdebug,
               (ltrim join`s
                Function: %A_ThisFunc% -
                Unknown error calling the "dwmapi\DwmGetWindowAttribute"
                function. RC=%DWMRC%,
                ErrorLevel=%ErrorLevel%,
                A_LastError=%A_LastError%
               )

            Return False
            }

    ;-- Populate the output variables
    X:=Left :=NumGet(RECTPlus,0,"Int")
    Y:=Top  :=NumGet(RECTPlus,4,"Int")
    Right   :=NumGet(RECTPlus,8,"Int")
    Bottom  :=NumGet(RECTPlus,12,"Int")
    Width   :=Right-Left
    Height  :=Bottom-Top
    OffSet_X:=NumGet(RECT,0,"Int")
    OffSet_Y:=NumGet(RECT,4,"Int")

    ;-- If DWM is not used (older than Vista), we're done
    if (DWMRC<>S_OK)
	{
	    ;-- Calculate offsets and update output variables
    	NumPut(Offset_X,RECTPlus,16,"Int")
    	NumPut(Offset_Y,RECTPlus,20,"Int")
        Return &RECTPlus
	}
    ;-- Collect dimensions via GetWindowRect
    VarSetCapacity(RECT,16,0)
    DllCall("GetWindowRect",PtrType,hWindow,PtrType,&RECT)
    GWR_Width :=NumGet(RECT,8,"Int")-NumGet(RECT,0,"Int")
        ;-- Right minus Left
    GWR_Height:=NumGet(RECT,12,"Int")-NumGet(RECT,4,"Int")
        ;-- Bottom minus Top

    ;-- Calculate offsets and update output variables
    NumPut(Offset_X:=(Width-GWR_Width)//2,RECTPlus,16,"Int")
    NumPut(Offset_Y:=(Height-GWR_Height)//2,RECTPlus,20,"Int")
    Return &RECTPlus
    }
User avatar
jballi
Posts: 723
Joined: 29 Sep 2013, 17:34

Re: [Function] WinGetPosEx v0.0.2 - Get the real size of win

03 Jun 2014, 20:45

Skrell,

This is just a summary of our offline discussion.

Since your version of the function changes the definition of the offset variables (Offset_X and Offset_Y) when run on a Windows XP box, it's use in scripts that can run in multiple OS environments (including Windows XP) can be problematic. However, since your version may provide value to some Windows XP developers, I've included a link to it on the first post. Thank you for your feedback.
User avatar
jballi
Posts: 723
Joined: 29 Sep 2013, 17:34

Re: [Function] WinGetPosEx v0.1 (Preview) - Get the real size and position of a window

06 Sep 2015, 04:06

v0.1 (Preview)
Bug fix to keep the function operational if DWM is not enabled. See the function documentation for more information.

If you find a bug or idiosyncrasy, please let me know about it and be sure to include what version of Windows and version of AutoHotkey you are using.

Thanks for your help.
jiyongred
Posts: 4
Joined: 28 Dec 2015, 02:52
Contact:

Re: [Function] WinGetPosEx v0.1 (Preview) - Get the real position and size of a window

06 Jan 2016, 02:39

@jballi

I've been using this to get the offset values and it's been working great. Recently, however, as I've been playing with different monitor configurations (number, resolution, DPI) I noticed that the offset is not correct when the window is on a monitor with DPI scaling (I'm running Windows 10 build 10586, AutoHotkey 1.1.22.09).

In Windows 10, separate monitors can have separate DPI and that is where I first noticed the issue but I also see it with both monitors set to (for example) 125% and in 8.1 with DPI set to 125%.

To take DPI scaling into account, I've replaced lines 140 to the end of the method (ie, the last three lines of the method) with the following. (I commented the changes so I won't repeat them here.) I've tested this on Windows 10 and Windows 8.1 using single and multiple monitors and with various DPI settings. I haven't tested on Windows 7 yet but will do that in the next couple days. [Edit: Tested on Windows 7 and it works there, as well.]

Please take a look and let me know what you think. DPI related stuff is not what I enjoy and I may be missing something but in the testing I've done so far this seems to work.

Jiyongred

Code: Select all

    ;-- Adjust width and height for offset calculations if DPI is in play
    ;   See https://msdn.microsoft.com/en-us/library/windows/desktop/dn280512(v=vs.85).aspx
    ;   The current version of AutoHotkey is PROCESS_SYSTEM_DPI_AWARE (contains "<dpiAware>true</dpiAware>" in its manifest)
    ;   DwmGetWindowAttribute returns DPI scaled sizes
    ;   GetWindowRect does not
    ; get monitor handle where the window is at so we can get the monitor name
    hMonitor := DllCall("MonitorFromRect",PtrType,&RECT,UInt,2) ; MONITOR_DEFAULTTONEAREST = 2 (Returns a handle to the display monitor that is nearest to the rectangle)
    ; get monitor name so we can get a handle to the monitor device context
    VarSetCapacity(MONITORINFOEX,104)
    NumPut(104,MONITORINFOEX)
    DllCall("GetMonitorInfo",PtrType,hMonitor,PtrType,&MONITORINFOEX)
    monitorName := StrGet(&MONITORINFOEX+40)
    ; get handle to monitor device context so we can get the dpi adjusted and actual screen sizes
    hdc := DllCall("CreateDC",Str,monitorName,PtrType,0,PtrType,0,PtrType,0)
    ; get dpi adjusted and actual screen sizes
    dpiAdjustedScreenHeight := DllCall("GetDeviceCaps",PtrType,hdc,Int,10) ; VERTRES = 10 (Height, in raster lines, of the screen)
    actualScreenHeight := DllCall("GetDeviceCaps",PtrType,hdc,Int,117) ; DESKTOPVERTRES = 117
    ; delete hdc as instructed
    DllCall("DeleteDC",PtrType,hdc)
    ; calculate dpi adjusted width and height
    dpiFactor := actualScreenHeight/dpiAdjustedScreenHeight ; this will be 1.0 if DPI is 100%
    dpiAdjusted_Width := Ceil(Width/dpiFactor)
    dpiAdjusted_Height := Ceil(Height/dpiFactor)

    ;-- Calculate offsets and update output variables
    NumPut(Offset_X:=(dpiAdjusted_Width-GWR_Width)//2,RECTPlus,16,"Int")
    NumPut(Offset_Y:=(dpiAdjusted_Height-GWR_Height)//2,RECTPlus,20,"Int")
    Return &RECTPlus
Prescription
Posts: 7
Joined: 15 Feb 2016, 15:11

Re: [Function] WinGetPosEx v0.1 (Preview) - Get the real position and size of a window

17 Feb 2016, 09:14

Hi, I'm a beginner and new here. I was asked by the Ask-for-Help-ers, at the risk of asking become recursive, to re-post within this thread my question.

I Googled and read through many AHK posts about why WinMove does not work the way it used to -- intuitively and with no fuss -- on more recent, crapified versions of Windows due to "Aero Glass" and its invisible fattening of window sizes.

For example, with XP and two identical monitors in place, the simple Winkey-3 macro below would move/resize the current window (say, a FIrefox window) to fill the first half of the second monitor:

Code: Select all

#3::
WinMove,A,, %a_ScreenWidth%,0,(a_ScreenWidth/2)+a_ScreenWidth, %A_ScreenHeight%
return
Now, in the garbage called "Windows 10" that I am forced to use at work, the above code renders the window misplaced, with it positioned on the second monitor approximately 1/8" inward from the left and shrunken approximately 1/8" upward from the bottom. I understand that all of this is due to the always-on-in-Garbage-10 "Desktop Window Manager" and its visual stench:

Image
A Garbage-10 window capture catches what appear to be three transparent edges of my second monitor's 0,0-WinMoved window


As you can see in the above image, the desktop background shows through, and the Firefox window looks misplaced, not at 0,0.

How do I fix that? I read through WinGetPosEx, but I do not know how to adapt it to my simple macro.

P.S. I think that, for ordinary citizens, a simple switch (such as "/AERO," which could be served by WinGetPosEx) should be added to WinMove (and anything else that needs it), to fix the command's broken simplicity. If documented and explained under WinMove in the desktop help file, either /AERO or WinGetPosEx could save a lot of time and pain.
User avatar
Drugwash
Posts: 850
Joined: 29 May 2014, 21:07
Location: Ploieşti, Romania
Contact:

Re: [Function] WinGetPosEx v0.1 (Preview) - Get the real position and size of a window

17 Feb 2016, 10:58

Refer your boss to this forum topic: http://www.msfn.org/board/topic/174208- ... pressions/
Tell him/her to read it thoroughly.
Windows10 is not an operating system, it's a spyware system.
The choice is yours!
Part of my AHK work can be found here.
Prescription
Posts: 7
Joined: 15 Feb 2016, 15:11

Re: [Function] WinGetPosEx v0.1 (Preview) - Get the real position and size of a window

18 Feb 2016, 09:01

I have shown him several excellent articles about Garbage 10's spyware functionality, and he understands the issue, but the committee of untouchables who signed our major contracts bought into the extortion of M$'s Software Assurance and scare tactics, i.e., legal exposure if the OS is not updated to the very latest. Apparently, the signatories prefer built-in to drive-by espionage.
User avatar
Drugwash
Posts: 850
Joined: 29 May 2014, 21:07
Location: Ploieşti, Romania
Contact:

Re: [Function] WinGetPosEx v0.1 (Preview) - Get the real position and size of a window

18 Feb 2016, 12:19

Too bad then. :(

Wish I could help but there isn't (and never will be) any W10 machine near me to test possible changes to the function.
Hopefully someone else here would chime in.
Good luck!
Part of my AHK work can be found here.
Skrell
Posts: 302
Joined: 23 Jan 2014, 12:05

Re: [Function] WinGetPosEx v0.1 (Preview) - Get the real position and size of a window

18 Feb 2016, 13:07

Drugwash wrote:Too bad then. :(

Wish I could help but there isn't (and never will be) any W10 machine near me to test possible changes to the function.
Hopefully someone else here would chime in.
Good luck!
There are like 63 pages of posts at the link you posted...can you perhaps highlight a few of the more meaningful posts that are particularly damning to W10?
Prescription
Posts: 7
Joined: 15 Feb 2016, 15:11

Re: [Function] WinGetPosEx v0.1 (Preview) - Get the real position and size of a window

18 Feb 2016, 13:20

Drugwash wrote:Too bad then. :(

Wish I could help but there isn't (and never will be) any W10 machine near me to test possible changes to the function.
Hopefully someone else here would chime in.
Good luck!
I came to Garbage 10 from XP, so, I skipped over still-could-turn-it-off Aero in Windows 7. I presume that transparent-edge windows rendered by Aero under Windows 7 cause the same problem with WinMove that I am trying to work around.
User avatar
Drugwash
Posts: 850
Joined: 29 May 2014, 21:07
Location: Ploieşti, Romania
Contact:

Re: [Function] WinGetPosEx v0.1 (Preview) - Get the real position and size of a window

18 Feb 2016, 13:38

@ Skrell: There are many comments that simply link to articles posted on various sites, quoting them partly. There are many reports of unwanted "undoings" after installing updates, large amount of telemetry data sent over to M$ that cannot be turned off, large number of M$ servers that are being contacted continuously and so on. I couldn't pinpoint specific comments, there's just too many and it's an ongoing discussion.

@ Prescription: I'm still on 98SE with an XP only for the USB GPRS modem connection (which should soon be replaced by a Linux machine). I haven't looked at the function in a long time, dunno if the changes I suggested some time ago regarding GetWindowRect() have been implemented. Have a look at the pieces of code above, see if you can patch something in to do the job. Maybe W10 needs the original GetWindowRgnBox() instead of GetWindowRect() when Aero is not enabled (there's an Aero project for W10 at the MSFN board).
Part of my AHK work can be found here.
guest3456
Posts: 3454
Joined: 09 Oct 2013, 10:31

Re: [Function] WinGetPosEx v0.1 (Preview) - Get the real position and size of a window

25 Feb 2016, 18:48

Prescription wrote: Now, in the garbage called "Windows 10" that I am forced to use at work, the above code renders the window misplaced, with it positioned on the second monitor approximately 1/8" inward from the left and shrunken approximately 1/8" upward from the bottom. I understand that all of this is due to the always-on-in-Garbage-10 "Desktop Window Manager" and its visual stench:

http://imgup.io/images/2016/02/16/e25bb ... 27662e.png

A Garbage-10 window capture catches what appear to be three transparent edges of my second monitor's 0,0-WinMoved window


As you can see in the above image, the desktop background shows through, and the Firefox window looks misplaced, not at 0,0.
I'm noticing the same problem on Win10

The example script from the first post seems to work

FELITH
Posts: 2
Joined: 27 Jun 2018, 23:01

Re: [Function] WinGetPosEx v0.1 (Preview) - Get the real position and size of a window

27 Jun 2018, 23:29

Hi I just got onto scripting the AutoHotkey and found out that AutoHotkey's GetWinPos doesn't give the real size of the window. not have even coordmode for this function.
So I search about this and found this thread pretty excited.. but not for long xD coz after I try the function it seems not to be work with the game that I'm scripting on which it need 16-bit color depth to be set. so I'm stuck now xD
Spoiler
if you could update the function I would be very grateful
guest3456
Posts: 3454
Joined: 09 Oct 2013, 10:31

Re: [Function] WinGetPosEx v0.1 (Preview) - Get the real position and size of a window

28 Jun 2018, 23:11

FELITH wrote:Hi I just got onto scripting the AutoHotkey and found out that AutoHotkey's GetWinPos doesn't give the real size of the window. not have even coordmode for this function.
So I search about this and found this thread pretty excited.. but not for long xD coz after I try the function it seems not to be work with the game that I'm scripting on which it need 16-bit color depth to be set. so I'm stuck now xD
Spoiler
if you could update the function I would be very grateful
how do you know it doesn't work? downloading the screenshot and opening it shows 806x628 w/h


Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: IfThenElse and 145 guests