From 0b2eff41b7bb3eb9416f637a5dd02cb5e515f18c Mon Sep 17 00:00:00 2001 From: Mikolaj Zalewski Date: Mon, 17 Sep 2007 11:03:52 -0700 Subject: [PATCH] user32: better fix how to handle GetWindowLongPtr[AW](..., GWLP_WNDPROC) for builtin winprocs --- dlls/user32/class.c | 6 ++++- dlls/user32/controls.h | 2 ++ dlls/user32/edit.c | 2 ++ dlls/user32/tests/class.c | 59 +++++++++++++++++++++++++++++++++++++++++---- dlls/user32/win.c | 25 ++++++++++++++++++- dlls/user32/winproc.c | 41 +++---------------------------- 6 files changed, 90 insertions(+), 45 deletions(-) diff --git a/dlls/user32/class.c b/dlls/user32/class.c index 6be4cad..e5dd701 100644 --- a/dlls/user32/class.c +++ b/dlls/user32/class.c @@ -402,12 +402,13 @@ void CLASS_RegisterBuiltinClasses(void) extern const struct builtin_class_descr SCROLL_builtin_class; extern const struct builtin_class_descr STATIC_builtin_class; + CLASS *edit_class; + register_builtin( &DESKTOP_builtin_class ); register_builtin( &BUTTON_builtin_class ); register_builtin( &COMBO_builtin_class ); register_builtin( &COMBOLBOX_builtin_class ); register_builtin( &DIALOG_builtin_class ); - register_builtin( &EDIT_builtin_class ); register_builtin( &ICONTITLE_builtin_class ); register_builtin( &LISTBOX_builtin_class ); register_builtin( &MDICLIENT_builtin_class ); @@ -415,6 +416,9 @@ void CLASS_RegisterBuiltinClasses(void) register_builtin( &SCROLL_builtin_class ); register_builtin( &STATIC_builtin_class ); + edit_class = register_builtin( &EDIT_builtin_class ); + EDIT_winproc_handle = edit_class->winproc; + /* the DefWindowProc winprocs are magic too */ WINPROC_AllocProc( DefWindowProcA, DefWindowProcW ); } diff --git a/dlls/user32/controls.h b/dlls/user32/controls.h index 6178100..594b665 100644 --- a/dlls/user32/controls.h +++ b/dlls/user32/controls.h @@ -43,6 +43,8 @@ struct builtin_class_descr HBRUSH brush; /* brush or system color */ }; +extern WNDPROC EDIT_winproc_handle; + /* Class functions */ struct tagCLASS; /* opaque structure */ struct tagWND; diff --git a/dlls/user32/edit.c b/dlls/user32/edit.c index b11bf10..51e1890 100644 --- a/dlls/user32/edit.c +++ b/dlls/user32/edit.c @@ -293,6 +293,8 @@ static void EDIT_ImeComposition(HWND hwn LRESULT WINAPI EditWndProcA(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); LRESULT WINAPI EditWndProcW(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +WNDPROC EDIT_winproc_handle; /* filled after registering the classes in classes.c */ + /********************************************************************* * edit class descriptor */ diff --git a/dlls/user32/tests/class.c b/dlls/user32/tests/class.c index 7f54e2f..bd62343 100644 --- a/dlls/user32/tests/class.c +++ b/dlls/user32/tests/class.c @@ -39,6 +39,9 @@ static const WCHAR WC_EDITW[] = {'E','d' #define NUMCLASSWORDS 4 +/* we may need to update it for Win64 */ +#define IS_WNDPROC_HANDLE(x) (((LONG_PTR)x & 0xffff0000) == 0xffff0000) + static LRESULT WINAPI ClassTest_WndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { return DefWindowProcW (hWnd, msg, wParam, lParam); @@ -565,12 +568,21 @@ static void test_instances(void) check_thread_instance( "EDIT", (HINSTANCE)0x12345678, (HINSTANCE)0x12345678, (HINSTANCE)0xdeadbeef ); } -static void test_defwndproc(void) +static void test_builtinproc(void) { + /* Edit behaves differently. ScrollBar have currently only a Unicode winproc */ + static const CHAR NORMAL_CLASSES[][40] = { + "Button", + "Static", + "ComboBox", + "ListBox", + }; + static const int NUM_NORMAL_CLASSES = (sizeof(NORMAL_CLASSES)/sizeof(NORMAL_CLASSES[0])); 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; + WNDPROC oldproc; WNDCLASSEXA cls; /* the memory layout of WNDCLASSEXA and WNDCLASSEXW is the same */ WCHAR buf[128]; ATOM atom; @@ -662,10 +674,42 @@ static void test_defwndproc(void) 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 */ + /* For most of the builtin controls both GetWindowLongPtrA and W returns a pointer that is executed directly + * by CallWindowProcA/W */ + for (i = 0; i < NUM_NORMAL_CLASSES; i++) + { + WNDPROC procA, procW; + hwnd = CreateWindowExA(0, NORMAL_CLASSES[i], classA, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, + NULL, NULL, NULL, 0); + ok(hwnd != NULL, "Couldn't create window of class %s\n", NORMAL_CLASSES[i]); + SetWindowText(hwnd, classA); /* ComboBox needs this */ + procA = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC); + procW = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC); + ok(!IS_WNDPROC_HANDLE(procA), "procA should not be a handle for %s (%p)\n", NORMAL_CLASSES[i], procA); + ok(!IS_WNDPROC_HANDLE(procW), "procW should not be a handle for %s (%p)\n", NORMAL_CLASSES[i], procW); + CallWindowProcA(procA, hwnd, WM_GETTEXT, 120, (LPARAM)buf); + ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT A/A invalid return for class %s\n", NORMAL_CLASSES[i]); + CallWindowProcA(procW, hwnd, WM_GETTEXT, 120, (LPARAM)buf); + ok(memcmp(buf, classW, sizeof(classW)) == 0, "WM_GETTEXT A/W invalid return for class %s\n", NORMAL_CLASSES[i]); + CallWindowProcW(procA, hwnd, WM_GETTEXT, 120, (LPARAM)buf); + ok(memcmp(buf, classA, sizeof(classA)) == 0, "WM_GETTEXT W/A invalid return for class %s\n", NORMAL_CLASSES[i]); + CallWindowProcW(procW, hwnd, WM_GETTEXT, 120, (LPARAM)buf); + ok(memcmp(buf, classW, sizeof(classW)) == 0, "WM_GETTEXT W/W invalid return for class %s\n", NORMAL_CLASSES[i]); + + oldproc = SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)ClassTest_WndProc); + ok(IS_WNDPROC_HANDLE(oldproc) == FALSE, "Class %s shouldn't return a handle\n", NORMAL_CLASSES[i]); + DestroyWindow(hwnd); + } + + /* Edit controls are special - they return a wndproc handle when GetWindowLongPtr is called with a different A/W. + * On the other hand there is no W->A->W conversion so this control is threated specially. */ hwnd = CreateWindowW(WC_EDITW, unistring, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, NULL, 0); + /* GetClassLongPtr returns that both the Unicode and ANSI wndproc */ + ok(IS_WNDPROC_HANDLE(GetClassLongPtrA(hwnd, GCLP_WNDPROC)) == FALSE, "Edit control class should have a Unicode wndproc\n"); + ok(IS_WNDPROC_HANDLE(GetClassLongPtrW(hwnd, GCLP_WNDPROC)) == FALSE, "Edit control class should have a ANSI wndproc\n"); + /* But GetWindowLongPtr returns only a handle for the ANSI one */ + ok(IS_WNDPROC_HANDLE(GetWindowLongPtrA(hwnd, GWLP_WNDPROC)), "Edit control should return a wndproc handle\n"); 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); @@ -677,7 +721,9 @@ static void test_defwndproc(void) 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); + oldproc = SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)ClassTest_WndProc2); + /* SetWindowLongPtr returns a wndproc handle - like GetWindowLongPtr */ + ok(IS_WNDPROC_HANDLE(oldproc), "Edit control should return a wndproc handle\n"); ok(IsWindowUnicode(hwnd) == FALSE, "SetWindowLongPtrA should have changed window to ANSI\n"); SetWindowTextA(hwnd, classA); /* Windows resets the title to WideStringToMultiByte(unistring) */ memset(buf, 0, sizeof(buf)); @@ -696,6 +742,7 @@ static void test_defwndproc(void) hwnd = CreateWindowA(WC_EDITA, classA, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, NULL, 0); + ok(IS_WNDPROC_HANDLE(GetWindowLongPtrW(hwnd, GWLP_WNDPROC)), "Edit control should return a wndproc handle\n"); 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); @@ -785,6 +832,8 @@ START_TEST(class) ClassTest(hInstance,TRUE); CreateDialogParamTest(hInstance); test_styles(); + test_builtinproc(); + + /* this test unregisters the Button class so it should be executed at the end */ test_instances(); - test_defwndproc(); } diff --git a/dlls/user32/win.c b/dlls/user32/win.c index 41eb108..92474c1 100644 --- a/dlls/user32/win.c +++ b/dlls/user32/win.c @@ -1788,7 +1788,21 @@ static LONG_PTR WIN_GetWindowLong( HWND case GWL_STYLE: retvalue = wndPtr->dwStyle; break; case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break; case GWLP_ID: retvalue = (ULONG_PTR)wndPtr->wIDmenu; break; - case GWLP_WNDPROC: retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode ); break; + case GWLP_WNDPROC: + { + /* This looks like a hack only for the edit control (see tests). This makes these controls + * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests + * that the hack is in GetWindowLongPtr[AW], not in winprocs. + */ + if (wndPtr->winproc == EDIT_winproc_handle) + if ((unicode && !(wndPtr->flags & WIN_ISUNICODE)) || (!unicode && (wndPtr->flags & WIN_ISUNICODE))) + { + retvalue = (ULONG_PTR)wndPtr->winproc; + break; + } + retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode ); + break; + } case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break; default: WARN("Unknown offset %d\n", offset ); @@ -1877,7 +1891,14 @@ LONG_PTR WIN_SetWindowLong( HWND hwnd, I { WNDPROC proc; UINT old_flags = wndPtr->flags; - retval = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode ); + /* see comment in WIN_GetWindowLong */ + if (wndPtr->winproc == EDIT_winproc_handle && + ((unicode && !(wndPtr->flags & WIN_ISUNICODE)) || (!unicode && (wndPtr->flags & WIN_ISUNICODE)))) + { + retval = (ULONG_PTR)wndPtr->winproc; + } + else + retval = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode ); if (unicode) proc = WINPROC_AllocProc( NULL, (WNDPROC)newval ); else proc = WINPROC_AllocProc( (WNDPROC)newval, NULL ); if (proc) wndPtr->winproc = proc; diff --git a/dlls/user32/winproc.c b/dlls/user32/winproc.c index e58d1f0..51e5112 100644 --- a/dlls/user32/winproc.c +++ b/dlls/user32/winproc.c @@ -113,19 +113,6 @@ static inline WINDOWPROC *find_winproc( return NULL; } -/* find an existing builtin winproc */ -static inline WINDOWPROC *find_builtin_proc( WNDPROC func ) -{ - unsigned int i; - - for (i = 0; i < builtin_used; i++) - { - if (winproc_array[i].procA == func || winproc_array[i].procW == func) - return &winproc_array[i]; - } - return NULL; -} - /* return the window proc for a given handle, or NULL for an invalid handle */ static inline WINDOWPROC *handle_to_proc( WNDPROC handle ) { @@ -2288,12 +2275,7 @@ LRESULT WINAPI CallWindowProcA( if (!func) return 0; if (!(proc = handle_to_proc( func ))) - { - if ((proc = find_builtin_proc( func )) && !IsWindowUnicode( hwnd )) - call_window_proc( hwnd, msg, wParam, lParam, &result, proc->procA ); - else - call_window_proc( hwnd, msg, wParam, lParam, &result, func ); - } + call_window_proc( hwnd, msg, wParam, lParam, &result, func ); else if (proc->procA) call_window_proc( hwnd, msg, wParam, lParam, &result, proc->procA ); else if (proc->procW) @@ -2319,12 +2301,7 @@ LRESULT WINAPI CallWindowProcW( WNDPROC if (!func) return 0; if (!(proc = handle_to_proc( func ))) - { - if ((proc = find_builtin_proc( func )) && IsWindowUnicode( hwnd )) - call_window_proc( hwnd, msg, wParam, lParam, &result, proc->procW ); - else - call_window_proc( hwnd, msg, wParam, lParam, &result, func ); - } + call_window_proc( hwnd, msg, wParam, lParam, &result, func ); else if (proc->procW) call_window_proc( hwnd, msg, wParam, lParam, &result, proc->procW ); else if (proc->procA) @@ -2382,12 +2359,7 @@ INT_PTR WINPROC_CallDlgProcA( DLGPROC fu if (!func) return 0; if (!(proc = handle_to_proc( func ))) - { - if ((proc = find_builtin_proc( func )) && !IsWindowUnicode( hwnd )) - ret = call_dialog_proc( hwnd, msg, wParam, lParam, &result, proc->procA ); - else - ret = call_dialog_proc( hwnd, msg, wParam, lParam, &result, 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 ); else if (proc->procW) @@ -2417,12 +2389,7 @@ INT_PTR WINPROC_CallDlgProcW( DLGPROC fu if (!func) return 0; if (!(proc = handle_to_proc( func ))) - { - if ((proc = find_builtin_proc( func )) && IsWindowUnicode( hwnd )) - ret = call_dialog_proc( hwnd, msg, wParam, lParam, &result, proc->procW ); - else - ret = call_dialog_proc( hwnd, msg, wParam, lParam, &result, 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 ); else if (proc->procA) -- 1.4.1