#include "alfpriv.h" #include static DWORD ALF_DllGetVersion(const char *dll) { HMODULE hDll = GetModuleHandleA(dll); if (hDll) { DLLGETVERSIONPROC pDllGetVersion; pDllGetVersion = (DLLGETVERSIONPROC)(void*)GetProcAddress(hDll, "DllGetVersion"); if (pDllGetVersion) { DLLVERSIONINFO dvi; HRESULT hr; ZeroMemory(&dvi, sizeof(dvi)); dvi.cbSize = sizeof(dvi); hr = (*pDllGetVersion)(&dvi); if (SUCCEEDED(hr)) { return MAKELONG(dvi.dwMinorVersion, dvi.dwMajorVersion); } } } return 0; } static int WINAPI fallbackGetSystemMetricsForDpi(int nIndex, UINT dpi) { (void)dpi; if (LOBYTE(LOWORD(GetVersion())) < 4) { // old NT does not support several properties, so we fake them switch (nIndex) { case SM_CXEDGE: case SM_CYEDGE: return 2; } } return GetSystemMetrics(nIndex); } static BOOL WINAPI fallbackIsAppThemed(void) { return FALSE; } static UINT WINAPI fallbackGetDpiForWindow(HWND win) { (void)win; UINT dpi = 0; HDC hdcScreen = GetDC(NULL); if (hdcScreen) { dpi = GetDeviceCaps(hdcScreen, LOGPIXELSY); ReleaseDC(NULL, hdcScreen); } if (!dpi) { dpi = 96; // FIXME! fallback to default DPI } return dpi; } static BOOL WINAPI fallbackSystemParametersInfoForDpi(UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni, UINT dpi) { (void)dpi; return SystemParametersInfo(uiAction, uiParam, pvParam, fWinIni); } static BOOL WINAPI fallbackAdjustWindowRectExForDpi(LPRECT lpRect, DWORD dwStyle, BOOL bMenu, DWORD dwExStyle, UINT dpi) { (void)dpi; return AdjustWindowRectEx(lpRect, dwStyle, bMenu, dwExStyle); } // FIXME: these support one subclass only, negating the whole point of it typedef struct { ALF_COMPAT_SUBCLASSPROC pfnSubclass; UINT_PTR uIdSubclass; DWORD_PTR dwRefData; UINT runCounter; WNDPROC orig; } ALFWindowSubclassData; static LRESULT CALLBACK fallbackSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { ALFWindowSubclassData *data = (ALFWindowSubclassData *)GetWindowLongPtr(hwnd, GWLP_USERDATA); LRESULT ret = 0; data->runCounter++; if (data->pfnSubclass) ret = data->pfnSubclass(hwnd, uMsg, wParam, lParam, data->uIdSubclass, data->dwRefData); else ret = CallWindowProc(data->orig, hwnd, uMsg, wParam, lParam); data->runCounter--; if (!data->pfnSubclass && !data->runCounter) { SetWindowLongPtr(hwnd, GWLP_USERDATA, 0); HeapFree(GetProcessHeap(), 0, data); } return ret; } static BOOL WINAPI fallbackSetWindowSubclass(HWND hwnd, ALF_COMPAT_SUBCLASSPROC pfnSubclass, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) { ALFWindowSubclassData *data = (ALFWindowSubclassData *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ALFWindowSubclassData)); data->pfnSubclass = pfnSubclass; data->uIdSubclass = uIdSubclass; data->dwRefData = dwRefData; data->orig = (WNDPROC)GetWindowLongPtr(hwnd, GWLP_WNDPROC); SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)data); SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)fallbackSubclassProc); return TRUE; } static LRESULT WINAPI fallbackDefSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { ALFWindowSubclassData *data = (ALFWindowSubclassData *)GetWindowLongPtr(hwnd, GWLP_USERDATA); return CallWindowProc(data->orig, hwnd, uMsg, wParam, lParam); } static BOOL WINAPI fallbackRemoveWindowSubclass(HWND hwnd, ALF_COMPAT_SUBCLASSPROC pfnSubclass, UINT_PTR uIdSubclass) { (void)pfnSubclass; (void)uIdSubclass; ALFWindowSubclassData *data = (ALFWindowSubclassData *)GetWindowLongPtr(hwnd, GWLP_USERDATA); data->pfnSubclass = 0; data->uIdSubclass = 0; SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)data->orig); // can't free it while the subclass is running, possibly in a nested SendMessage // and wants to call DefSubclassProc if (!data->runCounter) { SetWindowLongPtr(hwnd, GWLP_USERDATA, 0); HeapFree(GetProcessHeap(), 0, data); } return TRUE; } ALFCompatFunctions * ALF_CreateCompatFuncTable(void) { ALFCompatFunctions *compatfn = (ALFCompatFunctions*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY|HEAP_GENERATE_EXCEPTIONS, sizeof(ALFCompatFunctions)); #define COMPAT(dll, entrypoint, ordinal, fallback) \ do { \ FARPROC p = GetProcAddress(GetModuleHandleA(#dll), #entrypoint); \ if (!p && ordinal) \ p = GetProcAddress(GetModuleHandleA(#dll), (char*)ordinal); \ CopyMemory(&compatfn->entrypoint, &p, sizeof(void*)); \ \ if (!compatfn->entrypoint) \ compatfn->entrypoint = fallback; \ } while (0) COMPAT(comctl32.dll, SetWindowSubclass, 410, fallbackSetWindowSubclass); COMPAT(comctl32.dll, DefSubclassProc, 413, fallbackDefSubclassProc); COMPAT(comctl32.dll, RemoveWindowSubclass, 412, fallbackRemoveWindowSubclass); COMPAT(user32.dll, GetSystemMetricsForDpi, 0, fallbackGetSystemMetricsForDpi); COMPAT(user32.dll, GetDpiForWindow, 0, fallbackGetDpiForWindow); // FIXME: SystemParametersInfoForDpi is Unicode-Only. // Writing a wrapper function would have been The Right Way, but such a function // is yet to be written. So the current practical recommendation is to make // ANSI builds System DPI aware only. #ifdef UNICODE COMPAT(user32.dll, SystemParametersInfoForDpi, 0, fallbackSystemParametersInfoForDpi); #else compatfn->SystemParametersInfoForDpi = fallbackSystemParametersInfoForDpi; #endif COMPAT(user32.dll, AdjustWindowRectExForDpi, 0, fallbackAdjustWindowRectExForDpi); // IsAppThemed would return TRUE even when we're linked against comctl32 v5 if (ALF_DllGetVersion("comctl32.dll") >= 0x60000) { LoadLibraryA("uxtheme.dll"); COMPAT(uxtheme.dll, IsAppThemed, 0, fallbackIsAppThemed); } else { compatfn->IsAppThemed = fallbackIsAppThemed; } #undef COMPAT UINT oldErrorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX); // stop win32s from barking about rpcrt4 HMODULE rpc = LoadLibraryA("rpcrt4.dll"); if (rpc) { // NT always has rpcrt4.dll compatfn->UuidCreate = (ULONG(WINAPI*)(UUID*))(void*)GetProcAddress(rpc, "UuidCreate"); } else { // Win32s always has OLE32 HMODULE ole32 = LoadLibraryA("ole32.dll"); compatfn->UuidCreate = (ULONG(WINAPI*)(UUID*))(void*)GetProcAddress(ole32, "CoCreateGuid"); } SetErrorMode(oldErrorMode); return compatfn; } long ALF_GetAveCharWidth(HDC hdc) { // see: HOWTO: Calculate Dialog Units When Not Using the System Font SIZE s; GetTextExtentPoint32A(hdc, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 52, &s); return (s.cx / 26 + 1) / 2; }