Reputation: 357
I am playing with the raw Windows API here. I am trying to pass a font to a dialog during the WM_INITDIALOG message and then keep using that font whenever a new child window is created inside that dialog. But I do not want to keep passing that HFONT I created, I want to retrieve it from the dialog window instead, whenever I need it.
So when I enter my WM_INITDIALOG handler, I create the font and then send it to the dialog using SendMessage(WM_SETFONT). Then, whenever I wanted to create a new child window, I thought that all I needed to do was to retrieve the dialog font, using SendMessage(WM_GETFONT). But the handle I receive from the dialog is not the one I created, so it is no surprise that when I use that new handle to set the new control font I get the wrong font.
I am only destroying the font handle when the application terminates. But I bet that an invalid handle is not the problem otherwise, in the example below, the control where I explicit pass my font handle would not be displaying the correct one.
Any ideas?
#include <Windows.h>
#include <CommCtrl.h>
static INT_PTR CALLBACK DialogProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam)
{
static HFONT hFont = NULL;
switch(uMsg)
{
case WM_CLOSE:
::EndDialog(hwndDlg, 0);
::DeleteObject(hFont);
return TRUE;
case WM_INITDIALOG:
{
// create our font
hFont = ::CreateFontW(
36,
0,
0,
0,
FW_NORMAL,
0,
0,
0,
DEFAULT_CHARSET,
OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS,
CLEARTYPE_QUALITY,
VARIABLE_PITCH,
L"Tahoma");
// set that font as the dialog font
::SendMessageW(hwndDlg, WM_SETFONT, (WPARAM)hFont, TRUE);
// retrieve the dialog font
HFONT hFontDialog = (HFONT)::SendMessageW(hwndDlg, WM_GETFONT, 0, 0);
// create two child windows
HWND hwndStatic1 = ::CreateWindowExW(0, WC_STATIC, L"hFont", WS_VISIBLE | WS_CHILD, 0, 0, 100, 30, hwndDlg, NULL, 0, 0);
HWND hwndStatic2 = ::CreateWindowExW(0, WC_STATIC, L"hFontDialog", WS_VISIBLE | WS_CHILD, 0, 50, 100, 20, hwndDlg, NULL, 0, 0);
// set their fonts, using the one we created for the first one and
// the one from the dialog for the second one
::SendMessageW(hwndStatic1, WM_SETFONT, (WPARAM)hFont, TRUE);
::SendMessageW(hwndStatic2, WM_SETFONT, (WPARAM)hFontDialog, TRUE);
return FALSE;
}
}
return FALSE;
}
#include <PshPack2.h>
struct DialogTemplate
{
DLGTEMPLATE Base;
WORD Menu;
WORD Class;
WCHAR Title[1];
};
#include <PopPack.h>
int WINAPI wWinMain(
__in HINSTANCE hInstance,
__in_opt HINSTANCE hPrevInstance,
__in LPWSTR lpCmdLine,
__in int nShowCmd)
{
DialogTemplate dt = {0};
dt.Base.style = DS_CENTER | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU;
dt.Base.cx = 200;
dt.Base.cy = 200;
return ::DialogBoxIndirectParamW(
::GetModuleHandle(NULL),
(DLGTEMPLATE*)&dt, // holy hack, Batman! I hope this is OK...
NULL,
DialogProc,
(LPARAM)0);
}
Upvotes: 0
Views: 713
Reputation: 37192
Dialogs don't respond to WM_SETFONT
. A dialog has a font that is defined in its template, and if the DS_SETFONT
style is set it will propogate that to all its child controls on creation. The font you get back from WM_GETFONT
is the one created initially based on the template.
If you want to change control fonts after the dialog has been created you need to send them WM_SETFONT
messages individually.
My theory as to why this is the case: dialog layout is based on the font size ("dialog units" are a fraction of the font height and average font width). Therefore, the dialog needs to know its font upon creation, in order to resize and layout the controls. Changing the font afterwards, from the dialog's point of view, would potentially require a resize/re-layout and this is not functionality that has been implemented in the dialog manager.
Upvotes: 2