Commit 095bdc6c authored by Zhiyi Zhang's avatar Zhiyi Zhang Committed by Alexandre Julliard

user32: Add a cache for EnumDisplayDevicesW().

parent 9b2f59cb
......@@ -107,6 +107,32 @@ 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;
static UINT monitor_count;
......@@ -3792,6 +3818,69 @@ HMONITOR WINAPI MonitorFromWindow(HWND hWnd, DWORD 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)
{
SP_DEVINFO_DATA device_data = {sizeof(device_data)};
......@@ -4118,6 +4207,76 @@ 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];
......@@ -4125,17 +4284,11 @@ BOOL WINAPI EnumDisplayDevicesW( LPCWSTR device, DWORD index, DISPLAY_DEVICEW *i
WCHAR bufferW[1024];
LONG adapter_index;
WCHAR *next_charW;
HANDLE mutex;
DWORD size;
DWORD type;
HKEY hkey;
BOOL ret = FALSE;
TRACE("%s %d %p %#x\n", debugstr_w( device ), index, info, flags);
wait_graphics_driver_ready();
mutex = get_display_device_init_mutex();
/* Find adapter */
if (!device)
{
......@@ -4145,46 +4298,40 @@ BOOL WINAPI EnumDisplayDevicesW( LPCWSTR device, DWORD index, DISPLAY_DEVICEW *i
goto done;
/* DeviceKey */
if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceKey) + sizeof(info->DeviceKey))
lstrcpyW( info->DeviceKey, bufferW );
lstrcpyW( info->device_key, bufferW );
/* DeviceName */
swprintf( info->DeviceName, ARRAY_SIZE(info->DeviceName), L"\\\\.\\DISPLAY%d", index + 1 );
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->DeviceString);
size = sizeof(info->device_string);
if (RegGetValueW( HKEY_LOCAL_MACHINE, key_nameW, L"DriverDesc", RRF_RT_REG_SZ, NULL,
info->DeviceString, &size ))
info->device_string, &size ))
goto done;
/* StateFlags */
size = sizeof(info->StateFlags);
size = sizeof(info->state_flags);
if (RegGetValueW( HKEY_CURRENT_CONFIG, key_nameW, L"StateFlags", RRF_RT_REG_DWORD, NULL,
&info->StateFlags, &size ))
&info->state_flags, &size ))
goto done;
/* Interface name */
info->interface_name[0] = 0;
/* DeviceID */
if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceID) + sizeof(info->DeviceID))
{
if (flags & EDD_GET_DEVICE_INTERFACE_NAME)
info->DeviceID[0] = 0;
else
{
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->DeviceID, bufferW );
}
}
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
......@@ -4201,7 +4348,7 @@ BOOL WINAPI EnumDisplayDevicesW( LPCWSTR device, DWORD index, DISPLAY_DEVICEW *i
goto done;
/* DeviceName */
swprintf( info->DeviceName, ARRAY_SIZE(info->DeviceName), L"\\\\.\\DISPLAY%d\\Monitor%d", adapter_index, index );
swprintf( info->device_name, ARRAY_SIZE(info->device_name), L"\\\\.\\DISPLAY%d\\Monitor%d", adapter_index, index );
/* Get monitor instance */
/* Strip \Registry\Machine\ first */
......@@ -4218,63 +4365,51 @@ BOOL WINAPI EnumDisplayDevicesW( LPCWSTR device, DWORD index, DISPLAY_DEVICEW *i
/* StateFlags */
if (!SetupDiGetDevicePropertyW( set, &device_data, &WINE_DEVPROPKEY_MONITOR_STATEFLAGS, &type,
(BYTE *)&info->StateFlags, sizeof(info->StateFlags), NULL, 0 ))
(BYTE *)&info->state_flags, sizeof(info->state_flags), NULL, 0 ))
goto done;
/* DeviceString */
if (!SetupDiGetDeviceRegistryPropertyW( set, &device_data, SPDRP_DEVICEDESC, NULL,
(BYTE *)info->DeviceString,
sizeof(info->DeviceString), NULL ))
(BYTE *)info->device_string,
sizeof(info->device_string), NULL ))
goto done;
/* DeviceKey */
if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceKey) + sizeof(info->DeviceKey))
{
if (!SetupDiGetDeviceRegistryPropertyW( set, &device_data, SPDRP_DRIVER, NULL, (BYTE *)bufferW,
sizeof(bufferW), NULL ))
goto done;
if (!SetupDiGetDeviceRegistryPropertyW( set, &device_data, SPDRP_DRIVER, NULL, (BYTE *)bufferW,
sizeof(bufferW), NULL ))
goto done;
lstrcpyW( info->DeviceKey, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\" );
lstrcatW( info->DeviceKey, bufferW );
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 (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceID) + sizeof(info->DeviceID))
{
if (flags & EDD_GET_DEVICE_INTERFACE_NAME)
{
lstrcpyW( info->DeviceID, L"\\\\\?\\" );
lstrcatW( info->DeviceID, instanceW );
lstrcatW( info->DeviceID, L"#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}" );
/* Replace '\\' with '#' after prefix */
for (next_charW = info->DeviceID + lstrlenW( L"\\\\\?\\" ); *next_charW;
next_charW++)
{
if (*next_charW == '\\')
*next_charW = '#';
}
}
else
{
if (!SetupDiGetDeviceRegistryPropertyW( set, &device_data, SPDRP_HARDWAREID, NULL, (BYTE *)bufferW,
sizeof(bufferW), NULL ))
goto done;
if (!SetupDiGetDeviceRegistryPropertyW( set, &device_data, SPDRP_HARDWAREID, NULL, (BYTE *)bufferW,
sizeof(bufferW), NULL ))
goto done;
lstrcpyW( info->DeviceID, bufferW );
lstrcatW( info->DeviceID, L"\\" );
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;
if (!SetupDiGetDeviceRegistryPropertyW( set, &device_data, SPDRP_DRIVER, NULL, (BYTE *)bufferW,
sizeof(bufferW), NULL ))
goto done;
lstrcatW( info->DeviceID, bufferW );
}
}
lstrcatW( info->device_id, bufferW );
}
ret = TRUE;
done:
release_display_device_init_mutex( mutex );
SetupDiDestroyDeviceInfoList( set );
if (ret)
return ret;
......@@ -4294,17 +4429,12 @@ done:
/* Adapter */
if (!device)
{
lstrcpyW( info->DeviceName, L"\\\\.\\DISPLAY1" );
lstrcpyW( info->DeviceString, L"Wine Adapter" );
info->StateFlags =
DISPLAY_DEVICE_ATTACHED_TO_DESKTOP | DISPLAY_DEVICE_PRIMARY_DEVICE | DISPLAY_DEVICE_VGA_COMPATIBLE;
if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceID) + sizeof(info->DeviceID))
{
if (flags & EDD_GET_DEVICE_INTERFACE_NAME)
info->DeviceID[0] = 0;
else
lstrcpyW( info->DeviceID, L"PCI\\VEN_0000&DEV_0000&SUBSYS_00000000&REV_00" );
}
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
......@@ -4312,21 +4442,14 @@ done:
if (lstrcmpiW( L"\\\\.\\DISPLAY1", device ))
return FALSE;
lstrcpyW( info->DeviceName, L"\\\\.\\DISPLAY1\\Monitor0" );
lstrcpyW( info->DeviceString, L"Generic Non-PnP Monitor" );
info->StateFlags = DISPLAY_DEVICE_ACTIVE | DISPLAY_DEVICE_ATTACHED;
if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceID) + sizeof(info->DeviceID))
{
if (flags & EDD_GET_DEVICE_INTERFACE_NAME)
lstrcpyW( info->DeviceID, L"\\\\\?\\DISPLAY#Default_Monitor#4&17f0ff54&0&UID0#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}" );
else
lstrcpyW( info->DeviceID, L"MONITOR\\Default_Monitor\\{4d36e96e-e325-11ce-bfc1-08002be10318}\\0000" );
}
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;
}
if (info->cb >= offsetof(DISPLAY_DEVICEW, DeviceKey) + sizeof(info->DeviceKey))
info->DeviceKey[0] = 0;
return TRUE;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment