diff options
| author | Jonas Kümmerlin <jonas@kuemmerlin.eu> | 2019-01-03 23:57:56 +0100 |
|---|---|---|
| committer | Jonas Kümmerlin <jonas@kuemmerlin.eu> | 2019-01-03 23:57:56 +0100 |
| commit | 9c385f9a366da308d2a37ad5deda5d40f9285abb (patch) | |
| tree | 578f6739c8e99f61c0b8747502d8e133e585a7d0 | |
| parent | cd7b608f0517c1100f79b4a3ec654e4178373506 (diff) | |
extend compatibility to Win95 RTM, NT3.1 and Win32s
Only NT3.51 actually works mostly right, all others suffer from various
kinds of breakage. Running a 3.1-compatible binary on newer windows
enables some kind of compatibility mode with bizarro background brushes
and weirdly sized combo boxes.
Going forward, I'm committed to keep NT3.51 running as long as Win95RTM
is supported. The future of NT3.1 and Win32s support is uncertain.
| -rw-r--r-- | Makefile.mingw | 2 | ||||
| -rw-r--r-- | Makefile.vc6 | 2 | ||||
| -rw-r--r-- | Makefile.vc6-ansi | 2 | ||||
| -rw-r--r-- | Makefile.vc6-ansi-31 | 36 | ||||
| -rw-r--r-- | Makefile.vc6-nt31 | 36 | ||||
| -rw-r--r-- | alf/alf.cpp | 116 | ||||
| -rw-r--r-- | alf/alfcombobox.cpp | 46 | ||||
| -rw-r--r-- | alf/alfcompat.cpp | 107 | ||||
| -rw-r--r-- | alf/alfcompat.h | 4 | ||||
| -rw-r--r-- | alf/alfedit.cpp | 18 | ||||
| -rw-r--r-- | alf/alflist.h | 2 | ||||
| -rw-r--r-- | alf/alfpriv.h | 2 | ||||
| -rwxr-xr-x | makemakefile.sh | 55 | ||||
| -rw-r--r-- | widgetfactory.cpp | 17 |
14 files changed, 378 insertions, 67 deletions
diff --git a/Makefile.mingw b/Makefile.mingw index 4bc45ce..a93af76 100644 --- a/Makefile.mingw +++ b/Makefile.mingw @@ -2,7 +2,7 @@ CXX = i686-w64-mingw32-c++ CFLAGS = -std=c++98 -Wall -Wextra -mwindows -municode -DUNICODE -D_UNICODE -fno-exceptions -fno-rtti -gstabs -LDFLAGS = -luser32 -lcomctl32 -lshell32 -lrpcrt4 -lversion -static +LDFLAGS = -luser32 -lcomctl32 -lshell32 -lversion -static out/widgetfactory.exe: out/widgetfactory.o out/alfbutton.o out/alfcombobox.o out/alfcompat.o out/alf.o out/alfdpiaware.o out/alfedit.o out/alflabel.o $(CXX) $(CFLAGS) -o $@ $^ $(LDFLAGS) diff --git a/Makefile.vc6 b/Makefile.vc6 index c0ab753..8a37758 100644 --- a/Makefile.vc6 +++ b/Makefile.vc6 @@ -2,7 +2,7 @@ CXX = cl.exe CFLAGS = -O2 -GA -W3 -DUNICODE -D_UNICODE -D_WIN32=0x0501 -D_WIN32_WINNT=0x0501 -D_WIN32_IE=0x0501 -nologo -LDFLAGS = /link unicows.lib kernel32.lib user32.lib comctl32.lib shell32.lib gdi32.lib version.lib rpcrt4.lib +LDFLAGS = /link unicows.lib kernel32.lib user32.lib comctl32.lib shell32.lib gdi32.lib version.lib out/widgetfactory.exe: out/widgetfactory.obj out/alfbutton.obj out/alfcombobox.obj out/alfcompat.obj out/alf.obj out/alfdpiaware.obj out/alfedit.obj out/alflabel.obj $(CXX) $(CFLAGS) -Fe$@ $** $(LDFLAGS) diff --git a/Makefile.vc6-ansi b/Makefile.vc6-ansi index 569e9a5..3bf0cb6 100644 --- a/Makefile.vc6-ansi +++ b/Makefile.vc6-ansi @@ -2,7 +2,7 @@ CXX = cl.exe CFLAGS = -O2 -GA -W3 -D_WIN32=0x0501 -D_WIN32_WINNT=0x0501 -D_WIN32_IE=0x0501 -nologo -LDFLAGS = /link kernel32.lib user32.lib comctl32.lib shell32.lib gdi32.lib version.lib rpcrt4.lib +LDFLAGS = /link /entry:_entry kernel32.lib user32.lib comctl32.lib shell32.lib gdi32.lib version.lib out/widgetfactory.exe: out/widgetfactory.obj out/alfbutton.obj out/alfcombobox.obj out/alfcompat.obj out/alf.obj out/alfdpiaware.obj out/alfedit.obj out/alflabel.obj $(CXX) $(CFLAGS) -Fe$@ $** $(LDFLAGS) diff --git a/Makefile.vc6-ansi-31 b/Makefile.vc6-ansi-31 new file mode 100644 index 0000000..adb8512 --- /dev/null +++ b/Makefile.vc6-ansi-31 @@ -0,0 +1,36 @@ +# automatically created by makemakefile.sh. DO NOT EDIT! + +CXX = cl.exe +CFLAGS = -O2 -GA -W3 -D_WIN32=0x0501 -D_WIN32_WINNT=0x0501 -D_WIN32_IE=0x0501 -nologo +LDFLAGS = /link /subsystem:windows,3.10 /entry:_entry /fixed:no kernel32.lib user32.lib comctl32.lib shell32.lib gdi32.lib version.lib + +out/widgetfactory.exe: out/widgetfactory.obj out/alfbutton.obj out/alfcombobox.obj out/alfcompat.obj out/alf.obj out/alfdpiaware.obj out/alfedit.obj out/alflabel.obj + $(CXX) $(CFLAGS) -Fe$@ $** $(LDFLAGS) + +out/alfbutton.obj: alf/alfbutton.cpp alf/alfcompat.h alf/alf.h alf/alflist.h alf/alfpriv.h + $(CXX) $(CFLAGS) -c -Fo$@ alf/alfbutton.cpp + +out/alfcombobox.obj: alf/alfcombobox.cpp alf/alfcompat.h alf/alf.h alf/alflist.h alf/alfpriv.h + $(CXX) $(CFLAGS) -c -Fo$@ alf/alfcombobox.cpp + +out/alfcompat.obj: alf/alfcompat.cpp alf/alfcompat.h alf/alf.h alf/alflist.h alf/alfpriv.h + $(CXX) $(CFLAGS) -c -Fo$@ alf/alfcompat.cpp + +out/alf.obj: alf/alf.cpp alf/alfcompat.h alf/alf.h alf/alflist.h alf/alfpriv.h + $(CXX) $(CFLAGS) -c -Fo$@ alf/alf.cpp + +out/alfdpiaware.obj: alf/alfdpiaware.cpp alf/alfcompat.h alf/alf.h alf/alflist.h alf/alfpriv.h + $(CXX) $(CFLAGS) -c -Fo$@ alf/alfdpiaware.cpp + +out/alfedit.obj: alf/alfedit.cpp alf/alfcompat.h alf/alf.h alf/alflist.h alf/alfpriv.h + $(CXX) $(CFLAGS) -c -Fo$@ alf/alfedit.cpp + +out/alflabel.obj: alf/alflabel.cpp alf/alfcompat.h alf/alf.h alf/alflist.h alf/alfpriv.h + $(CXX) $(CFLAGS) -c -Fo$@ alf/alflabel.cpp + +out/widgetfactory.obj: widgetfactory.cpp alf/alf.h + $(CXX) $(CFLAGS) -c -Fo$@ widgetfactory.cpp + +clean: + del /f out\*.obj out\*.exe + diff --git a/Makefile.vc6-nt31 b/Makefile.vc6-nt31 new file mode 100644 index 0000000..339a91f --- /dev/null +++ b/Makefile.vc6-nt31 @@ -0,0 +1,36 @@ +# automatically created by makemakefile.sh. DO NOT EDIT! + +CXX = cl.exe +CFLAGS = -O2 -GA -W3 -DUNICODE -D_UNICODE -D_WIN32=0x0501 -D_WIN32_WINNT=0x0501 -D_WIN32_IE=0x0501 -nologo +LDFLAGS = /link /subsystem:windows,3.10 /entry:_entry kernel32.lib user32.lib comctl32.lib shell32.lib gdi32.lib version.lib + +out/widgetfactory.exe: out/widgetfactory.obj out/alfbutton.obj out/alfcombobox.obj out/alfcompat.obj out/alf.obj out/alfdpiaware.obj out/alfedit.obj out/alflabel.obj + $(CXX) $(CFLAGS) -Fe$@ $** $(LDFLAGS) + +out/alfbutton.obj: alf/alfbutton.cpp alf/alfcompat.h alf/alf.h alf/alflist.h alf/alfpriv.h + $(CXX) $(CFLAGS) -c -Fo$@ alf/alfbutton.cpp + +out/alfcombobox.obj: alf/alfcombobox.cpp alf/alfcompat.h alf/alf.h alf/alflist.h alf/alfpriv.h + $(CXX) $(CFLAGS) -c -Fo$@ alf/alfcombobox.cpp + +out/alfcompat.obj: alf/alfcompat.cpp alf/alfcompat.h alf/alf.h alf/alflist.h alf/alfpriv.h + $(CXX) $(CFLAGS) -c -Fo$@ alf/alfcompat.cpp + +out/alf.obj: alf/alf.cpp alf/alfcompat.h alf/alf.h alf/alflist.h alf/alfpriv.h + $(CXX) $(CFLAGS) -c -Fo$@ alf/alf.cpp + +out/alfdpiaware.obj: alf/alfdpiaware.cpp alf/alfcompat.h alf/alf.h alf/alflist.h alf/alfpriv.h + $(CXX) $(CFLAGS) -c -Fo$@ alf/alfdpiaware.cpp + +out/alfedit.obj: alf/alfedit.cpp alf/alfcompat.h alf/alf.h alf/alflist.h alf/alfpriv.h + $(CXX) $(CFLAGS) -c -Fo$@ alf/alfedit.cpp + +out/alflabel.obj: alf/alflabel.cpp alf/alfcompat.h alf/alf.h alf/alflist.h alf/alfpriv.h + $(CXX) $(CFLAGS) -c -Fo$@ alf/alflabel.cpp + +out/widgetfactory.obj: widgetfactory.cpp alf/alf.h + $(CXX) $(CFLAGS) -c -Fo$@ widgetfactory.cpp + +clean: + del /f out\*.obj out\*.exe + diff --git a/alf/alf.cpp b/alf/alf.cpp index 6936436..aef4167 100644 --- a/alf/alf.cpp +++ b/alf/alf.cpp @@ -1,6 +1,6 @@ #include "alfpriv.h" -#include <rpc.h> +#include <objbase.h> /* ALF App and Window */ @@ -62,26 +62,32 @@ ALF_UpdateFontsPriv(HWND win, ALFWindowPriv *priv) { priv->fonts.dpi = priv->app->compatFn->GetDpiForWindow(win); - // XXX: SystemParametersInfoForDpi needs the Vista+ NONCLIENTMETRICS, - // but we want to be able to build with WINVER = 0x0500 and PSDK2003 - ALF_NONCLIENTMETRICS_VISTA ncm; - ZeroMemory(&ncm, sizeof(ncm)); - ncm.cbSize = ALF_SizeOf_NONCLIENTMETRICS(); - - if (priv->app->compatFn->SystemParametersInfoForDpi(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0, priv->fonts.dpi)) { - priv->fonts.lfMessageFont = ncm.lfMessageFont; + if (LOBYTE(LOWORD(GetVersion())) < 4) { + // NT 3.x uses System font for everything, we copy that + priv->fonts.hMessageFont = (HFONT)GetStockObject(SYSTEM_FONT); + GetObject(priv->fonts.hMessageFont, sizeof(priv->fonts.lfMessageFont), &priv->fonts.lfMessageFont); } else { - // FIXME! fallback to default font, 8pt MS Shell Dlg - ZeroMemory(&priv->fonts.lfMessageFont, sizeof(priv->fonts.lfMessageFont)); + // XXX: SystemParametersInfoForDpi needs the Vista+ NONCLIENTMETRICS, + // but we want to be able to build with WINVER = 0x0500 and PSDK2003 + ALF_NONCLIENTMETRICS_VISTA ncm; + ZeroMemory(&ncm, sizeof(ncm)); + ncm.cbSize = ALF_SizeOf_NONCLIENTMETRICS(); + + if (priv->app->compatFn->SystemParametersInfoForDpi(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0, priv->fonts.dpi)) { + priv->fonts.lfMessageFont = ncm.lfMessageFont; + } else { + // FIXME! fallback to default font, 8pt MS Shell Dlg + ZeroMemory(&priv->fonts.lfMessageFont, sizeof(priv->fonts.lfMessageFont)); - priv->fonts.lfMessageFont.lfHeight = -MulDiv(8, priv->fonts.dpi, 72); - lstrcpy(priv->fonts.lfMessageFont.lfFaceName, TEXT("MS Shell Dlg")); - } + priv->fonts.lfMessageFont.lfHeight = -MulDiv(8, priv->fonts.dpi, 72); + lstrcpy(priv->fonts.lfMessageFont.lfFaceName, TEXT("MS Shell Dlg")); + } - if (priv->fonts.hMessageFont) { - DeleteObject(priv->fonts.hMessageFont); + if (priv->fonts.hMessageFont) { + DeleteObject(priv->fonts.hMessageFont); + } + priv->fonts.hMessageFont = CreateFontIndirect(&priv->fonts.lfMessageFont); } - priv->fonts.hMessageFont = CreateFontIndirect(&priv->fonts.lfMessageFont); ALF_FOR_LIST(ALFWidgetPriv, list, &priv->widgets, i) { ALF_UpdateFontForWidget(priv, i); @@ -249,6 +255,9 @@ ALF_ApplyLayout(HWND hwnd, ALFWindowPriv *win) HDWP hdwp = BeginDeferWindowPos(win->layout.occupiedColumnCount * win->layout.occupiedRowCount); ALF_FOR_LIST(ALFWidgetPriv, list, &win->widgets, c) { + if ((int)c->x >= win->layout.nColumns || (int)c->y >= win->layout.nRows) + continue; + int marginleft = ALF_CentipointsToPxPriv(win, c->cptMarginLeft); int marginright = ALF_CentipointsToPxPriv(win, c->cptMarginRight); int margintop = ALF_CentipointsToPxPriv(win, c->cptMarginTop); @@ -549,6 +558,23 @@ ALF_DefWindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) return TRUE; } + if (msg == WM_CTLCOLORSTATIC) { + HDC hdcStatic = (HDC)wparam; + HWND hwndStatic = (HWND)lparam; + + // HACK! return correct label background for NT3.x and NT4/95 + // get rid of this once we fixed the label to draw on the parent control background + if (LOBYTE(LOWORD(GetVersion())) < 4) { + SetTextColor(hdcStatic, GetSysColor(IsWindowEnabled(hwndStatic) ? COLOR_WINDOWTEXT : COLOR_GRAYTEXT)); + SetBkColor(hdcStatic, GetSysColor(COLOR_WINDOW)); + return (LRESULT)GetSysColorBrush(COLOR_WINDOW); + } else { + SetTextColor(hdcStatic, GetSysColor(IsWindowEnabled(hwndStatic) ? COLOR_BTNTEXT : COLOR_GRAYTEXT)); + SetBkColor(hdcStatic, GetSysColor(COLOR_BTNFACE)); + return (LRESULT)GetSysColorBrush(COLOR_BTNFACE); + } + } + return DefWindowProc(hwnd, msg, wparam, lparam); } @@ -599,12 +625,7 @@ ALF_CreateApplication(HINSTANCE hInstance) ALFAPP app = (ALFAPP)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY|HEAP_GENERATE_EXCEPTIONS, sizeof(struct ALFAppPriv)); app->hInstance = hInstance; - INITCOMMONCONTROLSEX icc; - ZeroMemory(&icc, sizeof(icc)); - icc.dwSize = sizeof(icc); - icc.dwICC = ICC_WIN95_CLASSES; - - InitCommonControlsEx(&icc); + InitCommonControls(); app->compatFn = ALF_CreateCompatFuncTable(); ALF_RegisterComboClass(app); @@ -620,23 +641,39 @@ ALF_TeardownApplication(ALFAPP app) HeapFree(GetProcessHeap(), 0, app); } +static void +ALF_IntToHex(TCHAR *buf, unsigned long num, int chars) +{ + char letters[] = { '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + for (int i = 0; i < chars; ++i) { + buf[chars-i-1] = letters[(num >> (i*4)) & 0xf]; + } +} + +static void +ALF_UuidToString(const GUID *guid, TCHAR *buf) +{ + ALF_IntToHex(buf, guid->Data1, 8); + buf[8] = '-'; + ALF_IntToHex(buf + 9, guid->Data2, 4); + buf[13] = '-'; + ALF_IntToHex(buf + 14, guid->Data3, 4); + buf[18] = '-'; + for (int i = 0; i < 8; ++i) { + ALF_IntToHex(buf + 19 + 2*i, guid->Data4[i], 2); + } + buf[35] = 0; +} + void -ALF_BuildRandomClassName(const TCHAR *prefix, TCHAR *buf) +ALF_BuildRandomClassName(ALFAPP app, const TCHAR* prefix, TCHAR* buf) { UUID uuid; - UuidCreate(&uuid); - -#ifdef UNICODE - unsigned short *uuidstr = NULL; -#else - unsigned char *uuidstr = NULL; -#endif - UuidToString(&uuid, &uuidstr); + app->compatFn->UuidCreate(&uuid); lstrcpy(buf, prefix); - lstrcat(buf, (LPCTSTR)uuidstr); - - RpcStringFree(&uuidstr); + ALF_UuidToString(&uuid, &buf[lstrlen(buf)]); } LPTSTR @@ -651,13 +688,18 @@ ALF_RegisterWindowClass(ALFAPP app, const ALFWindowClassParams *params) ZeroMemory(classNameBuf, sizeof(classNameBuf)); classNamePtr = classNameBuf; - ALF_BuildRandomClassName(TEXT("ALFWindow."), classNameBuf); + ALF_BuildRandomClassName(app, TEXT("ALFWindow."), classNameBuf); } cls.style = params->classStyle; cls.hInstance = app->hInstance; cls.hCursor = LoadCursor(NULL, (LPTSTR)IDC_ARROW); - cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1); + if (LOBYTE(LOWORD(GetVersion())) >= 4) { + cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1); + } else { + // NT 3.x has white dialog backgrounds + cls.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + } cls.lpszClassName = classNamePtr; cls.cbWndExtra = sizeof(void*); cls.cbClsExtra = sizeof(void*)*2; diff --git a/alf/alfcombobox.cpp b/alf/alfcombobox.cpp index 3007a20..8afdace 100644 --- a/alf/alfcombobox.cpp +++ b/alf/alfcombobox.cpp @@ -42,11 +42,15 @@ ALF__ComboWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) if (uMsg == WM_CREATE) { ALFComboCreateParams *params = (ALFComboCreateParams*)((CREATESTRUCT*)lParam)->lpCreateParams; + DWORD comboStyle = params->comboStyle; + if (LOBYTE(LOWORD(GetVersion())) >= 4) + comboStyle |= CBS_OWNERDRAWFIXED | CBS_HASSTRINGS; + HWND hwndCombo = CreateWindowEx(0, TEXT("COMBOBOX"), TEXT(""), - WS_CHILD | WS_VISIBLE | WS_TABSTOP | CBS_OWNERDRAWFIXED | CBS_HASSTRINGS | params->comboStyle, - 0, 0, 0, 200 /* FIXME needed for commctl32 v5, what is the best value here? */, + WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP | comboStyle, + 0, 0, 100, 200 /* FIXME needed for commctl32 v5, what is the best value here? */, hwnd, (HMENU) GetWindowLongPtrW(hwnd, GWLP_ID), ((CREATESTRUCT*)lParam)->hInstance, @@ -121,7 +125,9 @@ ALF__ComboWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) } if (uMsg == WM_COMMAND && (HWND)lParam == hwndChild) { - return SendMessage(GetParent(hwnd), WM_COMMAND, wParam, (LPARAM)hwnd); + // XXX: for whatever reason, Win95 (and only win95 - doesn't happen on NT) + // sends a wrong ID value in WPARAM. We fix it by replacing it with our own id. + return SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(GetWindowLong(hwnd, GWL_ID), HIWORD(wParam)), (LPARAM)hwnd); } if (uMsg == ALF_WM_QUERYSIZE) { @@ -218,15 +224,22 @@ ALF__ComboWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) if (uMsg == WM_WINDOWPOSCHANGED && hwndChild) { WINDOWPOS *pos = (WINDOWPOS *)lParam; if (!(pos->flags & SWP_NOSIZE)) { - RECT r; - GetWindowRect(hwndChild, &r); - SetWindowPos(hwndChild, NULL, 0, 1, pos->cx, r.bottom - r.top, SWP_NOZORDER|SWP_NOACTIVATE); - - SendMessage(hwndChild, CB_SETITEMHEIGHT, (WPARAM)-1, pos->cy - 8); - - int h = ALF__ComboItemHeight(hwnd); - if (h) - SendMessage(hwndChild, CB_SETITEMHEIGHT, (WPARAM)0, h); + // XXX: When resizing the combo box, it will improperly draw a selection. + // this appears to be a well-known bug that is still not fixed, even in Win10. + // workaround based on https://stackoverflow.com/questions/49603893/how-to-deal-with-invalidly-painted-combobox-control-in-win32-winapi + DWORD sel = SendMessage(hwndChild, CB_GETEDITSEL, 0, 0); + SendMessage(hwndChild, CB_SETEDITSEL, 0, -1); + // SWP_NOCOPYBITS because NT 3.51 doesn't properly repaint the drop-down button + SetWindowPos(hwndChild, NULL, 0, 1, pos->cx, 200, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOCOPYBITS); + SendMessage(hwndChild, CB_SETEDITSEL, 0, (LPARAM)sel); + + if (LOBYTE(LOWORD(GetVersion())) >= 4) { + SendMessage(hwndChild, CB_SETITEMHEIGHT, (WPARAM)-1, pos->cy - 8); + + int h = ALF__ComboItemHeight(hwnd); + if (h) + SendMessage(hwndChild, CB_SETITEMHEIGHT, (WPARAM)0, h); + } } } @@ -241,11 +254,16 @@ ALF_RegisterComboClass(ALFAPP app) ZeroMemory(&cls, sizeof(cls)); TCHAR classNameBuf[256]; - ALF_BuildRandomClassName(TEXT("ALFComboBox."), classNameBuf); + ALF_BuildRandomClassName(app, TEXT("ALFComboBox."), classNameBuf); cls.hInstance = app->hInstance; cls.hCursor = LoadCursor(NULL, (LPTSTR)IDC_ARROW); - cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1); + if (LOBYTE(LOWORD(GetVersion())) >= 4) { + cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1); + } else { + // NT 3.x has white dialog backgrounds + cls.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + } cls.lpszClassName = classNameBuf; cls.cbWndExtra = sizeof(void*)*2; cls.lpfnWndProc = ALF__ComboWindowProc; diff --git a/alf/alfcompat.cpp b/alf/alfcompat.cpp index 269b9f4..5486b19 100644 --- a/alf/alfcompat.cpp +++ b/alf/alfcompat.cpp @@ -32,6 +32,14 @@ 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); } @@ -77,6 +85,87 @@ fallbackAdjustWindowRectExForDpi(LPRECT lpRect, DWORD dwStyle, BOOL bMenu, DWORD 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) { @@ -93,9 +182,9 @@ ALF_CreateCompatFuncTable(void) compatfn->entrypoint = fallback; \ } while (0) - COMPAT(comctl32.dll, SetWindowSubclass, 410, NULL); - COMPAT(comctl32.dll, DefSubclassProc, 413, NULL); - COMPAT(comctl32.dll, RemoveWindowSubclass, 412, NULL); + 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); @@ -121,6 +210,18 @@ ALF_CreateCompatFuncTable(void) #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; } diff --git a/alf/alfcompat.h b/alf/alfcompat.h index ba315e1..2d590c8 100644 --- a/alf/alfcompat.h +++ b/alf/alfcompat.h @@ -1,4 +1,5 @@ #include <windows.h> +#include <rpc.h> #ifndef WM_DPICHANGED #define WM_DPICHANGED 0x02E0 @@ -6,7 +7,7 @@ typedef LRESULT (CALLBACK *ALF_COMPAT_SUBCLASSPROC)(HWND,UINT,WPARAM,LPARAM,UINT_PTR,DWORD_PTR); typedef struct { - LRESULT (WINAPI *SetWindowSubclass)(HWND, ALF_COMPAT_SUBCLASSPROC, UINT_PTR, DWORD_PTR); + BOOL (WINAPI *SetWindowSubclass)(HWND, ALF_COMPAT_SUBCLASSPROC, UINT_PTR, DWORD_PTR); LRESULT (WINAPI *DefSubclassProc)(HWND, UINT, WPARAM, LPARAM); BOOL (WINAPI *RemoveWindowSubclass)(HWND, ALF_COMPAT_SUBCLASSPROC, UINT_PTR); int (WINAPI *GetSystemMetricsForDpi)(int, UINT); @@ -14,6 +15,7 @@ typedef struct { UINT (WINAPI *GetDpiForWindow)(HWND); BOOL (WINAPI *SystemParametersInfoForDpi)(UINT,UINT,PVOID,UINT,UINT); BOOL (WINAPI *AdjustWindowRectExForDpi)(LPRECT,DWORD,BOOL,DWORD,UINT); + ULONG (WINAPI *UuidCreate)(UUID *); } ALFCompatFunctions; diff --git a/alf/alfedit.cpp b/alf/alfedit.cpp index fc1d876..bbe36b8 100644 --- a/alf/alfedit.cpp +++ b/alf/alfedit.cpp @@ -41,11 +41,12 @@ ALF__EditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_P } else if (uMsg == ALF_WM_APPLYSIZE) { RECT *p = (RECT *)lParam; + // SWP_NOCOPYBITS as a bandaid since NT 3.51 doesn't invalidate properly return (LRESULT)DeferWindowPos((HDWP)wParam, hwnd, NULL, p->left, p->top + 1, p->right - p->left, p->bottom - p->top - 2, - SWP_NOZORDER|SWP_NOACTIVATE); + SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOCOPYBITS); } else if (uMsg == WM_DESTROY) { app->compatFn->RemoveWindowSubclass(hwnd, ALF__EditSubclassProc, 0); } @@ -56,10 +57,21 @@ ALF__EditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_P HWND ALF_AddEdit(HWND win, WORD id, UINT x, UINT y, const TCHAR *text) { - HWND hwndEdit = CreateWindowEx(WS_EX_CLIENTEDGE, + DWORD exstyle; + DWORD style; + + if (LOBYTE(LOWORD(GetVersion())) >= 4) { + exstyle = WS_EX_CLIENTEDGE; + style = 0; + } else { + exstyle = 0; + style = WS_BORDER; + } + + HWND hwndEdit = CreateWindowEx(exstyle, TEXT("EDIT"), text, - WS_CHILD | WS_VISIBLE | WS_TABSTOP, + WS_CHILD | WS_VISIBLE | WS_TABSTOP | style, 0, 0, 100, 100, win, (HMENU)(int)id, diff --git a/alf/alflist.h b/alf/alflist.h index e0de033..6f63626 100644 --- a/alf/alflist.h +++ b/alf/alflist.h @@ -12,7 +12,7 @@ typedef struct ALFListHeader { *alf_list_##iteratorvar##_next = alf_list_##iteratorvar##_curr->next; \ alf_list_##iteratorvar##_curr != (listp); \ alf_list_##iteratorvar##_curr = alf_list_##iteratorvar##_next, \ - alf_list_##iteratorvar##_next = alf_list_##iteratorvar##_next->next) \ + alf_list_##iteratorvar##_next = alf_list_##iteratorvar##_curr->next) \ for (ContainerType *iteratorvar = (ContainerType *)((char *)alf_list_##iteratorvar##_curr - offsetof(ContainerType, containermember)); \ iteratorvar; iteratorvar = NULL) \ diff --git a/alf/alfpriv.h b/alf/alfpriv.h index 0d5be2f..95bcda4 100644 --- a/alf/alfpriv.h +++ b/alf/alfpriv.h @@ -71,4 +71,4 @@ void ALF_RegisterComboClass(ALFAPP app); void -ALF_BuildRandomClassName(const TCHAR *prefix, TCHAR *buf); +ALF_BuildRandomClassName(ALFAPP app, const TCHAR *prefix, TCHAR *buf); diff --git a/makemakefile.sh b/makemakefile.sh index 22ac030..86a69b4 100755 --- a/makemakefile.sh +++ b/makemakefile.sh @@ -13,7 +13,7 @@ ALF_VC6_OBJECTS=$(for i in $ALF_SOURCES; do printf ' out/%s.obj' "$(basename "$i printf '\n' printf 'CXX = i686-w64-mingw32-c++\n' printf 'CFLAGS = -std=c++98 -Wall -Wextra -mwindows -municode -DUNICODE -D_UNICODE -fno-exceptions -fno-rtti -gstabs\n' - printf 'LDFLAGS = -luser32 -lcomctl32 -lshell32 -lrpcrt4 -lversion -static\n' + printf 'LDFLAGS = -luser32 -lcomctl32 -lshell32 -lversion -static\n' printf '\n' printf 'out/widgetfactory.exe: out/widgetfactory.o %s\n' "$ALF_MINGW_OBJECTS" printf '\t$(CXX) $(CFLAGS) -o $@ $^ $(LDFLAGS)\n' @@ -37,7 +37,7 @@ ALF_VC6_OBJECTS=$(for i in $ALF_SOURCES; do printf ' out/%s.obj' "$(basename "$i printf '\n' printf 'CXX = cl.exe\n' printf 'CFLAGS = -O2 -GA -W3 -DUNICODE -D_UNICODE -D_WIN32=0x0501 -D_WIN32_WINNT=0x0501 -D_WIN32_IE=0x0501 -nologo\n' - printf 'LDFLAGS = /link unicows.lib kernel32.lib user32.lib comctl32.lib shell32.lib gdi32.lib version.lib rpcrt4.lib\n' + printf 'LDFLAGS = /link unicows.lib kernel32.lib user32.lib comctl32.lib shell32.lib gdi32.lib version.lib\n' printf '\n' printf 'out/widgetfactory.exe: out/widgetfactory.obj %s\n' "$ALF_VC6_OBJECTS" @@ -56,13 +56,38 @@ ALF_VC6_OBJECTS=$(for i in $ALF_SOURCES; do printf ' out/%s.obj' "$(basename "$i printf '\tdel /f out\\*.obj out\\*.exe\n\n' ) > Makefile.vc6 +# vc6 nt31 makefile +( + printf '# automatically created by makemakefile.sh. DO NOT EDIT!\n' + printf '\n' + printf 'CXX = cl.exe\n' + printf 'CFLAGS = -O2 -GA -W3 -DUNICODE -D_UNICODE -D_WIN32=0x0501 -D_WIN32_WINNT=0x0501 -D_WIN32_IE=0x0501 -nologo\n' + printf 'LDFLAGS = /link /subsystem:windows,3.10 /entry:_entry kernel32.lib user32.lib comctl32.lib shell32.lib gdi32.lib version.lib\n' + + printf '\n' + printf 'out/widgetfactory.exe: out/widgetfactory.obj %s\n' "$ALF_VC6_OBJECTS" + printf '\t$(CXX) $(CFLAGS) -Fe$@ $** $(LDFLAGS)\n' + printf '\n' + for i in $ALF_SOURCES; do + printf 'out/%s: %s %s\n' "$(basename "$i" .cpp).obj" "alf/$i" "$(for k in $ALF_HEADERS; do printf ' alf/%s' "$k"; done)" + printf '\t$(CXX) $(CFLAGS) -c -Fo$@ %s\n\n' "alf/$i" + done + + printf 'out/widgetfactory.obj: widgetfactory.cpp alf/alf.h\n' + printf '\t$(CXX) $(CFLAGS) -c -Fo$@ widgetfactory.cpp\n\n' + + + printf 'clean:\n' + printf '\tdel /f out\\*.obj out\\*.exe\n\n' +) > Makefile.vc6-nt31 + # vc6 ANSI makefile ( printf '# automatically created by makemakefile.sh. DO NOT EDIT!\n' printf '\n' printf 'CXX = cl.exe\n' printf 'CFLAGS = -O2 -GA -W3 -D_WIN32=0x0501 -D_WIN32_WINNT=0x0501 -D_WIN32_IE=0x0501 -nologo\n' - printf 'LDFLAGS = /link kernel32.lib user32.lib comctl32.lib shell32.lib gdi32.lib version.lib rpcrt4.lib\n' + printf 'LDFLAGS = /link /entry:_entry kernel32.lib user32.lib comctl32.lib shell32.lib gdi32.lib version.lib\n' printf '\n' printf 'out/widgetfactory.exe: out/widgetfactory.obj %s\n' "$ALF_VC6_OBJECTS" @@ -81,3 +106,27 @@ ALF_VC6_OBJECTS=$(for i in $ALF_SOURCES; do printf ' out/%s.obj' "$(basename "$i printf '\tdel /f out\\*.obj out\\*.exe\n\n' ) > Makefile.vc6-ansi +# vc6 NT3.1/Win32s ANSI makefile +( + printf '# automatically created by makemakefile.sh. DO NOT EDIT!\n' + printf '\n' + printf 'CXX = cl.exe\n' + printf 'CFLAGS = -O2 -GA -W3 -D_WIN32=0x0501 -D_WIN32_WINNT=0x0501 -D_WIN32_IE=0x0501 -nologo\n' + printf 'LDFLAGS = /link /subsystem:windows,3.10 /entry:_entry /fixed:no kernel32.lib user32.lib comctl32.lib shell32.lib gdi32.lib version.lib\n' + + printf '\n' + printf 'out/widgetfactory.exe: out/widgetfactory.obj %s\n' "$ALF_VC6_OBJECTS" + printf '\t$(CXX) $(CFLAGS) -Fe$@ $** $(LDFLAGS)\n' + printf '\n' + for i in $ALF_SOURCES; do + printf 'out/%s: %s %s\n' "$(basename "$i" .cpp).obj" "alf/$i" "$(for k in $ALF_HEADERS; do printf ' alf/%s' "$k"; done)" + printf '\t$(CXX) $(CFLAGS) -c -Fo$@ %s\n\n' "alf/$i" + done + + printf 'out/widgetfactory.obj: widgetfactory.cpp alf/alf.h\n' + printf '\t$(CXX) $(CFLAGS) -c -Fo$@ widgetfactory.cpp\n\n' + + + printf 'clean:\n' + printf '\tdel /f out\\*.obj out\\*.exe\n\n' +) > Makefile.vc6-ansi-31 diff --git a/widgetfactory.cpp b/widgetfactory.cpp index 42eb987..7956d5c 100644 --- a/widgetfactory.cpp +++ b/widgetfactory.cpp @@ -68,6 +68,9 @@ handleCommand(void *closure, HWND window, WORD notificationcode, WORD sourceid, HWND combo = ALF_WidgetHwndById(window, ID_COMBO2); ALF_ComboBoxSetCurrentIndex(combo, -1); } + if (control != NULL && sourceid == ID_B2) { + MessageBox(window, TEXT("Hello World!"), TEXT("Hello"), MB_ICONASTERISK|MB_OK); + } return 0; } @@ -151,7 +154,7 @@ WinMain ALF_ComboBoxSetText(hwndCombo2, TEXT("Goodbye World!")); - //EnableWindow(ALF_WidgetHwndById(win, ID_LBL3), FALSE); + EnableWindow(ALF_WidgetHwndById(win, ID_LBL3), FALSE); ALF_ResizeWindow(win, 1, 1); @@ -163,3 +166,15 @@ WinMain return 0; } + +void +_entry(void) +{ + ExitProcess( +#ifdef UNICODE +wWinMain +#else +WinMain +#endif + (GetModuleHandle(NULL), NULL, GetCommandLine(), SW_SHOW)); +} |
