Win10Move() - deceptive WinMove - move window based on what is visible ;)

Post your working scripts, libraries and tools
Coco
Posts: 771
Joined: 29 Sep 2013, 20:37
GitHub: cocobelgica

Win10Move() - deceptive WinMove - move window based on what is visible ;)

19 May 2016, 11:01

A possible solution to the WinMove - Windows 10 thread ;). Untested since I'm not currently on a Windows 10 machine, I might be doing this wrong :facepalm:

Code: Select all

; EXTENDED_FRAME_BOUNDS width is 0 with +Resize
Gui New, +Hwndhwnd ; +Resize
Gui Show, w300 h300

MsgBox

Win10Move("ahk_id " . hwnd, 0, 0)
return
GuiEscape:
GuiClose:
    ExitApp

Win10Move(wintitle, x:="", y:="", w:="", h:="")
{
; should probably check for OS version, a bit lazy right now

    WinGet hwnd, ID, %wintitle% ; WinExist() sets the last found window
    static init := false
    static offset_x, offset_y, offset_w, offset_h
    if (!init) {
    ; you can probably retrieve just one of the coordinates for each RECT structure
    ; since the extended frame width is the all the same but for the purpose of
    ; understanding the function, let's choose verbosity.
        VarSetCapacity(RECT, 16, 0)
        DllCall("GetWindowRect", "Ptr", hwnd, "Ptr", &RECT)
        left   := NumGet(RECT,  0, "Int")
        top    := NumGet(RECT,  4, "Int")
        right  := NumGet(RECT,  8, "Int")
        bottom := NumGet(RECT, 12, "Int")

        VarSetCapacity(EXTENDED_FRAME_BOUNDS, 16, 0)
        DllCall("dwmapi\DwmGetWindowAttribute", "Ptr", hwnd, "UInt", 9, "Ptr", &EXTENDED_FRAME_BOUNDS, "UInt", 16)
        ex_left   := NumGet(EXTENDED_FRAME_BOUNDS,  0, "Int")
        ex_top    := NumGet(EXTENDED_FRAME_BOUNDS,  4, "Int")
        ex_right  := NumGet(EXTENDED_FRAME_BOUNDS,  8, "Int")
        ex_bottom := NumGet(EXTENDED_FRAME_BOUNDS, 12, "Int")

        offset_x := left-ex_left
        offset_y := top-ex_top
        offset_w := (ex_right-ex_left) - (right-left)
        offset_h := (ex_bottom-ex_top) - (bottom-top)
        init := true
    }

    if (x != "")
        x -= offset_x
    if (y != "")
        y -= offset_y
    if (w != "")
        w += offset_w
    if (h != "")
        h += offset_h

    WinMove ahk_id %hwnd%,, %x%, %y%, %w%, %h%
}
User avatar
boiler
Posts: 5239
Joined: 21 Dec 2014, 02:44

Re: Win10Move() - deceptive WinMove - move window based on what is visible ;)

19 May 2016, 13:22

Looks like it's meant to move the window to be so there's no gap when moved to 0,0. It does not do that on my Win10 machine. There's about a 5 to 10 pixel gap from the left edge.
guest3456
Posts: 3109
Joined: 09 Oct 2013, 10:31

Re: Win10Move() - deceptive WinMove - move window based on what is visible ;)

19 May 2016, 13:35

its off by 2 pixels for me

just use the WinGetPosEx() func which already works to get the offsets, and then WinMove accordingly.

this is redundant

just me
Posts: 7107
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Win10Move() - deceptive WinMove - move window based on what is visible ;)

20 May 2016, 01:55

Hi Coco,

coincidentally I've been working on a similar function, too. ;)

Code: Select all

#NoEnv

SnapWindow(hWnd, X := "", Y := "", W := "", H := "") {
   If ((X . Y . W . H) = "")
      Return False
   If !WinExist("ahk_id " . hWnd)
      Return False
   VarSetCapacity(WI, 60, 0) ; WINDOWINFO structure
   NumPut(60, WI, "Uint")
   If !DllCall("GetWindowInfo", "Ptr", hWnd, "Ptr", &WI)
      Return False
   WX := NumGet(WI,  4, "Int")      ; X coordinate of the window
   WY := NumGet(WI,  8, "Int")      ; Y coordinate of the window
   WW := NumGet(WI, 12, "Int") - WX ; width of the window
   WH := NumGet(WI, 16, "Int") - WY ; height of the window
   BW := NumGet(WI, 48, "UInt") - 1 ; border width - 1
   BH := NumGet(WI, 52, "UInt") - 1 ; border height - 1
   X := X <> "" ? X - BW : WX
   Y := Y <> "" ? Y : WY
   W := W <> "" ? W + BW + BW : WW
   H := H <> "" ? H + BH : WH
   Return DllCall("MoveWindow", "Ptr", hWnd, "Int", X, "Int", Y, "Int", W, "Int", H, "UInt", 1)
}

