Signed-off-by: Nikolay Sivov nsivov@codeweavers.com ---
v2: fixed a test failure
dlls/user32/class.c | 5 ++ dlls/user32/tests/class.c | 223 +++++++++++++++++++++++++++++++++------------- 2 files changed, 167 insertions(+), 61 deletions(-)
diff --git a/dlls/user32/class.c b/dlls/user32/class.c index 441d5cb132..dce9bf2269 100644 --- a/dlls/user32/class.c +++ b/dlls/user32/class.c @@ -336,6 +336,7 @@ const WCHAR *CLASS_GetVersionedName( const WCHAR *name, UINT *basename_offset ) ULONG module_len; ULONG module_offset; } *wndclass; + const WCHAR *module;
if (basename_offset) *basename_offset = 0; @@ -354,6 +355,10 @@ const WCHAR *CLASS_GetVersionedName( const WCHAR *name, UINT *basename_offset ) if (basename_offset) *basename_offset = wndclass->name_len / sizeof(WCHAR) - strlenW(name);
+ module = (const WCHAR *)((BYTE *)data.lpSectionBase + wndclass->module_offset); + if (!GetModuleHandleW( module )) + LoadLibraryW( module ); + return (const WCHAR *)((BYTE *)wndclass + wndclass->name_offset); }
diff --git a/dlls/user32/tests/class.c b/dlls/user32/tests/class.c index 9ae306e090..ae885dbac9 100644 --- a/dlls/user32/tests/class.c +++ b/dlls/user32/tests/class.c @@ -38,6 +38,42 @@
#define IS_WNDPROC_HANDLE(x) (((ULONG_PTR)(x) >> 16) == (~0u >> 16))
+#ifdef __i386__ +#define ARCH "x86" +#elif defined __x86_64__ +#define ARCH "amd64" +#elif defined __arm__ +#define ARCH "arm" +#elif defined __aarch64__ +#define ARCH "arm64" +#else +#define ARCH "none" +#endif + +static const char comctl32_manifest[] = +"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" +"<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">\n" +" <assemblyIdentity\n" +" type="win32"\n" +" name="Wine.User32.Tests"\n" +" version="1.0.0.0"\n" +" processorArchitecture="" ARCH ""\n" +" />\n" +"<description>Wine comctl32 test suite</description>\n" +"<dependency>\n" +" <dependentAssembly>\n" +" <assemblyIdentity\n" +" type="win32"\n" +" name="microsoft.windows.common-controls"\n" +" version="6.0.0.0"\n" +" processorArchitecture="" ARCH ""\n" +" publicKeyToken="6595b64144ccf1df"\n" +" language="*"\n" +" />\n" +"</dependentAssembly>\n" +"</dependency>\n" +"</assembly>\n"; + static LRESULT WINAPI ClassTest_WndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { if (msg == WM_NCCREATE) return 1; @@ -1041,6 +1077,45 @@ static void test_icons(void) DestroyWindow(hwnd); }
+static void create_manifest_file(const char *filename, const char *manifest) +{ + WCHAR path[MAX_PATH]; + HANDLE file; + DWORD size; + + MultiByteToWideChar( CP_ACP, 0, filename, -1, path, MAX_PATH ); + file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError()); + WriteFile(file, manifest, strlen(manifest), &size, NULL); + CloseHandle(file); +} + +static HANDLE create_test_actctx(const char *file) +{ + WCHAR path[MAX_PATH]; + ACTCTXW actctx; + HANDLE handle; + + MultiByteToWideChar(CP_ACP, 0, file, -1, path, MAX_PATH); + memset(&actctx, 0, sizeof(ACTCTXW)); + actctx.cbSize = sizeof(ACTCTXW); + actctx.lpSource = path; + + handle = CreateActCtxW(&actctx); + ok(handle != INVALID_HANDLE_VALUE, "failed to create context, error %u\n", GetLastError()); + + ok(actctx.cbSize == sizeof(actctx), "cbSize=%d\n", actctx.cbSize); + ok(actctx.dwFlags == 0, "dwFlags=%d\n", actctx.dwFlags); + ok(actctx.lpSource == path, "lpSource=%p\n", actctx.lpSource); + ok(actctx.wProcessorArchitecture == 0, "wProcessorArchitecture=%d\n", actctx.wProcessorArchitecture); + ok(actctx.wLangId == 0, "wLangId=%d\n", actctx.wLangId); + ok(actctx.lpAssemblyDirectory == NULL, "lpAssemblyDirectory=%p\n", actctx.lpAssemblyDirectory); + ok(actctx.lpResourceName == NULL, "lpResourceName=%p\n", actctx.lpResourceName); + ok(actctx.lpApplicationName == NULL, "lpApplicationName=%p\n", actctx.lpApplicationName); + ok(actctx.hModule == NULL, "hModule=%p\n", actctx.hModule); + + return handle; +} static void test_comctl32_class( const char *name ) { WNDCLASSA wcA; @@ -1050,23 +1125,82 @@ static void test_comctl32_class( const char *name ) WCHAR nameW[20]; HWND hwnd;
- module = GetModuleHandleA( "comctl32" ); - ok( !module, "comctl32 already loaded\n" ); - ret = GetClassInfoA( 0, name, &wcA ); - ok( ret || broken(!ret) /* <= winxp */, "GetClassInfoA failed for %s\n", name ); - if (!ret) return; - MultiByteToWideChar( CP_ACP, 0, name, -1, nameW, sizeof(nameW)/sizeof(WCHAR) ); - ret = GetClassInfoW( 0, nameW, &wcW ); - ok( ret, "GetClassInfoW failed for %s\n", name ); - module = GetModuleHandleA( "comctl32" ); - ok( module != 0, "comctl32 not loaded\n" ); - FreeLibrary( module ); - module = GetModuleHandleA( "comctl32" ); - ok( !module, "comctl32 still loaded\n" ); - hwnd = CreateWindowA( name, "test", WS_OVERLAPPEDWINDOW, 0, 0, 10, 10, NULL, NULL, NULL, 0 ); - ok( hwnd != 0, "failed to create window for %s\n", name ); - module = GetModuleHandleA( "comctl32" ); - ok( module != 0, "comctl32 not loaded\n" ); + if (name[0] == '!') + { + char path[MAX_PATH]; + ULONG_PTR cookie; + HANDLE context; + + name++; + + GetTempPathA(sizeof(path)/sizeof(path[0]), path); + strcat(path, "comctl32_class.manifest"); + + create_manifest_file(path, comctl32_manifest); + context = create_test_actctx(path); + ret = DeleteFileA(path); + ok(ret, "Failed to delete manifest file, error %d.\n", GetLastError()); + + module = GetModuleHandleA( "comctl32" ); + ok( !module, "comctl32 already loaded\n" ); + + ret = ActivateActCtx(context, &cookie); + ok(ret, "Failed to activate context.\n"); + + /* Some systems load modules during context activation. In this case skip the rest of the test. */ + module = GetModuleHandleA( "comctl32" ); + ok( !module || broken(module != NULL) /* Vista/Win7 */, "comctl32 already loaded\n" ); + if (module) + { + win_skip("Module loaded during context activation. Skipping tests.\n"); + goto skiptest; + } + + ret = GetClassInfoA( 0, name, &wcA ); + ok( ret || broken(!ret) /* WinXP */, "GetClassInfoA failed for %s\n", name ); + if (!ret) + goto skiptest; + + MultiByteToWideChar( CP_ACP, 0, name, -1, nameW, sizeof(nameW)/sizeof(WCHAR) ); + ret = GetClassInfoW( 0, nameW, &wcW ); + ok( ret, "GetClassInfoW failed for %s\n", name ); + module = GetModuleHandleA( "comctl32" ); + ok( module != 0, "comctl32 not loaded\n" ); + FreeLibrary( module ); + module = GetModuleHandleA( "comctl32" ); + ok( !module || broken(module != NULL) /* Vista */, "comctl32 still loaded\n" ); + hwnd = CreateWindowA( name, "test", WS_OVERLAPPEDWINDOW, 0, 0, 10, 10, NULL, NULL, NULL, 0 ); + ok( hwnd != 0, "failed to create window for %s\n", name ); + module = GetModuleHandleA( "comctl32" ); + ok( module != 0, "comctl32 not loaded\n" ); + DestroyWindow( hwnd ); + + skiptest: + ret = DeactivateActCtx(0, cookie); + ok(ret, "Failed to deactivate context.\n"); + ReleaseActCtx(context); + } + else + { + module = GetModuleHandleA( "comctl32" ); + ok( !module, "comctl32 already loaded\n" ); + ret = GetClassInfoA( 0, name, &wcA ); + ok( ret || broken(!ret) /* <= winxp */, "GetClassInfoA failed for %s\n", name ); + if (!ret) return; + MultiByteToWideChar( CP_ACP, 0, name, -1, nameW, sizeof(nameW)/sizeof(WCHAR) ); + ret = GetClassInfoW( 0, nameW, &wcW ); + ok( ret, "GetClassInfoW failed for %s\n", name ); + module = GetModuleHandleA( "comctl32" ); + ok( module != 0, "comctl32 not loaded\n" ); + FreeLibrary( module ); + module = GetModuleHandleA( "comctl32" ); + ok( !module, "comctl32 still loaded\n" ); + hwnd = CreateWindowA( name, "test", WS_OVERLAPPEDWINDOW, 0, 0, 10, 10, NULL, NULL, NULL, 0 ); + ok( hwnd != 0, "failed to create window for %s\n", name ); + module = GetModuleHandleA( "comctl32" ); + ok( module != 0, "comctl32 not loaded\n" ); + DestroyWindow( hwnd ); + } }
/* verify that comctl32 classes are automatically loaded by user32 */ @@ -1099,7 +1233,9 @@ static void test_comctl32_classes(void) TOOLTIPS_CLASSA, TRACKBAR_CLASSA, WC_TREEVIEWA, - UPDOWN_CLASSA + UPDOWN_CLASSA, + "!Button", + "!Edit", };
winetest_get_mainargs( &argv ); @@ -1162,46 +1298,6 @@ static void test_IME(void) ok(!lstrcmpiA(ptr, "user32.dll") || !lstrcmpiA(ptr, "ntdll.dll"), "IME window proc implemented in %s\n", ptr); }
-static void create_manifest_file(const char *filename, const char *manifest) -{ - WCHAR path[MAX_PATH]; - HANDLE file; - DWORD size; - - MultiByteToWideChar( CP_ACP, 0, filename, -1, path, MAX_PATH ); - file = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError()); - WriteFile(file, manifest, strlen(manifest), &size, NULL); - CloseHandle(file); -} - -static HANDLE create_test_actctx(const char *file) -{ - WCHAR path[MAX_PATH]; - ACTCTXW actctx; - HANDLE handle; - - MultiByteToWideChar(CP_ACP, 0, file, -1, path, MAX_PATH); - memset(&actctx, 0, sizeof(ACTCTXW)); - actctx.cbSize = sizeof(ACTCTXW); - actctx.lpSource = path; - - handle = CreateActCtxW(&actctx); - ok(handle != INVALID_HANDLE_VALUE, "failed to create context, error %u\n", GetLastError()); - - ok(actctx.cbSize == sizeof(actctx), "cbSize=%d\n", actctx.cbSize); - ok(actctx.dwFlags == 0, "dwFlags=%d\n", actctx.dwFlags); - ok(actctx.lpSource == path, "lpSource=%p\n", actctx.lpSource); - ok(actctx.wProcessorArchitecture == 0, "wProcessorArchitecture=%d\n", actctx.wProcessorArchitecture); - ok(actctx.wLangId == 0, "wLangId=%d\n", actctx.wLangId); - ok(actctx.lpAssemblyDirectory == NULL, "lpAssemblyDirectory=%p\n", actctx.lpAssemblyDirectory); - ok(actctx.lpResourceName == NULL, "lpResourceName=%p\n", actctx.lpResourceName); - ok(actctx.lpApplicationName == NULL, "lpApplicationName=%p\n", actctx.lpApplicationName); - ok(actctx.hModule == NULL, "hModule=%p\n", actctx.hModule); - - return handle; -} - static void test_actctx_classes(void) { static const char main_manifest[] = @@ -1220,10 +1316,15 @@ static void test_actctx_classes(void) HINSTANCE hinst; char buff[64]; HWND hwnd; + char path[MAX_PATH]; + + GetTempPathA(sizeof(path)/sizeof(path[0]), path); + strcat(path, "actctx_classes.manifest");
- create_manifest_file("main.manifest", main_manifest); - context = create_test_actctx("main.manifest"); - DeleteFileA("main.manifest"); + create_manifest_file(path, main_manifest); + context = create_test_actctx(path); + ret = DeleteFileA(path); + ok(ret, "Failed to delete manifest file, error %d.\n", GetLastError());
ret = ActivateActCtx(context, &cookie); ok(ret, "Failed to activate context.\n");