windows-nt/Source/XPSP1/NT/shell/cpls/desknt5/ocpage.cpp
2020-09-26 16:20:57 +08:00

1916 lines
52 KiB
C++

/*++
Copyright (c) 1998-1999 Microsoft Corporation
Module Name:
ocpage.cpp
Abstract:
This file implements the display page setup.
Environment:
WIN32 User Mode
--*/
#include "precomp.h"
#pragma hdrstop
#include <stdio.h>
#include <tchar.h>
#include <devguid.h>
//
// Defines
//
#define DEFAULT_XRESOLUTION 640
#define DEFAULT_YRESOLUTION 480
#define DEFAULT_BPP 15
#define DEFAULT_VREFRESH 60
#define MIN_XRESOLUTION 800
#define MIN_YRESOLUTION 600
//
// Global Data
//
BOOL g_IsSetupInitComponentInitialized = FALSE;
SETUP_INIT_COMPONENT g_SetupInitComponent;
//
// Function prototypes
//
DWORD
HandleOcInitComponent(
PSETUP_INIT_COMPONENT SetupInitComponent
);
DWORD
HandleOcCompleteInstallation(
VOID
);
BOOL
MigrateUnattendedSettings(
HDEVINFO hDevInfo
);
VOID
MigrateRegistrySettings(
HDEVINFO hDevInfo
);
VOID
MigrateRegistrySettingsBasedOnBusLocation(
HDEVINFO hDevInfo,
HKEY hPhysicalDeviceKey,
DWORD LogicalDevicesCount,
DWORD BusNumber,
DWORD Address
);
VOID
MigrateRegistrySettingsLegacy(
HDEVINFO hDevInfo,
HKEY hPhysicalDeviceKey
);
VOID
MigrateRegistrySettingsHelper(
HDEVINFO hDevInfo,
PSP_DEVINFO_DATA pDevInfoData,
HKEY hPhysicalDeviceKey,
DWORD LogicalDevicesCount
);
VOID
MigrateDeviceKeySettings(
HDEVINFO hDevInfo,
PSP_DEVINFO_DATA pDevInfoData,
HKEY hLogicalDeviceKey,
DWORD Index
);
//
// Implementation
//
extern "C" {
DWORD
DisplayOcSetupProc(
IN LPCVOID ComponentId,
IN LPCVOID SubcomponentId,
IN UINT Function,
IN UINT_PTR Param1,
IN OUT PVOID Param2
)
{
switch (Function) {
case OC_PREINITIALIZE:
return OCFLAG_UNICODE;
case OC_INIT_COMPONENT:
return HandleOcInitComponent((PSETUP_INIT_COMPONENT)Param2);
case OC_QUERY_STATE:
return SubcompOn; // we are always installed
case OC_COMPLETE_INSTALLATION:
return HandleOcCompleteInstallation();
default:
break;
}
return ERROR_SUCCESS;
}
} // extern "C"
DWORD
HandleOcInitComponent(
PSETUP_INIT_COMPONENT SetupInitComponent
)
{
DWORD retValue = ERROR_SUCCESS;
if (OCMANAGER_VERSION <= SetupInitComponent->OCManagerVersion) {
SetupInitComponent->ComponentVersion = OCMANAGER_VERSION;
g_IsSetupInitComponentInitialized = TRUE;
CopyMemory(
&g_SetupInitComponent,
(LPVOID)SetupInitComponent,
sizeof(SETUP_INIT_COMPONENT));
} else {
DeskLogError(LogSevInformation, IDS_SETUPLOG_MSG_100);
retValue = ERROR_CALL_NOT_IMPLEMENTED;
}
return retValue;
}
DWORD
HandleOcCompleteInstallation(
VOID
)
{
BOOL bUnattended = FALSE;
HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;
HKEY hKey;
DeskOpenLog();
hDevInfo = SetupDiGetClassDevs((LPGUID)&GUID_DEVCLASS_DISPLAY,
NULL,
NULL,
DIGCF_PRESENT);
if (hDevInfo == INVALID_HANDLE_VALUE) {
DeskLogError(LogSevInformation, IDS_SETUPLOG_MSG_101);
goto Cleanup;
}
if ((g_SetupInitComponent.SetupData.OperationFlags & SETUPOP_BATCH) != 0) {
//
// Unattended settings
//
bUnattended = MigrateUnattendedSettings(hDevInfo);
}
if ((!bUnattended) &&
((g_SetupInitComponent.SetupData.OperationFlags & SETUPOP_NTUPGRADE) != 0)) {
//
// Registry settings
//
MigrateRegistrySettings(hDevInfo);
}
Cleanup:
RegDeleteKey(HKEY_LOCAL_MACHINE, SZ_DETECT_DISPLAY);
RegDeleteKey(HKEY_LOCAL_MACHINE, SZ_NEW_DISPLAY);
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
SZ_UPDATE_SETTINGS_PATH,
0,
KEY_WRITE,
&hKey) == ERROR_SUCCESS) {
SHDeleteKey(hKey, SZ_UPDATE_SETTINGS_KEY);
RegCloseKey(hKey);
} else {
DeskLogError(LogSevInformation, IDS_SETUPLOG_MSG_102);
}
if (hDevInfo != INVALID_HANDLE_VALUE) {
SetupDiDestroyDeviceInfoList(hDevInfo);
}
DeskCloseLog();
return ERROR_SUCCESS;
}
BOOL
MigrateUnattendedSettings(
HDEVINFO hDevInfo
)
{
INFCONTEXT context;
HINF hInf;
TCHAR szName[128];
DWORD value;
DWORD cFields = 0;
DWORD BitsPerPel = 0, XResolution = 0, YResolution = 0, VRefresh = 0;
DWORD UsePreferredMode = 0;
DWORD AttachedToDesktop = 0;
SP_DEVINFO_DATA DevInfoData;
SP_DEVICE_INTERFACE_DATA InterfaceData;
HKEY hInterfaceKey = (HKEY)INVALID_HANDLE_VALUE;
HKEY hInterfaceLogicalDeviceKey = (HKEY)INVALID_HANDLE_VALUE;
DWORD DevInfoIndex = 0;
//
// Get the handle to the answer file
//
hInf = g_SetupInitComponent.HelperRoutines.GetInfHandle(
INFINDEX_UNATTENDED,
g_SetupInitComponent.HelperRoutines.OcManagerContext);
if ((hInf == NULL) ||
(hInf == (HINF)INVALID_HANDLE_VALUE)) {
return FALSE;
}
//
// Read the settings from the answer file
//
if (SetupFindFirstLine(hInf, TEXT("Display"), NULL, &context)) {
do {
if (SetupGetStringField(&context,
0,
szName,
ARRAYSIZE(szName),
&value)) {
if (lstrcmpi(szName, TEXT("BitsPerPel")) == 0) {
if (SetupGetIntField(&context, 1, (PINT)&value)) {
++cFields;
BitsPerPel = value;
} else {
SetupGetStringField(&context,
1,
szName,
ARRAYSIZE(szName),
&value);
DeskLogError(LogSevInformation,
IDS_SETUPLOG_MSG_096,
szName);
}
} else if (lstrcmpi(szName, TEXT("Xresolution")) == 0) {
if (SetupGetIntField(&context, 1, (PINT)&value)) {
++cFields;
XResolution = value;
} else {
SetupGetStringField(&context,
1,
szName,
ARRAYSIZE(szName),
&value);
DeskLogError(LogSevInformation, IDS_SETUPLOG_MSG_060);
}
} else if (lstrcmpi(szName, TEXT("YResolution")) == 0) {
if (SetupGetIntField(&context, 1, (PINT) &value)) {
++cFields;
YResolution = value;
} else {
SetupGetStringField(&context,
1,
szName,
ARRAYSIZE(szName),
&value);
DeskLogError(LogSevInformation,
IDS_SETUPLOG_MSG_062,
szName);
}
} else if (lstrcmpi( szName, TEXT("VRefresh")) == 0) {
if (SetupGetIntField(&context, 1, (PINT) &value)) {
++cFields;
VRefresh = value;
} else {
SetupGetStringField(&context,
1,
szName,
ARRAYSIZE(szName),
&value);
DeskLogError(LogSevInformation,
IDS_SETUPLOG_MSG_064,
szName);
}
} else {
DeskLogError(LogSevInformation,
IDS_SETUPLOG_MSG_065,
szName);
}
}
} while (SetupFindNextLine(&context, &context));
}
if (cFields == 0) {
//
// The answer file doesn't contain any display settings
//
goto Fallout;
}
//
// "Normalize" the display settings
//
AttachedToDesktop = 1;
if (BitsPerPel == 0) {
DeskLogError(LogSevInformation,
IDS_SETUPLOG_MSG_069,
DEFAULT_BPP);
BitsPerPel = DEFAULT_BPP;
}
if ((XResolution == 0) || (YResolution == 0)) {
DeskLogError(LogSevInformation,
IDS_SETUPLOG_MSG_067,
DEFAULT_XRESOLUTION,
DEFAULT_YRESOLUTION);
XResolution = DEFAULT_XRESOLUTION;
YResolution = DEFAULT_YRESOLUTION;
}
if (VRefresh == 0) {
DeskLogError(LogSevInformation,
IDS_SETUPLOG_MSG_068,
DEFAULT_VREFRESH);
VRefresh = DEFAULT_VREFRESH;
}
//
// Apply the display settings to all video cards
//
DevInfoIndex = 0;
DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
while (SetupDiEnumDeviceInfo(hDevInfo, DevInfoIndex, &DevInfoData)) {
InterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
if (!SetupDiCreateDeviceInterface(hDevInfo,
&DevInfoData,
&GUID_DISPLAY_ADAPTER_INTERFACE,
NULL,
0,
&InterfaceData)) {
DeskLogError(LogSevInformation, IDS_SETUPLOG_MSG_103);
goto NextDevice;
}
hInterfaceKey = SetupDiCreateDeviceInterfaceRegKey(hDevInfo,
&InterfaceData,
0,
KEY_SET_VALUE,
NULL,
NULL);
if (hInterfaceKey == INVALID_HANDLE_VALUE) {
DeskLogError(LogSevInformation, IDS_SETUPLOG_MSG_104);
goto NextDevice;
}
if (RegCreateKeyEx(hInterfaceKey,
TEXT("0"),
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_WRITE,
NULL,
&hInterfaceLogicalDeviceKey,
NULL) != ERROR_SUCCESS) {
DeskLogError(LogSevInformation, IDS_SETUPLOG_MSG_105, 0);
hInterfaceLogicalDeviceKey = (HKEY)INVALID_HANDLE_VALUE;
goto NextDevice;
}
//
// Do not use the preferred mode for unattended installs
//
UsePreferredMode = 0;
RegSetValueEx(hInterfaceLogicalDeviceKey,
SZ_VU_PREFERRED_MODE,
0,
REG_DWORD,
(PBYTE)&UsePreferredMode,
sizeof(UsePreferredMode));
//
// AttachedToDesktop
//
RegSetValueEx(hInterfaceLogicalDeviceKey,
SZ_VU_ATTACHED_TO_DESKTOP,
0,
REG_DWORD,
(PBYTE)&AttachedToDesktop,
sizeof(AttachedToDesktop));
//
// BitsPerPel
//
if (RegSetValueEx(hInterfaceLogicalDeviceKey,
SZ_VU_BITS_PER_PEL,
0,
REG_DWORD,
(PBYTE)&BitsPerPel,
sizeof(BitsPerPel)) == ERROR_SUCCESS) {
DeskLogError(LogSevInformation,
IDS_SETUPLOG_MSG_106,
BitsPerPel);
}
//
// XResolution
//
if (RegSetValueEx(hInterfaceLogicalDeviceKey,
SZ_VU_X_RESOLUTION,
0,
REG_DWORD,
(PBYTE)&XResolution,
sizeof(XResolution)) == ERROR_SUCCESS) {
DeskLogError(LogSevInformation,
IDS_SETUPLOG_MSG_107,
XResolution);
}
//
// dwYResolution
//
if (RegSetValueEx(hInterfaceLogicalDeviceKey,
SZ_VU_Y_RESOLUTION,
0,
REG_DWORD,
(PBYTE)&YResolution,
sizeof(YResolution)) == ERROR_SUCCESS) {
DeskLogError(LogSevInformation,
IDS_SETUPLOG_MSG_108,
YResolution);
}
//
// dwVRefresh
//
if (RegSetValueEx(hInterfaceLogicalDeviceKey,
SZ_VU_VREFRESH,
0,
REG_DWORD,
(PBYTE)&VRefresh,
sizeof(VRefresh)) == ERROR_SUCCESS) {
DeskLogError(LogSevInformation,
IDS_SETUPLOG_MSG_109,
VRefresh);
}
NextDevice:
if (hInterfaceLogicalDeviceKey != INVALID_HANDLE_VALUE) {
RegCloseKey(hInterfaceLogicalDeviceKey);
hInterfaceLogicalDeviceKey = (HKEY)INVALID_HANDLE_VALUE;
}
if (hInterfaceKey != INVALID_HANDLE_VALUE) {
RegCloseKey(hInterfaceKey);
hInterfaceKey = (HKEY)INVALID_HANDLE_VALUE;
}
DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
++DevInfoIndex;
}
Fallout:
return (cFields != 0);
}
VOID
MigrateRegistrySettings(
HDEVINFO hDevInfo
)
{
HKEY hKey = 0, hPhysicalDeviceKey = 0;
DWORD PhysicalDevicesCount = 0, LogicalDevicesCount = 0;
DWORD cb = 0, PhysicalDevice = 0, Failed = 0;
TCHAR Buffer[20];
BOOL IsLegacy;
DWORD BusNumber = 0, Address = 0;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
SZ_UPDATE_SETTINGS,
0,
KEY_READ,
&hKey) != ERROR_SUCCESS) {
DeskLogError(LogSevInformation, IDS_SETUPLOG_MSG_075);
hKey = 0;
goto Cleanup;
}
cb = sizeof(DWORD);
if ((RegQueryValueEx(hKey,
SZ_UPGRADE_FAILED_ALLOW_INSTALL,
NULL,
NULL,
(LPBYTE)&Failed,
&cb) == ERROR_SUCCESS) &&
(Failed != 0)) {
DeskLogError(LogSevInformation, IDS_SETUPLOG_MSG_076);
goto Cleanup;
}
cb = sizeof(PhysicalDevicesCount);
if (RegQueryValueEx(hKey,
SZ_VU_COUNT,
0,
NULL,
(PBYTE)&PhysicalDevicesCount,
&cb) != ERROR_SUCCESS) {
DeskLogError(LogSevInformation, IDS_SETUPLOG_MSG_110);
goto Cleanup;
}
for(PhysicalDevice = 0;
PhysicalDevice < PhysicalDevicesCount;
PhysicalDevice++) {
_tcscpy(Buffer, SZ_VU_PHYSICAL);
_stprintf(Buffer + _tcslen(Buffer), TEXT("%d"), PhysicalDevice);
if (RegOpenKeyEx(hKey,
Buffer,
0,
KEY_READ,
&hPhysicalDeviceKey) != ERROR_SUCCESS) {
DeskLogError(LogSevInformation, IDS_SETUPLOG_MSG_111);
hPhysicalDeviceKey = 0;
goto NextPhysicalDevice;
}
//
// Get the count of logical devices
//
cb = sizeof(LogicalDevicesCount);
if (RegQueryValueEx(hPhysicalDeviceKey,
SZ_VU_COUNT,
0,
NULL,
(PBYTE)&LogicalDevicesCount,
&cb) != ERROR_SUCCESS) {
DeskLogError(LogSevInformation, IDS_SETUPLOG_MSG_112);
goto NextPhysicalDevice;
}
//
// Get the bus number and address
//
IsLegacy = TRUE;
cb = sizeof(BusNumber);
if (RegQueryValueEx(hPhysicalDeviceKey,
SZ_VU_BUS_NUMBER,
0,
NULL,
(PBYTE)&BusNumber,
&cb) == ERROR_SUCCESS) {
cb = sizeof(Address);
if (RegQueryValueEx(hPhysicalDeviceKey,
SZ_VU_ADDRESS,
0,
NULL,
(PBYTE)&Address,
&cb) == ERROR_SUCCESS) {
IsLegacy = FALSE;
}
}
if (!IsLegacy) {
MigrateRegistrySettingsBasedOnBusLocation(hDevInfo,
hPhysicalDeviceKey,
LogicalDevicesCount,
BusNumber,
Address);
} else if ((PhysicalDevicesCount == 1) &&
(LogicalDevicesCount == 1)) {
//
// If legacy, we support migration of a single device.
//
MigrateRegistrySettingsLegacy(hDevInfo,
hPhysicalDeviceKey);
}
NextPhysicalDevice:
if (hPhysicalDeviceKey != 0) {
RegCloseKey(hPhysicalDeviceKey);
hPhysicalDeviceKey = 0;
}
}
Cleanup:
if (hKey != 0) {
RegCloseKey(hKey);
}
return;
}
VOID
MigrateRegistrySettingsBasedOnBusLocation(
HDEVINFO hDevInfo,
HKEY hPhysicalDeviceKey,
DWORD LogicalDevicesCount,
DWORD BusNumber,
DWORD Address
)
{
SP_DEVINFO_DATA DevInfoData;
DWORD CurrentBusNumber = 0, CurrentAddress = 0;
DWORD DevInfoIndex = 0;
BOOL bFound = FALSE;
//
// Let's find the device with the same bus number and address
//
DevInfoIndex = 0;
DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
while (SetupDiEnumDeviceInfo(hDevInfo, DevInfoIndex, &DevInfoData)) {
if (SetupDiGetDeviceRegistryProperty(hDevInfo,
&DevInfoData,
SPDRP_BUSNUMBER,
NULL,
(PBYTE)&CurrentBusNumber,
sizeof(CurrentBusNumber),
NULL) &&
(CurrentBusNumber == BusNumber) &&
SetupDiGetDeviceRegistryProperty(hDevInfo,
&DevInfoData,
SPDRP_ADDRESS,
NULL,
(PBYTE)&CurrentAddress,
sizeof(CurrentAddress),
NULL) &&
(CurrentAddress == Address)) {
//
// We found the device with the same bus number and address
// So ... migrate the settings
//
MigrateRegistrySettingsHelper(hDevInfo,
&DevInfoData,
hPhysicalDeviceKey,
LogicalDevicesCount);
//
// We are done
//
bFound = TRUE;
break;
}
//
// Next device
//
DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
++DevInfoIndex;
}
if (!bFound) {
DeskLogError(LogSevInformation, IDS_SETUPLOG_MSG_113);
}
return;
}
VOID
MigrateRegistrySettingsLegacy(
HDEVINFO hDevInfo,
HKEY hPhysicalDeviceKey
)
{
SP_DEVINFO_DATA DevInfoData0, DevInfoData1;
DevInfoData0.cbSize = sizeof(SP_DEVINFO_DATA);
if (!SetupDiEnumDeviceInfo(hDevInfo, 0, &DevInfoData0)) {
DeskLogError(LogSevInformation, IDS_SETUPLOG_MSG_115);
return;
}
DevInfoData1.cbSize = sizeof(SP_DEVINFO_DATA);
if (SetupDiEnumDeviceInfo(hDevInfo, 1, &DevInfoData1)) {
//
// There are at least 2 video devices in the system
// We don't know which device to apply the settings to.
// So, just ignore this case
//
DeskLogError(LogSevInformation, IDS_SETUPLOG_MSG_114);
return;
}
MigrateRegistrySettingsHelper(hDevInfo,
&DevInfoData0,
hPhysicalDeviceKey,
1); // there is only one logical device
}
VOID
MigrateRegistrySettingsHelper(
HDEVINFO hDevInfo,
PSP_DEVINFO_DATA pDevInfoData,
HKEY hPhysicalDeviceKey,
DWORD LogicalDevicesCount
)
{
SP_DEVICE_INTERFACE_DATA InterfaceData;
HKEY hInterfaceKey = 0;
HKEY hInterfaceLogicalDeviceKey = 0;
HKEY hLogicalDeviceKey = 0;
TCHAR Buffer[20];
DWORD cb = 0, LogicalDevice = 0;
DWORD UsePreferredMode = 0;
DWORD AttachedToDesktop = 0;
DWORD RelativeX = 0;
DWORD RelativeY = 0;
DWORD BitsPerPel = 0;
DWORD XResolution = 0;
DWORD YResolution = 0;
DWORD VRefresh = 0;
DWORD Flags = 0;
InterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
if (!SetupDiCreateDeviceInterface(hDevInfo,
pDevInfoData,
&GUID_DISPLAY_ADAPTER_INTERFACE,
NULL,
0,
&InterfaceData)) {
DeskLogError(LogSevInformation, IDS_SETUPLOG_MSG_103);
return;
}
hInterfaceKey = SetupDiCreateDeviceInterfaceRegKey(hDevInfo,
&InterfaceData,
0,
KEY_SET_VALUE,
NULL,
NULL);
if (hInterfaceKey == INVALID_HANDLE_VALUE) {
DeskLogError(LogSevInformation, IDS_SETUPLOG_MSG_104);
return;
}
for (LogicalDevice = 0;
LogicalDevice < LogicalDevicesCount;
++LogicalDevice) {
_tcscpy(Buffer, SZ_VU_LOGICAL);
_stprintf(Buffer + _tcslen(Buffer), TEXT("%d"), LogicalDevice);
if (RegOpenKeyEx(hPhysicalDeviceKey,
Buffer,
0,
KEY_READ,
&hLogicalDeviceKey) != ERROR_SUCCESS) {
//
// We can not go on with this physical device
// The LogicalDevices order is important for DualView
//
DeskLogError(LogSevInformation, IDS_SETUPLOG_MSG_116);
break;
}
_stprintf(Buffer, TEXT("%d"), LogicalDevice);
if (RegCreateKeyEx(hInterfaceKey,
Buffer,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_WRITE,
NULL,
&hInterfaceLogicalDeviceKey,
NULL) != ERROR_SUCCESS) {
//
// We can not go on with this physical device
// The LogicalDevices order is important for DualView
//
DeskLogError(LogSevInformation, IDS_SETUPLOG_MSG_105, LogicalDevice);
RegCloseKey(hLogicalDeviceKey);
break;
}
//
// Use preferred mode?
//
cb = sizeof(XResolution);
if (RegQueryValueEx(hLogicalDeviceKey,
SZ_VU_X_RESOLUTION,
0,
NULL,
(PBYTE)&XResolution,
&cb) != ERROR_SUCCESS) {
XResolution = DEFAULT_XRESOLUTION;
}
cb = sizeof(YResolution);
if (RegQueryValueEx(hLogicalDeviceKey,
SZ_VU_Y_RESOLUTION,
0,
NULL,
(PBYTE)&YResolution,
&cb) != ERROR_SUCCESS) {
YResolution = DEFAULT_YRESOLUTION;
}
UsePreferredMode = ((XResolution < MIN_XRESOLUTION) ||
(YResolution < MIN_YRESOLUTION));
RegSetValueEx(hInterfaceLogicalDeviceKey,
SZ_VU_PREFERRED_MODE,
0,
REG_DWORD,
(PBYTE)&UsePreferredMode,
sizeof(UsePreferredMode));
if (UsePreferredMode) {
DeskLogError(LogSevInformation,
IDS_SETUPLOG_MSG_130);
} else {
//
// AttachedToDesktop
//
cb = sizeof(AttachedToDesktop);
if (RegQueryValueEx(hLogicalDeviceKey,
SZ_VU_ATTACHED_TO_DESKTOP,
0,
NULL,
(PBYTE)&AttachedToDesktop,
&cb) == ERROR_SUCCESS) {
if (RegSetValueEx(hInterfaceLogicalDeviceKey,
SZ_VU_ATTACHED_TO_DESKTOP,
0,
REG_DWORD,
(PBYTE)&AttachedToDesktop,
sizeof(AttachedToDesktop)) == ERROR_SUCCESS) {
DeskLogError(LogSevInformation,
IDS_SETUPLOG_MSG_117,
AttachedToDesktop);
}
}
//
// RelativeX
//
cb = sizeof(RelativeX);
if (RegQueryValueEx(hLogicalDeviceKey,
SZ_VU_RELATIVE_X,
0,
NULL,
(PBYTE)&RelativeX,
&cb) == ERROR_SUCCESS) {
if (RegSetValueEx(hInterfaceLogicalDeviceKey,
SZ_VU_RELATIVE_X,
0,
REG_DWORD,
(PBYTE)&RelativeX,
sizeof(RelativeX)) == ERROR_SUCCESS) {
DeskLogError(LogSevInformation,
IDS_SETUPLOG_MSG_118,
RelativeX);
}
}
//
// RelativeY
//
cb = sizeof(RelativeY);
if (RegQueryValueEx(hLogicalDeviceKey,
SZ_VU_RELATIVE_Y,
0,
NULL,
(PBYTE)&RelativeY,
&cb) == ERROR_SUCCESS) {
if (RegSetValueEx(hInterfaceLogicalDeviceKey,
SZ_VU_RELATIVE_Y,
0,
REG_DWORD,
(PBYTE)&RelativeY,
sizeof(RelativeY)) == ERROR_SUCCESS) {
DeskLogError(LogSevInformation,
IDS_SETUPLOG_MSG_119,
RelativeY);
}
}
//
// BitsPerPel
//
cb = sizeof(BitsPerPel);
if (RegQueryValueEx(hLogicalDeviceKey,
SZ_VU_BITS_PER_PEL,
0,
NULL,
(PBYTE)&BitsPerPel,
&cb) == ERROR_SUCCESS) {
if (RegSetValueEx(hInterfaceLogicalDeviceKey,
SZ_VU_BITS_PER_PEL,
0,
REG_DWORD,
(PBYTE)&BitsPerPel,
sizeof(BitsPerPel)) == ERROR_SUCCESS) {
DeskLogError(LogSevInformation,
IDS_SETUPLOG_MSG_120,
BitsPerPel);
}
}
//
// XResolution
//
if (RegSetValueEx(hInterfaceLogicalDeviceKey,
SZ_VU_X_RESOLUTION,
0,
REG_DWORD,
(PBYTE)&XResolution,
sizeof(XResolution)) == ERROR_SUCCESS) {
DeskLogError(LogSevInformation,
IDS_SETUPLOG_MSG_121,
XResolution);
}
//
// dwYResolution
//
if (RegSetValueEx(hInterfaceLogicalDeviceKey,
SZ_VU_Y_RESOLUTION,
0,
REG_DWORD,
(PBYTE)&YResolution,
sizeof(YResolution)) == ERROR_SUCCESS) {
DeskLogError(LogSevInformation,
IDS_SETUPLOG_MSG_122,
YResolution);
}
//
// dwVRefresh
//
cb = sizeof(VRefresh);
if (RegQueryValueEx(hLogicalDeviceKey,
SZ_VU_VREFRESH,
0,
NULL,
(PBYTE)&VRefresh,
&cb) == ERROR_SUCCESS) {
if (RegSetValueEx(hInterfaceLogicalDeviceKey,
SZ_VU_VREFRESH,
0,
REG_DWORD,
(PBYTE)&VRefresh,
sizeof(VRefresh)) == ERROR_SUCCESS) {
DeskLogError(LogSevInformation,
IDS_SETUPLOG_MSG_123,
VRefresh);
}
}
//
// Flags
//
cb = sizeof(Flags);
if (RegQueryValueEx(hLogicalDeviceKey,
SZ_VU_FLAGS,
0,
NULL,
(PBYTE)&Flags,
&cb) == ERROR_SUCCESS) {
if (RegSetValueEx(hInterfaceLogicalDeviceKey,
SZ_VU_FLAGS,
0,
REG_DWORD,
(PBYTE)&Flags,
sizeof(Flags)) == ERROR_SUCCESS) {
DeskLogError(LogSevInformation,
IDS_SETUPLOG_MSG_124,
Flags);
}
}
}
//
// Migrate the hardware acceleration and the pruning mode
//
MigrateDeviceKeySettings(hDevInfo,
pDevInfoData,
hLogicalDeviceKey,
LogicalDevice);
RegCloseKey(hLogicalDeviceKey);
RegCloseKey(hInterfaceLogicalDeviceKey);
}
RegCloseKey(hInterfaceKey);
}
VOID
MigrateDeviceKeySettings(
HDEVINFO hDevInfo,
PSP_DEVINFO_DATA pDevInfoData,
HKEY hLogicalDeviceKey,
DWORD Index
)
{
HKEY hkPnP = (HKEY)INVALID_HANDLE_VALUE;
HKEY hkDevice = (HKEY)INVALID_HANDLE_VALUE;
LPTSTR pBuffer = NULL;
DWORD dwSize, len, cb;
DWORD HwAcceleration, PruningMode;
//
// Open the PnP key
//
hkPnP = SetupDiOpenDevRegKey(hDevInfo,
pDevInfoData,
DICS_FLAG_GLOBAL,
0,
DIREG_DEV,
KEY_READ);
if (hkPnP == INVALID_HANDLE_VALUE) {
DeskLogError(LogSevInformation,
IDS_SETUPLOG_MSG_127,
TEXT("SetupDiOpenDevRegKey"));
goto Fallout;
}
//
// Try to get the GUID from the PnP key
//
dwSize = 0;
if (RegQueryValueEx(hkPnP,
SZ_GUID,
0,
NULL,
NULL,
&dwSize) != ERROR_SUCCESS) {
DeskLogError(LogSevInformation,
IDS_SETUPLOG_MSG_127,
TEXT("RegQueryValueEx"));
goto Fallout;
}
len = _tcslen(SZ_VIDEO_DEVICES);
pBuffer = (LPTSTR)LocalAlloc(LPTR,
dwSize + (len + 6) * sizeof(TCHAR));
if (pBuffer == NULL) {
DeskLogError(LogSevInformation,
IDS_SETUPLOG_MSG_127,
TEXT("LocalAlloc"));
goto Fallout;
}
_tcscpy(pBuffer, SZ_VIDEO_DEVICES);
if (RegQueryValueEx(hkPnP,
SZ_GUID,
0,
NULL,
(PBYTE)(pBuffer + len),
&dwSize) != ERROR_SUCCESS) {
DeskLogError(LogSevInformation,
IDS_SETUPLOG_MSG_127,
TEXT("RegQueryValueEx"));
goto Fallout;
}
_stprintf(pBuffer + _tcslen(pBuffer), L"\\%04d", Index);
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
pBuffer,
0,
KEY_WRITE,
&hkDevice) != ERROR_SUCCESS) {
DeskLogError(LogSevInformation,
IDS_SETUPLOG_MSG_127,
TEXT("RegOpenKeyEx"));
hkDevice = (HKEY)INVALID_HANDLE_VALUE;
goto Fallout;
}
//
// Hardware acceleration
//
cb = sizeof(HwAcceleration);
if (RegQueryValueEx(hLogicalDeviceKey,
SZ_HW_ACCELERATION,
0,
NULL,
(PBYTE)&HwAcceleration,
&cb) == ERROR_SUCCESS) {
RegSetValueEx(hkDevice,
SZ_HW_ACCELERATION,
0,
REG_DWORD,
(PBYTE)&HwAcceleration,
sizeof(HwAcceleration));
}
//
// Pruning mode
//
cb = sizeof(PruningMode);
if (RegQueryValueEx(hLogicalDeviceKey,
SZ_PRUNNING_MODE,
0,
NULL,
(PBYTE)&PruningMode,
&cb) == ERROR_SUCCESS) {
RegSetValueEx(hkDevice,
SZ_PRUNNING_MODE,
0,
REG_DWORD,
(PBYTE)&PruningMode,
sizeof(PruningMode));
}
Fallout:
if (hkPnP != INVALID_HANDLE_VALUE) {
RegCloseKey(hkPnP);
}
if (pBuffer != NULL) {
LocalFree(pBuffer);
}
if (hkDevice != INVALID_HANDLE_VALUE) {
RegCloseKey(hkDevice);
}
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// type constants for DrawArrow
#define AW_TOP 1 // top
#define AW_BOTTOM 2 // bottom
#define AW_LEFT 3 // left
#define AW_RIGHT 4 // right
#define CCH_MAX_STRING 256
typedef struct _NEW_DESKTOP_PARAM {
LPDEVMODE lpdevmode;
LPTSTR pwszDevice;
DWORD dwTimeout;
} NEW_DESKTOP_PARAM, *PNEW_DESKTOP_PARAM;
// table of resolutions that we show off.
// if the resolution is larger, then we show that one too.
typedef struct tagRESTAB {
INT xRes;
INT yRes;
COLORREF crColor; // color to paint this resolution
} RESTAB;
RESTAB ResTab[] ={
{ 1600, 1200, RGB(255,0,0)},
{ 1280, 1024, RGB(0,255,0)},
{ 1152, 900, RGB(0,0,255)},
{ 1024, 768, RGB(255,0,0)},
{ 800, 600, RGB(0,255,0)},
// 640x480 or 640x400 handled specially
{ 0, 0, 0} // end of table
};
DWORD WINAPI
ApplyNowThd(
LPVOID lpThreadParameter
);
void
DrawBmp(
HDC hDC
);
VOID
LabelResolution(
HDC hDC,
INT xmin,
INT ymin,
INT xmax,
INT ymax
);
static VOID
PaintRect(
HDC hDC,
INT lowx,
INT lowy,
INT highx,
INT highy,
COLORREF rgb,
UINT idString
);
VOID
DrawArrows(
HDC hDC,
INT xRes,
INT yRes
);
static VOID
LabelRect(
HDC hDC,
PRECT pRect,
UINT idString
);
static VOID
DrawArrow(
HDC hDC,
INT type,
INT xPos,
INT yPos,
COLORREF crPenColor
);
VOID
MakeRect(
PRECT pRect,
INT xmin,
INT ymin,
INT xmax,
INT ymax
);
DWORD
DisplayTestSettingsW(
LPDEVMODEW lpDevMode,
LPWSTR pwszDevice,
DWORD dwTimeout
)
{
HANDLE hThread;
DWORD idThread;
DWORD bTest;
NEW_DESKTOP_PARAM desktopParam;
if (!lpDevMode || !pwszDevice)
return FALSE;
if (dwTimeout == 0)
dwTimeout = NORMAL_TIMEOUT;
desktopParam.lpdevmode = lpDevMode;
desktopParam.pwszDevice = pwszDevice;
desktopParam.dwTimeout = dwTimeout;
hThread = CreateThread(NULL,
4096,
ApplyNowThd,
(LPVOID) &desktopParam,
SYNCHRONIZE | THREAD_QUERY_INFORMATION,
&idThread
);
WaitForSingleObject(hThread, INFINITE);
GetExitCodeThread(hThread, &bTest);
CloseHandle(hThread);
return bTest;
}
DWORD WINAPI
ApplyNowThd(
LPVOID lpThreadParameter
)
{
PNEW_DESKTOP_PARAM lpDesktopParam = (PNEW_DESKTOP_PARAM) lpThreadParameter;
HDESK hdsk = NULL;
HDESK hdskDefault = NULL;
BOOL bTest = FALSE;
HDC hdc;
//
// HACK:
// We need to make a USER call before calling the desktop stuff so we can
// sure our threads internal data structure are associated with the default
// desktop.
// Otherwise USER has problems closing the desktop with our thread on it.
//
GetSystemMetrics(SM_CXSCREEN);
//
// Create the desktop
//
hdskDefault = GetThreadDesktop(GetCurrentThreadId());
if (hdskDefault != NULL) {
hdsk = CreateDesktop(TEXT("Display.Cpl Desktop"),
lpDesktopParam->pwszDevice,
lpDesktopParam->lpdevmode,
0,
MAXIMUM_ALLOWED,
NULL);
if (hdsk != NULL) {
//
// use the desktop for this thread
//
if (SetThreadDesktop(hdsk)) {
hdc = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
if (hdc) {
DrawBmp(hdc);
DeleteDC(hdc);
bTest = TRUE;
}
//
// Sleep for some seconds so you have time to look at the screen.
//
Sleep(lpDesktopParam->dwTimeout);
}
}
//
// Reset the thread to the right desktop
//
SetThreadDesktop(hdskDefault);
SwitchDesktop(hdskDefault);
//
// Can only close the desktop after we have switched to the new one.
//
if (hdsk != NULL) {
CloseDesktop(hdsk);
}
}
ExitThread((DWORD) bTest);
return 0;
}
/****************************************************************************
FUNCTION: DrawBmp
PURPOSE: Show off a fancy screen so the user has some idea
of what will be seen given this resolution, colour
depth and vertical refresh rate. Note that we do not
try to simulate the font sizes.
****************************************************************************/
void
DrawBmp(
HDC hDC
)
{
INT nBpp; // bits per pixel
INT nWidth; // width of screen in pixels
INT nHeight; // height of screen in pixels
INT xUsed,yUsed; // amount of x and y to use for dense bitmap
INT dx,dy; // delta x and y for color bars
RECT rct; // rectangle for passing bounds
HFONT hPrevFont=0; // previous font in DC
HFONT hNewFont; // new font if possible
HPEN hPrevPen; // previous pen handle
INT x,y,i;
INT off; // offset in dx units
hNewFont = (HFONT)NULL;
if (hNewFont) // if no font, use old
hPrevFont= (HFONT) SelectObject(hDC, hNewFont);
// get surface information
nBpp= GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES);
nWidth= GetDeviceCaps(hDC, HORZRES);
nHeight= GetDeviceCaps(hDC, VERTRES);
// background for everything is yellow.
PaintRect(hDC, 0, 0, nWidth, nHeight, RGB(255,255,0), 0);
LabelResolution( hDC, 0,0,nWidth, nHeight );
// Background for various resolutions
// biggest ones first
for(i = 0; ResTab[i].xRes !=0; i++) {
// Only draw if it will show
//if ((nWidth >= ResTab[i].xRes) | ( nHeight>=ResTab[i].yRes ) )
if ((nWidth >= ResTab[i].xRes) || (nHeight >= ResTab[i].yRes)) {
PaintRect(hDC, 0, 0, ResTab[i].xRes, ResTab[i].yRes, ResTab[i].crColor, 0);
LabelResolution(hDC, 0, 0, ResTab[i].xRes, ResTab[i].yRes);
}
}
// color bars - only in standard vga area
xUsed= min(nWidth, 640); // only use vga width
yUsed= min(nHeight, 480); // could be 400 on some boards
dx = xUsed / 2;
dy = yUsed / 6;
PaintRect(hDC, 0, 0, dx, dy*1, RGB(255,0,0), IDS_COLOR_RED);
PaintRect(hDC, 0, dy*1, dx, dy*2, RGB(0,255,0), IDS_COLOR_GREEN);
PaintRect(hDC, 0, dy*2, dx, dy*3, RGB(0,0,255), IDS_COLOR_BLUE);
PaintRect(hDC, 0, dy*3, dx, dy*4, RGB(255,255,0), IDS_COLOR_YELLOW);
PaintRect(hDC, 0, dy*4, dx, dy*5, RGB(255,0,255), IDS_COLOR_MAGENTA);
PaintRect(hDC, 0, dy*5, dx, yUsed, RGB(0,255,255), IDS_COLOR_CYAN);
// gradations of colors for true color detection
for (x = dx; x < xUsed; x++) {
int level;
level = 255 - (256 * (x-dx)) / dx;
PaintRect(hDC, x, dy*0, x+1, dy*1, RGB(level,0,0 ), 0);
PaintRect(hDC, x, dy*1, x+1, dy*2, RGB(0,level,0 ), 0);
PaintRect(hDC, x, dy*2, x+1, dy*3, RGB(0,0,level ), 0);
PaintRect(hDC, x, dy*5, x+1, dy*6, RGB(level,level,level), 0);
}
MakeRect(&rct, dx, 0, dx * 2, dy * 1);
LabelRect(hDC, &rct, IDS_RED_SHADES);
MakeRect(&rct, dx, dy, dx * 2, dy * 2);
LabelRect(hDC, &rct, IDS_GREEN_SHADES);
MakeRect(&rct, dx, 2 * dy, dx * 2, dy * 3);
LabelRect(hDC, &rct, IDS_BLUE_SHADES);
MakeRect(&rct, dx, 5 * dy, dx * 2, dy * 6);
LabelRect(hDC, &rct, IDS_GRAY_SHADES);
// horizontal lines for interlace detection
off = 3;
PaintRect(hDC, dx, dy*off, xUsed, dy * (off+1), RGB(255,255,255), 0); // white
hPrevPen = (HPEN) SelectObject(hDC, GetStockObject(BLACK_PEN));
for (y = dy * off; y < dy * (off+1); y = y+2) {
MoveToEx(hDC, dx, y, NULL);
LineTo( hDC, dx * 2, y);
}
SelectObject(hDC, hPrevPen);
MakeRect(&rct, dx, dy * off, dx * 2, dy * (off+1));
LabelRect(hDC, &rct, IDS_PATTERN_HORZ);
// vertical lines for bad dac detection
off = 4;
PaintRect(hDC, dx, dy * off, xUsed,dy * (off+1), RGB(255,255,255), 0); // white
hPrevPen= (HPEN) SelectObject(hDC, GetStockObject(BLACK_PEN));
for (x = dx; x < xUsed; x = x+2) {
MoveToEx(hDC, x, dy * off, NULL);
LineTo( hDC, x, dy * (off+1));
}
SelectObject(hDC, hPrevPen);
MakeRect(&rct, dx, dy * off, dx * 2, dy * (off+1));
LabelRect(hDC, &rct, IDS_PATTERN_VERT);
DrawArrows(hDC, nWidth, nHeight);
LabelResolution(hDC, 0, 0, xUsed, yUsed);
// delete created font if one was created
if (hPrevFont) {
hPrevFont = (HFONT) SelectObject(hDC, hPrevFont);
DeleteObject(hPrevFont);
}
}
/****************************************************************************
FUNCTION: LabelResolution
PURPOSE: Labels the resolution in a form a user may understand.
FEATURE: We could label vertically too.
****************************************************************************/
VOID
LabelResolution(
HDC hDC,
INT xmin,
INT ymin,
INT xmax,
INT ymax
)
{
TCHAR szRes[120]; // text for resolution
TCHAR szFmt[CCH_MAX_STRING]; // format string
SIZE size;
INT iStatus;
iStatus = LoadString(hInstance, ID_DSP_TXT_XBYY /* remove IDS_RESOLUTION_FMT */, szFmt, ARRAYSIZE(szFmt) );
if (!iStatus || iStatus == sizeof(szFmt)) {
lstrcpy(szFmt,TEXT("%d x %d")); // make sure we get something
}
wsprintf(szRes, szFmt, xmax, ymax);
SetBkMode(hDC, TRANSPARENT);
SetTextColor(hDC, RGB(0,0,0));
GetTextExtentPoint32(hDC, szRes, lstrlen(szRes), &size);
// Text near bottom of screen ~10 pixels from bottom
TextOut(hDC, xmax/2 - size.cx/2, ymax - 10-size.cy, szRes, lstrlen(szRes));
}
/****************************************************************************
FUNCTION: PaintRect
PURPOSE: Color in a rectangle and label it.
****************************************************************************/
static VOID
PaintRect(
HDC hDC, // DC to paint
INT lowx, // coordinates describing rectangle to fill
INT lowy, //
INT highx, //
INT highy, //
COLORREF rgb, // color to fill in rectangle with
UINT idString // resource ID to use to label or 0 is none
)
{
RECT rct;
HBRUSH hBrush;
MakeRect(&rct, lowx, lowy, highx, highy);
hBrush = CreateSolidBrush(rgb);
if (hBrush)
{
FillRect(hDC, &rct, hBrush);
DeleteObject(hBrush);
}
LabelRect(hDC, &rct, idString);
}
/****************************************************************************
FUNCTION: DrawArrows
PURPOSE: Draw all the arrows showing edges of resolution.
****************************************************************************/
VOID
DrawArrows(
HDC hDC,
INT xRes,
INT yRes
)
{
INT dx,dy;
INT x,y;
COLORREF color= RGB(0,0,0); // color of arrow
dx= xRes/8;
dy= yRes/8;
for (x = 0; x < xRes; x += dx) {
DrawArrow(hDC, AW_TOP, dx/2+x, 0, color);
DrawArrow(hDC, AW_BOTTOM, dx/2+x, yRes-1, color);
}
for (y = 0; y < yRes; y += dy) {
DrawArrow(hDC, AW_LEFT, 0, dy/2+y, color);
DrawArrow(hDC, AW_RIGHT, xRes-1, dy/2+y, color);
}
}
/****************************************************************************
FUNCTION: LabelRect
PURPOSE: Label a rectangle with centered text given resource ID.
****************************************************************************/
static VOID
LabelRect(
HDC hDC,
PRECT pRect,
UINT idString
)
{
UINT iStatus;
INT xStart, yStart;
SIZE size; // for size of string
TCHAR szMsg[CCH_MAX_STRING];
if (idString == 0) // make it easy to ignore call
return;
SetBkMode(hDC, OPAQUE);
SetBkColor(hDC, RGB(0,0,0));
SetTextColor(hDC, RGB(255,255,255));
// center
xStart = (pRect->left + pRect->right) / 2;
yStart = (pRect->top + pRect->bottom) / 2;
iStatus = LoadString(hInstance, idString, szMsg, ARRAYSIZE(szMsg));
if (!iStatus) {
return; // can't find string - print nothing
}
GetTextExtentPoint32(hDC, szMsg, lstrlen(szMsg), &size);
TextOut(hDC, xStart-size.cx/2, yStart-size.cy/2, szMsg, lstrlen(szMsg));
}
/****************************************************************************
FUNCTION: DrawArrow
PURPOSE: Draw one arrow in a given color.
****************************************************************************/
static VOID
DrawArrow(
HDC hDC,
INT type,
INT xPos,
INT yPos,
COLORREF crPenColor
)
{
INT shaftlen=30; // length of arrow shaft
INT headlen=15; // height or width of arrow head (not length)
HPEN hPen, hPrevPen = NULL; // pens
INT x,y;
INT xdir, ydir; // directions of x and y (1,-1)
hPen= CreatePen( PS_SOLID, 1, crPenColor );
if( hPen )
hPrevPen= (HPEN) SelectObject( hDC, hPen );
MoveToEx( hDC, xPos, yPos, NULL );
xdir= ydir= 1; // defaults
switch( type )
{
case AW_BOTTOM:
ydir= -1;
case AW_TOP:
LineTo(hDC, xPos, yPos+ydir*shaftlen);
for( x=0; x<3; x++ )
{
MoveToEx( hDC, xPos, yPos+ydir*x, NULL );
LineTo( hDC, xPos-(headlen-x), yPos+ydir*headlen );
MoveToEx( hDC, xPos, yPos+ydir*x, NULL );
LineTo( hDC, xPos+(headlen-x), yPos+ydir*headlen );
}
break;
case AW_RIGHT:
xdir= -1;
case AW_LEFT:
LineTo( hDC, xPos + xdir*shaftlen, yPos );
for( y=0; y<3; y++ )
{
MoveToEx( hDC, xPos + xdir*y, yPos, NULL );
LineTo( hDC, xPos + xdir*headlen, yPos+(headlen-y));
MoveToEx( hDC, xPos + xdir*y, yPos, NULL );
LineTo( hDC, xPos + xdir*headlen, yPos-(headlen-y));
}
break;
}
if( hPrevPen )
SelectObject( hDC, hPrevPen );
if (hPen)
DeleteObject(hPen);
}
/****************************************************************************
FUNCTION: MakeRect
PURPOSE: Fill in RECT structure given contents.
****************************************************************************/
VOID
MakeRect(
PRECT pRect,
INT xmin,
INT ymin,
INT xmax,
INT ymax
)
{
pRect->left= xmin;
pRect->right= xmax;
pRect->bottom= ymin;
pRect->top= ymax;
}