Gui, +hwndHGUI
Gui, Margin, 200, 100
Gui, Add, Button, gMove, MoveIt
Gui, Add, Button, x+10 yp gSnap, SnapIt
Gui, Add, Button, x+10 yp gResize vBtnResize, +Resize
Gui, Show, , SnapIt
Return
GuiClose:
ExitApp
Resize:
GuiControlGet, BtnResize
Gui, %BtnResize%
Gui, Show
GuiControl, , BtnResize, % (BtnResize = "+Resize" ? "-Resize" : "+Resize")
Return
Move:
WinMove, ahk_id %HGUI%, , 0, 0, A_ScreenWidth
Return
Snap:
SnapWindow(HGUI, 0, 0, A_ScreenWidth)
Return
But Windows is still forcing a 1 (?) pixel gap at the right side of a resizable window.
guest3456
Posts: 3109
Joined: 09 Oct 2013, 10:31

Re: Win10Move() - deceptive WinMove - move window based on what is visible ;)

20 May 2016, 10:09

just me wrote:Hi Coco,

coincidentally I've been working on a similar function, too. ;)

Code: Select all

#NoEnv

SnapWindow(hWnd, X := "", Y := "", W := "", H := "") {
   If ((X . Y . W . H) = "")
      Return False
   If !WinExist("ahk_id " . hWnd)
      Return False
   VarSetCapacity(WI, 60, 0) ; WINDOWINFO structure
   NumPut(60, WI, "Uint")
   If !DllCall("GetWindowInfo", "Ptr", hWnd, "Ptr", &WI)
      Return False
   WX := NumGet(WI,  4, "Int")      ; X coordinate of the window
   WY := NumGet(WI,  8, "Int")      ; Y coordinate of the window
   WW := NumGet(WI, 12, "Int") - WX ; width of the window
   WH := NumGet(WI, 16, "Int") - WY ; height of the window
   BW := NumGet(WI, 48, "UInt") - 1 ; border width - 1
   BH := NumGet(WI, 52, "UInt") - 1 ; border height - 1
   X := X <> "" ? X - BW : WX
   Y := Y <> "" ? Y : WY
   W := W <> "" ? W + BW + BW : WW
   H := H <> "" ? H + BH : WH
   Return DllCall("MoveWindow", "Ptr", hWnd, "Int", X, "Int", Y, "Int", W, "Int", H, "UInt", 1)
}

Gui, +hwndHGUI
Gui, Margin, 200, 100
Gui, Add, Button, gMove, MoveIt
Gui, Add, Button, x+10 yp gSnap, SnapIt
Gui, Add, Button, x+10 yp gResize vBtnResize, +Resize
Gui, Show, , SnapIt
Return
GuiClose:
ExitApp
Resize:
GuiControlGet, BtnResize
Gui, %BtnResize%
Gui, Show
GuiControl, , BtnResize, % (BtnResize = "+Resize" ? "-Resize" : "+Resize")
Return
Move:
WinMove, ahk_id %HGUI%, , 0, 0, A_ScreenWidth
Return
Snap:
SnapWindow(HGUI, 0, 0, A_ScreenWidth)
Return
But Windows is still forcing a 1 (?) pixel gap at the right side of a resizable window.
nice alternative, but on Win7, this actually puts the visible borders offscreen.

WinGetPosEx handles it correctly on win7, but it too fails by a few pixels when trying to make the GUI fullscreenwidth on win10

just me
Posts: 7107
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Win10Move() - deceptive WinMove - move window based on what is visible ;)

20 May 2016, 11:13

Interesting, what does the MsgBox show on Win 7?

Code: Select all

#NoEnv
Gui New, +HwndHGUI +Resize
Gui Show, w300 h300, Test

; DWMWA_EXTENDED_FRAME_BOUNDS = 9
VarSetCapacity(RC, 16, 0)
DllCall("Dwmapi.dll\DwmGetWindowAttribute", "Ptr", HGUI, "UInt", 9, "Ptr", &RC, "UInt", 16)
FL := NumGet(RC, 0, "Int"), FT := NumGet(RC, 4, "Int"), FR := NumGet(RC, 8, "Int"), FB := NumGet(RC, 12, "Int")
DllCall("GetWindowRect", "Ptr", HGUI, "Ptr", &RC)
WL := NumGet(RC, 0, "Int"), WT := NumGet(RC, 4, "Int"), WR := NumGet(RC, 8, "Int"), WB := NumGet(RC, 12, "Int")
VarSetCapacity(WI, 60, 0) ; WINDOWINFO structure
NumPut(60, WI, "Uint")
DllCall("GetWindowInfo", "Ptr", HGUI, "Ptr", &WI)
BW := NumGet(WI, 48, "UInt"), BH := NumGet(WI, 52, "UInt")
MsgBox, 0, Bounds
      , ExtFrame Bounds:`n%FL% - %FT% - %FR% - %FB%`n`nWindow Bounds:`n%WL% - %WT% - %WR% - %WB%`n`nBorders: %BW% - %BH%

