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.

Roland Stowasser

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?

Charles Pegge

#16
Hi Roland,

You might not have the typeface

  LF.LFFaceName = "Segoe UI"

Roland Stowasser

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

Pierre Bellisle

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)

Pierre Bellisle

#19
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)

Roland Stowasser

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

Charles Pegge

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.