#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 ALF_Compat_fallbackGetSystemMetricsForDpi(int nIndex, UINT dpi) { (void)dpi; if (!ALF_Compat_IsMinWindowsVersion(4, 0)) { // 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 ALF_Compat_fallbackIsAppThemed(void) { return FALSE; } static UINT WINAPI ALF_Compat_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 ALF_Compat_fallbackSystemParametersInfoForDpi(UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni, UINT dpi) { (void)dpi; // NOTE: we only use SystemParametersInfoForDpi for SPI_GETNONCLIENTMETRICS, // therefore we only provide a fallback for that. // SystemParametersInfoForDpi only accepts the Vista+ version of NONCLIENTMETRICSW. if (uiAction == SPI_GETNONCLIENTMETRICS && uiParam == sizeof(ALF_NONCLIENTMETRICSW_VISTA)) { ALF_NONCLIENTMETRICSW_VISTA *ncmw = (ALF_NONCLIENTMETRICSW_VISTA*)pvParam; // SystemParametersInfoForDpi is Unicode-only, but // we need to provide a fallback even on ANSI systems #ifdef UNICODE SIZE_T s = sizeof(*ncmw); if (!ALF_Compat_IsMinWindowsVersion(6, 0)) { // pre-vista OS doesn't contain last member s -= sizeof(ncmw->iPaddedBorderWidth); ncmw->iPaddedBorderWidth = 0; } ncmw->cbSize = s; return SystemParametersInfo(SPI_GETNONCLIENTMETRICS, s, ncmw, fWinIni); #else ALF_NONCLIENTMETRICSA_VISTA ncma; ZeroMemory(&ncma, sizeof(ncma)); SIZE_T s = sizeof(ncma); if (!ALF_Compat_IsMinWindowsVersion(6, 0)) { // pre-vista OS doesn't contain last member s -= sizeof(ncma.iPaddedBorderWidth); ncma.iPaddedBorderWidth = 0; } ncma.cbSize = s; if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, s, &ncma, fWinIni)) { ncmw->iBorderWidth = ncma.iBorderWidth; ncmw->iScrollWidth = ncma.iScrollWidth; ncmw->iScrollHeight = ncma.iScrollHeight; ncmw->iCaptionWidth = ncma.iCaptionWidth; ncmw->iCaptionHeight = ncma.iCaptionHeight; ALF_Compat_LogFontAtoW(&ncma.lfCaptionFont, &ncmw->lfCaptionFont); ncmw->iSmCaptionWidth = ncma.iSmCaptionWidth; ncmw->iSmCaptionHeight = ncma.iSmCaptionHeight; ALF_Compat_LogFontAtoW(&ncma.lfSmCaptionFont, &ncmw->lfSmCaptionFont); ncmw->iMenuWidth = ncma.iMenuWidth; ncmw->iMenuHeight = ncma.iMenuHeight; ALF_Compat_LogFontAtoW(&ncma.lfMenuFont, &ncmw->lfMenuFont); ALF_Compat_LogFontAtoW(&ncma.lfStatusFont, &ncmw->lfStatusFont); ALF_Compat_LogFontAtoW(&ncma.lfMessageFont, &ncmw->lfMessageFont); ncmw->iPaddedBorderWidth = ncma.iPaddedBorderWidth; return TRUE; } return FALSE; #endif } return FALSE; } static BOOL WINAPI ALF_Compat_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 ALF_Compat_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); ALF_Free(data); } return ret; } static BOOL WINAPI ALF_Compat_fallbackSetWindowSubclass(HWND hwnd, ALF_COMPAT_SUBCLASSPROC pfnSubclass, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) { ALFWindowSubclassData *data = ALF_New(ALFWindowSubclassData, 1); 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)ALF_Compat_fallbackSubclassProc); return TRUE; } static LRESULT WINAPI ALF_Compat_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 ALF_Compat_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); ALF_Free(data); } return TRUE; } 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; } static HTHEME WINAPI ALF_Compat_fallbackOpenThemeData(HWND window, LPCWSTR classNames) { (void)window; (void)classNames; return NULL; } static HRESULT WINAPI ALF_Compat_fallbackCloseThemeData(HTHEME hTheme) { (void)hTheme; return S_OK; } static BOOL WINAPI ALF_Compat_fallbackIsThemeBackgroundPartiallyTransparent(HTHEME hTheme, int iPartId, int iStateId) { (void)hTheme; (void)iPartId; (void)iStateId; return TRUE; } static HRESULT WINAPI ALF_Compat_fallbackDrawThemeParentBackground(HWND hwnd, HDC hdc, RECT *prc) { HWND parent = GetParent(hwnd); if (!parent) return E_NOTIMPL; RECT rc; if (prc) { rc = *prc; } else { GetClientRect(hwnd, &rc); } MapWindowRect(hwnd, parent, &rc); RECT childr; GetClientRect(hwnd, &childr); MapWindowRect(hwnd, parent, &childr); POINT o; OffsetViewportOrgEx(hdc, -childr.left, -childr.top, &o); HRGN oldClipRgn = CreateRectRgn(0, 0, 0, 0); if (!GetClipRgn(hdc, oldClipRgn)) { DeleteObject(oldClipRgn); oldClipRgn = NULL; } IntersectClipRect(hdc, rc.left, rc.top, rc.right, rc.bottom); SendMessage(parent, WM_ERASEBKGND, (WPARAM)hdc, 0); SendMessage(parent, WM_PRINTCLIENT, (WPARAM)hdc, (LPARAM)PRF_CLIENT); SelectClipRgn(hdc, oldClipRgn); if (oldClipRgn) { DeleteObject(oldClipRgn); } SetViewportOrgEx(hdc, o.x, o.y, NULL); return S_OK; } static HRESULT WINAPI ALF_Compat_fallbackDrawThemeBackground(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, const RECT *pClipRect) { (void)hTheme; (void)hdc; (void)iPartId; (void)iStateId; (void)pRect; (void)pClipRect; return E_NOTIMPL; } static HRESULT WINAPI ALF_Compat_fallbackGetThemeBackgroundContentRect(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pBoundingRect, RECT *pContentRect) { (void)hTheme; (void)hdc; (void)iPartId; (void)iStateId; (void)pBoundingRect; (void)pContentRect; return E_NOTIMPL; } static HRESULT WINAPI ALF_Compat_fallbackGetThemeTextExtent(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCWSTR pszText, int iCharCount, DWORD dwTextFlags, const RECT *pBoundingRect, RECT *pExtentRect) { (void)hTheme; (void)hdc; (void)iPartId; (void)iStateId; (void)pszText; (void)iCharCount; (void)dwTextFlags; (void)pBoundingRect; (void)pExtentRect; return E_NOTIMPL; } static HRESULT WINAPI ALF_Compat_fallbackDrawThemeText(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCWSTR pszText, int iCharCount, DWORD dwTextFlags, DWORD dwTextFlags2, const RECT *pRect) { (void)hTheme; (void)hdc; (void)iPartId; (void)iStateId; (void)pszText; (void)iCharCount; (void)dwTextFlags; (void)dwTextFlags2; (void)pRect; return E_NOTIMPL; } static BOOL WINAPI ALF_Compat_fallbackTrackMouseEvent(LPTRACKMOUSEEVENT tme) { (void)tme; return FALSE; } static HRESULT WINAPI ALF_Compat_fallbackBufferedPaintInit(void) { return E_NOTIMPL; } static HRESULT WINAPI ALF_Compat_fallbackBufferedPaintUnInit(void) { return E_NOTIMPL; } static ALF_Compat_HANIMATIONBUFFER WINAPI ALF_Compat_fallbackBeginBufferedAnimation(HWND hwnd, HDC hdcTarget, const RECT *prcTarget, DWORD dwFormat, ALF_Compat_BP_PAINTPARAMS *pPaintParams, ALF_Compat_BP_ANIMATIONPARAMS *pAnimationParams, HDC *phdcFrom, HDC *phdcTo) { (void)hwnd; (void)hdcTarget; (void)prcTarget; (void)dwFormat; (void)pPaintParams; (void)pAnimationParams; (void)phdcFrom; (void)phdcTo; return NULL; } static HRESULT WINAPI ALF_Compat_fallbackEndBufferedAnimation(ALF_Compat_HANIMATIONBUFFER hbpAnimation, BOOL fUpdateTarget) { (void)hbpAnimation; (void)fUpdateTarget; return E_NOTIMPL; } static BOOL WINAPI ALF_Compat_fallbackBufferedPaintRenderAnimation(HWND hwnd, HDC hdc) { (void)hwnd; (void)hdc; return FALSE; } static HRESULT WINAPI ALF_Compat_fallbackGetThemeTransitionDuration(HTHEME hTheme, int iPartId, int iStateIdFrom, int iStateIdTo, int iPropId, DWORD *pdwDuration) { (void)hTheme; (void)iPartId; (void)iStateIdFrom; (void)iStateIdTo; (void)iPropId; (void)pdwDuration; return E_NOTIMPL; } #define LOAD_FUNC(dll, name) do { \ if (_alf_dll_##dll) \ *((FARPROC*)&ALF_Compat_##name) = GetProcAddress(_alf_dll_##dll, #name); \ else \ ALF_Compat_##name = NULL; \ \ if (!ALF_Compat_##name) \ ALF_Compat_##name = ALF_Compat_fallback##name; \ } while (0) #define UNLOAD_FUNC(name) do { ALF_Compat_##name = NULL; } while (0) static HMODULE _alf_dll_uxtheme = NULL; static HMODULE _alf_dll_user32 = NULL; static HMODULE _alf_dll_comctl32 = NULL; void ALF_LoadCompatFunctions(void) { if (ALF_Compat_IsWinNT()) // don't attempt to load uxtheme.dll on non-NT platforms (ugly error on Win32s) _alf_dll_uxtheme = LoadLibraryA("uxtheme.dll"); _alf_dll_user32 = LoadLibraryA("user32.dll"); _alf_dll_comctl32 = LoadLibraryA("comctl32.dll"); if (ALF_DllGetVersion("comctl32.dll") >= 0x60000) LOAD_FUNC(uxtheme, IsAppThemed); else ALF_Compat_IsAppThemed = ALF_Compat_fallbackIsAppThemed; LOAD_FUNC(user32, GetDpiForWindow); LOAD_FUNC(user32, AdjustWindowRectExForDpi); LOAD_FUNC(user32, GetSystemMetricsForDpi); *((FARPROC*)&ALF_Compat_SetWindowSubclass) = GetProcAddress(_alf_dll_comctl32, "SetWindowSubclass"); if (!ALF_Compat_SetWindowSubclass) *((FARPROC*)&ALF_Compat_SetWindowSubclass) = GetProcAddress(_alf_dll_comctl32, (char*)410); if (!ALF_Compat_SetWindowSubclass) ALF_Compat_SetWindowSubclass = ALF_Compat_fallbackSetWindowSubclass; *((FARPROC*)&ALF_Compat_DefSubclassProc) = GetProcAddress(_alf_dll_comctl32, "DefSubclassProc"); if (!ALF_Compat_DefSubclassProc) *((FARPROC*)&ALF_Compat_DefSubclassProc) = GetProcAddress(_alf_dll_comctl32, (char*)413); if (!ALF_Compat_DefSubclassProc) ALF_Compat_DefSubclassProc = ALF_Compat_fallbackDefSubclassProc; *((FARPROC*)&ALF_Compat_RemoveWindowSubclass) = GetProcAddress(_alf_dll_comctl32, "RemoveWindowSubclass"); if (!ALF_Compat_RemoveWindowSubclass) *((FARPROC*)&ALF_Compat_RemoveWindowSubclass) = GetProcAddress(_alf_dll_comctl32, (char*)412); if (!ALF_Compat_RemoveWindowSubclass) ALF_Compat_RemoveWindowSubclass = ALF_Compat_fallbackRemoveWindowSubclass; LOAD_FUNC(user32, SystemParametersInfoForDpi); *((FARPROC*)&ALF_Compat_TrackMouseEvent) = GetProcAddress(_alf_dll_comctl32, "_TrackMouseEvent"); if (!ALF_Compat_TrackMouseEvent) ALF_Compat_TrackMouseEvent = ALF_Compat_fallbackTrackMouseEvent; LOAD_FUNC(uxtheme, OpenThemeData); LOAD_FUNC(uxtheme, CloseThemeData); LOAD_FUNC(uxtheme, IsThemeBackgroundPartiallyTransparent); LOAD_FUNC(uxtheme, DrawThemeParentBackground); LOAD_FUNC(uxtheme, DrawThemeBackground); LOAD_FUNC(uxtheme, GetThemeBackgroundContentRect); LOAD_FUNC(uxtheme, GetThemeTextExtent); LOAD_FUNC(uxtheme, DrawThemeText); LOAD_FUNC(uxtheme, BufferedPaintInit); LOAD_FUNC(uxtheme, BufferedPaintUnInit); LOAD_FUNC(uxtheme, BeginBufferedAnimation); LOAD_FUNC(uxtheme, EndBufferedAnimation); LOAD_FUNC(uxtheme, BufferedPaintRenderAnimation); LOAD_FUNC(uxtheme, GetThemeTransitionDuration); } void ALF_UnloadCompatFunctions(void) { UNLOAD_FUNC(IsAppThemed); UNLOAD_FUNC(GetDpiForWindow); UNLOAD_FUNC(AdjustWindowRectExForDpi); UNLOAD_FUNC(GetSystemMetricsForDpi); UNLOAD_FUNC(SetWindowSubclass); UNLOAD_FUNC(DefSubclassProc); UNLOAD_FUNC(RemoveWindowSubclass); UNLOAD_FUNC(SystemParametersInfoForDpi); UNLOAD_FUNC(TrackMouseEvent); UNLOAD_FUNC(OpenThemeData); UNLOAD_FUNC(CloseThemeData); UNLOAD_FUNC(IsThemeBackgroundPartiallyTransparent); UNLOAD_FUNC(DrawThemeParentBackground); UNLOAD_FUNC(DrawThemeBackground); UNLOAD_FUNC(GetThemeBackgroundContentRect); UNLOAD_FUNC(GetThemeTextExtent); UNLOAD_FUNC(DrawThemeText); UNLOAD_FUNC(BufferedPaintInit); UNLOAD_FUNC(BufferedPaintUnInit); UNLOAD_FUNC(BeginBufferedAnimation); UNLOAD_FUNC(EndBufferedAnimation); UNLOAD_FUNC(BufferedPaintRenderAnimation); UNLOAD_FUNC(GetThemeTransitionDuration); FreeLibrary(_alf_dll_uxtheme); FreeLibrary(_alf_dll_user32); FreeLibrary(_alf_dll_comctl32); } #undef LOAD_FUNC #undef UNLOAD_FUNC BOOL (WINAPI *ALF_Compat_IsAppThemed)(void) = NULL; UINT (WINAPI *ALF_Compat_GetDpiForWindow)(HWND /*window*/) = NULL; BOOL (WINAPI *ALF_Compat_AdjustWindowRectExForDpi)(LPRECT,DWORD,BOOL,DWORD,UINT) = NULL; int (WINAPI *ALF_Compat_GetSystemMetricsForDpi)(int, UINT) = NULL; BOOL (WINAPI *ALF_Compat_SetWindowSubclass)(HWND, ALF_COMPAT_SUBCLASSPROC, UINT_PTR, DWORD_PTR) = NULL; LRESULT (WINAPI *ALF_Compat_DefSubclassProc)(HWND, UINT, WPARAM, LPARAM) = NULL; BOOL (WINAPI *ALF_Compat_RemoveWindowSubclass)(HWND, ALF_COMPAT_SUBCLASSPROC, UINT_PTR) = NULL; BOOL (WINAPI *ALF_Compat_SystemParametersInfoForDpi)(UINT,UINT,PVOID,UINT,UINT) = NULL; HTHEME (WINAPI *ALF_Compat_OpenThemeData)(HWND, LPCWSTR) = NULL; HRESULT (WINAPI *ALF_Compat_CloseThemeData)(HTHEME) = NULL; BOOL (WINAPI *ALF_Compat_IsThemeBackgroundPartiallyTransparent)(HTHEME,int,int) = NULL; HRESULT (WINAPI *ALF_Compat_DrawThemeParentBackground)(HWND,HDC,RECT *) = NULL; HRESULT (WINAPI *ALF_Compat_DrawThemeBackground)(HTHEME, HDC, int, int, const RECT *, const RECT *) = NULL; HRESULT (WINAPI *ALF_Compat_GetThemeBackgroundContentRect)(HTHEME,HDC,int,int,const RECT *,RECT *) = NULL; HRESULT (WINAPI *ALF_Compat_GetThemeTextExtent)(HTHEME,HDC,int,int,LPCWSTR,int,DWORD,const RECT *, RECT *) = NULL; HRESULT (WINAPI *ALF_Compat_DrawThemeText)(HTHEME,HDC,int,int,LPCWSTR,int,DWORD,DWORD,const RECT *) = NULL; BOOL (WINAPI *ALF_Compat_TrackMouseEvent)(LPTRACKMOUSEEVENT tme) = NULL; HRESULT (WINAPI *ALF_Compat_BufferedPaintInit)(void) = NULL; HRESULT (WINAPI *ALF_Compat_BufferedPaintUnInit)(void) = NULL; ALF_Compat_HANIMATIONBUFFER (WINAPI *ALF_Compat_BeginBufferedAnimation)(HWND,HDC,const RECT *,DWORD,ALF_Compat_BP_PAINTPARAMS *,ALF_Compat_BP_ANIMATIONPARAMS *,HDC *,HDC *) = NULL; HRESULT (WINAPI *ALF_Compat_EndBufferedAnimation)(ALF_Compat_HANIMATIONBUFFER,BOOL) = NULL; BOOL (WINAPI *ALF_Compat_BufferedPaintRenderAnimation)(HWND,HDC) = NULL; HRESULT (WINAPI *ALF_Compat_GetThemeTransitionDuration)(HTHEME,int,int,int,int,DWORD*) = NULL;