Message box hook

Started by Pierre Bellisle, April 16, 2023, 09:47:13 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Pierre Bellisle

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...

Charles Pegge

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
'_____________________________________________________________________________
'

Pierre Bellisle

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

Charles Pegge

#3
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


Pierre Bellisle

Thanks,
This is going in my learning scrappbook.
I will put a note for Nicola's help file. 

Nicola

#5
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

Zlatko Vid

<<< Strings are not supported <<<

wait..but then how i use it ?
i always forget that part ..with byte at ..
do i have right ?

Zlatko Vid

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 "+"

Zlatko Vid

ouch this is just one char

Zlatko Vid

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

Anthon Com

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? 

Pierre Bellisle

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.

Pierre Bellisle

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.

Zlatko Vid

<<<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

Zlatko Vid

maybe we should open new topic about that ?
i am fine with IF for strings in all my programs