Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47915 Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/user32/tests/win.c | 109 +++++++++++++++++++++++++++++++++++++++- dlls/user32/user32.spec | 1 + dlls/user32/win.c | 51 +++++++++++++++++++ 3 files changed, 160 insertions(+), 1 deletion(-)
diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c index a37afd2dc5e..3f58f7a2b11 100644 --- a/dlls/user32/tests/win.c +++ b/dlls/user32/tests/win.c @@ -64,6 +64,7 @@ static BOOL (WINAPI *pGetWindowDisplayAffinity)(HWND hwnd, DWORD *affinity); static BOOL (WINAPI *pSetWindowDisplayAffinity)(HWND hwnd, DWORD affinity); static BOOL (WINAPI *pAdjustWindowRectExForDpi)(LPRECT,DWORD,BOOL,DWORD,UINT); static BOOL (WINAPI *pSystemParametersInfoForDpi)(UINT,UINT,void*,UINT,UINT); +static HICON (WINAPI *pInternalGetWindowIcon)(HWND window, UINT type);
static BOOL test_lbuttondown_flag; static DWORD num_gettext_msgs; @@ -2369,6 +2370,19 @@ todo_wine DestroyWindow(mdi_hwndMain); }
+static DWORD WINAPI internal_get_icon_thread(void *arg) +{ + HICON icon; + BOOL ret; + + icon = pInternalGetWindowIcon( arg, ICON_BIG ); + ok( icon != 0, "expected nonzero icon\n" ); + ret = DestroyIcon( icon ); + ok( ret, "got error %u\n", GetLastError() ); + + return 0; +} + static void test_icons(void) { WNDCLASSEXA cls; @@ -2377,7 +2391,9 @@ static void test_icons(void) HICON icon2 = LoadIconA(0, (LPCSTR)IDI_QUESTION); HICON small_icon = LoadImageA(0, (LPCSTR)IDI_APPLICATION, IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED ); - HICON res; + HICON res, res2, res3; + HANDLE thread; + BOOL ret;
cls.cbSize = sizeof(cls); cls.style = 0; @@ -2400,35 +2416,125 @@ static void test_icons(void)
res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_BIG, 0 ); ok( res == 0, "wrong big icon %p/0\n", res ); + SetLastError( 0xdeadbeef ); + res2 = pInternalGetWindowIcon( hwnd, ICON_BIG ); + ok( res2 != 0, "expected nonzero icon\n" ); + ok( GetLastError() == 0xdeadbeef, "got error %u\n", GetLastError() ); + res3 = pInternalGetWindowIcon( hwnd, ICON_BIG ); + ok( res3 && res3 != res2, "got %p\n", res3 ); + ret = DestroyIcon( res2 ); + ok( ret, "got error %u\n", GetLastError() ); + ret = DestroyIcon( res3 ); + ok( ret, "got error %u\n", GetLastError() ); + res = (HICON)SendMessageA( hwnd, WM_SETICON, ICON_BIG, (LPARAM)icon ); ok( res == 0, "wrong previous big icon %p/0\n", res ); res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_BIG, 0 ); ok( res == icon, "wrong big icon after set %p/%p\n", res, icon ); + res2 = pInternalGetWindowIcon( hwnd, ICON_BIG ); + ok( res2 && res2 != icon, "got %p\n", res2 ); + res3 = pInternalGetWindowIcon( hwnd, ICON_BIG ); + ok( res3 && res3 != res2, "got %p\n", res3 ); + ret = DestroyIcon( res2 ); + ok( ret, "got error %u\n", GetLastError() ); + ret = DestroyIcon( res3 ); + ok( ret, "got error %u\n", GetLastError() ); + res = (HICON)SendMessageA( hwnd, WM_SETICON, ICON_BIG, (LPARAM)icon2 ); ok( res == icon, "wrong previous big icon %p/%p\n", res, icon ); res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_BIG, 0 ); ok( res == icon2, "wrong big icon after set %p/%p\n", res, icon2 ); + res2 = pInternalGetWindowIcon( hwnd, ICON_BIG ); + ok( res2 && res2 != icon2, "got %p\n", res2 ); + ret = DestroyIcon( res2 ); + ok( ret, "got error %u\n", GetLastError() );
res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL, 0 ); ok( res == 0, "wrong small icon %p/0\n", res ); + res2 = pInternalGetWindowIcon( hwnd, ICON_SMALL ); + ok( res2 != 0, "expected nonzero icon\n" ); + res3 = pInternalGetWindowIcon( hwnd, ICON_SMALL ); + ok( res3 && res3 != res2, "got %p\n", res3 ); + ret = DestroyIcon( res2 ); + ok( ret, "got error %u\n", GetLastError() ); + ret = DestroyIcon( res3 ); + ok( ret, "got error %u\n", GetLastError() ); + res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL2, 0 ); ok( (res && res != small_icon && res != icon2) || broken(!res), "wrong small2 icon %p\n", res ); + res2 = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL2, 0 ); + ok( res2 == res, "expected icon to match\n" ); + res2 = pInternalGetWindowIcon( hwnd, ICON_SMALL2 ); + ok( res2 && res2 != small_icon && res2 != icon2 && res2 != res, "got %p\n", res2 ); + res3 = pInternalGetWindowIcon( hwnd, ICON_SMALL2 ); + ok( res3 && res3 != res2, "got %p\n", res3 ); + ret = DestroyIcon( res2 ); + ok( ret, "got error %u\n", GetLastError() ); + ret = DestroyIcon( res3 ); + ok( ret, "got error %u\n", GetLastError() ); + res = (HICON)SendMessageA( hwnd, WM_SETICON, ICON_SMALL, (LPARAM)icon ); ok( res == 0, "wrong previous small icon %p/0\n", res ); res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL, 0 ); ok( res == icon, "wrong small icon after set %p/%p\n", res, icon ); + res2 = pInternalGetWindowIcon( hwnd, ICON_SMALL ); + ok( res2 && res2 != icon, "got %p\n", res2 ); + res3 = pInternalGetWindowIcon( hwnd, ICON_SMALL ); + ok( res3 && res3 != res2, "got %p\n", res3 ); + ret = DestroyIcon( res2 ); + ok( ret, "got error %u\n", GetLastError() ); + ret = DestroyIcon( res3 ); + ok( ret, "got error %u\n", GetLastError() ); + res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL2, 0 ); ok( res == icon || broken(!res), "wrong small2 icon after set %p/%p\n", res, icon ); + res2 = pInternalGetWindowIcon( hwnd, ICON_SMALL2 ); + ok( res2 && res2 != icon && res2 != res, "got %p\n", res2 ); + res3 = pInternalGetWindowIcon( hwnd, ICON_SMALL2 ); + ok( res3 && res3 != res2, "got %p\n", res3 ); + ret = DestroyIcon( res2 ); + ok( ret, "got error %u\n", GetLastError() ); + ret = DestroyIcon( res3 ); + ok( ret, "got error %u\n", GetLastError() ); + res = (HICON)SendMessageA( hwnd, WM_SETICON, ICON_SMALL, (LPARAM)small_icon ); ok( res == icon, "wrong previous small icon %p/%p\n", res, icon ); res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL, 0 ); ok( res == small_icon, "wrong small icon after set %p/%p\n", res, small_icon ); + res2 = pInternalGetWindowIcon( hwnd, ICON_SMALL ); + ok( res2 && res2 != small_icon, "got %p\n", res2 ); + ret = DestroyIcon( res2 ); + ok( ret, "got error %u\n", GetLastError() ); + res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL2, 0 ); ok( res == small_icon || broken(!res), "wrong small2 icon after set %p/%p\n", res, small_icon ); + res2 = pInternalGetWindowIcon( hwnd, ICON_SMALL2 ); + ok( res2 && res2 != small_icon && res2 != res, "got %p\n", res2 ); + ret = DestroyIcon( res2 ); + ok( ret, "got error %u\n", GetLastError() );
/* make sure the big icon hasn't changed */ res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_BIG, 0 ); ok( res == icon2, "wrong big icon after set %p/%p\n", res, icon2 ); + res2 = pInternalGetWindowIcon( hwnd, ICON_BIG ); + ok( res2 && res2 != icon2, "got %p\n", res2 ); + ret = DestroyIcon( res2 ); + ok( ret, "got error %u\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + res = pInternalGetWindowIcon( NULL, ICON_BIG ); + ok( !res, "got %p\n", res ); + ok( GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "got error %u\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + res = pInternalGetWindowIcon( hwnd, 0xdeadbeef ); + ok( !res, "got %p\n", res ); + ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %u\n", GetLastError() ); + + thread = CreateThread( NULL, 0, internal_get_icon_thread, hwnd, 0, NULL ); + ret = WaitForSingleObject( thread, 1000 ); + ok( !ret, "wait timed out\n" ); + CloseHandle( thread );
DestroyWindow( hwnd ); } @@ -12027,6 +12133,7 @@ START_TEST(win) pSetWindowDisplayAffinity = (void *)GetProcAddress( user32, "SetWindowDisplayAffinity" ); pAdjustWindowRectExForDpi = (void *)GetProcAddress( user32, "AdjustWindowRectExForDpi" ); pSystemParametersInfoForDpi = (void *)GetProcAddress( user32, "SystemParametersInfoForDpi" ); + pInternalGetWindowIcon = (void *)GetProcAddress( user32, "InternalGetWindowIcon" );
if (argc == 4) { diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec index 190ee74fd6c..391e304a063 100644 --- a/dlls/user32/user32.spec +++ b/dlls/user32/user32.spec @@ -445,6 +445,7 @@ @ stdcall InsertMenuItemA(long long long ptr) @ stdcall InsertMenuItemW(long long long ptr) @ stdcall InsertMenuW(long long long long ptr) +@ stdcall InternalGetWindowIcon(ptr long) @ stdcall InternalGetWindowText(long ptr long) @ stdcall IntersectRect(ptr ptr ptr) @ stdcall InvalidateRect(long ptr long) diff --git a/dlls/user32/win.c b/dlls/user32/win.c index 680defc2071..bd540953278 100644 --- a/dlls/user32/win.c +++ b/dlls/user32/win.c @@ -4239,3 +4239,54 @@ BOOL WINAPI SetWindowCompositionAttribute(HWND hwnd, void *data) SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } + +/*********************************************************************** + * InternalGetWindowIcon (USER32.@) + */ +HICON WINAPI InternalGetWindowIcon( HWND hwnd, UINT type ) +{ + WND *win = WIN_GetPtr( hwnd ); + HICON ret; + + TRACE( "hwnd %p, type %#x\n", hwnd, type ); + + if (!win) + { + SetLastError( ERROR_INVALID_WINDOW_HANDLE ); + return 0; + } + if (win == WND_OTHER_PROCESS || win == WND_DESKTOP) + { + if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd ); + return 0; + } + + switch (type) + { + case ICON_BIG: + ret = win->hIcon; + if (!ret) ret = (HICON)GetClassLongPtrW( hwnd, GCLP_HICON ); + break; + + case ICON_SMALL: + ret = win->hIconSmall; + if (!ret) ret = (HICON)GetClassLongPtrW( hwnd, GCLP_HICONSM ); + break; + + case ICON_SMALL2: + ret = win->hIconSmall ? win->hIconSmall : win->hIconSmall2; + if (!ret) ret = (HICON)GetClassLongPtrW( hwnd, GCLP_HICONSM ); + break; + + default: + SetLastError( ERROR_INVALID_PARAMETER ); + WIN_ReleasePtr( win ); + return 0; + } + + if (!ret) ret = LoadIconW( 0, (const WCHAR *)IDI_WINLOGO ); + ret = CopyIcon( ret ); + + WIN_ReleasePtr( win ); + return ret; +}