If you aren't aware, if you hand-code a GUI with the Windows API you will find your controls look quite ugly by default due to their font. Running this code:
#include <Windows.h>
#include <windowsx.h>
#include <CommCtrl.h>
#include <strsafe.h>
#include <sal.h>
#pragma comment(lib, "comctl32.lib")
#if defined _M_IX86
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
#elif defined _M_IA64
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#elif defined _M_X64
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#else
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#endif
CONST WCHAR g_wszClassName[] = L"FONT_DEMO_WINDOW";
VOID WINAPI OnClose(
HWND hWnd
)
{
DestroyWindow(hWnd);
}
VOID WINAPI OnCommand(
HWND hWnd,
INT nID,
HWND hwSource,
UINT uNotify
)
{
HWND hButton = FindWindowExW(hWnd, NULL, L"Button", NULL);
if (hButton == hwSource)
{
WCHAR *wszBuffer = NULL;
HWND hEdit = FindWindowExW(hWnd, NULL, L"Edit", NULL);
HWND hStatic = FindWindowExW(hWnd, NULL, L"Static", NULL);
HANDLE hHeap = GetProcessHeap();
INT nLen = GetWindowTextLengthW(hEdit) + 1;
wszBuffer = (WCHAR *) HeapAlloc(hHeap, HEAP_ZERO_MEMORY, nLen * sizeof(WCHAR));
if (NULL == wszBuffer)
{
MessageBoxW(NULL, L"Out of memory", L"Error", MB_OK | MB_ICONSTOP);
ExitProcess(ERROR_OUTOFMEMORY);
}
GetWindowTextW(hEdit, wszBuffer, nLen);
SetWindowTextW(hStatic, wszBuffer);
HeapFree(hHeap, 0, wszBuffer);
wszBuffer = NULL;
}
}
BOOL WINAPI OnCreate(
HWND hWnd,
LPCREATESTRUCTW lpCreateStruct
)
{
INITCOMMONCONTROLSEX iccx;
HINSTANCE hInstance = lpCreateStruct->hInstance;
iccx.dwICC = ICC_STANDARD_CLASSES;
iccx.dwSize = sizeof(INITCOMMONCONTROLSEX);
InitCommonControlsEx(&iccx);
CreateWindowW(L"Button", L"Click Me", WS_VISIBLE | WS_CHILD, 205, 210, 90, 30, hWnd, NULL, hInstance, NULL);
CreateWindowW(L"Static", L"", WS_VISIBLE | WS_CHILD, 10, 100, 490, 20, hWnd, NULL, hInstance, NULL);
CreateWindowW(L"Edit", L"Type something in here", WS_VISIBLE | WS_CHILD, 10, 10, 470, 20, hWnd, NULL, hInstance, NULL);
return TRUE;
}
VOID WINAPI OnDestroy(
HWND hWnd
)
{
PostQuitMessage(ERROR_SUCCESS);
}
VOID WINAPI OnPaint(
HWND hWnd
)
{
PAINTSTRUCT ps;
BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
}
LRESULT CALLBACK WindowProc(
HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam
)
{
switch (Msg)
{
HANDLE_MSG(hWnd, WM_CLOSE, OnClose);
HANDLE_MSG(hWnd, WM_CREATE, OnCreate);
HANDLE_MSG(hWnd, WM_COMMAND, OnCommand);
HANDLE_MSG(hWnd, WM_DESTROY, OnDestroy);
HANDLE_MSG(hWnd, WM_PAINT, OnPaint);
default:
return DefWindowProcW(hWnd, Msg, wParam, lParam);
}
return 0;
}
ATOM WINAPI RegisterWCEX(
HINSTANCE hInstance
)
{
WNDCLASSEXW wcex;
ZeroMemory(&wcex, sizeof(WNDCLASSEXW));
wcex.cbSize = sizeof(WNDCLASSEXW);
wcex.hInstance = hInstance;
wcex.lpszClassName = g_wszClassName;
wcex.hbrBackground = (HBRUSH) COLOR_WINDOW;
wcex.hCursor = LoadCursorW(NULL, IDC_ARROW);
wcex.hIcon = wcex.hIconSm = LoadIconW(NULL, IDI_APPLICATION);
wcex.lpfnWndProc = WindowProc;
return RegisterClassExW(&wcex);
}
INT APIENTRY wWinMain(
_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ INT nShowCmd
)
{
HWND hWnd;
MSG Msg;
if (RegisterWCEX(hInstance) == 0)
{
MessageBoxW(NULL, L"Window registration failed", L"Error", MB_OK | MB_ICONSTOP);
return -1;
}
hWnd = CreateWindowExW(WS_EX_OVERLAPPEDWINDOW, g_wszClassName, L"Windows Font Demo", WS_VISIBLE | WS_SYSMENU, 100, 100, 500, 350, NULL, NULL, hInstance, NULL);
if (NULL == hWnd)
{
MessageBoxW(NULL, L"Window creation failed", L"Error", MB_OK | MB_ICONSTOP);
return -1;
}
ShowWindow(hWnd, nShowCmd);
UpdateWindow(hWnd);
while (GetMessageW(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessageW(&Msg);
}
return Msg.wParam;
}
Will give us the following window:
I therefore make the following addition to any GUI project I code (key changes: the EnumChildProc
function, the SystemsParameterInfoW
and EnumChildWindows
calls in wWinMain
):
#include <Windows.h>
#include <windowsx.h>
#include <CommCtrl.h>
#include <strsafe.h>
#include <sal.h>
#pragma comment(lib, "comctl32.lib")
#if defined _M_IX86
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
#elif defined _M_IA64
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#elif defined _M_X64
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#else
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#endif
CONST WCHAR g_wszClassName[] = L"FONT_DEMO_WINDOW";
BOOL CALLBACK EnumChildProc(
HWND hWnd,
LPARAM lParam
)
{
HFONT hfDefault = *(HFONT *) lParam;
SendMessageW(hWnd, WM_SETFONT, (WPARAM) hfDefault, MAKELPARAM(TRUE, 0));
return TRUE;
}
VOID WINAPI OnClose(
HWND hWnd
)
{
DestroyWindow(hWnd);
}
VOID WINAPI OnCommand(
HWND hWnd,
INT nID,
HWND hwSource,
UINT uNotify
)
{
HWND hButton = FindWindowExW(hWnd, NULL, L"Button", NULL);
if (hButton == hwSource)
{
WCHAR *wszBuffer = NULL;
HWND hEdit = FindWindowExW(hWnd, NULL, L"Edit", NULL);
HWND hStatic = FindWindowExW(hWnd, NULL, L"Static", NULL);
HANDLE hHeap = GetProcessHeap();
INT nLen = GetWindowTextLengthW(hEdit) + 1;
wszBuffer = (WCHAR *) HeapAlloc(hHeap, HEAP_ZERO_MEMORY, nLen * sizeof(WCHAR));
if (NULL == wszBuffer)
{
MessageBoxW(NULL, L"Out of memory", L"Error", MB_OK | MB_ICONSTOP);
ExitProcess(ERROR_OUTOFMEMORY);
}
GetWindowTextW(hEdit, wszBuffer, nLen);
SetWindowTextW(hStatic, wszBuffer);
HeapFree(hHeap, 0, wszBuffer);
wszBuffer = NULL;
}
}
BOOL WINAPI OnCreate(
HWND hWnd,
LPCREATESTRUCTW lpCreateStruct
)
{
INITCOMMONCONTROLSEX iccx;
HINSTANCE hInstance = lpCreateStruct->hInstance;
iccx.dwICC = ICC_STANDARD_CLASSES;
iccx.dwSize = sizeof(INITCOMMONCONTROLSEX);
InitCommonControlsEx(&iccx);
CreateWindowW(L"Button", L"Click Me", WS_VISIBLE | WS_CHILD, 205, 210, 90, 30, hWnd, NULL, hInstance, NULL);
CreateWindowW(L"Static", L"", WS_VISIBLE | WS_CHILD, 10, 100, 490, 20, hWnd, NULL, hInstance, NULL);
CreateWindowW(L"Edit", L"Type something in here", WS_VISIBLE | WS_CHILD, 10, 10, 470, 20, hWnd, NULL, hInstance, NULL);
return TRUE;
}
VOID WINAPI OnDestroy(
HWND hWnd
)
{
PostQuitMessage(ERROR_SUCCESS);
}
VOID WINAPI OnPaint(
HWND hWnd
)
{
PAINTSTRUCT ps;
BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
}
LRESULT CALLBACK WindowProc(
HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam
)
{
switch (Msg)
{
HANDLE_MSG(hWnd, WM_CLOSE, OnClose);
HANDLE_MSG(hWnd, WM_CREATE, OnCreate);
HANDLE_MSG(hWnd, WM_COMMAND, OnCommand);
HANDLE_MSG(hWnd, WM_DESTROY, OnDestroy);
HANDLE_MSG(hWnd, WM_PAINT, OnPaint);
default:
return DefWindowProcW(hWnd, Msg, wParam, lParam);
}
return 0;
}
ATOM WINAPI RegisterWCEX(
HINSTANCE hInstance
)
{
WNDCLASSEXW wcex;
ZeroMemory(&wcex, sizeof(WNDCLASSEXW));
wcex.cbSize = sizeof(WNDCLASSEXW);
wcex.hInstance = hInstance;
wcex.lpszClassName = g_wszClassName;
wcex.hbrBackground = (HBRUSH) COLOR_WINDOW;
wcex.hCursor = LoadCursorW(NULL, IDC_ARROW);
wcex.hIcon = wcex.hIconSm = LoadIconW(NULL, IDI_APPLICATION);
wcex.lpfnWndProc = WindowProc;
return RegisterClassExW(&wcex);
}
INT APIENTRY wWinMain(
_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ INT nShowCmd
)
{
HWND hWnd;
MSG Msg;
NONCLIENTMETRICSW ncm;
HFONT hfDefault;
ZeroMemory(&ncm, sizeof(NONCLIENTMETRICSW));
ncm.cbSize = sizeof(NONCLIENTMETRICSW);
SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICSW), &ncm, FALSE);
hfDefault = CreateFontIndirectW(&ncm.lfMessageFont);
if (RegisterWCEX(hInstance) == 0)
{
MessageBoxW(NULL, L"Window registration failed", L"Error", MB_OK | MB_ICONSTOP);
return -1;
}
hWnd = CreateWindowExW(WS_EX_OVERLAPPEDWINDOW, g_wszClassName, L"Windows Font Demo", WS_VISIBLE | WS_SYSMENU, 100, 100, 500, 350, NULL, NULL, hInstance, NULL);
if (NULL == hWnd)
{
MessageBoxW(NULL, L"Window creation failed", L"Error", MB_OK | MB_ICONSTOP);
return -1;
}
ShowWindow(hWnd, nShowCmd);
EnumChildWindows(hWnd, EnumChildProc, (LPARAM) &hfDefault);
UpdateWindow(hWnd);
while (GetMessageW(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessageW(&Msg);
}
return Msg.wParam;
}
Which gives us the much more aesthetically pleasing window:
Is this an advisable, efficient, and correct solution to this problem?