user32: Automatically load comctl32 when one of its classes is requested.

This commit is contained in:
Alexandre Julliard 2013-10-28 18:41:04 +01:00
parent 4c41c20e02
commit c25c019883
3 changed files with 160 additions and 22 deletions

View file

@ -120,6 +120,47 @@ ATOM get_int_atom_value( LPCWSTR name )
}
/***********************************************************************
* is_comctl32_class
*/
static BOOL is_comctl32_class( const WCHAR *name )
{
static const WCHAR classesW[][20] =
{
{'C','o','m','b','o','B','o','x','E','x','3','2',0},
{'m','s','c','t','l','s','_','h','o','t','k','e','y','3','2',0},
{'m','s','c','t','l','s','_','p','r','o','g','r','e','s','s','3','2',0},
{'m','s','c','t','l','s','_','s','t','a','t','u','s','b','a','r','3','2',0},
{'m','s','c','t','l','s','_','t','r','a','c','k','b','a','r','3','2',0},
{'m','s','c','t','l','s','_','u','p','d','o','w','n','3','2',0},
{'N','a','t','i','v','e','F','o','n','t','C','t','l',0},
{'R','e','B','a','r','W','i','n','d','o','w','3','2',0},
{'S','y','s','A','n','i','m','a','t','e','3','2',0},
{'S','y','s','D','a','t','e','T','i','m','e','P','i','c','k','3','2',0},
{'S','y','s','H','e','a','d','e','r','3','2',0},
{'S','y','s','I','P','A','d','d','r','e','s','s','3','2',0},
{'S','y','s','L','i','s','t','V','i','e','w','3','2',0},
{'S','y','s','M','o','n','t','h','C','a','l','3','2',0},
{'S','y','s','P','a','g','e','r',0},
{'S','y','s','T','a','b','C','o','n','t','r','o','l','3','2',0},
{'S','y','s','T','r','e','e','V','i','e','w','3','2',0},
{'T','o','o','l','b','a','r','W','i','n','d','o','w','3','2',0},
{'t','o','o','l','t','i','p','s','_','c','l','a','s','s','3','2',0},
};
int min = 0, max = (sizeof(classesW) / sizeof(classesW[0])) - 1;
while (min <= max)
{
int res, pos = (min + max) / 2;
if (!(res = strcmpiW( name, classesW[pos] ))) return TRUE;
if (res < 0) max = pos - 1;
else min = pos + 1;
}
return FALSE;
}
/***********************************************************************
* set_server_info
*
@ -261,35 +302,44 @@ static void CLASS_FreeClass( CLASS *classPtr )
* CLASS_FindClass
*
* Return a pointer to the class.
* hinstance has been normalized by the caller.
*/
static CLASS *CLASS_FindClass( LPCWSTR name, HINSTANCE hinstance )
{
static const WCHAR comctl32W[] = {'c','o','m','c','t','l','3','2','.','d','l','l',0};
struct list *ptr;
ATOM atom = get_int_atom_value( name );
GetDesktopWindow(); /* create the desktop window to trigger builtin class registration */
USER_Lock();
LIST_FOR_EACH( ptr, &class_list )
for (;;)
{
CLASS *class = LIST_ENTRY( ptr, CLASS, entry );
if (atom)
USER_Lock();
LIST_FOR_EACH( ptr, &class_list )
{
if (class->atomName != atom) continue;
}
else
{
if (!name || strcmpiW( class->name, name )) continue;
}
if (!hinstance || !class->local || class->hInstance == hinstance)
{
TRACE("%s %p -> %p\n", debugstr_w(name), hinstance, class);
return class;
CLASS *class = LIST_ENTRY( ptr, CLASS, entry );
if (atom)
{
if (class->atomName != atom) continue;
}
else
{
if (!name || strcmpiW( class->name, name )) continue;
}
if (!class->local || class->hInstance == hinstance)
{
TRACE("%s %p -> %p\n", debugstr_w(name), hinstance, class);
return class;
}
}
USER_Unlock();
if (!is_comctl32_class( name )) break;
if (GetModuleHandleW( comctl32W )) break;
if (!LoadLibraryW( comctl32W )) break;
TRACE( "%s retrying after loading comctl32\n", debugstr_w(name) );
}
USER_Unlock();
TRACE("%s %p -> not found\n", debugstr_w(name), hinstance);
return NULL;
}

