-
Notifications
You must be signed in to change notification settings - Fork 41
/
WinGetPosEx.ahk
161 lines (152 loc) · 6.45 KB
/
WinGetPosEx.ahk
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
;------------------------------
;
; Function: WinGetPosEx
;
; Original author: jballi (https://autohotkey.com/boards/viewtopic.php?t=3392)
;
; Update author: RiseUp
;
; 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_Left, Offset_Top, Offset_Right, Offset_Bottom - Output variables.
; [Optional] 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.
;
; 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 16 bytes contain the offsets (4-byte integer for each of left,
; top, right, and bottom offsets).
;
; Also if successful (and if defined), the output variables (X, Y, Width,
; Height, Offset_Left, Offset_Top, Offset_Right, and Offset_Bottom) are
; updated. See the *Parameters* section for more more information.
;
; If not successful, FALSE is returned.
;
; Requirement:
;
; Windows 2000+
;
; Remarks, Observations, and Changes:
;
; * 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, the 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.
;
; * 20150906: The "dwmapi\DwmGetWindowAttribute" function can return odd errors
; if DWM is not enabled. One error I've discovered is a return code of
; 0x80070006 with a last error code of 6, i.e. ERROR_INVALID_HANDLE or "The
; handle is invalid." To keep the function operational during this types of
; conditions, the function has been modified to assume that all unexpected
; return codes mean that DWM is not available and continue to process without
; it. When DWM is a possibility (i.e. Vista+), a developer-friendly messsage
; will be dumped to the debugger when these errors occur.
;
; * 20171126: (RiseUp) Changed function to return 4 offset values instead of 2.
; Windows 10 has different offsets for the top versus the bottom of a window,
; so this function no longer assumes a symmetrical offset border around a
; given window.
;
; Credit:
;
; Idea and some code from *KaFu* (AutoIt forum)
;
;-------------------------------------------------------------------------------
WinGetPosEx(hWindow,ByRef X="",ByRef Y="",ByRef Width="",ByRef Height=""
,ByRef Offset_Left="",ByRef Offset_Top=""
,ByRef Offset_Right="",ByRef Offset_Bottom="")
{
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 GetWindowRect functions.
VarSetCapacity(RECTPlus,32,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)
{
;-- Do nothing else (for now)
}
else
outputdebug,
(ltrim join`s
Function: %A_ThisFunc% -
Unknown error calling "dwmapi\DwmGetWindowAttribute".
RC=%DWMRC%,
ErrorLevel=%ErrorLevel%,
A_LastError=%A_LastError%.
"GetWindowRect" used instead.
)
;-- Collect the position and size from "GetWindowRect"
DllCall("GetWindowRect",PtrType,hWindow,PtrType,&RECTPlus)
}
;-- 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_Left := 0
Offset_Top := 0
Offset_Right := 0
Offset_Bottom := 0
;-- If DWM is not used (older than Vista or DWM not enabled), we're done
if (DWMRC<>S_OK)
Return &RECTPlus
;-- Collect dimensions via GetWindowRect
VarSetCapacity(RECT,16,0)
DllCall("GetWindowRect",PtrType,hWindow,PtrType,&RECT)
GWR_Left := NumGet(RECT,0,"Int")
GWR_Top := NumGet(RECT,4,"Int")
GWR_Right := NumGet(RECT,8,"Int")
GWR_Bottom := NumGet(RECT,12,"Int")
;-- Calculate offsets and update output variables
NumPut(Offset_Left := Left - GWR_Left,RECTPlus,16,"Int")
NumPut(Offset_Top := Top - GWR_Top ,RECTPlus,20,"Int")
NumPut(Offset_Right := GWR_Right - Right ,RECTPlus,24,"Int")
NumPut(Offset_Bottom := GWR_Bottom - Bottom ,RECTPlus,28,"Int")
Return &RECTPlus
}