ExitApp
just me
Posts: 7107
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Win10Move() - deceptive WinMove - move window based on what is visible ;)

20 May 2016, 11:58

You mean the FL / WL etc values?
just me
Posts: 7107
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Win10Move() - deceptive WinMove - move window based on what is visible ;)

21 May 2016, 03:49

Well, so how behaves this version on Win 7?

Code: Select all

#NoEnv

WinSnap(WinTitle, X := "", Y := "", W := "", H := "") {
   If ((X . Y . W . H) = "") ;
      Return False
   WinGet, hWnd, ID, %WinTitle% ; taken from Coco's version
   If !(hWnd)
      Return False
   DL := DT := DR := DB := 0
   VarSetCapacity(RC, 16, 0)
   DllCall("GetWindowRect", "Ptr", hWnd, "Ptr", &RC)
   WL := NumGet(RC, 0, "Int"), WT := NumGet(RC, 4, "Int"), WR := NumGet(RC, 8, "Int"), WB := NumGet(RC, 12, "Int")
   If (DllCall("Dwmapi.dll\DwmGetWindowAttribute", "Ptr", hWnd, "UInt", 9, "Ptr", &RC, "UInt", 16) = 0) { ; S_OK = 0
      FL := NumGet(RC, 0, "Int"), FT := NumGet(RC, 4, "Int"), FR := NumGet(RC, 8, "Int"), FB := NumGet(RC, 12, "Int")
      DL := WL - FL, DT := WT - FT, DR := WR - FR, DB := WB - FB
   }
   X := X <> "" ? X + DL : WL, Y := Y <> "" ? Y + DT : WT
   W := W <> "" ? W - DL + DR : WR - WL - 1, H := H <> "" ? H - DT + DB - 1: WB - WT
   Return DllCall("MoveWindow", "Ptr", hWnd, "Int", X, "Int", Y, "Int", W, "Int", H, "UInt", 1)
}

SysGet, MWA, MonitorWorkArea
MH := MWABottom - MWATop

Gui, +hwndHGUI
Gui, Margin, 200, 100
Gui, Add, Button, gMove, MoveIt
Gui, Add, Button, x+10 yp gSnap, SnapIt
Gui, Add, Button, x+10 yp gResize vBtnResize, +Resize
Gui, Add, StatusBar
Gui, Show, , SnapIt
Return

GuiClose:
ExitApp
Resize:
GuiControlGet, BtnResize
Gui, %BtnResize%
Gui, Show
GuiControl, , BtnResize, % (BtnResize = "+Resize" ? "-Resize" : "+Resize")
Return
Move:
WinMove, ahk_id %HGUI%, , 0, 0, A_ScreenWidth, MH
Return
Snap:
WinSnap("ahk_id" . HGUI, 0, 0, A_ScreenWidth, MH)
Return

/*
; DWMWA_EXTENDED_FRAME_BOUNDS = 9
VarSetCapacity(RC, 16, 0)
DllCall("Dwmapi.dll\DwmGetWindowAttribute", "Ptr", HGUI, "UInt", 9, "Ptr", &RC, "UInt", 16)
FL := NumGet(RC, 0, "Int"), FT := NumGet(RC, 4, "Int"), FR := NumGet(RC, 8, "Int"), FB := NumGet(RC, 12, "Int")
DllCall("GetWindowRect", "Ptr", HGUI, "Ptr", &RC)
WL := NumGet(RC, 0, "Int"), WT := NumGet(RC, 4, "Int"), WR := NumGet(RC, 8, "Int"), WB := NumGet(RC, 12, "Int")
MsgBox, 0, SnapWindow, ExtFrame Bounds:`n%FL% - %FT% - %FR% - %FB%`n`nWindow Bounds:`n%WL% - %WT% - %WR% - %WB%
*/
Related to WinGetPosEx():
I think that this line is wrong for Win 10:

Code: Select all

    NumPut(Offset_Y:=(Height-GWR_Height)//2,RECTPlus,20,"Int")
guest3456
Posts: 3109
Joined: 09 Oct 2013, 10:31

Re: Win10Move() - deceptive WinMove - move window based on what is visible ;)

21 May 2016, 21:37

just me wrote:Well, so how behaves this version on Win 7?
much better. but with the +resize ends up like 1 or 2 pixels shorter in height compared with WinMove which seems to take up the full height

just me
Posts: 7107
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Win10Move() - deceptive WinMove - move window based on what is visible ;)

22 May 2016, 01:21

guest3456 wrote:... but with the +resize ends up like 1 or 2 pixels shorter in height compared with WinMove which seems to take up the full height
As you stated, the function shouldn't be needed at all for resizable windows on Win 7, because all frame gaps are zero. As is, it subtracts 1 pixel from the calculated height, because otherwise the bottom sizing border is completely covered by the taskbar on Win 10 if you set the height of the window to the height of the 'MonitorWorkArea'.

Return to “Scripts and Functions”

Who is online

Users browsing this forum: Splongus and 175 guests