View file

@ -28,13 +28,11 @@
#include "wine/test.h"
#include "windef.h"
#include "winbase.h"
#include "winnls.h"
#include "winreg.h"
#include "wingdi.h"
#include "winuser.h"
/* we don't want to include commctrl.h: */
static const CHAR WC_EDITA[] = "Edit";
static const WCHAR WC_EDITW[] = {'E','d','i','t',0};
#include "commctrl.h"
#define NUMCLASSWORDS 4
@ -1029,9 +1027,91 @@ static void test_icons(void)
DestroyWindow(hwnd);
}
static void test_comctl32_class( const char *name )
{
WNDCLASSA wcA;
WNDCLASSW wcW;
BOOL ret;
HMODULE module;
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) );
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" );
}
/* verify that comctl32 classes are automatically loaded by user32 */
static void test_comctl32_classes(void)
{
char path_name[MAX_PATH];
PROCESS_INFORMATION info;
STARTUPINFOA startup;
char **argv;
int i;
static const char *classes[] =
{
ANIMATE_CLASSA,
WC_COMBOBOXEXA,
DATETIMEPICK_CLASSA,
WC_HEADERA,
HOTKEY_CLASSA,
WC_IPADDRESSA,
WC_LISTVIEWA,
MONTHCAL_CLASSA,
WC_NATIVEFONTCTLA,
WC_PAGESCROLLERA,
PROGRESS_CLASSA,
REBARCLASSNAMEA,
STATUSCLASSNAMEA,
WC_TABCONTROLA,
TOOLBARCLASSNAMEA,
TOOLTIPS_CLASSA,
TRACKBAR_CLASSA,
WC_TREEVIEWA,
UPDOWN_CLASSA
};
winetest_get_mainargs( &argv );
for (i = 0; i < sizeof(classes) / sizeof(classes[0]); i++)
{
memset( &startup, 0, sizeof(startup) );
startup.cb = sizeof( startup );
sprintf( path_name, "%s class %s", argv[0], classes[i] );
ok( CreateProcessA( NULL, path_name, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info ),
"CreateProcess failed.\n" );
winetest_wait_child_process( info.hProcess );
CloseHandle( info.hProcess );
CloseHandle( info.hThread );
}
}
START_TEST(class)
{
char **argv;
HANDLE hInstance = GetModuleHandleA( NULL );
int argc = winetest_get_mainargs( &argv );
if (argc >= 3)
{
test_comctl32_class( argv[2] );
return;
}
test_GetClassInfo();
test_extra_values();
@ -1048,6 +1128,7 @@ START_TEST(class)
test_styles();
test_builtinproc();
test_icons();
test_comctl32_classes();
/* this test unregisters the Button class so it should be executed at the end */
test_instances();

View file

@ -1448,7 +1448,14 @@ HWND WIN_CreateWindowEx( CREATESTRUCTW *cs, LPCWSTR className, HINSTANCE module,
/* Create the window structure */
if (!(wndPtr = create_window_handle( parent, owner, className, module, unicode )))
return 0;
{
WNDCLASSW wc;
/* if it's a comctl32 class, GetClassInfo will load it, then we can retry */
if (GetLastError() != ERROR_INVALID_HANDLE ||
!GetClassInfoW( 0, className, &wc ) ||
!(wndPtr = create_window_handle( parent, owner, className, module, unicode )))
return 0;
}
hwnd = wndPtr->obj.handle;
/* Fill the window structure */