Creating GUIs from scratch is relatively simple. To create a custom class name, e.g. AutoHotkeyGUI, you use RegisterClassEx. To create windows and controls you use CreateWindowEx. To receive information from windows and controls you use a WndProc function, which is very similar to an OnMessage function.
The script is based on a script by majkinetor, which was the first time I saw a GUI made in AutoHotkey, made without the Gui commands, and made using DllCall only.
[EDIT:] Compared to that script, I have tidied up all the code and functions, and made them AHK v1.1 U64/U32 compatible, I have fixed the cursor to have the correct appearance (to not have the 'busy' cursor) when you hover over the MsgBox when it first appears, and I have made the GUI handle the Enter and Esc keys.
[tutorial] Creating windows without GUI commands - Scripts and Functions - AutoHotkey Community
https://autohotkey.com/board/topic/2112 ... -commands/
Code: Select all
;[updated: 2017-04-19]
#SingleInstance force
#KeyHistory 0
#UseHook
#NoEnv
ListLines, Off
Menu, Tray, Click, 1
AutoTrim, Off
#Persistent
DetectHiddenWindows, On
;SplitPath, A_ScriptName,,,, vScriptNameNoExt
;Menu, Tray, Tip, % vScriptNameNoExt
;AHK v1.1 script
;remake by jeeswg of:
;[tutorial] Creating windows without GUI commands - Scripts and Functions - AutoHotkey Community
;https://autohotkey.com/board/topic/21124-tutorial-creating-windows-without-gui-commands/
hFont := JEE_FontCreate("Courier New", 10)
JEE_ConstantsWinStyles()
vPIDAhk := DllCall("kernel32\GetCurrentProcessId", UInt)
return
;==================================================
q::
DetectHiddenWindows, On
if WinExist("ahk_id " hGui " ahk_pid " vPIDAhk)
return
vText := " ;continuation section
(LTrim
Volume in drive C has no label.
Volume Serial Number is B857-7430
Directory of C:\Documents and Settings\mmilic
07.09.2007 16:18 <DIR> .
07.09.2007 16:18 <DIR> ..
07.09.2007 10:12 <DIR> Desktop
19.01.2007 16:01 <DIR> Favorites
28.08.2007 15:28 <DIR> My Documents
07.09.2007 16:18 532 out
14.02.2007 16:57 <DIR> Start Menu
1 File(s) 532 bytes
6 Dir(s) 180.445.904.896 bytes free
)"
;DT_EDITCONTROL := 0x2000 ;DT_NOPREFIX := 0x800
;DT_CALCRECT := 0x400 ;DT_NOCLIP := 0x100
;DT_EXPANDTABS := 0x40 ;DT_SINGLELINE := 0x20
;DT_WORDBREAK := 0x10
vLimW := 500, vLimH := 500
JEE_StrGetDim(vText, hFont, vTextW, vTextH, 0x2D50, vLimW, vLimH)
;==================================================
;create window class e.g. AutoHotkeyGUI
;hIcon := LoadPicture(A_AhkPath, "", vType) ;AHK icon
;hIconSm := LoadPicture(A_AhkPath, "w16 h16", vType) ;AHK icon
;hIcon := LoadPicture(A_AhkPath, "Icon-160", vType) ;AHK file icon
;hIconSm := LoadPicture(A_AhkPath, "w16 h16 Icon-160", vType) ;AHK file icon
hIcon := hIconSm := 0
JEE_RegisterClassExCFI("JEEClass", "MyWndProc", hIcon, hIconSm)
;==================================================
;create window
;SplitPath, A_ScriptName,,,, vScriptNameNoExt
SysGet, vCaptionH, 31 ;SM_CYSIZE
vWinClass := "JEEClass"
vWinText := A_ScriptName ;window title
vWinStyle := WS_SYSMENU ;start off hidden with WS_VISIBLE off
vWinExStyle := WS_EX_DLGMODALFRAME | WS_EX_ACCEPTFILES
vPosX := 100, vPosY := 100
vPosW := vTextW+40, vPosH := vTextH+vCaptionH+80
hWndParent := 0, hMenu := 0, hInstance := 0, vParam := 0
hGui := JEE_DCCreateWindowEx(vWinExStyle, vWinClass, vWinText, vWinStyle, vPosX, vPosY, vPosW, vPosH, hWndParent, hMenu, hInstance, vParam)
;==================================================
;create Static control
;SS_EDITCONTROL := 0x2000 ;SS_NOPREFIX := 0x80
vWinClass := "Static"
vWinText := vText
vWinStyle := WS_VISIBLE | WS_CHILD | 0x2080
vWinExStyle := 0
vPosX := 0, vPosY := 0, vPosW := vTextW, vPosH := vTextH
hWndParent := hGui, hMenu := 0, hInstance := 0, vParam := 0
hStatic := JEE_DCCreateWindowEx(vWinExStyle, vWinClass, vWinText, vWinStyle, vPosX, vPosY, vPosW, vPosH, hWndParent, hMenu, hInstance, vParam)
SendMessage, 0x30, % hFont, 1,, % "ahk_id " hStatic ;WM_SETFONT := 0x30
;pStaticProc := RegisterCallback("MyStaticProc", "")
;GWL_WNDPROC := -4
;vSfx := (A_PtrSize=8) ? "Ptr" : ""
;pStaticProcOld := DllCall("SetWindowLong" vSfx, Ptr,hStatic, Int,-4, Ptr,pStaticProc, Ptr)
;==================================================
;create Button control
vWinClass := "Button"
vWinText := "OK"
vWinStyle := WS_VISIBLE | WS_CHILD
vWinExStyle := 0
vPosX := 10, vPosY := vTextH+30, vPosW := 50, vPosH := 25
hWndParent := hGui, hMenu := 0, hInstance := 0, vParam := 0
hBtn := JEE_DCCreateWindowEx(vWinExStyle, vWinClass, vWinText, vWinStyle, vPosX, vPosY, vPosW, vPosH, hWndParent, hMenu, hInstance, vParam)
pBtnProc := RegisterCallback("MyBtnProc", "")
;GWL_WNDPROC := -4
vSfx := (A_PtrSize=8) ? "Ptr" : ""
pBtnProcOld := DllCall("SetWindowLong" vSfx, Ptr,hBtn, Int,-4, Ptr,pBtnProc, Ptr)
;==================================================
ControlFocus,, % "ahk_id " hBtn
WinShow, % "ahk_id " hGui
WinActivate, % "ahk_id " hGui
return
;==================================================
MyWndProc(hWnd, uMsg, wParam, lParam)
{
DetectHiddenWindows, On
global hGui, hBtn
;VK_ESCAPE := 0x1B ;VK_RETURN := 0xD
if (uMsg = 0x102) ;WM_CHAR := 0x102
&& ((wParam = 0x1B) || (wParam = 0xD))
&& (hWnd = hGui)
DllCall("DestroyWindow", Ptr,hWnd)
;BN_CLICKED := 0
if (uMsg = 0x111) ;WM_COMMAND := 0x111
&& (wParam >> 16 = 0) && (lParam = hBtn)
DllCall("DestroyWindow", Ptr,hWnd)
return DllCall("DefWindowProc", Ptr,hWnd, UInt,uMsg, UPtr,wParam, Ptr,lParam, Ptr)
}
;==================================================
MyBtnProc(hWnd, uMsg, wParam, lParam)
{
global pBtnProcOld, hGui
;VK_ESCAPE := 0x1B ;VK_RETURN := 0xD
if (uMsg = 0x102) ;WM_CHAR := 0x102
&& ((wParam = 0x1B) || (wParam = 0xD))
DllCall("DestroyWindow", Ptr,hGui)
return DllCall("CallWindowProc", Ptr,pBtnProcOld, Ptr,hWnd, UInt,uMsg, UPtr,wParam, Ptr,lParam)
}
;==================================================
;;;FUNCTIONS
;JEE_FontCreate
;JEE_ConstantsWinStyles
;JEE_StrGetDim
;JEE_RegisterClassExCFI
;JEE_DCCreateWindowEx
;==================================================
;JEE_WinStylesInit
JEE_ConstantsWinStyles()
{
global
WS_OVERLAPPED := 0x0
WS_TABSTOP := 0x10000
WS_MAXIMIZEBOX := 0x10000
WS_MINIMIZEBOX := 0x20000
WS_GROUP := 0x20000
WS_THICKFRAME := 0x40000
WS_SYSMENU := 0x80000
WS_HSCROLL := 0x100000
WS_VSCROLL := 0x200000
WS_DLGFRAME := 0x400000
WS_BORDER := 0x800000
WS_CAPTION := 0xC00000
WS_OVERLAPPEDWINDOW := 0xCF0000
WS_MAXIMIZE := 0x1000000
WS_CLIPCHILDREN := 0x2000000
WS_CLIPSIBLINGS := 0x4000000
WS_DISABLED := 0x8000000
WS_VISIBLE := 0x10000000
WS_MINIMIZE := 0x20000000
WS_CHILD := 0x40000000
WS_POPUP := 0x80000000
WS_POPUPWINDOW := 0x80880000
WS_EX_LEFT := 0x0
WS_EX_LTRREADING := 0x0
WS_EX_RIGHTSCROLLBAR := 0x0
WS_EX_DLGMODALFRAME := 0x1
WS_EX_NOPARENTNOTIFY := 0x4
WS_EX_TOPMOST := 0x8
WS_EX_ACCEPTFILES := 0x10
WS_EX_TRANSPARENT := 0x20
WS_EX_MDICHILD := 0x40
WS_EX_TOOLWINDOW := 0x80
WS_EX_WINDOWEDGE := 0x100
WS_EX_CLIENTEDGE := 0x200
WS_EX_CONTEXTHELP := 0x400
WS_EX_RIGHT := 0x1000
WS_EX_RTLREADING := 0x2000
WS_EX_LEFTSCROLLBAR := 0x4000
WS_EX_CONTROLPARENT := 0x10000
WS_EX_STATICEDGE := 0x20000
WS_EX_APPWINDOW := 0x40000
WS_EX_OVERLAPPEDWINDOW := 0x300
WS_EX_PALETTEWINDOW := 0x188
}
;==================================================
JEE_DCCreateWindowEx(vWinExStyle, vWinClass, vWinText, vWinStyle, vPosX, vPosY, vPosW, vPosH, hWndParent, hMenu, hInstance, vParam)
{
return DllCall("CreateWindowEx", UInt,vWinExStyle, Str,vWinClass, Str,vWinText, UInt,vWinStyle, Int,vPosX, Int,vPosY, Int,vPosW, Int,vPosH, Ptr,hWndParent, Ptr,hMenu, Ptr,hInstance, Ptr,vParam, Ptr)
}
;==================================================
;e.g. hFont := JEE_FontCreate("Arial", 12, "bius")
;JEE_CreateFont
JEE_FontCreate(vName, vSize, vFontStyle="", vWeight="")
{
vHeight := -DllCall("kernel32\MulDiv", Int,vSize, Int,A_ScreenDPI, Int,72)
vWidth := 0
vEscapement := 0
vOrientation := 0
vWeight := (InStr(vFontStyle, "b") && (vWeight="")) ? 700 : 400
vItalic := InStr(vFontStyle, "i") ? 1 : 0
vUnderline := InStr(vFontStyle, "u") ? 1 : 0
vStrikeOut := InStr(vFontStyle, "s") ? 1 : 0
vCharSet := 0
vOutPrecision := 0
vClipPrecision := 0
vQuality := 0
vPitchAndFamily := 0
vFaceName := vName
vOutPrecision := 3
vClipPrecision := 2
vQuality := 1
vPitchAndFamily := 34
return DllCall("CreateFont", Int,vHeight, Int,vWidth, Int,vEscapement, Int,vOrientation, Int,vWeight, UInt,vItalic, UInt,vUnderline, UInt,vStrikeOut, UInt,vCharSet, UInt,vOutPrecision, UInt,vClipPrecision, UInt,vQuality, UInt,vPitchAndFamily, Str,vFaceName, Ptr)
}
;==================================================
JEE_RegisterClassExCFI(vWinClass, vFunc, hIcon=0, hIconSm="")
{
pWndProc := RegisterCallback(vFunc, "F")
hCursor := DllCall("LoadCursor", Ptr,0, Ptr,32512, Ptr) ;IDC_ARROW := 32512
if (hIconSm = "")
hIconSm := hIcon
vPIs64 := (A_PtrSize=8)
vSize := vPIs64?80:48
VarSetCapacity(WNDCLASSEX, vSize, 0)
NumPut(vSize, WNDCLASSEX, 0, "UInt") ;cbSize
NumPut(3, WNDCLASSEX, 4, "UInt") ;style
NumPut(pWndProc, WNDCLASSEX, 8, "Ptr") ;lpfnWndProc
NumPut(0, WNDCLASSEX, vPIs64?16:12, "Int") ;cbClsExtra
NumPut(0, WNDCLASSEX, vPIs64?20:16, "Int") ;cbWndExtra
NumPut(0, WNDCLASSEX, vPIs64?24:20, "Ptr") ;hInstance
NumPut(hIcon, WNDCLASSEX, vPIs64?32:24, "Ptr") ;hIcon
NumPut(hCursor, WNDCLASSEX, vPIs64?40:28, "Ptr") ;hCursor
NumPut(16, WNDCLASSEX, vPIs64?48:32, "Ptr") ;hbrBackground
NumPut(0, WNDCLASSEX, vPIs64?56:36, "Ptr") ;lpszMenuName
NumPut(&vWinClass, WNDCLASSEX, vPIs64?64:40, "Ptr") ;lpszClassName
NumPut(hIconSm, WNDCLASSEX, vPIs64?72:44, "Ptr") ;hIconSm
return DllCall("RegisterClassEx", Ptr,&WNDCLASSEX, UShort)
}
;==================================================
;JEE DrawText
JEE_StrGetDim(vText, hFont, ByRef vTextW, ByRef vTextH, vDTFlags:=0x400, vLimW:="", vLimH:="")
{
;DT_EDITCONTROL := 0x2000 ;DT_NOPREFIX := 0x800
;DT_CALCRECT := 0x400 ;DT_NOCLIP := 0x100
;DT_EXPANDTABS := 0x40 ;DT_SINGLELINE := 0x20
;DT_WORDBREAK := 0x10
;HWND_DESKTOP := 0
hDC := DllCall("user32\GetDC", Ptr,0, Ptr)
hFontOld := DllCall("gdi32\SelectObject", Ptr,hDC, Ptr,hFont)
VarSetCapacity(SIZE, 8, 0)
vTabLengthText := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
DllCall("GetTextExtentPoint32", Ptr,hDC, Str,vTabLengthText, Int,52, Ptr,&SIZE)
vTabLength := NumGet(SIZE, 0, "Int")
vTabLength := Floor((vTabLength/52)+0.5)
vTabLength := Round(vTabLength*(72/A_ScreenDPI))
vLen := StrLen(vText)
VarSetCapacity(DRAWTEXTPARAMS, 20, 0)
NumPut(20, DRAWTEXTPARAMS, 0, "UInt") ;cbSize
NumPut(vTabLength, DRAWTEXTPARAMS, 4, "Int") ;iTabLength
;NumPut(0, DRAWTEXTPARAMS, 8, "Int") ;iLeftMargin
;NumPut(0, DRAWTEXTPARAMS, 12, "Int") ;iRightMargin
NumPut(vLen, DRAWTEXTPARAMS, 16, "UInt") ;uiLengthDrawn
VarSetCapacity(RECT, 16, 0)
if !(vLimW = "")
NumPut(vLimW, RECT, 8, "Int")
if !(vLimH = "")
NumPut(vLimH, RECT, 12, "Int")
DllCall("user32\DrawTextEx", Ptr,hDC, Str,vText, Int,vLen, Ptr,&RECT, UInt,vDTFlags, Ptr,&DRAWTEXTPARAMS)
DllCall("gdi32\SelectObject", Ptr,hDC, Ptr,hFontOld)
DllCall("user32\ReleaseDC", Ptr,0, Ptr,hDC)
vTextW := NumGet(RECT, 8, "Int")
vTextH := NumGet(RECT, 12, "Int")
}
;==================================================
- it doesn't properly handle more than one MsgBox being open at the same time
- the window doesn't handle the Enter or Esc keys [EDIT: fixed]
To receive keypress messages directed at the Button control, do I need to subclass the control?
[EDIT:] I have since used subclassing. The problem I had was that SetWindowLongPtr appears to work for x64 but not x32. I thought that logically it should work for both x64 and x32. So I've made it use either SetWindowLongPtr or SetWindowLong based on the script's 'bitness'.
[function] Subclass - helper function to subclass control - Scripts and Functions - AutoHotkey Community
https://autohotkey.com/board/topic/2397 ... s-control/
The issue with multiple GUIs existing at the same time is one I've asked about here also:
An attempt at a script that creates MsgBoxes/InputBoxes for other scripts - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 53#p138253
Cheers.
[EDIT:] I have noticed that if you activate another window, and then re-activate the GUI, the OK button loses the focus.