Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Window System Menu Manipulator Library v2.0


  • Please log in to reply
8 replies to this topic
HuBa
  • Members
  • 175 posts
  • Last active: Feb 13 2012 09:51 AM
  • Joined: 24 Feb 2007
Few months ago I was wondering how can I prevent a window from accidental closing.
And now I needed a solution to prevent from moving, resizing (unmovable, anchored window).

The suggested solution is simple: removing menu items from window's SystemMenu by deleting the last 2 menu item in menu list. (See also here)

This will surely solve the problem but it's not as elegant as it should be, because some window appends additional commands to the systemmenu. So removing by menu position is not the best idea.

Fortunately there is another way: removing by system command ID.
SystemCommand IDs don't depend on position so they allow more flexible operation.

After implementing the close/move/resize methods, I added other functions too (minimize/maximize/restore/separatorline).
You can use this library by inserting #include WinSysMenuAPI.ahk into your script.

The functions can be used on the script's own Gui window too:
Gui +LastFoundExist  ; Set the GUI window as the last found
GUIhWnd := WinExist()  ; Get last found window handle
DisableWindowMoving(GUIhWnd)  ; Prevent window from moving
You can always restore the original menu by calling RevertSystemMenu() function.

; WinSysMenuAPI.ahk - Window System Menu Manipulator Library
;
; Functions to remove or reenable window managing menu items and commands.
;
; Example:
;   DisableWindowClosing(WinExist(ahk_class TTOTAL_CMD))
;   This will prevent closing Total Commander by mouse, but you can still close it with Alt+F4.
;
; If you call a function without the hWnd parameter,
; it will be performed on the active window.
;
; The functions can be used on the script's own Gui window too:
;   Gui +LastFoundExist  ; Set the GUI window as the last found
;   GUIhWnd := WinExist()  ; Get last found window handle
;   DisableWindowMoving(GUIhWnd)  ; Prevent window from moving
;
; You can always restore the original menu by calling RevertSystemMenu() function.
;
; Tested with AutoHotkey 1.0.47.04
;
; Created by HuBa
; Contact: http://www.autohotkey.com/forum/profile.php?mode=viewprofile&u=4693
;
; Discussion forum: http://www.autohotkey.com/forum/topic19303.html
;
; For system command constants see: http://source.winehq.org/source/include/winuser.h

GetSystemMenu(ByRef hWnd, Revert = False)  ; Get system menu handle
{
  hWnd := hWnd ? hWnd : WinExist("A")  ; Active window handle
  Return DllCall("GetSystemMenu", "UInt", hWnd, "UInt", Revert)
}

DrawMenuBar(hWnd)  ; Internal function: this is needed to apply menu changes
{
  Return DllCall("DrawMenuBar", "UInt", hWnd)
}

RevertSystemMenu(hWnd = "")  ; Restores all removed menu items
{
  Return DrawMenuBar(GetSystemMenu(hWnd, True))  ; Revert system menu
}


RemoveMenu(hWnd, Position, Flags = 0)  ; MF_BYCOMMAND = 0x0000
{
  DllCall("RemoveMenu", "UInt", GetSystemMenu(hWnd), "UInt", Position, "UInt", Flags)
  Return DrawMenuBar(hWnd)
}

DeleteWindowResizing(hWnd = "") {
  Return RemoveMenu(hWnd, 0xF000)  ; SC_SIZE = 0xF000
}

DeleteWindowMoving(hWnd = "") {
  Return RemoveMenu(hWnd, 0xF010)  ; SC_MOVE = 0xF010
}

DeleteWindowMinimizing(hWnd = "") {
  Return RemoveMenu(hWnd, 0xF020)  ; SC_MINIMIZE = 0xF020
}

DeleteWindowMaximizing(hWnd = "") {
  Return RemoveMenu(hWnd, 0xF030)  ; SC_MAXIMIZE = 0xF030
}

DeleteWindowArranging(hWnd = "") {
  Return RemoveMenu(hWnd, 0xF110)  ; SC_ARRANGE = 0xF110
}

DeleteWindowRestoring(hWnd = "") {
  Return RemoveMenu(hWnd, 0xF120)  ; SC_RESTORE = 0xF120
}

DeleteWindowClosing(hWnd = "") {
  Return RemoveMenu(hWnd, 0xF060)  ; SC_CLOSE = 0xF060
}

DeleteWindowMenuSeparator(hWnd = "") {  ; Removes the line above Close menuitem
  Return RemoveMenu(hWnd, 0)
}


