win32u: Move load_driver implementation from user32.

Signed-off-by: Jacek Caban <jacek@codeweavers.com>
Signed-off-by: Huw Davies <huw@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Jacek Caban 2022-03-09 15:20:48 +01:00 committed by Alexandre Julliard
parent 5df07a48a6
commit ca0f64f9ba
8 changed files with 147 additions and 107 deletions

View File

@ -28,74 +28,20 @@
#include "controls.h"
WINE_DEFAULT_DEBUG_CHANNEL(user);
WINE_DECLARE_DEBUG_CHANNEL(winediag);
static struct user_driver_funcs null_driver, lazy_load_driver;
const struct user_driver_funcs *USER_Driver = &lazy_load_driver;
static char driver_load_error[80];
static BOOL CDECL nodrv_CreateWindow( HWND hwnd );
static BOOL load_desktop_driver( HWND hwnd )
{
BOOL ret = FALSE;
HKEY hkey;
DWORD size;
WCHAR path[MAX_PATH];
WCHAR key[ARRAY_SIZE(L"System\\CurrentControlSet\\Control\\Video\\{}\\0000") + 40];
UINT guid_atom;
USER_CheckNotLock();
strcpy( driver_load_error, "The explorer process failed to start." ); /* default error */
wait_graphics_driver_ready();
guid_atom = HandleToULong( GetPropW( hwnd, L"__wine_display_device_guid" ));
lstrcpyW( key, L"System\\CurrentControlSet\\Control\\Video\\{" );
if (!GlobalGetAtomNameW( guid_atom, key + lstrlenW(key), 40 )) return 0;
lstrcatW( key, L"}\\0000" );
if (RegOpenKeyW( HKEY_LOCAL_MACHINE, key, &hkey )) return 0;
size = sizeof(path);
if (!RegQueryValueExW( hkey, L"GraphicsDriver", NULL, NULL, (BYTE *)path, &size ))
{
if (wcscmp( path, L"null" ))
{
ret = LoadLibraryW( path ) != NULL;
if (!ret) ERR( "failed to load %s\n", debugstr_w(path) );
}
else
{
__wine_set_user_driver( &null_driver, WINE_GDI_DRIVER_VERSION );
ret = TRUE;
}
TRACE( "%s\n", debugstr_w(path) );
}
else
{
size = sizeof(driver_load_error);
RegQueryValueExA( hkey, "DriverError", NULL, NULL, (BYTE *)driver_load_error, &size );
}
RegCloseKey( hkey );
return ret;
}
/* load the graphics driver */
static const struct user_driver_funcs *load_driver(void)
{
struct user_driver_funcs driver;
USEROBJECTFLAGS flags;
HWINSTA winstation;
if (!load_desktop_driver( GetDesktopWindow() ) || USER_Driver == &lazy_load_driver)
wait_graphics_driver_ready();
if (USER_Driver == &lazy_load_driver)
{
memset( &driver, 0, sizeof(driver) );
winstation = NtUserGetProcessWindowStation();
if (!NtUserGetObjectInformation( winstation, UOI_FLAGS, &flags, sizeof(flags), NULL )
|| (flags.dwFlags & WSF_VISIBLE))
driver.pCreateWindow = nodrv_CreateWindow;
__wine_set_user_driver( &driver, WINE_GDI_DRIVER_VERSION );
static struct user_driver_funcs empty_funcs;
WARN( "failed to load the display driver, falling back to null driver\n" );
__wine_set_user_driver( &empty_funcs, WINE_GDI_DRIVER_VERSION );
}
return USER_Driver;
@ -128,25 +74,6 @@ static void CDECL nulldrv_UpdateClipboard(void)
{
}
static BOOL CDECL nodrv_CreateWindow( HWND hwnd )
{
static int warned;
HWND parent = NtUserGetAncestor( hwnd, GA_PARENT );
/* HWND_MESSAGE windows don't need a graphics driver */
if (!parent || parent == get_user_thread_info()->msg_window) return TRUE;
if (warned++) return FALSE;
ERR_(winediag)( "Application tried to create a window, but no driver could be loaded.\n" );
if (driver_load_error[0]) ERR_(winediag)( "%s\n", driver_load_error );
return FALSE;
}
static BOOL CDECL nulldrv_CreateDesktopWindow( HWND hwnd )
{
return TRUE;
}
static BOOL CDECL nulldrv_CreateWindow( HWND hwnd )
{
return TRUE;
@ -253,11 +180,6 @@ static void CDECL loaderdrv_UpdateClipboard(void)
load_driver()->pUpdateClipboard();
}
static BOOL CDECL loaderdrv_CreateDesktopWindow( HWND hwnd )
{
return load_driver()->pCreateDesktopWindow( hwnd );
}
static BOOL CDECL loaderdrv_CreateWindow( HWND hwnd )
{
return load_driver()->pCreateWindow( hwnd );
@ -311,7 +233,7 @@ static struct user_driver_funcs lazy_load_driver =
NULL,
NULL,
/* windowing functions */
loaderdrv_CreateDesktopWindow,
NULL,
loaderdrv_CreateWindow,
nulldrv_DestroyWindow,
NULL,
@ -361,7 +283,6 @@ void CDECL __wine_set_user_driver( const struct user_driver_funcs *funcs, UINT v
SET_USER_FUNC(SetCursorPos);
SET_USER_FUNC(UpdateClipboard);
SET_USER_FUNC(CreateDesktopWindow);
SET_USER_FUNC(CreateWindow);
SET_USER_FUNC(DestroyWindow);
SET_USER_FUNC(GetDC);

View File

@ -144,6 +144,7 @@ static const struct user_callbacks user_funcs =
WindowFromDC,
free_dce,
MSG_SendInternalMessageTimeout,
(void *)__wine_set_user_driver,
};
static void WINAPI User32CallFreeIcon( ULONG *param, ULONG size )
@ -151,11 +152,17 @@ static void WINAPI User32CallFreeIcon( ULONG *param, ULONG size )
wow_handlers.free_icon_param( *param );
}
static BOOL WINAPI User32LoadDriver( const WCHAR *path, ULONG size )
{
return LoadLibraryW( path ) != NULL;
}
static const void *kernel_callback_table[NtUserCallCount] =
{
User32CallEnumDisplayMonitor,
User32CallWinEventHook,
User32CallWindowsHook,
User32LoadDriver,
User32CallFreeIcon,
};

View File

@ -188,7 +188,7 @@ static WND *create_window_handle( HWND parent, HWND owner, UNICODE_STRING *name,
{
if (!thread_info->top_window) thread_info->top_window = full_parent ? full_parent : handle;
else assert( full_parent == thread_info->top_window );
if (full_parent && !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
if (full_parent && !NtUserCallHwnd( thread_info->top_window, NtUserCreateDesktopWindow ))
ERR( "failed to create desktop window\n" );
register_builtin_classes();
}
@ -2098,7 +2098,7 @@ HWND WINAPI GetDesktopWindow(void)
SERVER_END_REQ;
}
if (!thread_info->top_window || !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
if (!thread_info->top_window || !NtUserCallHwnd( thread_info->top_window, NtUserCreateDesktopWindow ))
ERR( "failed to create desktop window\n" );
register_builtin_classes();

View File

@ -35,6 +35,7 @@
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(driver);
WINE_DECLARE_DEBUG_CHANNEL(winediag);
struct d3dkmt_adapter
{
@ -49,30 +50,13 @@ struct d3dkmt_device
};
static const struct user_driver_funcs lazy_load_driver;
static struct user_driver_funcs null_user_driver;
static struct list d3dkmt_adapters = LIST_INIT( d3dkmt_adapters );
static struct list d3dkmt_devices = LIST_INIT( d3dkmt_devices );
static pthread_mutex_t driver_lock = PTHREAD_MUTEX_INITIALIZER;
/**********************************************************************
* get_display_driver
*
* Special case for loading the display driver: get the name from the config file
*/
const struct gdi_dc_funcs *get_display_driver(void)
{
if (user_driver == &lazy_load_driver)
{
if (!get_desktop_window() || user_driver == &lazy_load_driver)
{
static struct user_driver_funcs empty_funcs;
WARN( "failed to load the display driver, falling back to null driver\n" );
__wine_set_display_driver( &empty_funcs, WINE_GDI_DRIVER_VERSION );
}
}
return &user_driver->dc_funcs;
}
static WCHAR driver_load_error[80];
static INT CDECL nulldrv_AbortDoc( PHYSDEV dev )
{
@ -767,6 +751,20 @@ static BOOL CDECL nulldrv_CreateDesktopWindow( HWND hwnd )
return TRUE;
}
static BOOL CDECL nodrv_CreateWindow( HWND hwnd )
{
static int warned;
HWND parent = NtUserGetAncestor( hwnd, GA_PARENT );
/* HWND_MESSAGE windows don't need a graphics driver */
if (!parent || parent == get_user_thread_info()->msg_window) return TRUE;
if (warned++) return FALSE;
ERR_(winediag)( "Application tried to create a window, but no driver could be loaded.\n" );
if (driver_load_error[0]) ERR_(winediag)( "%s\n", debugstr_w(driver_load_error) );
return FALSE;
}
static BOOL CDECL nulldrv_CreateWindow( HWND hwnd )
{
return TRUE;
@ -930,6 +928,83 @@ static void CDECL nulldrv_ThreadDetach( void )
{
}
static BOOL setup_null_driver(void)
{
if (user_callbacks)
user_callbacks->set_user_driver( &null_user_driver, WINE_GDI_DRIVER_VERSION );
else
__wine_set_display_driver( &null_user_driver, WINE_GDI_DRIVER_VERSION );
return TRUE;
}
static const WCHAR guid_key_prefixW[] =
{
'\\','R','e','g','i','s','t','r','y',
'\\','M','a','c','h','i','n','e',
'\\','S','y','s','t','e','m',
'\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
'\\','C','o','n','t','r','o','l',
'\\','V','i','d','e','o','\\','{'
};
static const WCHAR guid_key_suffixW[] = {'}','\\','0','0','0','0'};
static BOOL load_desktop_driver( HWND hwnd )
{
WCHAR key[ARRAYSIZE(guid_key_prefixW) + 40 + ARRAYSIZE(guid_key_suffixW)], *ptr;
char buf[4096];
KEY_VALUE_PARTIAL_INFORMATION *info = (void *)buf;
ATOM_BASIC_INFORMATION *abi = (ATOM_BASIC_INFORMATION *)buf;
BOOL ret = FALSE;
HKEY hkey;
DWORD size;
UINT guid_atom;
static const WCHAR prop_nameW[] =
{'_','_','w','i','n','e','_','d','i','s','p','l','a','y','_','d','e','v','i','c','e',
'_','g','u','i','d',0};
user_check_not_lock();
asciiz_to_unicode( driver_load_error, "The explorer process failed to start." ); /* default error */
/* wait for graphics driver to be ready */
send_message( hwnd, WM_NULL, 0, 0 );
guid_atom = HandleToULong( NtUserGetProp( hwnd, prop_nameW ));
memcpy( key, guid_key_prefixW, sizeof(guid_key_prefixW) );
ptr = key + ARRAYSIZE(guid_key_prefixW);
if (NtQueryInformationAtom( guid_atom, AtomBasicInformation, buf, sizeof(buf), NULL ))
return FALSE;
memcpy( ptr, abi->Name, abi->NameLength );
ptr += abi->NameLength / sizeof(WCHAR);
memcpy( ptr, guid_key_suffixW, sizeof(guid_key_suffixW) );
ptr += ARRAY_SIZE(guid_key_suffixW);
if (!(hkey = reg_open_key( NULL, key, (ptr - key) * sizeof(WCHAR) ))) return FALSE;
if ((size = query_reg_ascii_value( hkey, "GraphicsDriver", info, sizeof(buf) )))
{
static const WCHAR nullW[] = {'n','u','l','l',0};
TRACE( "trying driver %s\n", debugstr_wn( (const WCHAR *)info->Data,
info->DataLength / sizeof(WCHAR) ));
if (info->DataLength != sizeof(nullW) || memcmp( info->Data, nullW, sizeof(nullW) ))
{
void *ret_ptr;
ULONG ret_len;
ret = KeUserModeCallback( NtUserLoadDriver, info->Data, info->DataLength,
&ret_ptr, &ret_len );
}
else ret = setup_null_driver();
}
else if ((size = query_reg_ascii_value( hkey, "DriverError", info, sizeof(buf) )))
{
memcpy( driver_load_error, info->Data, min( info->DataLength, sizeof(driver_load_error) ));
driver_load_error[ARRAYSIZE(driver_load_error) - 1] = 0;
}
NtClose( hkey );
return ret;
}
/**********************************************************************
* Lazy loading user driver
*
@ -939,10 +1014,31 @@ static void CDECL nulldrv_ThreadDetach( void )
static const struct user_driver_funcs *load_driver(void)
{
get_display_driver();
USEROBJECTFLAGS flags;
HWINSTA winstation;
if (!load_desktop_driver( get_desktop_window() ) || user_driver == &lazy_load_driver)
{
winstation = NtUserGetProcessWindowStation();
if (!NtUserGetObjectInformation( winstation, UOI_FLAGS, &flags, sizeof(flags), NULL )
|| (flags.dwFlags & WSF_VISIBLE))
null_user_driver.pCreateWindow = nodrv_CreateWindow;
setup_null_driver();
}
return user_driver;
}
/**********************************************************************
* get_display_driver
*/
const struct gdi_dc_funcs *get_display_driver(void)
{
if (user_driver == &lazy_load_driver) load_driver();
return &user_driver->dc_funcs;
}
static BOOL CDECL loaderdrv_ActivateKeyboardLayout( HKL layout, UINT flags )
{
return load_driver()->pActivateKeyboardLayout( layout, flags );
@ -1031,6 +1127,11 @@ static void CDECL loaderdrv_UpdateDisplayDevices( const struct gdi_device_manage
load_driver()->pUpdateDisplayDevices( manager, force, param );
}
static BOOL CDECL loaderdrv_CreateDesktopWindow( HWND hwnd )
{
return load_driver()->pCreateDesktopWindow( hwnd );
}
static void CDECL loaderdrv_FlashWindowEx( FLASHWINFO *info )
{
load_driver()->pFlashWindowEx( info );
@ -1066,6 +1167,7 @@ static const struct user_driver_funcs lazy_load_driver =
.pEnumDisplaySettingsEx = loaderdrv_EnumDisplaySettingsEx,
.pUpdateDisplayDevices = loaderdrv_UpdateDisplayDevices,
/* windowing functions */
.pCreateDesktopWindow = loaderdrv_CreateDesktopWindow,
.pFlashWindowEx = loaderdrv_FlashWindowEx,
.pMsgWaitForMultipleObjectsEx = nulldrv_MsgWaitForMultipleObjectsEx,
.pScrollDC = nulldrv_ScrollDC,

View File

@ -38,6 +38,7 @@ struct user_callbacks
HWND (WINAPI *pWindowFromDC)( HDC );
void (WINAPI *free_dce)( struct dce *dce, HWND hwnd );
LRESULT (WINAPI *send_ll_message)( DWORD, DWORD, UINT, WPARAM, LPARAM, UINT, UINT, PDWORD_PTR );
void (CDECL *set_user_driver)( void *, UINT );
};
struct user_object

View File

@ -4537,6 +4537,8 @@ ULONG_PTR WINAPI NtUserCallNoParam( ULONG code )
{
switch(code)
{
case NtUserGetDesktopWindow:
return HandleToUlong( get_desktop_window() );
case NtUserGetInputState:
return get_input_state();
/* temporary exports */

View File

@ -1067,6 +1067,9 @@ DWORD WINAPI NtUserCallHwnd( HWND hwnd, DWORD code )
return is_window( hwnd );
case NtUserIsWindowVisible:
return is_window_visible( hwnd );
/* temporary exports */
case NtUserCreateDesktopWindow:
return user_driver->pCreateDesktopWindow( hwnd );
default:
FIXME( "invalid code %u\n", code );
return 0;

View File

@ -30,6 +30,7 @@ enum
NtUserCallEnumDisplayMonitor,
NtUserCallWinEventHook,
NtUserCallWindowsHook,
NtUserLoadDriver,
/* win16 hooks */
NtUserCallFreeIcon,
/* Vulkan support */
@ -86,6 +87,7 @@ struct win_hook_params
/* NtUserCallNoParam codes, not compatible with Windows */
enum
{
NtUserGetDesktopWindow,
NtUserGetInputState,
/* temporary exports */
NtUserThreadDetach,
@ -143,6 +145,8 @@ enum
NtUserGetWindowTextLength,
NtUserIsWindow,
NtUserIsWindowVisible,
/* temporary exports */
NtUserCreateDesktopWindow,
};
/* NtUserCallHwndParam codes, not compatible with Windows */