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