(That's a really nice tutorial; I've never subclassed anything before, but the code and tutorial makes doing so easy. Thank you, just me. Google Translate does a good job on the page
Hmm, hopefully I'm not misunderstanding something, but why not use the hook to subclass the MessageBox after WM_INITDIALOG is called? I think only a specific window can be subclassed, as opposed to an entire class, so you need some way to get that specific MessageBox window handle in the first place, and I can't think of any benefits that modifying WM_INITDIALOG brings. I tried my hand at subclassing a MessageBox window and stopping the window from being moved by subclassing and targeting WM_WINDOWPOSCHANGING (code also by just me - the nice thing about this approach is that it stops
Code: Select all
; GLOBAL SETTINGS ===============================================================================================================
#NoEnv
#SingleInstance Force
SetBatchLines -1
; GUI ===========================================================================================================================
Gui, +hWndhMyGUI
Gui, Margin, 10, 10
Gui, Add, Button, xm-1 ym w402 h200 gBUTTON_MSGBOX, % "Click me!"
Gui, Add, Edit, xm y+9 w400 0x801 vMyEdit
Gui, Show, AutoSize
GuiDisableMove(hMyGUI)
GuiDisableCloseButton(hMyGUI)
return
; SCRIPT ========================================================================================================================
BUTTON_MSGBOX:
ret := MessageBox(hMyGUI, "Random Title", "YES or NO?", 0x24)
; FileSelectFolder C
GuiControl,, MyEdit, % (ret = 7) ? "NO!" : "YES!"
return
; FUNCTIONS =====================================================================================================================
MessageBox(handle, title, text, options)
{
static WH_CALLWNDPROCRET := 12, lpCallWndProc := RegisterCallback("CallWndProc", "")
wndhook := DllCall("SetWindowsHookEx", "Int", WH_CALLWNDPROCRET, "Ptr", lpCallWndProc, "Ptr", 0, "UInt", DllCall("GetCurrentThreadId", "UInt"), "Ptr")
ret := DllCall("user32\MessageBox", "ptr", handle, "str", text, "str", title, "uint", options)
if (wndhook)
DllCall("UnhookWindowsHookEx", "Ptr", wndhook)
return ret
}
GuiDisableMove(handle)
{
hMenu := DllCall("user32\GetSystemMenu", "ptr", handle, "int", false, "ptr")
DllCall("user32\RemoveMenu", "ptr", hMenu, "uint", 0xf010, "uint", 0)
return DllCall("user32\DrawMenuBar", "ptr", handle)
}
GuiDisableCloseButton(handle)
{
hMenu := DllCall("user32\GetSystemMenu", "ptr", handle, "int", false, "ptr")
DllCall("user32\EnableMenuItem", "ptr", hMenu, "uint", 0xf060, "uint", 0x3)
return DllCall("user32\DrawMenuBar", "ptr", handle)
}
; ======================================================================================================================
; SubclassControl Installs, updates, or removes the subclass callback for the specified control.
; Installiert, ändert oder entfernt den Subclass-Funktionsaufruf für das angegebene Control.
; Author: just me (www.ahkscript.org)
; ======================================================================================================================
SubclassControl(HCTRL, FuncName, RefData := 0) {
Static ControlCB := []
If ControlCB.HasKey(HCTRL) {
DllCall("Comctl32.dll\RemoveWindowSubclass", "Ptr", HCTRL, "Ptr", ControlCB[HCTRL], "Ptr", HCTRL)
DllCall("Kernel32.dll\GlobalFree", "Ptr", ControlCB[HCTRL], "Ptr")
ControlCB.Remove(HCTRL, "")
If (FuncName = "")
Return True
}
If !DllCall("User32.dll\IsWindow", "Ptr", HCTRL, "UInt")
Or !IsFunc(FuncName) || (Func(FuncName).MaxParams <> 6)
Or !(CB := RegisterCallback(FuncName, , 6))
Return False
If !DllCall("Comctl32.dll\SetWindowSubclass", "Ptr", HCTRL, "Ptr", CB, "Ptr", HCTRL, "Ptr", RefData)
Return (DllCall("Kernel32.dll\GlobalFree", "Ptr", CB, "Ptr") & 0)
Return (ControlCB[HCTRL] := CB)
}
; EXIT ==========================================================================================================================
GuiEscape:
GuiClose:
ExitApp
; Callbacks =====================================================================================================================
NotAllowed(HWND, Msg, wParam, lParam, SubclassID, RefData) {
; WM_WINDOWPOSCHANGING = 0x0046, WM_DESTROY := 0x0002
If (Msg == 0x0046) {
; just me: https://autohotkey.com/board/topic/96671-prevent-window-from-moving/
Static SWP_NOMOVE := 2
Static SWP_NOSIZE := 1
Static OffFlags := A_PtrSize + A_PtrSize + 16 ; 24 (AHK x86) | 32 (AHK x64)
NumPut(NumGet(lParam + OffFlags, "UInt") | SWP_NOMOVE, lParam + OffFlags, "UInt")
Return 0
} else if (Msg == 0x0002) {
DllCall("Comctl32.dll\RemoveWindowSubclass", "Ptr", HWND, "Ptr", A_EventInfo, "Ptr", SubclassID)
funcobj := Func("SubclassControl").Bind(HWND, "")
SetTimer % funcobj, -100 ; eurgh - better off doing this in the hook? IIRC, WM_NCDESTROY follows, so it doesn't matter that it's a WH_CALLWNDPROCRET hook
}
Return DllCall("Comctl32.dll\DefSubclassProc", "Ptr", HWND, "UInt", Msg, "Ptr", wParam, "Ptr", lParam)
}
CallWndProc(nCode, wParam, lParam)
{
Critical 1000
if (nCode >= 0) { ; HC_ACTION
cwpmessage := NumGet(lParam+0, A_PtrSize * 3, "UInt")
if (cwpmessage == 0x0110) { ; WM_INITDIALOG
cwplparam := NumGet(lParam+0, A_PtrSize, "Ptr")
hWnd := NumGet(lParam+0, A_PtrSize * 4, "Ptr")
prevDetectHiddenWindows := A_DetectHiddenWindows
DetectHiddenWindows On ; grr
WinGetClass strClass, ahk_id %hWnd%
DetectHiddenWindows %prevDetectHiddenWindows%
if (cwplparam && strClass == "#32770" && DllCall(A_PtrSize == 8 ? "GetWindowLongPtr" : "GetWindowLong", "Ptr", hWnd, "Int", -21, "Ptr") == cwplparam) { ; assumptions abound from this point
static cbMSGBOXPARAMS := A_PtrSize * 10
if (NumGet(cwplparam+0,, "UInt") == cbMSGBOXPARAMS)
SubclassControl(hWnd, "NotAllowed")
}
}
}
return DllCall("CallNextHookEx", "Ptr", 0, "Int", nCode, "Ptr", wParam, "Ptr", lParam, "Ptr")
}
; ===============================================================================================================================