From 82c07abf1ab070208d3b83bb0f628caef41275da Mon Sep 17 00:00:00 2001 From: Whindmar Saksit Date: Sun, 17 Dec 2023 22:11:50 +0100 Subject: [PATCH] [USER32] Support loading icons from data file module (#6065) GetModuleFileName() fails on LOAD_LIBRARY_AS_DATAFILE causing LoadImage to fail. Use a fake filename for LR_SHARED (with same format as Windows). This may not be a good design, but it does match Windows' behaviour. + Added test. --- modules/rostests/apitests/user32/LoadImage.c | 47 ++++++++++++++++++++ win32ss/user/user32/windows/cursoricon.c | 16 ++++++- 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/modules/rostests/apitests/user32/LoadImage.c b/modules/rostests/apitests/user32/LoadImage.c index 64af37325d2..f46e4be7846 100644 --- a/modules/rostests/apitests/user32/LoadImage.c +++ b/modules/rostests/apitests/user32/LoadImage.c @@ -1,6 +1,50 @@ #include "precomp.h" +static void test_LoadImage_DataFile(void) +{ + static const struct + { + int result; + LPCWSTR file; + int res_id; + UINT lr; + BOOL same_handle; + BOOL after_unload; /* LR_SHARED stays valid */ + } + tests[] = + { + { 1, L"shell32.dll", 2, 0, 0, 0 }, + { 1, L"shell32.dll", 2, LR_SHARED, 1, 1 }, + { 0, L"shell32.dll", 0xfff0, 0, 1, 0 }, /* Icon should not exist */ + { 1, L"regedit.exe", 100, 0, 0, 0 }, + { 1, L"regedit.exe", 100, LR_SHARED, 1, 1 } + }; + + SIZE_T i; + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + HANDLE handle1, handle2; + HMODULE hMod = LoadLibraryExW(tests[i].file, NULL, LOAD_LIBRARY_AS_DATAFILE); + if (!((SIZE_T)hMod & 3)) + { + skip("Could not load library as datafile %ls\n", tests[i].file); + continue; + } + + handle1 = LoadImage(hMod, MAKEINTRESOURCE(tests[i].res_id), IMAGE_ICON, 0, 0, tests[i].lr); + ok(!!handle1 == !!tests[i].result, "Failed to load %ls,-%d from %p\n", tests[i].file, tests[i].res_id, hMod); + + handle2 = LoadImage(hMod, MAKEINTRESOURCE(tests[i].res_id), IMAGE_ICON, 0, 0, tests[i].lr); + ok(!!(handle1 == handle2) == !!tests[i].same_handle, "Shared handles don't match\n"); + + FreeLibrary(hMod); + + handle1 = LoadImage(hMod, MAKEINTRESOURCE(tests[i].res_id), IMAGE_ICON, 0, 0, tests[i].lr); + ok(!!handle1 == !!tests[i].after_unload, "LR_%x handle should %sload after FreeLibrary\n", tests[i].lr, tests[i].after_unload ? "" : "not "); + } +} + START_TEST(LoadImage) { char path[MAX_PATH]; @@ -77,6 +121,9 @@ START_TEST(LoadImage) DeleteObject(ii.hbmMask); if(ii.hbmColor) DeleteObject(ii.hbmColor); + /* LOAD_LIBRARY_AS_DATAFILE */ + test_LoadImage_DataFile(); + return; } diff --git a/win32ss/user/user32/windows/cursoricon.c b/win32ss/user/user32/windows/cursoricon.c index 1f6b71714aa..a3f8a48602e 100644 --- a/win32ss/user/user32/windows/cursoricon.c +++ b/win32ss/user/user32/windows/cursoricon.c @@ -1454,7 +1454,21 @@ CURSORICON_LoadImageW( RtlInitUnicodeString(&ustrRsrc, lpszName); } - if(hinst) + if(LDR_IS_RESOURCE(hinst)) + { + /* We don't have a real module for GetModuleFileName, construct a fake name instead. + * GetIconInfoEx reveals the name used by Windows. */ + LPCWSTR fakeNameFmt = sizeof(void*) > 4 ? L"\x01%016IX" : L"\x01%08IX"; + ustrModule.MaximumLength = 18 * sizeof(WCHAR); + ustrModule.Buffer = HeapAlloc(GetProcessHeap(), 0, ustrModule.MaximumLength); + if (!ustrModule.Buffer) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return NULL; + } + ustrModule.Length = wsprintfW(ustrModule.Buffer, fakeNameFmt, hinst) * sizeof(WCHAR); + } + else if(hinst) { DWORD size = MAX_PATH; /* Get the module name string */