summaryrefslogtreecommitdiff
path: root/alf/alfcompat.cpp
diff options
context:
space:
mode:
authorJonas Kümmerlin <jonas@kuemmerlin.eu>2019-01-03 23:57:56 +0100
committerJonas Kümmerlin <jonas@kuemmerlin.eu>2019-01-03 23:57:56 +0100
commit9c385f9a366da308d2a37ad5deda5d40f9285abb (patch)
tree578f6739c8e99f61c0b8747502d8e133e585a7d0 /alf/alfcompat.cpp
parentcd7b608f0517c1100f79b4a3ec654e4178373506 (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.
Diffstat (limited to 'alf/alfcompat.cpp')
-rw-r--r--alf/alfcompat.cpp107
1 files changed, 104 insertions, 3 deletions
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;
}