1878 lines
48 KiB
C++
1878 lines
48 KiB
C++
/*++
|
|
|
|
Copyright (c) 1998 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
migrate.cpp
|
|
|
|
Environment:
|
|
|
|
WIN32 User Mode
|
|
|
|
--*/
|
|
|
|
|
|
#ifndef WIN32_LEAN_AND_MEAN
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#endif
|
|
|
|
#include <initguid.h>
|
|
#include "migrate.h"
|
|
#include <regstr.h>
|
|
|
|
|
|
// this will change when the .h is moved to a public location
|
|
#include "comp.h"
|
|
|
|
const TCHAR szWhackDevice[] = TEXT("\\Device");
|
|
|
|
|
|
//
|
|
// Data
|
|
//
|
|
|
|
PFN_CM_LOCATE_DEVNODE gpfn_CM_Locate_DevNode = NULL;
|
|
PFN_SETUP_DI_ENUM_DEVICES_INTERFACES gpfn_SetupDiEnumDeviceInterfaces = NULL;
|
|
PFN_SETUP_DI_GET_DEVICE_INTERFACE_DETAIL gpfn_SetupDiGetDeviceInterfaceDetail = NULL;
|
|
PFN_SETUP_DI_CREATE_DEVICE_INTERFACE_REG_KEY gpfn_SetupDiCreateDeviceInterfaceRegKey = NULL;
|
|
PFN_SETUP_DI_OPEN_DEVICE_INTERFACE_REG_KEY gpfn_SetupDiOpenDeviceInterfaceRegKey = NULL;
|
|
PFN_SETUP_DI_CREATE_DEVICE_INTERFACE gpfn_SetupDiCreateDeviceInterface = NULL;
|
|
|
|
|
|
//
|
|
// DllMain
|
|
//
|
|
|
|
extern "C" {
|
|
|
|
BOOL APIENTRY
|
|
DllMain(HINSTANCE hDll,
|
|
DWORD dwReason,
|
|
LPVOID lpReserved)
|
|
{
|
|
switch (dwReason) {
|
|
|
|
case DLL_PROCESS_ATTACH:
|
|
break;
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
break;
|
|
|
|
case DLL_THREAD_DETACH:
|
|
break;
|
|
|
|
case DLL_THREAD_ATTACH:
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
VideoUpgradeCheck(
|
|
PCOMPAIBILITYCALLBACK CompatibilityCallback,
|
|
LPVOID Context
|
|
)
|
|
{
|
|
DWORD dwDisposition;
|
|
HKEY hKey = 0;
|
|
OSVERSIONINFO osVer;
|
|
DWORD cb;
|
|
BOOL bSuccess = FALSE;
|
|
|
|
if (RegCreateKeyEx(HKEY_LOCAL_MACHINE,
|
|
SZ_UPDATE_SETTINGS,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_WRITE,
|
|
NULL,
|
|
&hKey,
|
|
&dwDisposition) != ERROR_SUCCESS) {
|
|
|
|
//
|
|
// Oh well, guess we can't write it, no big deal
|
|
//
|
|
|
|
hKey = 0;
|
|
goto Cleanup;
|
|
}
|
|
|
|
ZeroMemory(&osVer, sizeof(OSVERSIONINFO));
|
|
osVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
|
|
if (!GetVersionEx(&osVer)) {
|
|
|
|
//
|
|
// We can't get the version info, no big deal
|
|
//
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Get the current device caps and store them away for the
|
|
// display applet to apply later.
|
|
// Do it only if this is not a remote session.
|
|
//
|
|
|
|
if (!GetSystemMetrics(SM_REMOTESESSION)) {
|
|
SaveDisplaySettings(hKey, &osVer);
|
|
}
|
|
|
|
//
|
|
// Store the OS version we are upgrading from
|
|
//
|
|
|
|
SaveOsInfo(hKey, &osVer);
|
|
|
|
//
|
|
// Save info about the legacy driver
|
|
//
|
|
|
|
SaveLegacyDriver(hKey);
|
|
|
|
//
|
|
// Save the video services
|
|
//
|
|
|
|
if ((osVer.dwPlatformId == VER_PLATFORM_WIN32_NT) &&
|
|
(osVer.dwMajorVersion <= 4)) {
|
|
|
|
SaveNT4Services(hKey);
|
|
}
|
|
|
|
//
|
|
// Save the applet extensions
|
|
//
|
|
|
|
if ((osVer.dwPlatformId == VER_PLATFORM_WIN32_NT) &&
|
|
(osVer.dwMajorVersion <= 5)) {
|
|
|
|
SaveAppletExtensions(hKey);
|
|
}
|
|
|
|
bSuccess = TRUE;
|
|
|
|
Cleanup:
|
|
|
|
if (hKey != 0) {
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
|
|
VOID
|
|
SaveOsInfo(
|
|
HKEY hKey,
|
|
POSVERSIONINFO posVer
|
|
)
|
|
{
|
|
DWORD cb;
|
|
|
|
//
|
|
// Can't just dump the struct into the registry b/c of the size
|
|
// difference between CHAR and WCHAR (ie, szCSDVersion)
|
|
//
|
|
|
|
cb = sizeof(DWORD);
|
|
RegSetValueEx(hKey,
|
|
SZ_UPGRADE_FROM_PLATFORM,
|
|
0,
|
|
REG_DWORD,
|
|
(PBYTE)&(posVer->dwPlatformId),
|
|
cb);
|
|
|
|
cb = sizeof(DWORD);
|
|
RegSetValueEx(hKey,
|
|
SZ_UPGRADE_FROM_MAJOR_VERSION,
|
|
0,
|
|
REG_DWORD,
|
|
(PBYTE)&(posVer->dwMajorVersion),
|
|
cb);
|
|
|
|
cb = sizeof(DWORD);
|
|
RegSetValueEx(hKey,
|
|
SZ_UPGRADE_FROM_MINOR_VERSION,
|
|
0,
|
|
REG_DWORD,
|
|
(PBYTE)&(posVer->dwMinorVersion),
|
|
cb);
|
|
|
|
cb = sizeof(DWORD);
|
|
RegSetValueEx(hKey,
|
|
SZ_UPGRADE_FROM_BUILD_NUMBER,
|
|
0,
|
|
REG_DWORD,
|
|
(PBYTE)&(posVer->dwBuildNumber),
|
|
cb);
|
|
|
|
cb = lstrlen(posVer->szCSDVersion);
|
|
RegSetValueEx(hKey,
|
|
SZ_UPGRADE_FROM_VERSION_DESC,
|
|
0,
|
|
REG_SZ,
|
|
(PBYTE)&(posVer->szCSDVersion),
|
|
cb);
|
|
}
|
|
|
|
|
|
VOID
|
|
SaveLegacyDriver(
|
|
HKEY hKey
|
|
)
|
|
{
|
|
LPTSTR pszEnd;
|
|
HKEY hKeyMap, hKeyDriver;
|
|
int i = 0, num = 0;
|
|
TCHAR szValueName[128], szData[128];
|
|
PTCHAR szPath;
|
|
DWORD cbValue, cbData, dwType;
|
|
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
SZ_VIDEOMAP,
|
|
0,
|
|
KEY_READ,
|
|
&hKeyMap) != ERROR_SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
for (cbValue = (sizeof(szValueName) - 1) / sizeof(TCHAR),
|
|
cbData = sizeof(szData) / sizeof(TCHAR);
|
|
|
|
RegEnumValue(hKeyMap, i++, szValueName, &cbValue, NULL, &dwType,
|
|
(PBYTE) szData, &cbData) != ERROR_NO_MORE_ITEMS;
|
|
|
|
cbValue = (sizeof(szValueName) - 1) / sizeof(TCHAR),
|
|
cbData = sizeof(szData) / sizeof(TCHAR) ) {
|
|
|
|
if ((REG_SZ != dwType) ||
|
|
(_tcsicmp(szData, TEXT("VgaSave")) == 0)) {
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Make sure the value's name is \Device\XxxY
|
|
//
|
|
|
|
if ((cbValue < (DWORD) lstrlen(szWhackDevice)) ||
|
|
_tcsnicmp(szValueName, szWhackDevice, lstrlen(szWhackDevice))) {
|
|
|
|
continue;
|
|
}
|
|
|
|
szPath = SubStrEnd(SZ_REGISTRYMACHINE, szData);
|
|
|
|
for (pszEnd = szPath + lstrlen(szPath);
|
|
pszEnd != szPath && *pszEnd != TEXT('\\');
|
|
pszEnd--) {
|
|
; // nothing
|
|
}
|
|
|
|
//
|
|
// Remove the \DeviceX at the end of the path
|
|
//
|
|
|
|
*pszEnd = TEXT('\0');
|
|
|
|
//
|
|
// First check if their is a binary name in there that we should use.
|
|
//
|
|
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
szPath,
|
|
0,
|
|
KEY_READ,
|
|
&hKeyDriver) == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// Parse the device map and open the registry.
|
|
//
|
|
|
|
cbValue = sizeof(szValueName);
|
|
if (RegQueryValueEx(hKeyDriver,
|
|
TEXT("ImagePath"),
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE) szValueName,
|
|
&cbValue) == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// This is a binary, extract the name, which will be of the form
|
|
// ...\driver.sys
|
|
//
|
|
|
|
LPTSTR pszDriver, pszDriverEnd;
|
|
|
|
pszDriver = szValueName;
|
|
pszDriverEnd = pszDriver + lstrlen(pszDriver);
|
|
|
|
while(pszDriverEnd != pszDriver &&
|
|
*pszDriverEnd != TEXT('.')) {
|
|
pszDriverEnd--;
|
|
}
|
|
|
|
*pszDriverEnd = UNICODE_NULL;
|
|
|
|
while(pszDriverEnd != pszDriver &&
|
|
*pszDriverEnd != TEXT('\\')) {
|
|
pszDriverEnd--;
|
|
}
|
|
|
|
pszDriverEnd++;
|
|
|
|
//
|
|
// If pszDriver and pszDriverEnd are different, we now
|
|
// have the driver name.
|
|
//
|
|
|
|
if (pszDriverEnd > pszDriver) {
|
|
if (_tcsicmp(pszDriverEnd, TEXT("vga")) != 0) {
|
|
RegCloseKey(hKeyDriver);
|
|
continue;
|
|
}
|
|
|
|
wsprintf(szValueName, TEXT("Driver%d"), num);
|
|
cbValue = lstrlen(pszDriverEnd);
|
|
RegSetValueEx(hKey,
|
|
szValueName,
|
|
0,
|
|
REG_SZ,
|
|
(PBYTE) pszDriverEnd,
|
|
cbValue);
|
|
}
|
|
}
|
|
|
|
RegCloseKey(hKeyDriver);
|
|
}
|
|
|
|
//
|
|
// Get the actual service name
|
|
//
|
|
|
|
for( ; pszEnd > szPath && *pszEnd != TEXT('\\'); pszEnd--) {
|
|
;
|
|
}
|
|
pszEnd++;
|
|
|
|
//
|
|
// Save the service name
|
|
//
|
|
|
|
wsprintf(szValueName, TEXT("Service%d"), num++);
|
|
cbValue = lstrlen(pszEnd);
|
|
RegSetValueEx(hKey,
|
|
szValueName,
|
|
0,
|
|
REG_SZ,
|
|
(PBYTE) pszEnd,
|
|
cbValue);
|
|
}
|
|
|
|
cbValue = sizeof(DWORD);
|
|
RegSetValueEx(hKey,
|
|
TEXT("NumDrivers"),
|
|
0,
|
|
REG_DWORD,
|
|
(PBYTE) &num,
|
|
cbValue);
|
|
|
|
RegCloseKey(hKeyMap);
|
|
}
|
|
|
|
|
|
BOOL
|
|
SaveDisplaySettings(
|
|
HKEY hKey,
|
|
POSVERSIONINFO posVer
|
|
)
|
|
{
|
|
PVU_PHYSICAL_DEVICE pPhysicalDevice = NULL;
|
|
BOOL bSuccess = FALSE;
|
|
|
|
if ((posVer->dwPlatformId == VER_PLATFORM_WIN32_NT) &&
|
|
(posVer->dwMajorVersion >= 5)) {
|
|
|
|
//
|
|
// Try the new way to get the display settings
|
|
//
|
|
|
|
CollectDisplaySettings(&pPhysicalDevice);
|
|
}
|
|
|
|
if (pPhysicalDevice == NULL) {
|
|
|
|
//
|
|
// Try the old way to get the display settings
|
|
//
|
|
|
|
LegacyCollectDisplaySettings(&pPhysicalDevice);
|
|
}
|
|
|
|
if (pPhysicalDevice != NULL) {
|
|
|
|
//
|
|
// Save the display settings to registry
|
|
//
|
|
|
|
bSuccess = WriteDisplaySettingsToRegistry(hKey, pPhysicalDevice);
|
|
|
|
//
|
|
// Cleanup
|
|
//
|
|
|
|
FreeAllNodes(pPhysicalDevice);
|
|
}
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetDevInfoData(
|
|
IN LPTSTR pDeviceKey,
|
|
OUT HDEVINFO* phDevInfo,
|
|
OUT PSP_DEVINFO_DATA pDevInfoData
|
|
)
|
|
|
|
/*
|
|
|
|
Note: If this function retuns success, the caller is responsible
|
|
to destroy the device info list returned in phDevInfo
|
|
|
|
*/
|
|
|
|
{
|
|
LPWSTR pwInterfaceName = NULL;
|
|
LPWSTR pwInstanceID = NULL;
|
|
BOOL bSuccess = FALSE;
|
|
|
|
ASSERT (pDeviceKey != NULL);
|
|
|
|
if (AllocAndReadInterfaceName(pDeviceKey, &pwInterfaceName)) {
|
|
|
|
bSuccess = GetDevInfoDataFromInterfaceName(pwInterfaceName,
|
|
phDevInfo,
|
|
pDevInfoData);
|
|
LocalFree(pwInterfaceName);
|
|
|
|
}
|
|
|
|
if ((!bSuccess) &&
|
|
AllocAndReadInstanceID(pDeviceKey, &pwInstanceID)) {
|
|
|
|
bSuccess = GetDevInfoDataFromInstanceID(pwInstanceID,
|
|
phDevInfo,
|
|
pDevInfoData);
|
|
LocalFree(pwInstanceID);
|
|
|
|
}
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetDevInfoDataFromInterfaceName(
|
|
IN LPWSTR pwInterfaceName,
|
|
OUT HDEVINFO* phDevInfo,
|
|
OUT PSP_DEVINFO_DATA pDevInfoData
|
|
)
|
|
|
|
/*
|
|
|
|
Note: If this function retuns success, the caller is responsible
|
|
to destroy the device info list returned in phDevInfo
|
|
|
|
*/
|
|
|
|
{
|
|
LPWSTR pwDevicePath = NULL;
|
|
HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;
|
|
SP_DEVINFO_DATA DevInfoData;
|
|
SP_DEVICE_INTERFACE_DATA InterfaceData;
|
|
PSP_DEVICE_INTERFACE_DETAIL_DATA pInterfaceDetailData = NULL;
|
|
DWORD InterfaceIndex = 0;
|
|
DWORD InterfaceSize = 0;
|
|
BOOL bMatch = FALSE;
|
|
|
|
ASSERT (pwInterfaceName != NULL);
|
|
ASSERT (phDevInfo != NULL);
|
|
ASSERT (pDevInfoData != NULL);
|
|
|
|
ASSERT(gpfn_SetupDiEnumDeviceInterfaces != NULL);
|
|
ASSERT(gpfn_SetupDiGetDeviceInterfaceDetail != NULL);
|
|
|
|
//
|
|
// Enumerate all display adapter interfaces
|
|
//
|
|
|
|
hDevInfo = SetupDiGetClassDevs(&GUID_DISPLAY_ADAPTER_INTERFACE,
|
|
NULL,
|
|
NULL,
|
|
DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
|
|
|
|
if (hDevInfo == INVALID_HANDLE_VALUE) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
InterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
|
|
while ((*gpfn_SetupDiEnumDeviceInterfaces)(hDevInfo,
|
|
NULL,
|
|
&GUID_DISPLAY_ADAPTER_INTERFACE,
|
|
InterfaceIndex,
|
|
&InterfaceData)) {
|
|
|
|
//
|
|
// Get the required size for the interface
|
|
//
|
|
|
|
InterfaceSize = 0;
|
|
(*gpfn_SetupDiGetDeviceInterfaceDetail)(hDevInfo,
|
|
&InterfaceData,
|
|
NULL,
|
|
0,
|
|
&InterfaceSize,
|
|
NULL);
|
|
|
|
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Alloc memory for the interface
|
|
//
|
|
|
|
pInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)
|
|
LocalAlloc(LPTR, InterfaceSize);
|
|
if (pInterfaceDetailData == NULL)
|
|
goto Cleanup;
|
|
|
|
//
|
|
// Get the interface
|
|
//
|
|
|
|
pInterfaceDetailData->cbSize =
|
|
sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
|
|
DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
|
|
|
|
if ((*gpfn_SetupDiGetDeviceInterfaceDetail)(hDevInfo,
|
|
&InterfaceData,
|
|
pInterfaceDetailData,
|
|
InterfaceSize,
|
|
&InterfaceSize,
|
|
&DevInfoData)) {
|
|
|
|
//
|
|
// Is the InterfaceName the same as the DevicePath?
|
|
//
|
|
|
|
#ifdef UNICODE
|
|
pwDevicePath = pInterfaceDetailData->DevicePath;
|
|
#else
|
|
{
|
|
SIZE_T cch = strlen(pInterfaceDetailData->DevicePath) + 1;
|
|
pwDevicePath = LocalAlloc(LPTR, cch * sizeof(WCHAR));
|
|
if (pwDevicePath == NULL) {
|
|
goto Cleanup;
|
|
}
|
|
MultiByteToWideChar(CP_ACP, 0,
|
|
pInterfaceDetailData->DevicePath,
|
|
-1, pwDevicePath, cch);
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// The first 4 characters of the interface name are different
|
|
// between user mode and kernel mode (e.g. "\\?\" vs "\\.\")
|
|
// Therefore, ignore them.
|
|
//
|
|
|
|
bMatch = (_wcsnicmp(pwInterfaceName + 4,
|
|
pwDevicePath + 4,
|
|
wcslen(pwInterfaceName + 4)) == 0);
|
|
|
|
#ifndef UNICODE
|
|
LocalFree(pwDevicePath);
|
|
pwDevicePath = NULL;
|
|
#endif
|
|
|
|
if (bMatch) {
|
|
|
|
//
|
|
// We found the device
|
|
//
|
|
|
|
*phDevInfo = hDevInfo;
|
|
CopyMemory(pDevInfoData, &DevInfoData, sizeof(SP_DEVINFO_DATA));
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Clean-up
|
|
//
|
|
|
|
LocalFree(pInterfaceDetailData);
|
|
pInterfaceDetailData = NULL;
|
|
|
|
//
|
|
// Next interface ...
|
|
//
|
|
|
|
InterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
|
|
++InterfaceIndex;
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
if (pInterfaceDetailData != NULL) {
|
|
LocalFree(pInterfaceDetailData);
|
|
}
|
|
|
|
//
|
|
// Upon success, the caller is responsible to destroy the list
|
|
//
|
|
|
|
if (!bMatch && (hDevInfo != INVALID_HANDLE_VALUE)) {
|
|
SetupDiDestroyDeviceInfoList(hDevInfo);
|
|
}
|
|
|
|
return bMatch;
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetDevInfoDataFromInstanceID(
|
|
IN LPWSTR pwInstanceID,
|
|
OUT HDEVINFO* phDevInfo,
|
|
OUT PSP_DEVINFO_DATA pDevInfoData
|
|
)
|
|
|
|
/*
|
|
|
|
Note: If this function retuns success, the caller is responsible
|
|
to destroy the device info list returned in phDevInfo
|
|
|
|
*/
|
|
|
|
{
|
|
LPTSTR pInstanceID = NULL;
|
|
HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;
|
|
DWORD DeviceIndex = 0;
|
|
SP_DEVINFO_DATA DevInfoData;
|
|
DEVINST DevInst;
|
|
BOOL bSuccess = FALSE, bLocate = FALSE;
|
|
|
|
ASSERT (pwInstanceID != NULL);
|
|
ASSERT (phDevInfo != NULL);
|
|
ASSERT (pDevInfoData != NULL);
|
|
|
|
ASSERT (gpfn_CM_Locate_DevNode != NULL);
|
|
|
|
#ifdef UNICODE
|
|
pInstanceID = pwInstanceID;
|
|
#else
|
|
{
|
|
SIZE_T cch = wcslen(pwInstanceID) + 1;
|
|
pInstanceID = LocalAlloc(LPTR, cch * sizeof(CHAR));
|
|
if (pInstanceID == NULL) {
|
|
return FALSE;
|
|
}
|
|
WideCharToMultiByte(CP_ACP, 0,
|
|
pwDeviceID, -1,
|
|
pInstanceID, cch * sizeof(CHAR),
|
|
NULL, NULL);
|
|
}
|
|
#endif
|
|
|
|
bLocate =
|
|
((*gpfn_CM_Locate_DevNode)(&DevInst, pInstanceID, 0) == CR_SUCCESS);
|
|
|
|
#ifndef UNICODE
|
|
LocalFree(pInstanceID);
|
|
pInstanceID = NULL;
|
|
#endif
|
|
|
|
if (!bLocate) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Enumerate all display adapters
|
|
//
|
|
|
|
hDevInfo = SetupDiGetClassDevs((LPGUID)&GUID_DEVCLASS_DISPLAY,
|
|
NULL,
|
|
NULL,
|
|
DIGCF_PRESENT);
|
|
|
|
if (hDevInfo == INVALID_HANDLE_VALUE) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
|
|
while (SetupDiEnumDeviceInfo(hDevInfo, DeviceIndex, &DevInfoData)) {
|
|
|
|
if (DevInfoData.DevInst == DevInst) {
|
|
|
|
//
|
|
// We found it
|
|
//
|
|
|
|
*phDevInfo = hDevInfo;
|
|
CopyMemory(pDevInfoData, &DevInfoData, sizeof(SP_DEVINFO_DATA));
|
|
bSuccess = TRUE;
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Next display adapter
|
|
//
|
|
|
|
++DeviceIndex;
|
|
DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
//
|
|
// Upon success, the caller is responsible to destroy the list
|
|
//
|
|
|
|
if (!bSuccess && (hDevInfo != INVALID_HANDLE_VALUE)) {
|
|
SetupDiDestroyDeviceInfoList(hDevInfo);
|
|
}
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
|
|
VOID
|
|
CollectDisplaySettings(
|
|
PVU_PHYSICAL_DEVICE* ppPhysicalDevice
|
|
)
|
|
{
|
|
DISPLAY_DEVICE DisplayDevice;
|
|
DEVMODE DevMode;
|
|
PVU_LOGICAL_DEVICE pLogicalDevice = NULL;
|
|
DWORD dwEnum = 0;
|
|
BOOL bGoOn = FALSE;
|
|
HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;
|
|
SP_DEVINFO_DATA DevInfoData;
|
|
DWORD BusNumber = 0, Address = 0;
|
|
LPTSTR pDeviceX = NULL, pX = NULL;
|
|
HINSTANCE hinstSetupApi = NULL;
|
|
BOOL bInserted = FALSE;
|
|
HKEY hDeviceKey = NULL;
|
|
BOOL bDummy;
|
|
|
|
hinstSetupApi = LoadLibrary(TEXT("SETUPAPI.DLL"));
|
|
|
|
if (hinstSetupApi == NULL) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
|
|
gpfn_CM_Locate_DevNode = (PFN_CM_LOCATE_DEVNODE)
|
|
GetProcAddress(hinstSetupApi, "CM_Locate_DevNodeW");
|
|
|
|
gpfn_SetupDiGetDeviceInterfaceDetail = (PFN_SETUP_DI_GET_DEVICE_INTERFACE_DETAIL)
|
|
GetProcAddress(hinstSetupApi, "SetupDiGetDeviceInterfaceDetailW");
|
|
|
|
gpfn_SetupDiCreateDeviceInterfaceRegKey = (PFN_SETUP_DI_CREATE_DEVICE_INTERFACE_REG_KEY)
|
|
GetProcAddress(hinstSetupApi, "SetupDiCreateDeviceInterfaceRegKeyW");
|
|
|
|
gpfn_SetupDiCreateDeviceInterface = (PFN_SETUP_DI_CREATE_DEVICE_INTERFACE)
|
|
GetProcAddress(hinstSetupApi, "SetupDiCreateDeviceInterfaceW");
|
|
|
|
#else // UNICODE
|
|
|
|
gpfn_CM_Locate_DevNode = (PFN_CM_LOCATE_DEVNODE)
|
|
GetProcAddress(hinstSetupApi, "CM_Locate_DevNodeA");
|
|
|
|
gpfn_SetupDiGetDeviceInterfaceDetail = (PFN_SETUP_DI_GET_DEVICE_INTERFACE_DETAIL)
|
|
GetProcAddress(hinstSetupApi, "SetupDiGetDeviceInterfaceDetailA");
|
|
|
|
gpfn_SetupDiCreateDeviceInterfaceRegKey = (PFN_SETUP_DI_CREATE_DEVICE_INTERFACE_REG_KEY)
|
|
GetProcAddress(hinstSetupApi, "SetupDiCreateDeviceInterfaceRegKeyA");
|
|
|
|
gpfn_SetupDiCreateDeviceInterface = (PFN_SETUP_DI_CREATE_DEVICE_INTERFACE)
|
|
GetProcAddress(hinstSetupApi, "SetupDiCreateDeviceInterfaceA");
|
|
|
|
#endif // UNICODE
|
|
|
|
gpfn_SetupDiEnumDeviceInterfaces = (PFN_SETUP_DI_ENUM_DEVICES_INTERFACES)
|
|
GetProcAddress(hinstSetupApi, "SetupDiEnumDeviceInterfaces");
|
|
|
|
gpfn_SetupDiOpenDeviceInterfaceRegKey = (PFN_SETUP_DI_OPEN_DEVICE_INTERFACE_REG_KEY)
|
|
GetProcAddress(hinstSetupApi, "SetupDiOpenDeviceInterfaceRegKey");
|
|
|
|
if ((gpfn_CM_Locate_DevNode == NULL) ||
|
|
(gpfn_SetupDiEnumDeviceInterfaces == NULL) ||
|
|
(gpfn_SetupDiGetDeviceInterfaceDetail == NULL) ||
|
|
(gpfn_SetupDiCreateDeviceInterfaceRegKey == NULL) ||
|
|
(gpfn_SetupDiOpenDeviceInterfaceRegKey == NULL) ||
|
|
(gpfn_SetupDiCreateDeviceInterface == NULL)) {
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Enumerate all video devices
|
|
//
|
|
|
|
DisplayDevice.cb = sizeof(DISPLAY_DEVICE);
|
|
while (EnumDisplayDevices(NULL, dwEnum, &DisplayDevice, 0)) {
|
|
|
|
bInserted = FALSE;
|
|
pLogicalDevice = NULL;
|
|
|
|
//
|
|
// Get the device info data corresponding to the current
|
|
// video device
|
|
//
|
|
|
|
if (!GetDevInfoData(DisplayDevice.DeviceKey,
|
|
&hDevInfo,
|
|
&DevInfoData)) {
|
|
|
|
goto NextDevice;
|
|
}
|
|
ASSERT (hDevInfo != INVALID_HANDLE_VALUE);
|
|
|
|
//
|
|
// Retrieve the bus number and address
|
|
//
|
|
|
|
bGoOn = SetupDiGetDeviceRegistryProperty(hDevInfo,
|
|
&DevInfoData,
|
|
SPDRP_BUSNUMBER,
|
|
NULL,
|
|
(PBYTE)&BusNumber,
|
|
sizeof(BusNumber),
|
|
NULL) &&
|
|
SetupDiGetDeviceRegistryProperty(hDevInfo,
|
|
&DevInfoData,
|
|
SPDRP_ADDRESS,
|
|
NULL,
|
|
(PBYTE)&Address,
|
|
sizeof(Address),
|
|
NULL);
|
|
|
|
SetupDiDestroyDeviceInfoList(hDevInfo);
|
|
|
|
if (!bGoOn) {
|
|
|
|
goto NextDevice;
|
|
}
|
|
|
|
//
|
|
// Allocate memory for the logical device
|
|
//
|
|
|
|
pLogicalDevice = (PVU_LOGICAL_DEVICE)
|
|
LocalAlloc(LPTR, sizeof(VU_LOGICAL_DEVICE));
|
|
|
|
if (pLogicalDevice == NULL) {
|
|
goto NextDevice;
|
|
}
|
|
|
|
//
|
|
// DeviceX
|
|
//
|
|
|
|
pDeviceX = DisplayDevice.DeviceKey + _tcslen(DisplayDevice.DeviceKey);
|
|
|
|
while ((pDeviceX != DisplayDevice.DeviceKey) &&
|
|
(*pDeviceX != TEXT('\\'))) {
|
|
pDeviceX--;
|
|
}
|
|
|
|
if (pDeviceX == DisplayDevice.DeviceKey) {
|
|
goto NextDevice;
|
|
}
|
|
|
|
pX = SubStrEnd(SZ_DEVICE, pDeviceX);
|
|
|
|
if (pX == pDeviceX) {
|
|
|
|
//
|
|
// The new key is used: CCS\Control\Video\[GUID]\000X
|
|
//
|
|
|
|
pX++;
|
|
pLogicalDevice->DeviceX = _ttoi(pX);
|
|
|
|
} else {
|
|
|
|
//
|
|
// The old key is used: CCS\Services\[SrvName]\DeviceX
|
|
//
|
|
|
|
pLogicalDevice->DeviceX = _ttoi(pX);
|
|
}
|
|
|
|
//
|
|
// AttachedToDesktop
|
|
//
|
|
|
|
pLogicalDevice->AttachedToDesktop =
|
|
((DisplayDevice.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) != 0);
|
|
pLogicalDevice->ValidFields |= VU_ATTACHED_TO_DESKTOP;
|
|
|
|
if (pLogicalDevice->AttachedToDesktop) {
|
|
|
|
//
|
|
// Get the current mode
|
|
//
|
|
|
|
DevMode.dmSize = sizeof(DEVMODE);
|
|
if (EnumDisplaySettings(DisplayDevice.DeviceName,
|
|
ENUM_CURRENT_SETTINGS,
|
|
&DevMode)) {
|
|
|
|
//
|
|
// RelativeX, RelativeY, BitsPerPel, XResolution,
|
|
// YResolution, VRefresh & Flags
|
|
//
|
|
|
|
pLogicalDevice->ValidFields |= VU_RELATIVE_X;
|
|
pLogicalDevice->RelativeX = DevMode.dmPosition.x;
|
|
|
|
pLogicalDevice->ValidFields |= VU_RELATIVE_Y;
|
|
pLogicalDevice->RelativeY = DevMode.dmPosition.y;
|
|
|
|
pLogicalDevice->ValidFields |= VU_BITS_PER_PEL;
|
|
pLogicalDevice->BitsPerPel = DevMode.dmBitsPerPel;
|
|
|
|
pLogicalDevice->ValidFields |= VU_X_RESOLUTION;
|
|
pLogicalDevice->XResolution = DevMode.dmPelsWidth;
|
|
|
|
pLogicalDevice->ValidFields |= VU_Y_RESOLUTION;
|
|
pLogicalDevice->YResolution = DevMode.dmPelsHeight;
|
|
|
|
pLogicalDevice->ValidFields |= VU_VREFRESH;
|
|
pLogicalDevice->VRefresh = DevMode.dmDisplayFrequency;
|
|
|
|
pLogicalDevice->ValidFields |= VU_FLAGS;
|
|
pLogicalDevice->Flags = DevMode.dmDisplayFlags;
|
|
|
|
//
|
|
// Ignore the following settings for now:
|
|
// DefaultSettings.XPanning - DevMode.dmPanningWidth
|
|
// DefaultSettings.YPanning - DevMode.dmPanningHeight
|
|
// DefaultSettings.DriverExtra - DevMode.dmDriverExtra
|
|
//
|
|
}
|
|
}
|
|
|
|
if (GetDeviceRegKey(DisplayDevice.DeviceKey,
|
|
&hDeviceKey,
|
|
&bDummy))
|
|
{
|
|
DWORD dwTemp, cb;
|
|
|
|
//
|
|
// Hardware acceleration
|
|
//
|
|
|
|
cb = sizeof(dwTemp);
|
|
if (RegQueryValueEx(hDeviceKey,
|
|
SZ_HW_ACCELERATION,
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)&dwTemp,
|
|
&cb) == ERROR_SUCCESS) {
|
|
|
|
pLogicalDevice->ValidFields |= VU_HW_ACCELERATION;
|
|
pLogicalDevice->HwAcceleration = dwTemp;
|
|
}
|
|
|
|
//
|
|
// Pruning mode
|
|
//
|
|
|
|
cb = sizeof(dwTemp);
|
|
if (RegQueryValueEx(hDeviceKey,
|
|
SZ_PRUNNING_MODE,
|
|
NULL,
|
|
NULL,
|
|
(LPBYTE)&dwTemp,
|
|
&cb) == ERROR_SUCCESS) {
|
|
|
|
pLogicalDevice->ValidFields |= VU_PRUNING_MODE;
|
|
pLogicalDevice->PruningMode = dwTemp;
|
|
}
|
|
|
|
RegCloseKey(hDeviceKey);
|
|
}
|
|
|
|
bInserted = InsertNode(ppPhysicalDevice,
|
|
pLogicalDevice,
|
|
0,
|
|
BusNumber,
|
|
Address);
|
|
|
|
NextDevice:
|
|
|
|
if (!bInserted && (pLogicalDevice != NULL)) {
|
|
|
|
LocalFree(pLogicalDevice);
|
|
pLogicalDevice = NULL;
|
|
}
|
|
|
|
DisplayDevice.cb = sizeof(DISPLAY_DEVICE);
|
|
++dwEnum;
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
if (hinstSetupApi != NULL) {
|
|
|
|
gpfn_CM_Locate_DevNode = NULL;
|
|
gpfn_SetupDiEnumDeviceInterfaces = NULL;
|
|
gpfn_SetupDiGetDeviceInterfaceDetail = NULL;
|
|
gpfn_SetupDiCreateDeviceInterfaceRegKey = NULL;
|
|
gpfn_SetupDiOpenDeviceInterfaceRegKey = NULL;
|
|
gpfn_SetupDiCreateDeviceInterface = NULL;
|
|
|
|
FreeLibrary(hinstSetupApi);
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
InsertNode(
|
|
PVU_PHYSICAL_DEVICE* ppPhysicalDevice,
|
|
PVU_LOGICAL_DEVICE pLogicalDevice,
|
|
DWORD Legacy,
|
|
DWORD BusNumber,
|
|
DWORD Address
|
|
)
|
|
{
|
|
PVU_PHYSICAL_DEVICE pPhysicalDevice = *ppPhysicalDevice;
|
|
BOOL bSuccess = FALSE;
|
|
PVU_LOGICAL_DEVICE pPrevLogicalDevice = NULL;
|
|
PVU_LOGICAL_DEVICE pNextLogicalDevice = NULL;
|
|
|
|
ASSERT (pLogicalDevice != NULL);
|
|
ASSERT((Legacy == 0) || (*ppPhysicalDevice == NULL));
|
|
|
|
if (Legacy == 0) {
|
|
|
|
//
|
|
// If not Legacy, try to find if there is a device
|
|
// with the same bus location
|
|
//
|
|
|
|
while (pPhysicalDevice != NULL) {
|
|
|
|
if ((pPhysicalDevice->BusNumber == BusNumber) &&
|
|
(pPhysicalDevice->Address == Address)) {
|
|
|
|
break;
|
|
}
|
|
|
|
pPhysicalDevice = pPhysicalDevice->pNextPhysicalDevice;
|
|
}
|
|
}
|
|
|
|
if (pPhysicalDevice != NULL) {
|
|
|
|
//
|
|
// There is already a logical device with the same address
|
|
//
|
|
|
|
ASSERT (pPhysicalDevice->pFirstLogicalDevice != NULL);
|
|
|
|
pPhysicalDevice->CountOfLogicalDevices++;
|
|
|
|
pPrevLogicalDevice = pNextLogicalDevice =
|
|
pPhysicalDevice->pFirstLogicalDevice;
|
|
|
|
while (pNextLogicalDevice &&
|
|
(pNextLogicalDevice->DeviceX <= pLogicalDevice->DeviceX)) {
|
|
|
|
pPrevLogicalDevice = pNextLogicalDevice;
|
|
pNextLogicalDevice = pNextLogicalDevice->pNextLogicalDevice;
|
|
}
|
|
|
|
if (pPrevLogicalDevice == pNextLogicalDevice) {
|
|
|
|
ASSERT (pPrevLogicalDevice == pPhysicalDevice->pFirstLogicalDevice);
|
|
|
|
pLogicalDevice->pNextLogicalDevice =
|
|
pPhysicalDevice->pFirstLogicalDevice;
|
|
pPhysicalDevice->pFirstLogicalDevice = pLogicalDevice;
|
|
|
|
} else {
|
|
|
|
pPrevLogicalDevice->pNextLogicalDevice = pLogicalDevice;
|
|
pLogicalDevice->pNextLogicalDevice = pNextLogicalDevice;
|
|
}
|
|
|
|
bSuccess = TRUE;
|
|
|
|
} else {
|
|
|
|
//
|
|
// This is a new physical device
|
|
//
|
|
|
|
pPhysicalDevice = (PVU_PHYSICAL_DEVICE)
|
|
LocalAlloc(LPTR, sizeof(VU_PHYSICAL_DEVICE));
|
|
|
|
if (pPhysicalDevice != NULL) {
|
|
|
|
pPhysicalDevice->pNextPhysicalDevice = *ppPhysicalDevice;
|
|
*ppPhysicalDevice = pPhysicalDevice;
|
|
|
|
pPhysicalDevice->pFirstLogicalDevice = pLogicalDevice;
|
|
pPhysicalDevice->CountOfLogicalDevices = 1;
|
|
pPhysicalDevice->Legacy = Legacy;
|
|
pPhysicalDevice->BusNumber = BusNumber;
|
|
pPhysicalDevice->Address = Address;
|
|
|
|
bSuccess = TRUE;
|
|
}
|
|
}
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
|
|
VOID
|
|
FreeAllNodes(
|
|
PVU_PHYSICAL_DEVICE pPhysicalDevice
|
|
)
|
|
{
|
|
PVU_PHYSICAL_DEVICE pTempPhysicalDevice = NULL;
|
|
PVU_LOGICAL_DEVICE pLogicalDevice = NULL, pTempLogicalDevice = NULL;
|
|
|
|
while (pPhysicalDevice != NULL) {
|
|
|
|
pTempPhysicalDevice = pPhysicalDevice->pNextPhysicalDevice;
|
|
pLogicalDevice = pPhysicalDevice->pFirstLogicalDevice;
|
|
|
|
while (pLogicalDevice != NULL) {
|
|
|
|
pTempLogicalDevice = pLogicalDevice->pNextLogicalDevice;
|
|
LocalFree(pLogicalDevice);
|
|
pLogicalDevice = pTempLogicalDevice;
|
|
}
|
|
|
|
LocalFree(pPhysicalDevice);
|
|
pPhysicalDevice = pTempPhysicalDevice;
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
WriteDisplaySettingsToRegistry(
|
|
HKEY hKey,
|
|
PVU_PHYSICAL_DEVICE pPhysicalDevice
|
|
)
|
|
{
|
|
PVU_LOGICAL_DEVICE pLogicalDevice = NULL;
|
|
DWORD CountOfPhysicalDevices = 0;
|
|
DWORD CountOfLogicalDevices = 0;
|
|
HKEY hPysicalDeviceKey = 0;
|
|
HKEY hLogicalDeviceKey = 0;
|
|
BOOL bSuccess = FALSE;
|
|
TCHAR Buffer[20];
|
|
|
|
while (pPhysicalDevice != NULL) {
|
|
|
|
//
|
|
// Create physical device subkey
|
|
//
|
|
|
|
_tcscpy(Buffer, SZ_VU_PHYSICAL);
|
|
_stprintf(Buffer + _tcslen(Buffer), TEXT("%d"), CountOfPhysicalDevices);
|
|
DeleteKeyAndSubkeys(hKey, Buffer);
|
|
|
|
if (RegCreateKeyEx(hKey,
|
|
Buffer,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_WRITE,
|
|
NULL,
|
|
&hPysicalDeviceKey,
|
|
NULL) != ERROR_SUCCESS) {
|
|
|
|
hPysicalDeviceKey = 0;
|
|
goto NextPhysicalDevice;
|
|
}
|
|
|
|
if (pPhysicalDevice->Legacy == 0) {
|
|
|
|
//
|
|
// BusNumber
|
|
//
|
|
|
|
if (RegSetValueEx(hPysicalDeviceKey,
|
|
SZ_VU_BUS_NUMBER,
|
|
0,
|
|
REG_DWORD,
|
|
(PBYTE)&pPhysicalDevice->BusNumber,
|
|
sizeof(pPhysicalDevice->BusNumber)) != ERROR_SUCCESS) {
|
|
|
|
goto NextPhysicalDevice;
|
|
}
|
|
|
|
//
|
|
// Address
|
|
//
|
|
|
|
if (RegSetValueEx(hPysicalDeviceKey,
|
|
SZ_VU_ADDRESS,
|
|
0,
|
|
REG_DWORD,
|
|
(PBYTE)&pPhysicalDevice->Address,
|
|
sizeof(pPhysicalDevice->Address)) != ERROR_SUCCESS) {
|
|
|
|
goto NextPhysicalDevice;
|
|
}
|
|
|
|
}
|
|
|
|
pLogicalDevice = pPhysicalDevice->pFirstLogicalDevice;
|
|
CountOfLogicalDevices = 0;
|
|
|
|
while (pLogicalDevice != NULL) {
|
|
|
|
//
|
|
// Create logical device subkey
|
|
//
|
|
|
|
_tcscpy(Buffer, SZ_VU_LOGICAL);
|
|
_stprintf(Buffer + _tcslen(Buffer), TEXT("%d"), CountOfLogicalDevices);
|
|
if (RegCreateKeyEx(hPysicalDeviceKey,
|
|
Buffer,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_WRITE,
|
|
NULL,
|
|
&hLogicalDeviceKey,
|
|
NULL) != ERROR_SUCCESS) {
|
|
|
|
hLogicalDeviceKey = 0;
|
|
|
|
//
|
|
// Cannot go on with this physical device.
|
|
// The order of logical devices DOES matter in the dual-view case.
|
|
//
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// AttachedToDesktop
|
|
//
|
|
|
|
if (pLogicalDevice->ValidFields & VU_ATTACHED_TO_DESKTOP) {
|
|
|
|
RegSetValueEx(hLogicalDeviceKey,
|
|
SZ_VU_ATTACHED_TO_DESKTOP,
|
|
0,
|
|
REG_DWORD,
|
|
(PBYTE)&pLogicalDevice->AttachedToDesktop,
|
|
sizeof(pLogicalDevice->AttachedToDesktop));
|
|
}
|
|
|
|
//
|
|
// RelativeX
|
|
//
|
|
|
|
if (pLogicalDevice->ValidFields & VU_RELATIVE_X) {
|
|
|
|
RegSetValueEx(hLogicalDeviceKey,
|
|
SZ_VU_RELATIVE_X,
|
|
0,
|
|
REG_DWORD,
|
|
(PBYTE)&pLogicalDevice->RelativeX,
|
|
sizeof(pLogicalDevice->RelativeX));
|
|
}
|
|
|
|
//
|
|
// RelativeY
|
|
//
|
|
|
|
if (pLogicalDevice->ValidFields & VU_RELATIVE_Y) {
|
|
|
|
RegSetValueEx(hLogicalDeviceKey,
|
|
SZ_VU_RELATIVE_Y,
|
|
0,
|
|
REG_DWORD,
|
|
(PBYTE)&pLogicalDevice->RelativeY,
|
|
sizeof(pLogicalDevice->RelativeY));
|
|
}
|
|
|
|
//
|
|
// BitsPerPel
|
|
//
|
|
|
|
if (pLogicalDevice->ValidFields & VU_BITS_PER_PEL) {
|
|
|
|
RegSetValueEx(hLogicalDeviceKey,
|
|
SZ_VU_BITS_PER_PEL,
|
|
0,
|
|
REG_DWORD,
|
|
(PBYTE)&pLogicalDevice->BitsPerPel,
|
|
sizeof(pLogicalDevice->BitsPerPel));
|
|
}
|
|
|
|
//
|
|
// XResolution
|
|
//
|
|
|
|
if (pLogicalDevice->ValidFields & VU_X_RESOLUTION) {
|
|
|
|
RegSetValueEx(hLogicalDeviceKey,
|
|
SZ_VU_X_RESOLUTION,
|
|
0,
|
|
REG_DWORD,
|
|
(PBYTE)&pLogicalDevice->XResolution,
|
|
sizeof(pLogicalDevice->XResolution));
|
|
}
|
|
|
|
//
|
|
// YResolution
|
|
//
|
|
|
|
if (pLogicalDevice->ValidFields & VU_Y_RESOLUTION) {
|
|
|
|
RegSetValueEx(hLogicalDeviceKey,
|
|
SZ_VU_Y_RESOLUTION,
|
|
0,
|
|
REG_DWORD,
|
|
(PBYTE)&pLogicalDevice->YResolution,
|
|
sizeof(pLogicalDevice->YResolution));
|
|
}
|
|
|
|
//
|
|
// VRefresh
|
|
//
|
|
|
|
if (pLogicalDevice->ValidFields & VU_VREFRESH) {
|
|
|
|
RegSetValueEx(hLogicalDeviceKey,
|
|
SZ_VU_VREFRESH,
|
|
0,
|
|
REG_DWORD,
|
|
(PBYTE)&pLogicalDevice->VRefresh,
|
|
sizeof(pLogicalDevice->VRefresh));
|
|
}
|
|
|
|
//
|
|
// Flags
|
|
//
|
|
|
|
if (pLogicalDevice->ValidFields & VU_FLAGS) {
|
|
|
|
RegSetValueEx(hLogicalDeviceKey,
|
|
SZ_VU_FLAGS,
|
|
0,
|
|
REG_DWORD,
|
|
(PBYTE)&pLogicalDevice->Flags,
|
|
sizeof(pLogicalDevice->Flags));
|
|
}
|
|
|
|
//
|
|
// Hardware acceleration
|
|
//
|
|
|
|
if (pLogicalDevice->ValidFields & VU_HW_ACCELERATION) {
|
|
|
|
RegSetValueEx(hLogicalDeviceKey,
|
|
SZ_HW_ACCELERATION,
|
|
0,
|
|
REG_DWORD,
|
|
(PBYTE)&pLogicalDevice->HwAcceleration,
|
|
sizeof(pLogicalDevice->HwAcceleration));
|
|
}
|
|
|
|
//
|
|
// Pruning mode
|
|
//
|
|
|
|
if (pLogicalDevice->ValidFields & VU_PRUNING_MODE) {
|
|
|
|
RegSetValueEx(hLogicalDeviceKey,
|
|
SZ_PRUNNING_MODE,
|
|
0,
|
|
REG_DWORD,
|
|
(PBYTE)&pLogicalDevice->PruningMode,
|
|
sizeof(pLogicalDevice->PruningMode));
|
|
}
|
|
|
|
++CountOfLogicalDevices;
|
|
|
|
RegCloseKey(hLogicalDeviceKey);
|
|
hLogicalDeviceKey = 0;
|
|
|
|
pLogicalDevice = pLogicalDevice->pNextLogicalDevice;
|
|
}
|
|
|
|
if ((CountOfLogicalDevices > 0) &&
|
|
(RegSetValueEx(hPysicalDeviceKey,
|
|
SZ_VU_COUNT,
|
|
0,
|
|
REG_DWORD,
|
|
(PBYTE)&CountOfLogicalDevices,
|
|
sizeof(CountOfLogicalDevices)) == ERROR_SUCCESS)) {
|
|
|
|
++CountOfPhysicalDevices;
|
|
}
|
|
|
|
NextPhysicalDevice:
|
|
|
|
if (hPysicalDeviceKey != 0) {
|
|
|
|
RegCloseKey(hPysicalDeviceKey);
|
|
hPysicalDeviceKey = 0;
|
|
}
|
|
|
|
pPhysicalDevice = pPhysicalDevice->pNextPhysicalDevice;
|
|
}
|
|
|
|
if (CountOfPhysicalDevices > 0) {
|
|
|
|
bSuccess =
|
|
(RegSetValueEx(hKey,
|
|
SZ_VU_COUNT,
|
|
0,
|
|
REG_DWORD,
|
|
(PBYTE)&CountOfPhysicalDevices,
|
|
sizeof(CountOfPhysicalDevices)) != ERROR_SUCCESS) ;
|
|
}
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
|
|
VOID
|
|
LegacyCollectDisplaySettings(
|
|
PVU_PHYSICAL_DEVICE* ppPhysicalDevice
|
|
)
|
|
{
|
|
PVU_LOGICAL_DEVICE pLogicalDevice = NULL;
|
|
DWORD cb;
|
|
INT Width, Height, Index;
|
|
BOOL useVga = FALSE;
|
|
HDC hDisplay;
|
|
POINT Res[] = {
|
|
{ 640, 480},
|
|
{ 800, 600},
|
|
{ 1024, 768},
|
|
{ 1152, 900},
|
|
{ 1280, 1024},
|
|
{ 1600, 1200},
|
|
{ 0, 0} // end of table
|
|
};
|
|
|
|
ASSERT (*ppPhysicalDevice == NULL);
|
|
|
|
//
|
|
// Allocate memory for the logical device
|
|
//
|
|
|
|
pLogicalDevice = (PVU_LOGICAL_DEVICE)
|
|
LocalAlloc(LPTR, sizeof(VU_LOGICAL_DEVICE));
|
|
if (pLogicalDevice == NULL) {
|
|
return;
|
|
}
|
|
|
|
Width = GetSystemMetrics(SM_CXSCREEN);
|
|
Height = GetSystemMetrics(SM_CYSCREEN);
|
|
|
|
if (Width == 0 || Height == 0) {
|
|
|
|
//
|
|
// Something went wrong, default to lowest common res
|
|
//
|
|
|
|
useVga = TRUE;
|
|
}
|
|
|
|
//
|
|
// NT 4.0 multimon via driver vendor, not the OS ... adjust the width and height
|
|
// back to normal values. Once setup is complete, the second card will come
|
|
// on line and it will be taken care of. In both cases, the video area must
|
|
// be rectangular, not like MM on 5.0 where we can have "holes"
|
|
//
|
|
|
|
else if (Width >= 2 * Height) {
|
|
|
|
//
|
|
// Wide
|
|
//
|
|
|
|
for (Index = 0; Res[Index].x != 0; Index++) {
|
|
|
|
if (Res[Index].y == Height) {
|
|
|
|
Width = Res[Index].x;
|
|
break;
|
|
}
|
|
}
|
|
|
|
useVga = (Res[Index].x == 0);
|
|
|
|
} else if (Height > Width) {
|
|
|
|
//
|
|
// Tall
|
|
//
|
|
|
|
for (Index = 0; Res[Index].x != 0; Index++) {
|
|
|
|
if (Res[Index].x == Width) {
|
|
|
|
Height = Res[Index].y;
|
|
break;
|
|
}
|
|
}
|
|
|
|
useVga = (Res[Index].x == 0);
|
|
}
|
|
|
|
if (useVga) {
|
|
|
|
//
|
|
// No match, default to VGA
|
|
//
|
|
|
|
Width = 640;
|
|
Height = 480;
|
|
}
|
|
|
|
pLogicalDevice->ValidFields |= VU_ATTACHED_TO_DESKTOP;
|
|
pLogicalDevice->AttachedToDesktop = 1;
|
|
|
|
pLogicalDevice->ValidFields |= VU_X_RESOLUTION;
|
|
pLogicalDevice->XResolution = Width;
|
|
|
|
pLogicalDevice->ValidFields |= VU_Y_RESOLUTION;
|
|
pLogicalDevice->YResolution = Height;
|
|
|
|
hDisplay = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
|
|
if (hDisplay)
|
|
{
|
|
pLogicalDevice->ValidFields |= VU_BITS_PER_PEL;
|
|
pLogicalDevice->BitsPerPel = GetDeviceCaps(hDisplay, BITSPIXEL);
|
|
|
|
pLogicalDevice->ValidFields |= VU_VREFRESH;
|
|
pLogicalDevice->VRefresh = GetDeviceCaps(hDisplay, VREFRESH);
|
|
DeleteDC(hDisplay);
|
|
}
|
|
|
|
if (!InsertNode(ppPhysicalDevice,
|
|
pLogicalDevice,
|
|
1,
|
|
0,
|
|
0)) {
|
|
|
|
//
|
|
// Clean-up
|
|
//
|
|
|
|
LocalFree(pLogicalDevice);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
SaveNT4Services(
|
|
HKEY hKey
|
|
)
|
|
{
|
|
SC_HANDLE hSCManager = NULL;
|
|
ENUM_SERVICE_STATUS* pmszAllServices = NULL;
|
|
QUERY_SERVICE_CONFIG* pServiceConfig = NULL;
|
|
SC_HANDLE hService = NULL;
|
|
DWORD cbBytesNeeded = 0;
|
|
DWORD ServicesReturned = 0;
|
|
DWORD ResumeHandle = 0;
|
|
DWORD ServiceLen = 0, TotalLen = 0, AllocatedLen = 128;
|
|
PTCHAR pmszVideoServices = NULL, pmszTemp = NULL;
|
|
|
|
//
|
|
// Allocate initial memory
|
|
//
|
|
|
|
pmszVideoServices = (PTCHAR)LocalAlloc(LPTR, AllocatedLen * sizeof(TCHAR));
|
|
if (pmszVideoServices == NULL) {
|
|
goto Fallout;
|
|
}
|
|
|
|
//
|
|
// Open the service control manager
|
|
//
|
|
|
|
hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
|
|
|
if (hSCManager == NULL) {
|
|
goto Fallout;
|
|
}
|
|
|
|
//
|
|
// Get the required size
|
|
//
|
|
|
|
if ((!EnumServicesStatus(hSCManager,
|
|
SERVICE_DRIVER,
|
|
SERVICE_STATE_ALL,
|
|
NULL,
|
|
0,
|
|
&cbBytesNeeded,
|
|
&ServicesReturned,
|
|
&ResumeHandle)) &&
|
|
(GetLastError() != ERROR_MORE_DATA)) {
|
|
|
|
goto Fallout;
|
|
}
|
|
|
|
//
|
|
// Allocate the memory
|
|
//
|
|
|
|
pmszAllServices = (ENUM_SERVICE_STATUS*)LocalAlloc(LPTR, cbBytesNeeded);
|
|
|
|
if (pmszAllServices == NULL) {
|
|
goto Fallout;
|
|
}
|
|
|
|
//
|
|
// Get the services
|
|
//
|
|
|
|
ServicesReturned = ResumeHandle = 0;
|
|
if (!EnumServicesStatus(hSCManager,
|
|
SERVICE_DRIVER,
|
|
SERVICE_STATE_ALL,
|
|
pmszAllServices,
|
|
cbBytesNeeded,
|
|
&cbBytesNeeded,
|
|
&ServicesReturned,
|
|
&ResumeHandle)) {
|
|
goto Fallout;
|
|
}
|
|
|
|
while (ServicesReturned--) {
|
|
|
|
//
|
|
// Open the service
|
|
//
|
|
|
|
hService = OpenService(hSCManager,
|
|
pmszAllServices[ServicesReturned].lpServiceName,
|
|
SERVICE_ALL_ACCESS);
|
|
|
|
if (hService != NULL) {
|
|
|
|
//
|
|
// Get the required size to store the config info
|
|
//
|
|
|
|
cbBytesNeeded = 0;
|
|
if (QueryServiceConfig(hService,
|
|
NULL,
|
|
0,
|
|
&cbBytesNeeded) ||
|
|
(GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
|
|
|
|
//
|
|
// Allocate the memory
|
|
//
|
|
|
|
pServiceConfig = (QUERY_SERVICE_CONFIG*)
|
|
LocalAlloc(LPTR, cbBytesNeeded);
|
|
|
|
if (pServiceConfig != NULL) {
|
|
|
|
//
|
|
// Get the config info
|
|
//
|
|
|
|
if (QueryServiceConfig(hService,
|
|
pServiceConfig,
|
|
cbBytesNeeded,
|
|
&cbBytesNeeded) &&
|
|
(pServiceConfig->dwStartType != SERVICE_DISABLED) &&
|
|
(_tcsicmp(pServiceConfig->lpLoadOrderGroup, TEXT("Video")) == 0)) {
|
|
|
|
ServiceLen = _tcslen(pmszAllServices[ServicesReturned].lpServiceName);
|
|
|
|
if (TotalLen + ServiceLen + 2 > AllocatedLen) {
|
|
|
|
AllocatedLen = TotalLen + ServiceLen + 128;
|
|
|
|
pmszTemp = (PTCHAR)LocalAlloc(LPTR, AllocatedLen * sizeof(TCHAR));
|
|
|
|
if (pmszTemp == NULL) {
|
|
goto Fallout;
|
|
}
|
|
|
|
memcpy(pmszTemp, pmszVideoServices, TotalLen * sizeof(TCHAR));
|
|
|
|
LocalFree(pmszVideoServices);
|
|
|
|
pmszVideoServices = pmszTemp;
|
|
pmszTemp = NULL;
|
|
}
|
|
|
|
_tcscpy(pmszVideoServices + TotalLen, pmszAllServices[ServicesReturned].lpServiceName);
|
|
TotalLen += ServiceLen + 1;
|
|
}
|
|
|
|
LocalFree(pServiceConfig);
|
|
pServiceConfig = NULL;
|
|
}
|
|
}
|
|
|
|
CloseServiceHandle(hService);
|
|
hService = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Save the services to the registry
|
|
//
|
|
|
|
pmszVideoServices[TotalLen++] = TEXT('\0');
|
|
RegSetValueEx(hKey,
|
|
SZ_SERVICES_TO_DISABLE,
|
|
0,
|
|
REG_MULTI_SZ,
|
|
(BYTE*)pmszVideoServices,
|
|
TotalLen * sizeof(TCHAR));
|
|
|
|
Fallout:
|
|
|
|
if (hService != NULL) {
|
|
CloseServiceHandle(hService);
|
|
}
|
|
|
|
if (pServiceConfig != NULL) {
|
|
LocalFree(pServiceConfig);
|
|
}
|
|
|
|
if (pmszAllServices != NULL) {
|
|
LocalFree(pmszAllServices);
|
|
}
|
|
|
|
if (hSCManager != NULL) {
|
|
CloseServiceHandle(hSCManager);
|
|
}
|
|
|
|
if (pmszVideoServices != NULL) {
|
|
LocalFree(pmszVideoServices);
|
|
}
|
|
|
|
} // SaveNT4Services
|
|
|
|
|
|
BOOL
|
|
DeleteKeyAndSubkeys(
|
|
HKEY hKey,
|
|
LPCTSTR lpSubKey
|
|
)
|
|
{
|
|
HKEY hkDeleteKey;
|
|
TCHAR szChild[MAX_PATH + 1];
|
|
BOOL bReturn = FALSE;
|
|
|
|
if (RegOpenKey(hKey, lpSubKey, &hkDeleteKey) == ERROR_SUCCESS) {
|
|
|
|
bReturn = TRUE;
|
|
while (RegEnumKey(hkDeleteKey, 0, szChild, MAX_PATH) ==
|
|
ERROR_SUCCESS) {
|
|
if (!DeleteKeyAndSubkeys(hkDeleteKey, szChild)) {
|
|
bReturn = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
RegCloseKey(hkDeleteKey);
|
|
|
|
if (bReturn)
|
|
bReturn = (RegDeleteKey(hKey, lpSubKey) == ERROR_SUCCESS);
|
|
}
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
|
|
VOID
|
|
SaveAppletExtensions(
|
|
HKEY hKey
|
|
)
|
|
{
|
|
PAPPEXT pAppExt = NULL;
|
|
PAPPEXT pAppExtTemp;
|
|
DWORD Len = 0;
|
|
PTCHAR pmszAppExt = NULL;
|
|
HKEY hkDisplay;
|
|
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
REGSTR_PATH_CONTROLSFOLDER_DISPLAY_SHEX_PROPSHEET,
|
|
0,
|
|
KEY_READ,
|
|
&hkDisplay) == ERROR_SUCCESS) {
|
|
|
|
DeskAESnapshot(hkDisplay, &pAppExt);
|
|
}
|
|
|
|
if (pAppExt == NULL)
|
|
return;
|
|
|
|
pAppExtTemp = pAppExt;
|
|
while (pAppExtTemp) {
|
|
|
|
Len += lstrlen(pAppExtTemp->szDefaultValue) + 1;
|
|
pAppExtTemp = pAppExtTemp->pNext;
|
|
}
|
|
|
|
pmszAppExt = (PTCHAR)LocalAlloc(LPTR, (Len + 1) * sizeof(TCHAR));
|
|
if (pmszAppExt != NULL) {
|
|
|
|
pAppExtTemp = pAppExt;
|
|
Len = 0;
|
|
while (pAppExtTemp) {
|
|
|
|
lstrcpy(pmszAppExt + Len, pAppExtTemp->szDefaultValue);
|
|
Len += lstrlen(pAppExtTemp->szDefaultValue) + 1;
|
|
pAppExtTemp = pAppExtTemp->pNext;
|
|
}
|
|
|
|
RegSetValueEx(hKey,
|
|
SZ_APPEXT_TO_DELETE,
|
|
0,
|
|
REG_MULTI_SZ,
|
|
(BYTE*)pmszAppExt,
|
|
(Len + 1) * sizeof(TCHAR));
|
|
|
|
LocalFree(pmszAppExt);
|
|
}
|
|
|
|
DeskAECleanup(pAppExt);
|
|
}
|
|
|