Signed-off-by: Nikolay Sivov <nsivov(a)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");
--
2.15.1