user32: Better fix how to handle GetWindowLongPtr[AW](..., GWLP_WNDPROC) for builtin winprocs.
This commit is contained in:
parent
55d274d1d2
commit
585329ed13
|
@ -366,7 +366,7 @@ static CLASS *CLASS_RegisterClass( ATOM atom, HINSTANCE hInstance, BOOL local,
|
|||
* Register a builtin control class.
|
||||
* This allows having both ASCII and Unicode winprocs for the same class.
|
||||
*/
|
||||
static CLASS *register_builtin( const struct builtin_class_descr *descr )
|
||||
static WNDPROC register_builtin( const struct builtin_class_descr *descr )
|
||||
{
|
||||
ATOM atom;
|
||||
CLASS *classPtr;
|
||||
|
@ -380,7 +380,7 @@ static CLASS *register_builtin( const struct builtin_class_descr *descr )
|
|||
classPtr->hbrBackground = descr->brush;
|
||||
classPtr->winproc = WINPROC_AllocProc( descr->procA, descr->procW );
|
||||
release_class_ptr( classPtr );
|
||||
return classPtr;
|
||||
return classPtr->winproc;
|
||||
}
|
||||
|
||||
|
||||
|
@ -407,7 +407,7 @@ void CLASS_RegisterBuiltinClasses(void)
|
|||
register_builtin( &COMBO_builtin_class );
|
||||
register_builtin( &COMBOLBOX_builtin_class );
|
||||
register_builtin( &DIALOG_builtin_class );
|
||||
register_builtin( &EDIT_builtin_class );
|
||||
EDIT_winproc_handle = register_builtin( &EDIT_builtin_class );
|
||||
register_builtin( &ICONTITLE_builtin_class );
|
||||
register_builtin( &LISTBOX_builtin_class );
|
||||
register_builtin( &MDICLIENT_builtin_class );
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -39,6 +39,8 @@ static const WCHAR WC_EDITW[] = {'E','d','i','t',0};
|
|||
|
||||
#define NUMCLASSWORDS 4
|
||||
|
||||
#define IS_WNDPROC_HANDLE(x) (((ULONG_PTR)(x) >> 16) == (~((ULONG_PTR)0) >> 16))
|
||||
|
||||
static LRESULT WINAPI ClassTest_WndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
return DefWindowProcW (hWnd, msg, wParam, lParam);
|
||||
|
@ -565,12 +567,23 @@ 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[][10] = {
|
||||
"Button",
|
||||
"Static",
|
||||
"ComboBox",
|
||||
"ComboLBox",
|
||||
"ListBox",
|
||||
"#32770", /* dialog */
|
||||
};
|
||||
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 +675,43 @@ 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 = (WNDPROC)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 treated 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");
|
||||
ok(!IS_WNDPROC_HANDLE(GetWindowLongPtrW(hwnd, GWLP_WNDPROC)), "Edit control shouldn't return a W 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 +723,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 = (WNDPROC)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 +744,12 @@ static void test_defwndproc(void)
|
|||
hwnd = CreateWindowA(WC_EDITA, classA, 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)), "Edit control class should have a Unicode wndproc\n");
|
||||
ok(!IS_WNDPROC_HANDLE(GetClassLongPtrW(hwnd, GCLP_WNDPROC)), "Edit control class should have a ANSI wndproc\n");
|
||||
/* But GetWindowLongPtr returns only a handle for the Unicode one */
|
||||
ok(!IS_WNDPROC_HANDLE(GetWindowLongPtrA(hwnd, GWLP_WNDPROC)), "Edit control shouldn't return an A wndproc handle\n");
|
||||
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 +839,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();
|
||||
}
|
||||
|
|
|
@ -1788,8 +1788,17 @@ static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicod
|
|||
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_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; 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 && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
|
||||
retvalue = (ULONG_PTR)wndPtr->winproc;
|
||||
else
|
||||
retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
|
||||
break;
|
||||
default:
|
||||
WARN("Unknown offset %d\n", offset );
|
||||
SetLastError( ERROR_INVALID_INDEX );
|
||||
|
@ -1877,7 +1886,7 @@ LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, B
|
|||
{
|
||||
WNDPROC proc;
|
||||
UINT old_flags = wndPtr->flags;
|
||||
retval = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
|
||||
retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
|
||||
if (unicode) proc = WINPROC_AllocProc( NULL, (WNDPROC)newval );
|
||||
else proc = WINPROC_AllocProc( (WNDPROC)newval, NULL );
|
||||
if (proc) wndPtr->winproc = proc;
|
||||
|
|
|
@ -54,6 +54,8 @@ typedef struct tagWINDOWPROC
|
|||
#define MAX_WINPROCS 8192
|
||||
#define BUILTIN_WINPROCS 8 /* first BUILTIN_WINPROCS entries are reserved for builtin procs */
|
||||
|
||||
WNDPROC EDIT_winproc_handle = 0;
|
||||
|
||||
static WINDOWPROC winproc_array[MAX_WINPROCS];
|
||||
static UINT builtin_used;
|
||||
static UINT winproc_used = BUILTIN_WINPROCS;
|
||||
|
@ -113,19 +115,6 @@ static inline WINDOWPROC *find_winproc( WNDPROC funcA, WNDPROC funcW )
|
|||
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 +2277,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 +2303,7 @@ LRESULT WINAPI CallWindowProcW( WNDPROC func, HWND hwnd, UINT msg,
|
|||
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 +2361,7 @@ INT_PTR WINPROC_CallDlgProcA( DLGPROC func, HWND hwnd, UINT msg, WPARAM wParam,
|
|||
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 +2391,7 @@ INT_PTR WINPROC_CallDlgProcW( DLGPROC func, HWND hwnd, UINT msg, WPARAM wParam,
|
|||
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)
|
||||
|
|
Loading…
Reference in New Issue