Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1877 lines
48 KiB

/*++
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);
}