Message box hook, for the fun of it...
// KickSwitch -64
// KickEnd
include once "D:\Dev\Oxygen\o2\inc\Dialogs.inc"
include once "D:\Dev\Oxygen\o2\~code\myInc\WinConsts.inc"
type CBT_CREATEWND
sys lpcs 'CREATESTRUCT PTR
sys hWndInsertAfter
end type
'____________________________________________________________________________
function MessageBoxProc(byval nCode as dword, byval hWin as sys, byval lparam as sys) as sys callback
static sys hStatic, hFont, hIcon, hButton 'type CREATESTRUCT type CBT_CREATEWND
static long DialogWidth, DialogHeight ' lpCreateParams as sys lpcs as sys 'CREATESTRUCT
' hInstance as sys hWndInsertAfter as sys
if nCode = HCBT_CREATEWND ' hMenu as sys end type
CBT_CREATEWND cbtWin at lparam ' hWndParent as sys
CREATESTRUCT cbtStruct at cbtWin.lpcs ' cy as long
' cx as long
ZSTRING zClass[64] ' y as long
GetClassName(hWin, @zClass, 64) ' x as long
' style as long
if zClass = "#32770" ' lpszName as char ptr
cbtStruct.cx = cbtStruct.cx * 2 ' lpszClass as char ptr
DialogWidth = cbtStruct.cx ' ExStyle as long
DialogHeight = cbtStruct.cy 'end type
'hIcon = LoadIcon(BYVAL NULL, IDI_INFORMATION)
hIcon = ExtractIcon(GetModuleHandle(""), "Shell32.dll", 294)
SendMessage(hWin, WM_SETICON, ICON_SMALL, hIcon)
elseif zClass = "Static"
if (cbtStruct.Style AND %SS_ICON) 'Icon id = 0x14
cbtStruct.x = 3 'Move icon near the left border
else 'Static id = 0xFFFF
cbtStruct.x = 38
cbtStruct.y = cbtStruct.y - 20
cbtStruct.cy = cbtStruct.cy + 35
cbtStruct.cx = DialogWidth - 50
hStatic = hWin
endif
elseif zClass = "Button"
if cbtStruct.hMenu = IDOK
cbtStruct.x = DialogWidth - cbtStruct.cx - 20
cbtStruct.y = DialogHeight - cbtStruct.cy - 40
hButton = hWin
endif
end if
elseif nCode = HCBT_ACTIVATE
LOGFONT LF
LF.LFHeight = 48 '%FW_NORMAL
LF.LFItalic = FALSE
LF.LFFaceName = "Segoe UI"
hFont = CreateFontIndirect(@LF)
'hFont = GetObject(GetStockObject(%ANSI_FIXED_FONT), SIZEOF(LF), @LF)
'hFont = GetObject(GetStockObject(%ANSI_VAR_FONT), SIZEOF(LF), BYVAL VARPTR(LF))
SendMessage(hStatic, WM_SETFONT, hFont, 0)
elseif nCode = HCBT_DESTROYWND
if hFont then DeleteObject(hFont)
IF hIcon THEN DestroyIcon(hIcon)
elseif nCode = HCBT_SETFOCUS
end if
end function
'____________________________________________________________________________
sys hMsgBoxHook = SetWindowsHookEx(WH_CBT, @MessageBoxProc, GetModuleHandle(""), GetCurrentThreadId())
MessageBox(HWND_DESKTOP, "Hooked message box", "Hooked message box", MB_OK | MB_SYSTEMMODAL | MB_TOPMOST | MB_ICONINFORMATION)
UnhookWindowsHookEx(hMsgBoxHook)
end
'_____________________________________________________________________________
'
Charles, if you see lines that could have been written in a better way, please tell...
Thanks Pierre,
Added some definitions from winuser.h to make standalone
uses dialogs
#define HCBT_MOVESIZE 0
#define HCBT_MINMAX 1
#define HCBT_QS 2
#define HCBT_CREATEWND 3
#define HCBT_DESTROYWND 4
#define HCBT_ACTIVATE 5
#define HCBT_CLICKSKIPPED 6
#define HCBT_KEYSKIPPED 7
#define HCBT_SYSCOMMAND 8
#define HCBT_SETFOCUS 9
#define WH_MIN -1
#define WH_MSGFILTER -1
#define WH_JOURNALRECORD 0
#define WH_JOURNALPLAYBACK 1
#define WH_KEYBOARD 2
#define WH_GETMESSAGE 3
#define WH_CALLWNDPROC 4
#define WH_CBT 5
#define WH_SYSMSGFILTER 6
#define WH_MOUSE 7
'#if defined(_WIN32_WINDOWS)
#define WH_HARDWARE 8
'#endif
#define WH_DEBUG 9
#define WH_SHELL 10
#define WH_FOREGROUNDIDLE 11
'#if(WINVER >= 0x0400)
#define WH_CALLWNDPROCRET 12
'#endif /* WINVER >= 0x0400 */
'#if (_WIN32_WINNT >= 0x0400)
#define WH_KEYBOARD_LL 13
#define WH_MOUSE_LL 14
'#endif // (_WIN32_WINNT >= 0x0400)
'#if(WINVER >= 0x0400)
'#if (_WIN32_WINNT >= 0x0400)
#define WH_MAX 14
'#else
'#define WH_MAX 12
'#endif // (_WIN32_WINNT >= 0x0400)
'#else
'#define WH_MAX 11
'#endif
#define WH_MINHOOK WH_MIN
#define WH_MAXHOOK WH_MAX
'sys constants (equates are limited to 32bit)
sys HWND_TOP = 0
sys HWND_BOTTOM = 1
sys HWND_TOPMOST =-1
sys HWND_NOTOPMOST =-2
sys HWND_DESKTOP = 0
sys HWND_BROADCAST = 0xffff
'#if(WINVER >= 0x0500
sys HWND_MESSAGE =-3
'#endif /* WINVER >= 0x0500 */
sys HWND_DESKTOP = 0
type CBT_CREATEWND
sys lpcs 'CREATESTRUCT PTR
sys hWndInsertAfter
end type
'____________________________________________________________________________
function MessageBoxProc(byval nCode as dword, byval hWin as sys, byval lparam as sys) as sys callback
static sys hStatic, hFont, hIcon, hButton 'type CREATESTRUCT type CBT_CREATEWND
static long DialogWidth, DialogHeight ' lpCreateParams as sys lpcs as sys 'CREATESTRUCT
' hInstance as sys hWndInsertAfter as sys
if nCode = HCBT_CREATEWND ' hMenu as sys end type
CBT_CREATEWND cbtWin at lparam ' hWndParent as sys
CREATESTRUCT cbtStruct at cbtWin.lpcs ' cy as long
' cx as long
ZSTRING zClass[64] ' y as long
GetClassName(hWin, @zClass, 64) ' x as long
' style as long
if zClass = "#32770" ' lpszName as char ptr
cbtStruct.cx = cbtStruct.cx * 2 ' lpszClass as char ptr
DialogWidth = cbtStruct.cx ' ExStyle as long
DialogHeight = cbtStruct.cy 'end type
'hIcon = LoadIcon(BYVAL NULL, IDI_INFORMATION)
hIcon = ExtractIcon(GetModuleHandle(""), "Shell32.dll", 294)
SendMessage(hWin, WM_SETICON, ICON_SMALL, hIcon)
elseif zClass = "Static"
if (cbtStruct.Style AND %SS_ICON) 'Icon id = 0x14
cbtStruct.x = 3 'Move icon near the left border
else 'Static id = 0xFFFF
cbtStruct.x = 38
cbtStruct.y = cbtStruct.y - 20
cbtStruct.cy = cbtStruct.cy + 35
cbtStruct.cx = DialogWidth - 50
hStatic = hWin
endif
elseif zClass = "Button"
if cbtStruct.hMenu = IDOK
cbtStruct.x = DialogWidth - cbtStruct.cx - 20
cbtStruct.y = DialogHeight - cbtStruct.cy - 40
hButton = hWin
endif
end if
elseif nCode = HCBT_ACTIVATE
LOGFONT LF
LF.LFHeight = 48 '%FW_NORMAL
LF.LFItalic = FALSE
LF.LFFaceName = "Segoe UI"
hFont = CreateFontIndirect(@LF)
'hFont = GetObject(GetStockObject(%ANSI_FIXED_FONT), SIZEOF(LF), @LF)
'hFont = GetObject(GetStockObject(%ANSI_VAR_FONT), SIZEOF(LF), BYVAL VARPTR(LF))
SendMessage(hStatic, WM_SETFONT, hFont, 0)
elseif nCode = HCBT_DESTROYWND
if hFont then DeleteObject(hFont)
IF hIcon THEN DestroyIcon(hIcon)
elseif nCode = HCBT_SETFOCUS
end if
end function
'____________________________________________________________________________
sys hMsgBoxHook = SetWindowsHookEx(WH_CBT, @MessageBoxProc, GetModuleHandle(""), GetCurrentThreadId())
MessageBox(HWND_DESKTOP, "Hooked message box", "Hooked message box", MB_OK | MB_SYSTEMMODAL | MB_TOPMOST | MB_ICONINFORMATION)
UnhookWindowsHookEx(hMsgBoxHook)
end
'_____________________________________________________________________________
'
Hi Charles,
It's a pleasure to be able to do stuff like
"CREATESTRUCT cbtStruct at cbtWin.lpcs", love it!
The "|" for "or" is nice, so many good stuff in your compiler.
About "case", if I understand, it doesn't support string type.
Also "endsel" is no more supported.
Am I right?
Thank you
Hi Pierre,
Yes endsel became endselect in 12/09/2022 RELEASE 0.5.0P7 according to oxylog.txt. It's more reliable than my memory! We also have end select of course.
Strings are not supported but you can do ascii codes
select 99
case "a"
print 1
case "b"
print 2
case "c"
print 3 'printed 3
case "d"
print 4
endselect
Thanks,
This is going in my learning scrappbook.
I will put a note for Nicola's help file.
Hi,
Interesting, though complex enough to have this useful feature.
I remember when I asked how to have a gui in the topmost position.
http://forum.it-berater.org/index.php?msg=24416
<<< Strings are not supported <<<
wait..but then how i use it ?
i always forget that part ..with byte at ..
do i have right ?
maybe like this..
i am sure that i have example somewhere
maybe with cast ..i must look in my archive
token = mid(code, i, 1)
'print token
byte t at strptr(token)
Select t
case "+"
ouch this is just one char
i think i found it
Charles may confirm
even he told me that is not safe to use large strings
'string select
string s
s = "tesT"
int *p = strptr s 'pointer select
Select p
Case "TEST"
print "wrong?"
Case "tesT"
print "right!"
End Select
Thanks Pierre and Charles, this is indeed a very good program.
What about an open file dialog with a hook to add a Help button or change the fonts etc?
Aurel,
>"he told me that is not safe to use large strings"
True on my side, from experimentation, with your last example,
if you try Case "tesT123" instead of Case "tesT" you will get a "right!"
This way is good for the four first letters of a word. Also if the word is less than 4 letters.
Anthon,
For the help button, if you use GetOpenFileName, you may use the .Flags = OFN_SHOWHELP
With Common Item Dialog IFileOpenDialog, you may use the showHelp method (NWMF_SHOWHELP).
GetOpenFileName() provide a .lpfnHook flag that will enable a hooked function.
IF you want two panes, you might be in trouble:
OFN_ENABLEHOOK OR OFN_EXPLORER give no folders pane, only files
OFN_ENABLEHOOK alone give a real old listbox and listview style
OFN_EXPLORER alone give a nice folders pane and files pane but no hook
If you want only the files pane without the folders pane, then you might do a lot of things.
You can even do a double hook by setting the .lpfnHook flag and doing a SetWindowsHookEx(WH_CBT...) like the above...
Note, IFileOpenDialog is real powerful and might do all you need without hook.
<<<This way is good for the four first letters of a word. Also if the word is less than 4 letters. >>>
ahh ..yes
i simply cannot found what i use
i search trough old examples and nothing
maybe we should open new topic about that ?
i am fine with IF for strings in all my programs
Hi Pierre, Charles,
unfortunately I only get a result with an unmodified font. I am using Win 10, O2 version 0.5.0 2022-12-30T09:44:57 with the slightly modified dialogs.inc. I have not yet looked much at the code, but maybe some constants of WinConsts.inc are different? Is WinConsts.inc available somewhere?
Hi Roland,
You might not have the typeface
LF.LFFaceName = "Segoe UI"
Hi Charles,
in Wordpad and the Win Editor I can use the Segoe UI and Segoe Script fonts, but this does not affect the demo for me. I tried Arial but I get the same result. Is this because I use Windows 10 (64 bit)?
Roland,
To keep example simple, I might have over simplified the font part to work with most Windows configuration.
Windows 10-64 should work fine with adequate code.
Try to replace the HCBT_ACTIVATE section with the following...
elseif nCode = HCBT_ACTIVATE
SYS hDC = GetDC(HWND_DESKTOP)
LONG LogPixY = GetDeviceCaps(hDC, LOGPIXELSY)
LONG LFHeight = 48 '<- Roland, the character height you want
LOGFONT LF
LF.LFHeight = MulDiv(ABS(LFHeight), 72, LogPixY)
LF.LFItalic = FALSE
LF.LFFaceName = "Segoe UI"
hFont = CreateFontIndirect(@LF)
SendMessage(hStatic, WM_SETFONT, hFont, 0)
ReleaseDC(HWND_DESKTOP, hDC)
Roland, you might also try the new GetDpiForWindow() api (Since Windows 10, version 1607).
It will be more valuable when dealing with scaling, DPI aware app and multi-monitor system.
elseif nCode = HCBT_ACTIVATE
'GetDpiForWindow: (Since Windows 10, version 1607)
'-DPI_AWARENESS Return value
'-DPI_AWARENESS_UNAWARE 96
'-DPI_AWARENESS_SYSTEM_AWARE The system DPI.
'-DPI_AWARENESS_PER_MONITOR_AWARE The DPI of the monitor where the window is located.
LONG LogPixY = GetDpiForWindow(GetDesktopWindow()) 'Get DPI for the desktop - https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdpiforwindow
LONG pointSize = 48 '<- Roland, the character height you want
LOGFONT LF
LF.LfHeight = MulDiv(ABS(pointSize), 72, LogPixY) 'DPI adjust. Const int POINTS_PER_INCH=72
LF.LfItalic = FALSE
LF.LfFaceName = "Segoe UI"
hFont = CreateFontIndirect(@LF)
SendMessage(hStatic, WM_SETFONT, hFont, 0)
Hi Pierre, Charles,
looking at the code I think Pierre's first code should work. If I comment out the piece for nCode = HCBT_DESTROYWND, then the demo works as expected - this is a bit strange(?). Is this result valid only for Win 10?
This is the slightly modified code - you do not need dialogs.inc for this example (#32770 is a special dialog class), I used Segoe Script as the font.
$ filename "MsgBoxHook.exe"
'uses rtl32
'uses rtl64
uses corewin
% WM_SETICON=0x80
% ICON_SMALL=0
% SS_ICON=3
#define HCBT_CREATEWND 3
#define HCBT_DESTROYWND 4
#define HCBT_ACTIVATE 5
#define HCBT_SETFOCUS 9
#define WH_CBT 5
% HWND_DESKTOP = 0
type CBT_CREATEWND
sys lpcs 'CREATESTRUCT PTR
sys hWndInsertAfter
end type
'____________________________________________________________________________
function MessageBoxProc(byval nCode as dword, byval hWin as sys, byval lparam as sys) as sys callback
static sys hStatic, hFont, hIcon, hButton 'type CREATESTRUCT type CBT_CREATEWND
static long DialogWidth, DialogHeight ' lpCreateParams as sys lpcs as sys 'CREATESTRUCT
' hInstance as sys hWndInsertAfter as sys
if nCode = HCBT_CREATEWND ' hMenu as sys end type
CBT_CREATEWND cbtWin at lparam ' hWndParent as sys
CREATESTRUCT cbtStruct at cbtWin.lpcs ' cy as long
' cx as long
ZSTRING zClass[64] ' y as long
GetClassName(hWin, @zClass, 64) ' x as long
' style as long
if zClass = "#32770" ' lpszName as char ptr
cbtStruct.cx = cbtStruct.cx * 2 ' lpszClass as char ptr
DialogWidth = cbtStruct.cx ' ExStyle as long
DialogHeight = cbtStruct.cy 'end type
'hIcon = LoadIcon(BYVAL NULL, IDI_INFORMATION)
hIcon = ExtractIcon(GetModuleHandle(""), "Shell32.dll", 294)
SendMessage(hWin, WM_SETICON, ICON_SMALL, hIcon)
elseif zClass = "Static"
if (cbtStruct.Style AND %SS_ICON) 'Icon id = 0x14
cbtStruct.x = 3 'Move icon near the left border
else 'Static id = 0xFFFF
cbtStruct.x = 38
cbtStruct.y = cbtStruct.y - 20
cbtStruct.cy = cbtStruct.cy + 35
cbtStruct.cx = DialogWidth - 50
hStatic = hWin
endif
elseif zClass = "Button"
if cbtStruct.hMenu = IDOK
cbtStruct.x = DialogWidth - cbtStruct.cx - 20
cbtStruct.y = DialogHeight - cbtStruct.cy - 40
hButton = hWin
endif
end if
elseif nCode = HCBT_ACTIVATE
LOGFONT LF
LF.LFHeight = 48 '%FW_NORMAL
LF.LFItalic = FALSE
LF.LFFaceName = "Segoe Script"
hFont = CreateFontIndirect(@LF)
'hFont = GetObject(GetStockObject(%ANSI_FIXED_FONT), SIZEOF(LF), @LF)
'hFont = GetObject(GetStockObject(%ANSI_VAR_FONT), SIZEOF(LF), BYVAL VARPTR(LF))
SendMessage(hStatic, WM_SETFONT, hFont, 0)
/*
elseif nCode = HCBT_DESTROYWND
if hFont then DeleteObject(hFont)
IF hIcon THEN DestroyIcon(hIcon)
*/
elseif nCode = HCBT_SETFOCUS
end if
end function
'____________________________________________________________________________
sys hMsgBoxHook = SetWindowsHookEx(WH_CBT, @MessageBoxProc, GetModuleHandle(""), GetCurrentThreadId())
MessageBox(HWND_DESKTOP, "Hooked message box", "Hooked message box", MB_OK | MB_SYSTEMMODAL | MB_TOPMOST | MB_ICONINFORMATION)
UnhookWindowsHookEx(hMsgBoxHook)
end
'_____________________________________________________________________________
'
Thanks Roland, I'll include it in demos\wingui
I was wondering whether Dialogs are necessary, when an application already contains a general Windows code-base. It's more stuff to learn.