From f6abd9d14027b0bb24225328678e4d2901720514 Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Tue, 30 Nov 2021 13:26:48 +0100 Subject: [PATCH] win32u: Implement NtUserEnumDisplayDevices. And use it in user32. Signed-off-by: Jacek Caban Signed-off-by: Huw Davies Signed-off-by: Alexandre Julliard --- dlls/user32/sysparams.c | 335 +---------------------------------- dlls/win32u/dc.c | 6 - dlls/win32u/gdiobj.c | 1 + dlls/win32u/ntgdi_private.h | 1 - dlls/win32u/sysparams.c | 71 ++++++++ dlls/win32u/win32u.spec | 2 +- dlls/win32u/win32u_private.h | 10 ++ dlls/win32u/wrappers.c | 10 +- include/ntuser.h | 2 + 9 files changed, 96 insertions(+), 342 deletions(-) diff --git a/dlls/user32/sysparams.c b/dlls/user32/sysparams.c index 9d8fe1c66fa..92c62d815ba 100644 --- a/dlls/user32/sysparams.c +++ b/dlls/user32/sysparams.c @@ -106,31 +106,6 @@ DEFINE_DEVPROPKEY(WINE_DEVPROPKEY_MONITOR_ADAPTERNAME, 0x233a9ef3, 0xafc4, 0x4ab #define NULLDRV_DEFAULT_HMONITOR ((HMONITOR)(UINT_PTR)(0x10000 + 1)) -/* Cached display device information */ -struct display_device -{ - struct list entry; /* Device list entry */ - struct list children; /* Child device list entry. For adapters, this is monitor list. For monitors, this is unused. */ - WCHAR device_name[32]; /* as DeviceName in DISPLAY_DEVICEW */ - WCHAR device_string[128]; /* as DeviceString in DISPLAY_DEVICEW */ - DWORD state_flags; /* as StateFlags in DISPLAY_DEVICEW */ - WCHAR device_id[128]; /* as DeviceID in DISPLAY_DEVICEW when EDD_GET_DEVICE_INTERFACE_NAME is not set */ - WCHAR interface_name[128]; /* as DeviceID in DISPLAY_DEVICEW when EDD_GET_DEVICE_INTERFACE_NAME is set */ - WCHAR device_key[128]; /* as DeviceKey in DISPLAY_DEVICEW */ -}; - -static struct list adapters = LIST_INIT(adapters); -static FILETIME last_query_display_time; -static CRITICAL_SECTION display_section; -static CRITICAL_SECTION_DEBUG display_critsect_debug = -{ - 0, 0, &display_section, - { &display_critsect_debug.ProcessLocksList, &display_critsect_debug.ProcessLocksList }, - 0, 0, { (DWORD_PTR)(__FILE__ ": display_section") } -}; -static CRITICAL_SECTION display_section = { &display_critsect_debug, -1, 0, 0, 0, 0 }; - -static BOOL enum_display_device( WCHAR *device, DWORD index, struct display_device *info ); /* Cached monitor information */ static MONITORINFOEXW *monitors; @@ -3816,69 +3791,6 @@ HMONITOR WINAPI MonitorFromWindow(HWND hWnd, DWORD dwFlags) return MonitorFromRect( &rect, dwFlags ); } -/* Return FALSE on failure and TRUE on success */ -static BOOL update_display_cache(void) -{ - struct display_device device, *adapter, *adapter2, *monitor, *monitor2; - DWORD adapter_idx, monitor_idx; - struct list *monitor_list; - FILETIME filetime = {0}; - HANDLE mutex = NULL; - BOOL ret = FALSE; - - /* Update display cache from SetupAPI if it's outdated */ - wait_graphics_driver_ready(); - - if (!video_key && RegOpenKeyW( HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\VIDEO", &video_key )) - return FALSE; - if (RegQueryInfoKeyW( video_key, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, &filetime )) - return FALSE; - if (CompareFileTime( &filetime, &last_query_display_time ) < 1) - return TRUE; - - mutex = get_display_device_init_mutex(); - EnterCriticalSection( &display_section ); - - LIST_FOR_EACH_ENTRY_SAFE(adapter, adapter2, &adapters, struct display_device, entry) - { - LIST_FOR_EACH_ENTRY_SAFE(monitor, monitor2, &adapter->children, struct display_device, entry) - { - list_remove( &monitor->entry ); - heap_free( monitor ); - } - list_remove( &adapter->entry ); - heap_free( adapter ); - } - - for (adapter_idx = 0; enum_display_device( NULL, adapter_idx, &device ); ++adapter_idx) - { - adapter = heap_alloc( sizeof(*adapter) ); - if (!adapter) - goto fail; - - memcpy( adapter, &device, sizeof(device) ); - monitor_list = &adapter->children; - list_init( monitor_list ); - list_add_tail( &adapters, &adapter->entry ); - for (monitor_idx = 0; enum_display_device( adapter->device_name, monitor_idx, &device ); ++monitor_idx) - { - monitor = heap_alloc( sizeof(*monitor) ); - if (!monitor) - goto fail; - - memcpy( monitor, &device, sizeof(device) ); - list_add_tail( monitor_list, &monitor->entry ); - } - } - - last_query_display_time = filetime; - ret = TRUE; -fail: - LeaveCriticalSection( &display_section ); - release_display_device_init_mutex( mutex ); - return ret; -} - /* Return FALSE on failure and TRUE on success */ static BOOL update_monitor_cache(void) { @@ -4214,250 +4126,9 @@ BOOL WINAPI EnumDisplayDevicesA( LPCSTR device, DWORD index, DISPLAY_DEVICEA *in */ BOOL WINAPI EnumDisplayDevicesW( LPCWSTR device, DWORD index, DISPLAY_DEVICEW *info, DWORD flags ) { - struct display_device *adapter, *monitor, *found = NULL; - DWORD device_idx = 0; - - TRACE("%s %u %p %#x\n", debugstr_w( device ), index, info, flags); - - if (!update_display_cache()) - return FALSE; - - EnterCriticalSection( &display_section ); - /* Enumerate adapters */ - if (!device) - { - LIST_FOR_EACH_ENTRY(adapter, &adapters, struct display_device, entry) - { - if (index == device_idx++) - { - found = adapter; - break; - } - } - } - /* Enumerate monitors */ - else - { - LIST_FOR_EACH_ENTRY(adapter, &adapters, struct display_device, entry) - { - if (!lstrcmpiW( device, adapter->device_name )) - { - found = adapter; - break; - } - } - - if (found) - { - found = NULL; - LIST_FOR_EACH_ENTRY(monitor, &adapter->children, struct display_device, entry) - { - if (index == device_idx++) - { - found = monitor; - break; - } - } - } - } - - if (!found) - { - LeaveCriticalSection( &display_section ); - return FALSE; - } - - if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceName) + sizeof(info->DeviceName)) - lstrcpyW( info->DeviceName, found->device_name ); - if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceString) + sizeof(info->DeviceString)) - lstrcpyW( info->DeviceString, found->device_string ); - if (info->cb >= offsetof(DISPLAY_DEVICEW, StateFlags) + sizeof(info->StateFlags)) - info->StateFlags = found->state_flags; - if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceID) + sizeof(info->DeviceID)) - lstrcpyW( info->DeviceID, (flags & EDD_GET_DEVICE_INTERFACE_NAME) ? found->interface_name : found->device_id ); - if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceKey) + sizeof(info->DeviceKey)) - lstrcpyW( info->DeviceKey, found->device_key ); - LeaveCriticalSection( &display_section ); - return TRUE; -} - -/* Call this function with the display_device_init mutex held */ -static BOOL enum_display_device( WCHAR *device, DWORD index, struct display_device *info ) -{ - SP_DEVINFO_DATA device_data = {sizeof(device_data)}; - HDEVINFO set = INVALID_HANDLE_VALUE; - WCHAR key_nameW[MAX_PATH]; - WCHAR instanceW[MAX_PATH]; - WCHAR bufferW[1024]; - LONG adapter_index; - WCHAR *next_charW; - DWORD size; - DWORD type; - HKEY hkey; - BOOL ret = FALSE; - - /* Find adapter */ - if (!device) - { - swprintf( key_nameW, ARRAY_SIZE(key_nameW), L"\\Device\\Video%d", index ); - size = sizeof(bufferW); - if (RegGetValueW( HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\VIDEO", key_nameW, RRF_RT_REG_SZ, NULL, bufferW, &size )) - goto done; - - /* DeviceKey */ - lstrcpyW( info->device_key, bufferW ); - - /* DeviceName */ - swprintf( info->device_name, ARRAY_SIZE(info->device_name), L"\\\\.\\DISPLAY%d", index + 1 ); - - /* Strip \Registry\Machine\ */ - lstrcpyW( key_nameW, bufferW + 18 ); - - /* DeviceString */ - size = sizeof(info->device_string); - if (RegGetValueW( HKEY_LOCAL_MACHINE, key_nameW, L"DriverDesc", RRF_RT_REG_SZ, NULL, - info->device_string, &size )) - goto done; - - /* StateFlags */ - size = sizeof(info->state_flags); - if (RegGetValueW( HKEY_CURRENT_CONFIG, key_nameW, L"StateFlags", RRF_RT_REG_DWORD, NULL, - &info->state_flags, &size )) - goto done; - - /* Interface name */ - info->interface_name[0] = 0; - - /* DeviceID */ - size = sizeof(bufferW); - if (RegGetValueW( HKEY_CURRENT_CONFIG, key_nameW, L"GPUID", RRF_RT_REG_SZ | RRF_ZEROONFAILURE, NULL, - bufferW, &size )) - goto done; - set = SetupDiCreateDeviceInfoList( &GUID_DEVCLASS_DISPLAY, NULL ); - if (!SetupDiOpenDeviceInfoW( set, bufferW, NULL, 0, &device_data ) - || !SetupDiGetDeviceRegistryPropertyW( set, &device_data, SPDRP_HARDWAREID, NULL, (BYTE *)bufferW, - sizeof(bufferW), NULL )) - goto done; - lstrcpyW( info->device_id, bufferW ); - } - /* Find monitor */ - else - { - /* Check adapter name */ - if (wcsnicmp( device, L"\\\\.\\DISPLAY", lstrlenW(L"\\\\.\\DISPLAY") )) - goto done; - - adapter_index = wcstol( device + lstrlenW(L"\\\\.\\DISPLAY"), NULL, 10 ); - swprintf( key_nameW, ARRAY_SIZE(key_nameW), L"\\Device\\Video%d", adapter_index - 1 ); - - size = sizeof(bufferW); - if (RegGetValueW( HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\VIDEO", key_nameW, RRF_RT_REG_SZ, NULL, bufferW, &size )) - goto done; - - /* DeviceName */ - swprintf( info->device_name, ARRAY_SIZE(info->device_name), L"\\\\.\\DISPLAY%d\\Monitor%d", adapter_index, index ); - - /* Get monitor instance */ - /* Strip \Registry\Machine\ first */ - lstrcpyW( key_nameW, bufferW + 18 ); - swprintf( bufferW, ARRAY_SIZE(bufferW), L"MonitorID%d", index ); - - size = sizeof(instanceW); - if (RegGetValueW( HKEY_CURRENT_CONFIG, key_nameW, bufferW, RRF_RT_REG_SZ, NULL, instanceW, &size )) - goto done; - - set = SetupDiCreateDeviceInfoList( &GUID_DEVCLASS_MONITOR, NULL ); - if (!SetupDiOpenDeviceInfoW( set, instanceW, NULL, 0, &device_data )) - goto done; - - /* StateFlags */ - if (!SetupDiGetDevicePropertyW( set, &device_data, &WINE_DEVPROPKEY_MONITOR_STATEFLAGS, &type, - (BYTE *)&info->state_flags, sizeof(info->state_flags), NULL, 0 )) - goto done; - - /* DeviceString */ - if (!SetupDiGetDeviceRegistryPropertyW( set, &device_data, SPDRP_DEVICEDESC, NULL, - (BYTE *)info->device_string, - sizeof(info->device_string), NULL )) - goto done; - - /* DeviceKey */ - if (!SetupDiGetDeviceRegistryPropertyW( set, &device_data, SPDRP_DRIVER, NULL, (BYTE *)bufferW, - sizeof(bufferW), NULL )) - goto done; - - lstrcpyW( info->device_key, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\" ); - lstrcatW( info->device_key, bufferW ); - - /* Interface name */ - lstrcpyW( info->interface_name, L"\\\\\?\\" ); - lstrcatW( info->interface_name, instanceW ); - lstrcatW( info->interface_name, L"#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}" ); - /* Replace '\\' with '#' after prefix */ - for (next_charW = info->interface_name + lstrlenW( L"\\\\\?\\" ); *next_charW; next_charW++) - { - if (*next_charW == '\\') - *next_charW = '#'; - } - - /* DeviceID */ - if (!SetupDiGetDeviceRegistryPropertyW( set, &device_data, SPDRP_HARDWAREID, NULL, (BYTE *)bufferW, - sizeof(bufferW), NULL )) - goto done; - - lstrcpyW( info->device_id, bufferW ); - lstrcatW( info->device_id, L"\\" ); - - if (!SetupDiGetDeviceRegistryPropertyW( set, &device_data, SPDRP_DRIVER, NULL, (BYTE *)bufferW, - sizeof(bufferW), NULL )) - goto done; - - lstrcatW( info->device_id, bufferW ); - } - - ret = TRUE; -done: - SetupDiDestroyDeviceInfoList( set ); - if (ret) - return ret; - - /* Fallback to report at least one adapter and monitor, if user driver didn't initialize display device registry */ - if (index) - return FALSE; - - /* If user driver did initialize the registry, then exit */ - if (!RegOpenKeyW( HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\VIDEO", &hkey )) - { - RegCloseKey( hkey ); - return FALSE; - } - WARN("Reporting fallback display devices\n"); - - /* Adapter */ - if (!device) - { - lstrcpyW( info->device_name, L"\\\\.\\DISPLAY1" ); - lstrcpyW( info->device_string, L"Wine Adapter" ); - info->state_flags = DISPLAY_DEVICE_ATTACHED_TO_DESKTOP | DISPLAY_DEVICE_PRIMARY_DEVICE | DISPLAY_DEVICE_VGA_COMPATIBLE; - info->interface_name[0] = 0; - lstrcpyW( info->device_id, L"PCI\\VEN_0000&DEV_0000&SUBSYS_00000000&REV_00" ); - info->device_key[0] = 0; - } - /* Monitor */ - else - { - if (lstrcmpiW( L"\\\\.\\DISPLAY1", device )) - return FALSE; - - lstrcpyW( info->device_name, L"\\\\.\\DISPLAY1\\Monitor0" ); - lstrcpyW( info->device_string, L"Generic Non-PnP Monitor" ); - info->state_flags = DISPLAY_DEVICE_ACTIVE | DISPLAY_DEVICE_ATTACHED; - lstrcpyW( info->interface_name, L"\\\\\?\\DISPLAY#Default_Monitor#4&17f0ff54&0&UID0#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}" ); - lstrcpyW( info->device_id, L"MONITOR\\Default_Monitor\\{4d36e96e-e325-11ce-bfc1-08002be10318}\\0000" ); - info->device_key[0] = 0; - } - - return TRUE; + UNICODE_STRING str; + RtlInitUnicodeString( &str, device ); + return NtUserEnumDisplayDevices( &str, index, info, flags ); } /********************************************************************** diff --git a/dlls/win32u/dc.c b/dlls/win32u/dc.c index 0d7d82f9aa6..1456eb1b887 100644 --- a/dlls/win32u/dc.c +++ b/dlls/win32u/dc.c @@ -53,12 +53,6 @@ struct dc_attr_bucket static struct list dc_attr_buckets = LIST_INIT( dc_attr_buckets ); -static inline const char *debugstr_us( const UNICODE_STRING *us ) -{ - if (!us) return ""; - return debugstr_wn( us->Buffer, us->Length / sizeof(WCHAR) ); -} - static BOOL DC_DeleteObject( HGDIOBJ handle ); static const struct gdi_obj_funcs dc_funcs = diff --git a/dlls/win32u/gdiobj.c b/dlls/win32u/gdiobj.c index 253f6f14ae1..e74c025e838 100644 --- a/dlls/win32u/gdiobj.c +++ b/dlls/win32u/gdiobj.c @@ -1169,6 +1169,7 @@ static struct unix_funcs unix_funcs = NtGdiWidenPath, NtUserActivateKeyboardLayout, NtUserCountClipboardFormats, + NtUserEnumDisplayDevices, NtUserGetDisplayConfigBufferSizes, NtUserGetKeyNameText, NtUserGetKeyboardLayoutList, diff --git a/dlls/win32u/ntgdi_private.h b/dlls/win32u/ntgdi_private.h index 20227c486e6..df7fb5e8f4e 100644 --- a/dlls/win32u/ntgdi_private.h +++ b/dlls/win32u/ntgdi_private.h @@ -640,6 +640,5 @@ extern void CDECL free_heap_bits( struct gdi_image_bits *bits ) DECLSPEC_HIDDEN; void set_gdi_client_ptr( HGDIOBJ handle, void *ptr ) DECLSPEC_HIDDEN; extern SYSTEM_BASIC_INFORMATION system_info DECLSPEC_HIDDEN; -extern const struct user_callbacks *user_callbacks DECLSPEC_HIDDEN; #endif /* __WINE_NTGDI_PRIVATE_H */ diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 26ea6f01f1f..1b2e67031d3 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -1211,3 +1211,74 @@ LONG WINAPI NtUserGetDisplayConfigBufferSizes( UINT32 flags, UINT32 *num_path_in TRACE( "returning %u paths %u modes\n", *num_path_info, *num_mode_info ); return ERROR_SUCCESS; } + +static struct adapter *find_adapter( UNICODE_STRING *name ) +{ + struct adapter *adapter; + + LIST_FOR_EACH_ENTRY(adapter, &adapters, struct adapter, entry) + { + if (!name || !name->Length) return adapter; /* use primary adapter */ + if (!wcsnicmp( name->Buffer, adapter->dev.device_name, name->Length / sizeof(WCHAR) ) && + !adapter->dev.device_name[name->Length / sizeof(WCHAR)]) + return adapter; + } + return NULL; +} + +/*********************************************************************** + * NtUserEnumDisplayDevices (win32u.@) + */ +BOOL WINAPI NtUserEnumDisplayDevices( UNICODE_STRING *device, DWORD index, + DISPLAY_DEVICEW *info, DWORD flags ) +{ + struct display_device *found = NULL; + struct adapter *adapter; + struct monitor *monitor; + + TRACE( "%s %u %p %#x\n", debugstr_us( device ), index, info, flags ); + + if (!lock_display_devices()) return FALSE; + + if (!device || !device->Length) + { + /* Enumerate adapters */ + LIST_FOR_EACH_ENTRY(adapter, &adapters, struct adapter, entry) + { + if (index == adapter->id) + { + found = &adapter->dev; + break; + } + } + } + else if ((adapter = find_adapter( device ))) + { + /* Enumerate monitors */ + LIST_FOR_EACH_ENTRY(monitor, &monitors, struct monitor, entry) + { + if (monitor->adapter == adapter && index == monitor->id) + { + found = &monitor->dev; + break; + } + } + } + + if (found) + { + if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceName) + sizeof(info->DeviceName)) + lstrcpyW( info->DeviceName, found->device_name ); + if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceString) + sizeof(info->DeviceString)) + lstrcpyW( info->DeviceString, found->device_string ); + if (info->cb >= offsetof(DISPLAY_DEVICEW, StateFlags) + sizeof(info->StateFlags)) + info->StateFlags = found->state_flags; + if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceID) + sizeof(info->DeviceID)) + lstrcpyW( info->DeviceID, (flags & EDD_GET_DEVICE_INTERFACE_NAME) + ? found->interface_name : found->device_id ); + if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceKey) + sizeof(info->DeviceKey)) + lstrcpyW( info->DeviceKey, found->device_key ); + } + unlock_display_devices(); + return !!found; +} diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index ede3a68925b..b210dc1062e 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -875,7 +875,7 @@ @ stub NtUserEndDeferWindowPosEx @ stub NtUserEndMenu @ stub NtUserEndPaint -@ stub NtUserEnumDisplayDevices +@ stdcall NtUserEnumDisplayDevices(ptr long ptr long) @ stub NtUserEnumDisplayMonitors @ stub NtUserEnumDisplaySettings @ stub NtUserEvent diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index d4454a3066a..e881a8eb2ce 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -44,6 +44,8 @@ struct user_callbacks HWND (WINAPI *pWindowFromDC)( HDC ); }; +extern const struct user_callbacks *user_callbacks DECLSPEC_HIDDEN; + struct unix_funcs { /* win32u functions */ @@ -196,6 +198,8 @@ struct unix_funcs BOOL (WINAPI *pNtGdiWidenPath)( HDC hdc ); HKL (WINAPI *pNtUserActivateKeyboardLayout)( HKL layout, UINT flags ); INT (WINAPI *pNtUserCountClipboardFormats)(void); + BOOL (WINAPI *pNtUserEnumDisplayDevices)( UNICODE_STRING *device, DWORD index, + DISPLAY_DEVICEW *info, DWORD flags ); LONG (WINAPI *pNtUserGetDisplayConfigBufferSizes)( UINT32 flags, UINT32 *num_path_info, UINT32 *num_mode_info ); INT (WINAPI *pNtUserGetKeyNameText)( LONG lparam, WCHAR *buffer, INT size ); @@ -390,4 +394,10 @@ static inline BOOL is_win9x(void) return NtCurrentTeb()->Peb->OSPlatformId == VER_PLATFORM_WIN32s; } +static inline const char *debugstr_us( const UNICODE_STRING *us ) +{ + if (!us) return ""; + return debugstr_wn( us->Buffer, us->Length / sizeof(WCHAR) ); +} + #endif /* __WINE_WIN32U_PRIVATE */ diff --git a/dlls/win32u/wrappers.c b/dlls/win32u/wrappers.c index 9d55c4d06b6..9c4937643cf 100644 --- a/dlls/win32u/wrappers.c +++ b/dlls/win32u/wrappers.c @@ -606,6 +606,12 @@ INT WINAPI NtUserCountClipboardFormats(void) return unix_funcs->pNtUserCountClipboardFormats(); } +BOOL WINAPI NtUserEnumDisplayDevices( UNICODE_STRING *device, DWORD index, + DISPLAY_DEVICEW *info, DWORD flags ) +{ + return unix_funcs->pNtUserEnumDisplayDevices( device, index, info, flags ); +} + LONG WINAPI NtUserGetDisplayConfigBufferSizes( UINT32 flags, UINT32 *num_path_info, UINT32 *num_mode_info ) { @@ -847,7 +853,7 @@ static HWND WINAPI call_WindowFromDC( HDC hdc ) return pWindowFromDC ? pWindowFromDC( hdc ) : NULL; } -static const struct user_callbacks user_callbacks = +static const struct user_callbacks user_funcs = { call_GetDesktopWindow, call_GetDpiForSystem, @@ -863,6 +869,6 @@ static const struct user_callbacks user_callbacks = extern void wrappers_init( unixlib_handle_t handle ) { - const void *args = &user_callbacks; + const void *args = &user_funcs; if (!__wine_unix_call( handle, 1, &args )) unix_funcs = args; } diff --git a/include/ntuser.h b/include/ntuser.h index abf9f86b23e..b4e5a65cfaa 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -64,6 +64,8 @@ HDESK WINAPI NtUserCreateDesktopEx( OBJECT_ATTRIBUTES *attr, UNICODE_STRING *d ULONG heap_size ); HWINSTA WINAPI NtUserCreateWindowStation( OBJECT_ATTRIBUTES *attr, ACCESS_MASK mask, ULONG arg3, ULONG arg4, ULONG arg5, ULONG arg6, ULONG arg7 ); +BOOL WINAPI NtUserEnumDisplayDevices( UNICODE_STRING *device, DWORD index, + DISPLAY_DEVICEW *info, DWORD flags ); INT WINAPI NtUserGetClipboardFormatName( UINT format, WCHAR *buffer, INT maxlen ); HWND WINAPI NtUserGetClipboardOwner(void); DWORD WINAPI NtUserGetClipboardSequenceNumber(void);