user32: CallWindowProc[AW] for mismatched built-in winprocs should take into account if the window is Unicode (with testcase, fixes bug #9198)

Mikołaj Zalewski mikolaj at zalewski.pl
Tue Aug 7 23:45:07 CDT 2007


  This strange algorithm is probably to make built-in winprocs work the 
same as custom ones. Hopefully that's the last thing we're missing in A 
and W winprocs and there will be no more regressions
-------------- next part --------------
>From 6905f7b02c92000018ff98a93e276b0d44668890 Mon Sep 17 00:00:00 2001
From: =?utf-8?q?Miko=C5=82aj_Zalewski?= <mikolaj at zalewski.pl>
Date: Tue, 7 Aug 2007 21:35:16 -0700
Subject: [PATCH] user32: CallWindowProc[AW] for mismatched built-in winprocs should take into account if the window is Unicode (with testcase)

---
 dlls/user32/tests/class.c |  116 +++++++++++++++++++++++++++++++++++++++++++-
 dlls/user32/winproc.c     |   48 +++++++++++++++++--
 2 files changed, 157 insertions(+), 7 deletions(-)

diff --git a/dlls/user32/tests/class.c b/dlls/user32/tests/class.c
index 9878ac1..3e55726 100644
--- a/dlls/user32/tests/class.c
+++ b/dlls/user32/tests/class.c
@@ -32,6 +32,7 @@
 #include "winreg.h"
 #include "wingdi.h"
 #include "winuser.h"
+#include <commctrl.h>  /* for WC_EDITW */
 
 #define NUMCLASSWORDS 4
 
@@ -40,6 +41,11 @@ static LRESULT WINAPI ClassTest_WndProc (HWND hWnd, UINT msg, WPARAM wParam, LPA
     return DefWindowProcW (hWnd, msg, wParam, lParam);
 }
 
+static LRESULT WINAPI ClassTest_WndProc2 (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    return DefWindowProcA (hWnd, msg, wParam, lParam);
+}
+
 /***********************************************************************
  */
 static void ClassTest(HINSTANCE hInstance, BOOL global)
@@ -560,7 +566,12 @@ static void test_defwndproc()
 {
     static const char classA[] = "deftest";
     static const WCHAR classW[] = {'d','e','f','t','e','s','t',0};
+    WCHAR unistring[] = {0x142, 0x40e, 0x3b4, 0};  /* a string that would be destoryed by a W->A->W conversion */
     WNDPROC pDefWindowProcA, pDefWindowProcW;
+    WNDCLASSEXA cls;  /* the memory layout of WNDCLASSEXA and WNDCLASSEXW is the same */
+    WCHAR buf[128];
+    ATOM atom;
+    HWND hwnd;
     int i;
 
     pDefWindowProcA = (void *)GetProcAddress(GetModuleHandle("user32.dll"), "DefWindowProcA");
@@ -568,9 +579,6 @@ static void test_defwndproc()
 
     for (i = 0; i < 4; i++)
     {
-        WNDCLASSEXA cls;  /* the memory layout of WNDCLASSEXA and WNDCLASSEXW is the same */
-        ATOM atom;
-        HWND hwnd;
         ZeroMemory(&cls, sizeof(cls));
         cls.cbSize = sizeof(cls);
         cls.hInstance = GetModuleHandle(NULL);
@@ -608,8 +616,110 @@ static void test_defwndproc()
         DestroyWindow(hwnd);
         UnregisterClass((LPSTR)(DWORD_PTR)atom, GetModuleHandle(NULL));
     }
+
+    /* built-in winproc - window A/W type automatically detected */
+    ZeroMemory(&cls, sizeof(cls));
+    cls.cbSize = sizeof(cls);
+    cls.hInstance = GetModuleHandle(NULL);
+    cls.hbrBackground = GetStockObject (WHITE_BRUSH);
+    cls.lpszClassName = classA;
+    cls.lpfnWndProc = pDefWindowProcW;
+    atom = RegisterClassExA(&cls);
+
+    hwnd = CreateWindowExW(0, classW, NULL, WS_OVERLAPPEDWINDOW,
+        CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, GetModuleHandleA(NULL), 0);
+    ok(IsWindowUnicode(hwnd), "\n");
+    SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)pDefWindowProcA);
+    ok(IsWindowUnicode(hwnd), "\n");
+    ok(GetWindowLongPtrW(hwnd, GWLP_WNDPROC) == (LONG_PTR)pDefWindowProcW, "\n");
+    ok(GetWindowLongPtrA(hwnd, GWLP_WNDPROC) == (LONG_PTR)pDefWindowProcA, "\n");
+    SetWindowLongPtrA(hwnd, GWL_WNDPROC, (LONG_PTR)ClassTest_WndProc);
+    ok(IsWindowUnicode(hwnd) == FALSE, "\n");
+
+    DestroyWindow(hwnd);
+    UnregisterClass((LPSTR)(DWORD_PTR)atom, GetModuleHandle(NULL));
+
+    /* custom winproc - the same function can be used as both A and W*/
+    ZeroMemory(&cls, sizeof(cls));
+    cls.cbSize = sizeof(cls);
+    cls.hInstance = GetModuleHandle(NULL);
+    cls.hbrBackground = GetStockObject (WHITE_BRUSH);
+    cls.lpszClassName = classA;
+    cls.lpfnWndProc = ClassTest_WndProc2;
+    atom = RegisterClassExA(&cls);
+
+    hwnd = CreateWindowExW(0, classW, NULL, WS_OVERLAPPEDWINDOW,
+        CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, GetModuleHandleA(NULL), 0);
+    ok(IsWindowUnicode(hwnd) == FALSE, "\n");
+    SetWindowLongPtrW(hwnd, GWL_WNDPROC, (LONG_PTR)ClassTest_WndProc);
+    ok(IsWindowUnicode(hwnd), "\n");
+    SetWindowLongPtrA(hwnd, GWL_WNDPROC, (LONG_PTR)ClassTest_WndProc);
+    ok(IsWindowUnicode(hwnd) == FALSE, "\n");
+
+    DestroyWindow(hwnd);
+    UnregisterClass((LPSTR)(DWORD_PTR)atom, GetModuleHandle(NULL));
+
+    /* calling built-in and custom winprocs with CallWindowProc[AW]. Despite
+     * a slightly different nature the end result is the same */
+    hwnd = CreateWindowW(WC_EDITW, unistring, WS_OVERLAPPEDWINDOW, 
+      CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, NULL, 0);
+    CallWindowProcW((WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf);
+    ok(memcmp(buf, unistring, sizeof(unistring)) == 0, "WM_GETTEXT invalid return\n");
+    CallWindowProcA((WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf);
+    ok(memcmp(buf, unistring, sizeof(unistring)) == 0, "WM_GETTEXT invalid return\n");
+    CallWindowProcW((WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf);
+    ok(memcmp(buf, unistring, sizeof(unistring)) == 0, "WM_GETTEXT invalid return\n");
+
+    SetWindowTextW(hwnd, classW);
+    CallWindowProcA((WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf);
+    ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT invalid return\n");
+
+    SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)ClassTest_WndProc2);
+    ok(IsWindowUnicode(hwnd) == FALSE, "\n");
+    SetWindowTextA(hwnd, classA);  /* Windows resets the title to WideStringToMultiByte(unistring) */
+    memset(buf, 0, sizeof(buf));
+    CallWindowProcA((WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf);
+    ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT invalid return\n");
+    CallWindowProcA((WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf);
+    ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT invalid return\n");
+    CallWindowProcW((WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf);
+    ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT invalid return\n");
+
+    CallWindowProcW((WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf);
+    ok(memcmp(buf, classW, sizeof(classW)) == 0, "WM_GETTEXT invalid return\n");
+
+    DestroyWindow(hwnd);
+
+    hwnd = CreateWindowA(WC_EDITA, classA, WS_OVERLAPPEDWINDOW, 
+      CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, NULL, 0);
+
+    CallWindowProcA((WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf);
+    ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT invalid return\n");
+    CallWindowProcA((WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf);
+    ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT invalid return\n");
+    CallWindowProcW((WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf);
+    ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT invalid return\n");
+
+    CallWindowProcW((WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf);
+    ok(memcmp(buf, classW, sizeof(classW)) == 0, "WM_GETTEXT invalid return\n");
+
+    SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)ClassTest_WndProc);
+    SetWindowTextW(hwnd, unistring);
+    CallWindowProcW((WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf);
+    ok(memcmp(buf, unistring, sizeof(unistring)) == 0, "WM_GETTEXT invalid return\n");
+    CallWindowProcA((WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf);
+    ok(memcmp(buf, unistring, sizeof(unistring)) == 0, "WM_GETTEXT invalid return\n");
+    CallWindowProcW((WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf);
+    ok(memcmp(buf, unistring, sizeof(unistring)) == 0, "WM_GETTEXT invalid return\n");
+
+    SetWindowTextW(hwnd, classW);
+    CallWindowProcA((WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC), hwnd, WM_GETTEXT, 120, (LPARAM)buf);
+    ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT invalid return\n");
+
+    DestroyWindow(hwnd);
 }
 
+
 static LRESULT WINAPI TestDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 {
     return DefWindowProc(hWnd, uMsg, wParam, lParam);
diff --git a/dlls/user32/winproc.c b/dlls/user32/winproc.c
index 27b31a1..4feb3d5 100644
--- a/dlls/user32/winproc.c
+++ b/dlls/user32/winproc.c
@@ -2257,7 +2257,17 @@ LRESULT WINAPI CallWindowProcA(
 
     if (!func) return 0;
 
-    if (!(proc = handle_to_proc( func )) && !(proc = find_builtin_proc( func )))
+    /* for built-in procs we do as if the second item was a thunk */
+    if ((proc = find_builtin_proc( func )) != NULL)
+    {
+	if (func == proc->procA || !IsWindowUnicode( hwnd ))
+	    call_window_proc( hwnd, msg, wParam, lParam, &result, proc->procA );
+	else
+	    call_window_proc( hwnd, msg, wParam, lParam, &result, proc->procW );
+	return result;
+    }
+    
+    if (!(proc = handle_to_proc( func )))
         call_window_proc( hwnd, msg, wParam, lParam, &result, func );
     else if (proc->procA)
         call_window_proc( hwnd, msg, wParam, lParam, &result, proc->procA );
@@ -2281,8 +2291,18 @@ LRESULT WINAPI CallWindowProcW( WNDPROC func, HWND hwnd, UINT msg,
     LRESULT result;
 
     if (!func) return 0;
+    
+    /* for built-in procs we do as if the second item was a thunk */
+    if ((proc = find_builtin_proc( func )) != NULL)
+    {
+	if (func == proc->procW || IsWindowUnicode( hwnd ))
+	    call_window_proc( hwnd, msg, wParam, lParam, &result, proc->procW );
+	else
+	    call_window_proc( hwnd, msg, wParam, lParam, &result, proc->procA );
+	return result;
+    }
 
-    if (!(proc = handle_to_proc( func )) && !(proc = find_builtin_proc( func )))
+    if (!(proc = handle_to_proc( func )))
         call_window_proc( hwnd, msg, wParam, lParam, &result, func );
     else if (proc->procW)
         call_window_proc( hwnd, msg, wParam, lParam, &result, proc->procW );
@@ -2340,7 +2360,17 @@ INT_PTR WINPROC_CallDlgProcA( DLGPROC func, HWND hwnd, UINT msg, WPARAM wParam,
 
     if (!func) return 0;
 
-    if (!(proc = handle_to_proc( func )) && !(proc = find_builtin_proc( func )))
+    /* for built-in procs we do as if the second item was a thunk */
+    if ((proc = find_builtin_proc( func )) != NULL)
+    {
+	if (func == proc->procA || !IsWindowUnicode( hwnd ))
+	    call_dialog_proc( hwnd, msg, wParam, lParam, &result, proc->procA );
+	else
+	    call_dialog_proc( hwnd, msg, wParam, lParam, &result, proc->procW );
+	return result;
+    }
+
+    if (!(proc = handle_to_proc( func )))
         ret = call_dialog_proc( hwnd, msg, wParam, lParam, &result, func );
     else if (proc->procA)
         ret = call_dialog_proc( hwnd, msg, wParam, lParam, &result, proc->procA );
@@ -2368,8 +2398,18 @@ INT_PTR WINPROC_CallDlgProcW( DLGPROC func, HWND hwnd, UINT msg, WPARAM wParam,
     INT_PTR ret;
 
     if (!func) return 0;
+    
+    /* for built-in procs we do as if the second item was a thunk */
+    if ((proc = find_builtin_proc( func )) != NULL)
+    {
+	if (func == proc->procW || IsWindowUnicode( hwnd ))
+	    call_dialog_proc( hwnd, msg, wParam, lParam, &result, proc->procW );
+	else
+	    call_dialog_proc( hwnd, msg, wParam, lParam, &result, proc->procA );
+	return result;
+    }
 
-    if (!(proc = handle_to_proc( func )) && !(proc = find_builtin_proc( func )))
+    if (!(proc = handle_to_proc( func )))
         ret = call_dialog_proc( hwnd, msg, wParam, lParam, &result, func );
     else if (proc->procW)
         ret = call_dialog_proc( hwnd, msg, wParam, lParam, &result, proc->procW );
-- 
1.4.4.2



More information about the wine-patches mailing list