From ea30b96334d91ec2229dc68c6323d2cb9a307abc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herv=C3=A9=20Poussineau?= Date: Sat, 22 Oct 2022 14:37:50 +0200 Subject: [PATCH] [WIN32SS:ENG] When VGA mode is requested, drop all graphic devices except VGA one We don't need driver cooperation anymore to handle VGA mode request. --- win32ss/gdi/eng/device.c | 140 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/win32ss/gdi/eng/device.c b/win32ss/gdi/eng/device.c index 7940a059752..a4bbb2c7254 100644 --- a/win32ss/gdi/eng/device.c +++ b/win32ss/gdi/eng/device.c @@ -32,6 +32,110 @@ InitDeviceImpl(VOID) return STATUS_SUCCESS; } +static +BOOLEAN +EngpHasVgaDriver( + _In_ PGRAPHICS_DEVICE pGraphicsDevice) +{ + WCHAR awcDeviceKey[256], awcServiceName[100]; + PWSTR lastBkSlash; + NTSTATUS Status; + ULONG cbValue; + HKEY hkey; + + /* Open the key for the adapters */ + Status = RegOpenKey(L"\\Registry\\Machine\\HARDWARE\\DEVICEMAP\\VIDEO", &hkey); + if (!NT_SUCCESS(Status)) + { + ERR("Could not open HARDWARE\\DEVICEMAP\\VIDEO registry key: 0x%08lx\n", Status); + return FALSE; + } + + /* Read the name of the device key */ + cbValue = sizeof(awcDeviceKey); + Status = RegQueryValue(hkey, pGraphicsDevice->szNtDeviceName, REG_SZ, awcDeviceKey, &cbValue); + ZwClose(hkey); + if (!NT_SUCCESS(Status)) + { + ERR("Could not read '%S' registry value: 0x%08lx\n", Status); + return FALSE; + } + + /* Replace 'DeviceN' by 'Video' */ + lastBkSlash = wcsrchr(awcDeviceKey, L'\\'); + if (!lastBkSlash) + { + ERR("Invalid registry key '%S'\n", lastBkSlash); + return FALSE; + } + if (!NT_SUCCESS(RtlStringCchCopyW(lastBkSlash + 1, + ARRAYSIZE(awcDeviceKey) - (lastBkSlash + 1 - awcDeviceKey), + L"Video"))) + { + ERR("Failed to add 'Video' to registry key '%S'\n", awcDeviceKey); + return FALSE; + } + + /* Open device key */ + Status = RegOpenKey(awcDeviceKey, &hkey); + if (!NT_SUCCESS(Status)) + { + ERR("Could not open %S registry key: 0x%08lx\n", awcDeviceKey, Status); + return FALSE; + } + + /* Read service name */ + cbValue = sizeof(awcServiceName); + Status = RegQueryValue(hkey, L"Service", REG_SZ, awcServiceName, &cbValue); + ZwClose(hkey); + if (!NT_SUCCESS(Status)) + { + ERR("Could not read Service registry value in %S: 0x%08lx\n", awcDeviceKey, Status); + return FALSE; + } + + /* Device is using VGA driver if service name starts with 'VGA' (case insensitive) */ + return (_wcsnicmp(awcServiceName, L"VGA", 3) == 0); +} + +/* + * Remove a device from gpGraphicsDeviceFirst/gpGraphicsDeviceLast list. + */ +_Requires_lock_held_(ghsemGraphicsDeviceList) +static +VOID +EngpUnlinkGraphicsDevice( + _In_ PGRAPHICS_DEVICE pToDelete) +{ + PGRAPHICS_DEVICE pPrevGraphicsDevice = NULL; + PGRAPHICS_DEVICE pGraphicsDevice = gpGraphicsDeviceFirst; + + TRACE("EngpUnlinkGraphicsDevice('%S')\n", pToDelete->szNtDeviceName); + + while (pGraphicsDevice) + { + if (pGraphicsDevice != pToDelete) + { + /* Keep current device */ + pPrevGraphicsDevice = pGraphicsDevice; + pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice; + } + else + { + /* We need to remove current device */ + pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice; + + /* Unlink chain */ + if (!pPrevGraphicsDevice) + gpGraphicsDeviceFirst = pToDelete->pNextGraphicsDevice; + else + pPrevGraphicsDevice->pNextGraphicsDevice = pToDelete->pNextGraphicsDevice; + if (gpGraphicsDeviceLast == pToDelete) + gpGraphicsDeviceLast = pPrevGraphicsDevice; + } + } +} + NTSTATUS EngpUpdateGraphicsDeviceList(VOID) { @@ -41,6 +145,7 @@ EngpUpdateGraphicsDeviceList(VOID) WCHAR awcBuffer[256]; NTSTATUS Status; PGRAPHICS_DEVICE pGraphicsDevice; + BOOLEAN bFoundNewDevice = FALSE; ULONG cbValue; HKEY hkey; @@ -109,6 +214,7 @@ EngpUpdateGraphicsDeviceList(VOID) TRACE("gpVgaGraphicsDevice = %p\n", gpVgaGraphicsDevice); } } + bFoundNewDevice = TRUE; /* Set the first one as primary device */ if (!gpPrimaryGraphicsDevice) @@ -121,6 +227,40 @@ EngpUpdateGraphicsDeviceList(VOID) /* Close the device map registry key */ ZwClose(hkey); + if (bFoundNewDevice && gbBaseVideo) + { + PGRAPHICS_DEVICE pToDelete; + + /* Lock list */ + EngAcquireSemaphore(ghsemGraphicsDeviceList); + + /* Remove every device from linked list, except base-video one */ + pGraphicsDevice = gpGraphicsDeviceFirst; + while (pGraphicsDevice) + { + if (!EngpHasVgaDriver(pGraphicsDevice)) + { + /* Not base-video device. Remove it */ + pToDelete = pGraphicsDevice; + TRACE("Removing non-base-video device %S (%S)\n", pToDelete->szWinDeviceName, pToDelete->szNtDeviceName); + + EngpUnlinkGraphicsDevice(pGraphicsDevice); + pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice; + + /* Free memory */ + ExFreePoolWithTag(pToDelete->pDiplayDrivers, GDITAG_DRVSUP); + ExFreePoolWithTag(pToDelete, GDITAG_GDEVICE); + } + else + { + pGraphicsDevice = pGraphicsDevice->pNextGraphicsDevice; + } + } + + /* Unlock list */ + EngReleaseSemaphore(ghsemGraphicsDeviceList); + } + return STATUS_SUCCESS; }