EnableMenuItem(hWnd, SystemCommand, EnableFlag)
{
  DllCall("EnableMenuItem", "UInt", GetSystemMenu(hWnd), "UInt", SystemCommand, "UInt", EnableFlag)  ; MF_BYCOMMAND = 0
  Return DrawMenuBar(hWnd)
}


DisableWindowResizing(hWnd = "") {
  Return DeleteWindowResizing()  ; Disabling has no effect, use delete instead
}

DisableWindowMoving(hWnd = "") {
  Return DeleteWindowMoving()
}

DisableWindowMinimizing(hWnd = "") {
  Return DeleteWindowMinimizing()
}

DisableWindowMaximizing(hWnd = "") {
  Return DeleteWindowMaximizing()
}

DisableWindowArranging(hWnd = "") {
  Return DeleteWindowArranging()
}

DisableWindowRestoring(hWnd = "") {
  Return DeleteWindowRestoring()
}

DisableWindowClosing(hWnd = "") {
  Return EnableMenuItem(hWnd, 0xF060, 1)  ; MF_GRAYED = 0x0001
}


EnableWindowResizing(hWnd = "") {
  Return EnableMenuItem(hWnd, 0xF000, 0)  ; MF_ENABLED = 0x0000
}

EnableWindowMoving(hWnd = "") {
  Return EnableMenuItem(hWnd, 0xF010, 0)
}

EnableWindowMinimizing(hWnd = "") {
  Return EnableMenuItem(hWnd, 0xF020, 0)
}

EnableWindowMaximizing(hWnd = "") {
  Return EnableMenuItem(hWnd, 0xF030, 0)
}

EnableWindowArranging(hWnd = "") {
  Return EnableMenuItem(hWnd, 0xF110, 0)
}

EnableWindowRestoring(hWnd = "") {
  Return EnableMenuItem(hWnd, 0xF120, 0)
}

EnableWindowClosing(hWnd = "") {
  Return EnableMenuItem(hWnd, 0xF060, 0)
}


majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
Thx.

It would be more reliable to move globals in functions as statics or hardcode them (you can put message name in comment)
Posted Image

HuBa
  • Members
  • 175 posts
  • Last active: Feb 13 2012 09:51 AM
  • Joined: 24 Feb 2007
You are right! I was also planning to do this.
I updated the original post.

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
Thx for wrapping this up.

Some coding suggestions:

Now you can write:
if hWnd = 
  hWnd := WinExist("A")  ; Active window handle

as

hWnd .= hwnd ? : WinExist("A")

or

hWnd := hwnd ? hwnd : WinExist("A")

you can even put it in function call.
Makes things lil bit faster and shorter
Posted Image

Joy2DWorld
  • Members
  • 562 posts
  • Last active: Jun 30 2014 07:48 PM
  • Joined: 04 Dec 2006
hmmm...

it's like the trolls who dug too far.. too deep...


hWnd .= hwnd ? : WinExist("A")



is cute....

although,


perhaps,

imperfect:


msgbox % hWnd .= hwnd ? : 0
msgbox % hWnd .= hwnd ? : 0
exitapp

Joyce Jamce

HuBa
  • Members
  • 175 posts
  • Last active: Feb 13 2012 09:51 AM
  • Joined: 24 Feb 2007
I updated the library.

Some coding suggestions:

hWnd := hwnd ? hwnd : WinExist("A")

you can even put it in function call.
Makes things lil bit faster and shorter

Done.

Now there are separated functions for every DllCall and uses Windows API naming convention.

3 groups: enable, disable, delete.

It seems that the window-appearance functions are immune to disable command so I implemented them as delete.

At least the close menu behaves as expected.

Skrell
  • Members
  • 384 posts
  • Last active: Jul 07 2016 05:03 PM
  • Joined: 23 Aug 2011

This is a fantastic library !   The only thing is that i want a way to disable the ability to close a window WITHOUT actually "greying" out the close button; is this possible?



evilc
  • Members
  • 340 posts
  • Last active: Oct 27 2015 11:07 PM
  • Joined: 17 Nov 2005
Hi Skan, thanks for your code..

Is there a bug?
 
	DisableWindowMoving(hWnd := "") {
	  Return DeleteWindowMoving()
	}
I had to change it to this to get it to work:
	DisableWindowMoving(hWnd := "") {
	  Return DeleteWindowMoving(hWnd)
	}


evilc
  • Members
  • 340 posts
  • Last active: Oct 27 2015 11:07 PM
  • Joined: 17 Nov 2005
Hmm, also, is it not possible to disable window moving, then re-enable it?

[Edit: NM, RevertSystemMenu works but EnableWindowMoving does not]