Add a test for accessing classes from another thread
Dmitry Timoshkov
dmitry at baikal.ru
Thu May 27 23:33:14 CDT 2004
"Alexandre Julliard" <julliard at winehq.org> wrote:
> > So, I decided to write a test for that. The test passes under Wine.
>
> Not for me:
>
> class.c:258: Test failed: GetLastError() should be set to ERROR_CLASS_HAS_WINDOWS
> class.c:258: Test failed: GetLastError() should be set to ERROR_CLASS_HAS_WINDOWS
>
Oops, sorry about that. Forgot to include a one liner fix for it.
Changelog:
Dmitry Timoshkov <dmitry at codeweavers.com>
Add a test for accessing classes from another thread.
Fix UnregisterClass behaviour with NULL hInstance.
diff -u cvs/hq/wine/dlls/user/tests/class.c wine/dlls/user/tests/class.c
--- cvs/hq/wine/dlls/user/tests/class.c Sat May 22 18:32:16 2004
+++ wine/dlls/user/tests/class.c Fri May 28 13:23:41 2004
@@ -49,7 +49,7 @@ static void ClassTest(HINSTANCE hInstanc
static const WCHAR winName[] = {'W','i','n','C','l','a','s','s','T','e','s','t',0};
ATOM test_atom;
HWND hTestWnd;
- DWORD i;
+ LONG i;
WCHAR str[20];
ATOM classatom;
@@ -254,9 +254,43 @@ static void check_instance( const char *
ok( (HINSTANCE)GetWindowLongA( hwnd, GWL_HINSTANCE ) == inst,
"Wrong GWL instance %p/%p for window %s\n",
(HINSTANCE)GetWindowLongA( hwnd, GWL_HINSTANCE ), inst, name );
+ ok(!UnregisterClassA(name, inst), "UnregisterClassA should fail while exists a class window\n");
+ ok(GetLastError() == ERROR_CLASS_HAS_WINDOWS, "GetLastError() should be set to ERROR_CLASS_HAS_WINDOWS not %ld\n", GetLastError());
DestroyWindow(hwnd);
}
+struct class_info
+{
+ const char *name;
+ HINSTANCE inst, info_inst, gcl_inst;
+};
+
+static DWORD WINAPI thread_proc(void *param)
+{
+ struct class_info *class_info = (struct class_info *)param;
+
+ check_instance(class_info->name, class_info->inst, class_info->info_inst, class_info->gcl_inst);
+
+ return 0;
+}
+
+static void check_thread_instance( const char *name, HINSTANCE inst, HINSTANCE info_inst, HINSTANCE gcl_inst )
+{
+ HANDLE hThread;
+ DWORD tid;
+ struct class_info class_info;
+
+ class_info.name = name;
+ class_info.inst = inst;
+ class_info.info_inst = info_inst;
+ class_info.gcl_inst = gcl_inst;
+
+ hThread = CreateThread(NULL, 0, thread_proc, &class_info, 0, &tid);
+ ok(hThread != NULL, "CreateThread failed, error %ld\n", GetLastError());
+ ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
+ CloseHandle(hThread);
+}
+
/* test various instance parameters */
static void test_instances(void)
{
@@ -279,6 +313,7 @@ static void test_instances(void)
ok( RegisterClassA( &cls ), "Failed to register local class for main module\n" );
check_class( main_module, name, "main_module" );
check_instance( name, main_module, main_module, main_module );
+ check_thread_instance( name, main_module, main_module, main_module );
cls.lpszMenuName = "kernel32";
cls.hInstance = kernel32;
@@ -286,6 +321,7 @@ static void test_instances(void)
check_class( kernel32, name, "kernel32" );
check_class( main_module, name, "main_module" );
check_instance( name, kernel32, kernel32, kernel32 );
+ check_thread_instance( name, kernel32, kernel32, kernel32 );
ok( UnregisterClassA( name, kernel32 ), "Unregister failed for kernel32\n" );
/* setting global flag doesn't change status of class */
@@ -298,6 +334,8 @@ static void test_instances(void)
check_class( main_module, name, "main_module" );
check_instance( name, kernel32, kernel32, kernel32 );
check_instance( name, main_module, main_module, main_module );
+ check_thread_instance( name, kernel32, kernel32, kernel32 );
+ check_thread_instance( name, main_module, main_module, main_module );
ok( UnregisterClassA( name, kernel32 ), "Unregister failed for kernel32\n" );
/* changing the instance doesn't make it global */
@@ -305,6 +343,7 @@ static void test_instances(void)
ok( RegisterClassA( &cls ), "Failed to register local class for kernel32\n" );
check_class( kernel32, name, "kernel32" );
check_instance( name, kernel32, kernel32, kernel32 );
+ check_thread_instance( name, kernel32, kernel32, kernel32 );
ok( !GetClassInfo( 0, name, &wc ), "Class found with null instance\n" );
ok( UnregisterClassA( name, kernel32 ), "Unregister failed for kernel32\n" );
@@ -317,6 +356,9 @@ static void test_instances(void)
check_instance( name, kernel32, kernel32, kernel32 );
check_instance( name, user32, 0, user32 );
check_instance( name, 0, 0, kernel32 );
+ check_thread_instance( name, kernel32, kernel32, kernel32 );
+ check_thread_instance( name, user32, 0, user32 );
+ check_thread_instance( name, 0, 0, kernel32 );
ok( UnregisterClassA( name, kernel32 ), "Unregister failed for kernel32\n" );
SetClassLongA( hwnd, GCL_HMODULE, 0x12345678 );
@@ -325,6 +367,8 @@ static void test_instances(void)
check_class( (HINSTANCE)0x12345678, name, "main_module" );
check_instance( name, kernel32, kernel32, kernel32 );
check_instance( name, (HINSTANCE)0x12345678, (HINSTANCE)0x12345678, (HINSTANCE)0x12345678 );
+ check_thread_instance( name, kernel32, kernel32, kernel32 );
+ check_thread_instance( name, (HINSTANCE)0x12345678, (HINSTANCE)0x12345678, (HINSTANCE)0x12345678 );
ok( !GetClassInfo( 0, name, &wc ), "Class found with null instance\n" );
/* creating a window with instance 0 uses the first class found */
@@ -364,6 +408,7 @@ static void test_instances(void)
/* must be found with main module handle */
check_class( main_module, name, "null" );
check_instance( name, main_module, main_module, main_module );
+ check_thread_instance( name, main_module, main_module, main_module );
ok( !GetClassInfo( 0, name, &wc ), "Class found with null instance\n" );
ok( GetLastError() == ERROR_CLASS_DOES_NOT_EXIST, "Wrong error code %ld\n", GetLastError() );
ok( UnregisterClassA( name, 0 ), "Unregister failed for null instance\n" );
@@ -403,11 +448,15 @@ static void test_instances(void)
check_class( (HINSTANCE)0x12345678, name, "main_module" );
check_instance( name, main_module, main_module, main_module );
check_instance( name, (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, main_module );
+ check_thread_instance( name, main_module, main_module, main_module );
+ check_thread_instance( name, (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, main_module );
/* changing the instance for global class doesn't make much difference */
SetClassLongA( hwnd, GCL_HMODULE, 0xdeadbeef );
check_instance( name, main_module, main_module, (HINSTANCE)0xdeadbeef );
check_instance( name, (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef );
+ check_thread_instance( name, main_module, main_module, (HINSTANCE)0xdeadbeef );
+ check_thread_instance( name, (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef );
DestroyWindow( hwnd );
ok( UnregisterClassA( name, (HINSTANCE)0x87654321 ), "Unregister failed for main module global\n" );
@@ -418,6 +467,8 @@ static void test_instances(void)
ok( RegisterClassA( &cls ), "Failed to register global class for dummy instance\n" );
check_instance( name, main_module, main_module, (HINSTANCE)0x12345678 );
check_instance( name, (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, (HINSTANCE)0x12345678 );
+ check_thread_instance( name, main_module, main_module, (HINSTANCE)0x12345678 );
+ check_thread_instance( name, (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, (HINSTANCE)0x12345678 );
ok( UnregisterClassA( name, (HINSTANCE)0x87654321 ), "Unregister failed for main module global\n" );
/* check system classes */
@@ -450,6 +501,9 @@ static void test_instances(void)
check_instance( "BUTTON", 0, 0, user32 );
check_instance( "BUTTON", (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, user32 );
check_instance( "BUTTON", user32, 0, user32 );
+ check_thread_instance( "BUTTON", 0, 0, user32 );
+ check_thread_instance( "BUTTON", (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, user32 );
+ check_thread_instance( "BUTTON", user32, 0, user32 );
/* we can unregister system classes */
ok( GetClassInfo( 0, "BUTTON", &wc ), "Button class not found with null instance\n" );
@@ -462,14 +516,22 @@ static void test_instances(void)
/* we can change the instance of a system class */
check_instance( "EDIT", (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, user32 );
+ check_thread_instance( "EDIT", (HINSTANCE)0xdeadbeef, (HINSTANCE)0xdeadbeef, user32 );
hwnd = CreateWindowExA( 0, "EDIT", "test", 0, 0, 0, 0, 0, 0, 0, main_module, 0 );
SetClassLongA( hwnd, GCL_HMODULE, 0xdeadbeef );
check_instance( "EDIT", (HINSTANCE)0x12345678, (HINSTANCE)0x12345678, (HINSTANCE)0xdeadbeef );
+ check_thread_instance( "EDIT", (HINSTANCE)0x12345678, (HINSTANCE)0x12345678, (HINSTANCE)0xdeadbeef );
}
START_TEST(class)
{
HANDLE hInstance = GetModuleHandleA( NULL );
+
+ if (!GetModuleHandleW(0))
+ {
+ trace("Class test is incompatible with Win9x implementation, skipping\n");
+ return;
+ }
ClassTest(hInstance,FALSE);
ClassTest(hInstance,TRUE);
diff -u cvs/hq/wine/windows/class.c wine/windows/class.c
--- cvs/hq/wine/windows/class.c Thu Feb 12 15:36:02 2004
+++ wine/windows/class.c Fri May 28 13:23:06 2004
@@ -741,8 +741,6 @@ BOOL WINAPI UnregisterClassW( LPCWSTR cl
return FALSE;
}
- if (!hInstance) hInstance = GetModuleHandleW( NULL );
-
SERVER_START_REQ( destroy_class )
{
req->atom = atom;
More information about the wine-patches
mailing list