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.

1915 lines
52 KiB

  1. /*++
  2. Copyright (c) 1998-1999 Microsoft Corporation
  3. Module Name:
  4. ocpage.cpp
  5. Abstract:
  6. This file implements the display page setup.
  7. Environment:
  8. WIN32 User Mode
  9. --*/
  10. #include "precomp.h"
  11. #pragma hdrstop
  12. #include <stdio.h>
  13. #include <tchar.h>
  14. #include <devguid.h>
  15. //
  16. // Defines
  17. //
  18. #define DEFAULT_XRESOLUTION 640
  19. #define DEFAULT_YRESOLUTION 480
  20. #define DEFAULT_BPP 15
  21. #define DEFAULT_VREFRESH 60
  22. #define MIN_XRESOLUTION 800
  23. #define MIN_YRESOLUTION 600
  24. //
  25. // Global Data
  26. //
  27. BOOL g_IsSetupInitComponentInitialized = FALSE;
  28. SETUP_INIT_COMPONENT g_SetupInitComponent;
  29. //
  30. // Function prototypes
  31. //
  32. DWORD
  33. HandleOcInitComponent(
  34. PSETUP_INIT_COMPONENT SetupInitComponent
  35. );
  36. DWORD
  37. HandleOcCompleteInstallation(
  38. VOID
  39. );
  40. BOOL
  41. MigrateUnattendedSettings(
  42. HDEVINFO hDevInfo
  43. );
  44. VOID
  45. MigrateRegistrySettings(
  46. HDEVINFO hDevInfo
  47. );
  48. VOID
  49. MigrateRegistrySettingsBasedOnBusLocation(
  50. HDEVINFO hDevInfo,
  51. HKEY hPhysicalDeviceKey,
  52. DWORD LogicalDevicesCount,
  53. DWORD BusNumber,
  54. DWORD Address
  55. );
  56. VOID
  57. MigrateRegistrySettingsLegacy(
  58. HDEVINFO hDevInfo,
  59. HKEY hPhysicalDeviceKey
  60. );
  61. VOID
  62. MigrateRegistrySettingsHelper(
  63. HDEVINFO hDevInfo,
  64. PSP_DEVINFO_DATA pDevInfoData,
  65. HKEY hPhysicalDeviceKey,
  66. DWORD LogicalDevicesCount
  67. );
  68. VOID
  69. MigrateDeviceKeySettings(
  70. HDEVINFO hDevInfo,
  71. PSP_DEVINFO_DATA pDevInfoData,
  72. HKEY hLogicalDeviceKey,
  73. DWORD Index
  74. );
  75. //
  76. // Implementation
  77. //
  78. extern "C" {
  79. DWORD
  80. DisplayOcSetupProc(
  81. IN LPCVOID ComponentId,
  82. IN LPCVOID SubcomponentId,
  83. IN UINT Function,
  84. IN UINT_PTR Param1,
  85. IN OUT PVOID Param2
  86. )
  87. {
  88. switch (Function) {
  89. case OC_PREINITIALIZE:
  90. return OCFLAG_UNICODE;
  91. case OC_INIT_COMPONENT:
  92. return HandleOcInitComponent((PSETUP_INIT_COMPONENT)Param2);
  93. case OC_QUERY_STATE:
  94. return SubcompOn; // we are always installed
  95. case OC_COMPLETE_INSTALLATION:
  96. return HandleOcCompleteInstallation();
  97. default:
  98. break;
  99. }
  100. return ERROR_SUCCESS;
  101. }
  102. } // extern "C"
  103. DWORD
  104. HandleOcInitComponent(
  105. PSETUP_INIT_COMPONENT SetupInitComponent
  106. )
  107. {
  108. DWORD retValue = ERROR_SUCCESS;
  109. if (OCMANAGER_VERSION <= SetupInitComponent->OCManagerVersion) {
  110. SetupInitComponent->ComponentVersion = OCMANAGER_VERSION;
  111. g_IsSetupInitComponentInitialized = TRUE;
  112. CopyMemory(
  113. &g_SetupInitComponent,
  114. (LPVOID)SetupInitComponent,
  115. sizeof(SETUP_INIT_COMPONENT));
  116. } else {
  117. DeskLogError(LogSevInformation, IDS_SETUPLOG_MSG_100);
  118. retValue = ERROR_CALL_NOT_IMPLEMENTED;
  119. }
  120. return retValue;
  121. }
  122. DWORD
  123. HandleOcCompleteInstallation(
  124. VOID
  125. )
  126. {
  127. BOOL bUnattended = FALSE;
  128. HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;
  129. HKEY hKey;
  130. DeskOpenLog();
  131. hDevInfo = SetupDiGetClassDevs((LPGUID)&GUID_DEVCLASS_DISPLAY,
  132. NULL,
  133. NULL,
  134. DIGCF_PRESENT);
  135. if (hDevInfo == INVALID_HANDLE_VALUE) {
  136. DeskLogError(LogSevInformation, IDS_SETUPLOG_MSG_101);
  137. goto Cleanup;
  138. }
  139. if ((g_SetupInitComponent.SetupData.OperationFlags & SETUPOP_BATCH) != 0) {
  140. //
  141. // Unattended settings
  142. //
  143. bUnattended = MigrateUnattendedSettings(hDevInfo);
  144. }
  145. if ((!bUnattended) &&
  146. ((g_SetupInitComponent.SetupData.OperationFlags & SETUPOP_NTUPGRADE) != 0)) {
  147. //
  148. // Registry settings
  149. //
  150. MigrateRegistrySettings(hDevInfo);
  151. }
  152. Cleanup:
  153. RegDeleteKey(HKEY_LOCAL_MACHINE, SZ_DETECT_DISPLAY);
  154. RegDeleteKey(HKEY_LOCAL_MACHINE, SZ_NEW_DISPLAY);
  155. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  156. SZ_UPDATE_SETTINGS_PATH,
  157. 0,
  158. KEY_WRITE,
  159. &hKey) == ERROR_SUCCESS) {
  160. SHDeleteKey(hKey, SZ_UPDATE_SETTINGS_KEY);
  161. RegCloseKey(hKey);
  162. } else {
  163. DeskLogError(LogSevInformation, IDS_SETUPLOG_MSG_102);
  164. }
  165. if (hDevInfo != INVALID_HANDLE_VALUE) {
  166. SetupDiDestroyDeviceInfoList(hDevInfo);
  167. }
  168. DeskCloseLog();
  169. return ERROR_SUCCESS;
  170. }
  171. BOOL
  172. MigrateUnattendedSettings(
  173. HDEVINFO hDevInfo
  174. )
  175. {
  176. INFCONTEXT context;
  177. HINF hInf;
  178. TCHAR szName[128];
  179. DWORD value;
  180. DWORD cFields = 0;
  181. DWORD BitsPerPel = 0, XResolution = 0, YResolution = 0, VRefresh = 0;
  182. DWORD UsePreferredMode = 0;
  183. DWORD AttachedToDesktop = 0;
  184. SP_DEVINFO_DATA DevInfoData;
  185. SP_DEVICE_INTERFACE_DATA InterfaceData;
  186. HKEY hInterfaceKey = (HKEY)INVALID_HANDLE_VALUE;
  187. HKEY hInterfaceLogicalDeviceKey = (HKEY)INVALID_HANDLE_VALUE;
  188. DWORD DevInfoIndex = 0;
  189. //
  190. // Get the handle to the answer file
  191. //
  192. hInf = g_SetupInitComponent.HelperRoutines.GetInfHandle(
  193. INFINDEX_UNATTENDED,
  194. g_SetupInitComponent.HelperRoutines.OcManagerContext);
  195. if ((hInf == NULL) ||
  196. (hInf == (HINF)INVALID_HANDLE_VALUE)) {
  197. return FALSE;
  198. }
  199. //
  200. // Read the settings from the answer file
  201. //
  202. if (SetupFindFirstLine(hInf, TEXT("Display"), NULL, &context)) {
  203. do {
  204. if (SetupGetStringField(&context,
  205. 0,
  206. szName,
  207. ARRAYSIZE(szName),
  208. &value)) {
  209. if (lstrcmpi(szName, TEXT("BitsPerPel")) == 0) {
  210. if (SetupGetIntField(&context, 1, (PINT)&value)) {
  211. ++cFields;
  212. BitsPerPel = value;
  213. } else {
  214. SetupGetStringField(&context,
  215. 1,
  216. szName,
  217. ARRAYSIZE(szName),
  218. &value);
  219. DeskLogError(LogSevInformation,
  220. IDS_SETUPLOG_MSG_096,
  221. szName);
  222. }
  223. } else if (lstrcmpi(szName, TEXT("Xresolution")) == 0) {
  224. if (SetupGetIntField(&context, 1, (PINT)&value)) {
  225. ++cFields;
  226. XResolution = value;
  227. } else {
  228. SetupGetStringField(&context,
  229. 1,
  230. szName,
  231. ARRAYSIZE(szName),
  232. &value);
  233. DeskLogError(LogSevInformation, IDS_SETUPLOG_MSG_060);
  234. }
  235. } else if (lstrcmpi(szName, TEXT("YResolution")) == 0) {
  236. if (SetupGetIntField(&context, 1, (PINT) &value)) {
  237. ++cFields;
  238. YResolution = value;
  239. } else {
  240. SetupGetStringField(&context,
  241. 1,
  242. szName,
  243. ARRAYSIZE(szName),
  244. &value);
  245. DeskLogError(LogSevInformation,
  246. IDS_SETUPLOG_MSG_062,
  247. szName);
  248. }
  249. } else if (lstrcmpi( szName, TEXT("VRefresh")) == 0) {
  250. if (SetupGetIntField(&context, 1, (PINT) &value)) {
  251. ++cFields;
  252. VRefresh = value;
  253. } else {
  254. SetupGetStringField(&context,
  255. 1,
  256. szName,
  257. ARRAYSIZE(szName),
  258. &value);
  259. DeskLogError(LogSevInformation,
  260. IDS_SETUPLOG_MSG_064,
  261. szName);
  262. }
  263. } else {
  264. DeskLogError(LogSevInformation,
  265. IDS_SETUPLOG_MSG_065,
  266. szName);
  267. }
  268. }
  269. } while (SetupFindNextLine(&context, &context));
  270. }
  271. if (cFields == 0) {
  272. //
  273. // The answer file doesn't contain any display settings
  274. //
  275. goto Fallout;
  276. }
  277. //
  278. // "Normalize" the display settings
  279. //
  280. AttachedToDesktop = 1;
  281. if (BitsPerPel == 0) {
  282. DeskLogError(LogSevInformation,
  283. IDS_SETUPLOG_MSG_069,
  284. DEFAULT_BPP);
  285. BitsPerPel = DEFAULT_BPP;
  286. }
  287. if ((XResolution == 0) || (YResolution == 0)) {
  288. DeskLogError(LogSevInformation,
  289. IDS_SETUPLOG_MSG_067,
  290. DEFAULT_XRESOLUTION,
  291. DEFAULT_YRESOLUTION);
  292. XResolution = DEFAULT_XRESOLUTION;
  293. YResolution = DEFAULT_YRESOLUTION;
  294. }
  295. if (VRefresh == 0) {
  296. DeskLogError(LogSevInformation,
  297. IDS_SETUPLOG_MSG_068,
  298. DEFAULT_VREFRESH);
  299. VRefresh = DEFAULT_VREFRESH;
  300. }
  301. //
  302. // Apply the display settings to all video cards
  303. //
  304. DevInfoIndex = 0;
  305. DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  306. while (SetupDiEnumDeviceInfo(hDevInfo, DevInfoIndex, &DevInfoData)) {
  307. InterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
  308. if (!SetupDiCreateDeviceInterface(hDevInfo,
  309. &DevInfoData,
  310. &GUID_DISPLAY_ADAPTER_INTERFACE,
  311. NULL,
  312. 0,
  313. &InterfaceData)) {
  314. DeskLogError(LogSevInformation, IDS_SETUPLOG_MSG_103);
  315. goto NextDevice;
  316. }
  317. hInterfaceKey = SetupDiCreateDeviceInterfaceRegKey(hDevInfo,
  318. &InterfaceData,
  319. 0,
  320. KEY_SET_VALUE,
  321. NULL,
  322. NULL);
  323. if (hInterfaceKey == INVALID_HANDLE_VALUE) {
  324. DeskLogError(LogSevInformation, IDS_SETUPLOG_MSG_104);
  325. goto NextDevice;
  326. }
  327. if (RegCreateKeyEx(hInterfaceKey,
  328. TEXT("0"),
  329. 0,
  330. NULL,
  331. REG_OPTION_NON_VOLATILE,
  332. KEY_WRITE,
  333. NULL,
  334. &hInterfaceLogicalDeviceKey,
  335. NULL) != ERROR_SUCCESS) {
  336. DeskLogError(LogSevInformation, IDS_SETUPLOG_MSG_105, 0);
  337. hInterfaceLogicalDeviceKey = (HKEY)INVALID_HANDLE_VALUE;
  338. goto NextDevice;
  339. }
  340. //
  341. // Do not use the preferred mode for unattended installs
  342. //
  343. UsePreferredMode = 0;
  344. RegSetValueEx(hInterfaceLogicalDeviceKey,
  345. SZ_VU_PREFERRED_MODE,
  346. 0,
  347. REG_DWORD,
  348. (PBYTE)&UsePreferredMode,
  349. sizeof(UsePreferredMode));
  350. //
  351. // AttachedToDesktop
  352. //
  353. RegSetValueEx(hInterfaceLogicalDeviceKey,
  354. SZ_VU_ATTACHED_TO_DESKTOP,
  355. 0,
  356. REG_DWORD,
  357. (PBYTE)&AttachedToDesktop,
  358. sizeof(AttachedToDesktop));
  359. //
  360. // BitsPerPel
  361. //
  362. if (RegSetValueEx(hInterfaceLogicalDeviceKey,
  363. SZ_VU_BITS_PER_PEL,
  364. 0,
  365. REG_DWORD,
  366. (PBYTE)&BitsPerPel,
  367. sizeof(BitsPerPel)) == ERROR_SUCCESS) {
  368. DeskLogError(LogSevInformation,
  369. IDS_SETUPLOG_MSG_106,
  370. BitsPerPel);
  371. }
  372. //
  373. // XResolution
  374. //
  375. if (RegSetValueEx(hInterfaceLogicalDeviceKey,
  376. SZ_VU_X_RESOLUTION,
  377. 0,
  378. REG_DWORD,
  379. (PBYTE)&XResolution,
  380. sizeof(XResolution)) == ERROR_SUCCESS) {
  381. DeskLogError(LogSevInformation,
  382. IDS_SETUPLOG_MSG_107,
  383. XResolution);
  384. }
  385. //
  386. // dwYResolution
  387. //
  388. if (RegSetValueEx(hInterfaceLogicalDeviceKey,
  389. SZ_VU_Y_RESOLUTION,
  390. 0,
  391. REG_DWORD,
  392. (PBYTE)&YResolution,
  393. sizeof(YResolution)) == ERROR_SUCCESS) {
  394. DeskLogError(LogSevInformation,
  395. IDS_SETUPLOG_MSG_108,
  396. YResolution);
  397. }
  398. //
  399. // dwVRefresh
  400. //
  401. if (RegSetValueEx(hInterfaceLogicalDeviceKey,
  402. SZ_VU_VREFRESH,
  403. 0,
  404. REG_DWORD,
  405. (PBYTE)&VRefresh,
  406. sizeof(VRefresh)) == ERROR_SUCCESS) {
  407. DeskLogError(LogSevInformation,
  408. IDS_SETUPLOG_MSG_109,
  409. VRefresh);
  410. }
  411. NextDevice:
  412. if (hInterfaceLogicalDeviceKey != INVALID_HANDLE_VALUE) {
  413. RegCloseKey(hInterfaceLogicalDeviceKey);
  414. hInterfaceLogicalDeviceKey = (HKEY)INVALID_HANDLE_VALUE;
  415. }
  416. if (hInterfaceKey != INVALID_HANDLE_VALUE) {
  417. RegCloseKey(hInterfaceKey);
  418. hInterfaceKey = (HKEY)INVALID_HANDLE_VALUE;
  419. }
  420. DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  421. ++DevInfoIndex;
  422. }
  423. Fallout:
  424. return (cFields != 0);
  425. }
  426. VOID
  427. MigrateRegistrySettings(
  428. HDEVINFO hDevInfo
  429. )
  430. {
  431. HKEY hKey = 0, hPhysicalDeviceKey = 0;
  432. DWORD PhysicalDevicesCount = 0, LogicalDevicesCount = 0;
  433. DWORD cb = 0, PhysicalDevice = 0, Failed = 0;
  434. TCHAR Buffer[20];
  435. BOOL IsLegacy;
  436. DWORD BusNumber = 0, Address = 0;
  437. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  438. SZ_UPDATE_SETTINGS,
  439. 0,
  440. KEY_READ,
  441. &hKey) != ERROR_SUCCESS) {
  442. DeskLogError(LogSevInformation, IDS_SETUPLOG_MSG_075);
  443. hKey = 0;
  444. goto Cleanup;
  445. }
  446. cb = sizeof(DWORD);
  447. if ((RegQueryValueEx(hKey,
  448. SZ_UPGRADE_FAILED_ALLOW_INSTALL,
  449. NULL,
  450. NULL,
  451. (LPBYTE)&Failed,
  452. &cb) == ERROR_SUCCESS) &&
  453. (Failed != 0)) {
  454. DeskLogError(LogSevInformation, IDS_SETUPLOG_MSG_076);
  455. goto Cleanup;
  456. }
  457. cb = sizeof(PhysicalDevicesCount);
  458. if (RegQueryValueEx(hKey,
  459. SZ_VU_COUNT,
  460. 0,
  461. NULL,
  462. (PBYTE)&PhysicalDevicesCount,
  463. &cb) != ERROR_SUCCESS) {
  464. DeskLogError(LogSevInformation, IDS_SETUPLOG_MSG_110);
  465. goto Cleanup;
  466. }
  467. for(PhysicalDevice = 0;
  468. PhysicalDevice < PhysicalDevicesCount;
  469. PhysicalDevice++) {
  470. _tcscpy(Buffer, SZ_VU_PHYSICAL);
  471. _stprintf(Buffer + _tcslen(Buffer), TEXT("%d"), PhysicalDevice);
  472. if (RegOpenKeyEx(hKey,
  473. Buffer,
  474. 0,
  475. KEY_READ,
  476. &hPhysicalDeviceKey) != ERROR_SUCCESS) {
  477. DeskLogError(LogSevInformation, IDS_SETUPLOG_MSG_111);
  478. hPhysicalDeviceKey = 0;
  479. goto NextPhysicalDevice;
  480. }
  481. //
  482. // Get the count of logical devices
  483. //
  484. cb = sizeof(LogicalDevicesCount);
  485. if (RegQueryValueEx(hPhysicalDeviceKey,
  486. SZ_VU_COUNT,
  487. 0,
  488. NULL,
  489. (PBYTE)&LogicalDevicesCount,
  490. &cb) != ERROR_SUCCESS) {
  491. DeskLogError(LogSevInformation, IDS_SETUPLOG_MSG_112);
  492. goto NextPhysicalDevice;
  493. }
  494. //
  495. // Get the bus number and address
  496. //
  497. IsLegacy = TRUE;
  498. cb = sizeof(BusNumber);
  499. if (RegQueryValueEx(hPhysicalDeviceKey,
  500. SZ_VU_BUS_NUMBER,
  501. 0,
  502. NULL,
  503. (PBYTE)&BusNumber,
  504. &cb) == ERROR_SUCCESS) {
  505. cb = sizeof(Address);
  506. if (RegQueryValueEx(hPhysicalDeviceKey,
  507. SZ_VU_ADDRESS,
  508. 0,
  509. NULL,
  510. (PBYTE)&Address,
  511. &cb) == ERROR_SUCCESS) {
  512. IsLegacy = FALSE;
  513. }
  514. }
  515. if (!IsLegacy) {
  516. MigrateRegistrySettingsBasedOnBusLocation(hDevInfo,
  517. hPhysicalDeviceKey,
  518. LogicalDevicesCount,
  519. BusNumber,
  520. Address);
  521. } else if ((PhysicalDevicesCount == 1) &&
  522. (LogicalDevicesCount == 1)) {
  523. //
  524. // If legacy, we support migration of a single device.
  525. //
  526. MigrateRegistrySettingsLegacy(hDevInfo,
  527. hPhysicalDeviceKey);
  528. }
  529. NextPhysicalDevice:
  530. if (hPhysicalDeviceKey != 0) {
  531. RegCloseKey(hPhysicalDeviceKey);
  532. hPhysicalDeviceKey = 0;
  533. }
  534. }
  535. Cleanup:
  536. if (hKey != 0) {
  537. RegCloseKey(hKey);
  538. }
  539. return;
  540. }
  541. VOID
  542. MigrateRegistrySettingsBasedOnBusLocation(
  543. HDEVINFO hDevInfo,
  544. HKEY hPhysicalDeviceKey,
  545. DWORD LogicalDevicesCount,
  546. DWORD BusNumber,
  547. DWORD Address
  548. )
  549. {
  550. SP_DEVINFO_DATA DevInfoData;
  551. DWORD CurrentBusNumber = 0, CurrentAddress = 0;
  552. DWORD DevInfoIndex = 0;
  553. BOOL bFound = FALSE;
  554. //
  555. // Let's find the device with the same bus number and address
  556. //
  557. DevInfoIndex = 0;
  558. DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  559. while (SetupDiEnumDeviceInfo(hDevInfo, DevInfoIndex, &DevInfoData)) {
  560. if (SetupDiGetDeviceRegistryProperty(hDevInfo,
  561. &DevInfoData,
  562. SPDRP_BUSNUMBER,
  563. NULL,
  564. (PBYTE)&CurrentBusNumber,
  565. sizeof(CurrentBusNumber),
  566. NULL) &&
  567. (CurrentBusNumber == BusNumber) &&
  568. SetupDiGetDeviceRegistryProperty(hDevInfo,
  569. &DevInfoData,
  570. SPDRP_ADDRESS,
  571. NULL,
  572. (PBYTE)&CurrentAddress,
  573. sizeof(CurrentAddress),
  574. NULL) &&
  575. (CurrentAddress == Address)) {
  576. //
  577. // We found the device with the same bus number and address
  578. // So ... migrate the settings
  579. //
  580. MigrateRegistrySettingsHelper(hDevInfo,
  581. &DevInfoData,
  582. hPhysicalDeviceKey,
  583. LogicalDevicesCount);
  584. //
  585. // We are done
  586. //
  587. bFound = TRUE;
  588. break;
  589. }
  590. //
  591. // Next device
  592. //
  593. DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  594. ++DevInfoIndex;
  595. }
  596. if (!bFound) {
  597. DeskLogError(LogSevInformation, IDS_SETUPLOG_MSG_113);
  598. }
  599. return;
  600. }
  601. VOID
  602. MigrateRegistrySettingsLegacy(
  603. HDEVINFO hDevInfo,
  604. HKEY hPhysicalDeviceKey
  605. )
  606. {
  607. SP_DEVINFO_DATA DevInfoData0, DevInfoData1;
  608. DevInfoData0.cbSize = sizeof(SP_DEVINFO_DATA);
  609. if (!SetupDiEnumDeviceInfo(hDevInfo, 0, &DevInfoData0)) {
  610. DeskLogError(LogSevInformation, IDS_SETUPLOG_MSG_115);
  611. return;
  612. }
  613. DevInfoData1.cbSize = sizeof(SP_DEVINFO_DATA);
  614. if (SetupDiEnumDeviceInfo(hDevInfo, 1, &DevInfoData1)) {
  615. //
  616. // There are at least 2 video devices in the system
  617. // We don't know which device to apply the settings to.
  618. // So, just ignore this case
  619. //
  620. DeskLogError(LogSevInformation, IDS_SETUPLOG_MSG_114);
  621. return;
  622. }
  623. MigrateRegistrySettingsHelper(hDevInfo,
  624. &DevInfoData0,
  625. hPhysicalDeviceKey,
  626. 1); // there is only one logical device
  627. }
  628. VOID
  629. MigrateRegistrySettingsHelper(
  630. HDEVINFO hDevInfo,
  631. PSP_DEVINFO_DATA pDevInfoData,
  632. HKEY hPhysicalDeviceKey,
  633. DWORD LogicalDevicesCount
  634. )
  635. {
  636. SP_DEVICE_INTERFACE_DATA InterfaceData;
  637. HKEY hInterfaceKey = 0;
  638. HKEY hInterfaceLogicalDeviceKey = 0;
  639. HKEY hLogicalDeviceKey = 0;
  640. TCHAR Buffer[20];
  641. DWORD cb = 0, LogicalDevice = 0;
  642. DWORD UsePreferredMode = 0;
  643. DWORD AttachedToDesktop = 0;
  644. DWORD RelativeX = 0;
  645. DWORD RelativeY = 0;
  646. DWORD BitsPerPel = 0;
  647. DWORD XResolution = 0;
  648. DWORD YResolution = 0;
  649. DWORD VRefresh = 0;
  650. DWORD Flags = 0;
  651. InterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
  652. if (!SetupDiCreateDeviceInterface(hDevInfo,
  653. pDevInfoData,
  654. &GUID_DISPLAY_ADAPTER_INTERFACE,
  655. NULL,
  656. 0,
  657. &InterfaceData)) {
  658. DeskLogError(LogSevInformation, IDS_SETUPLOG_MSG_103);
  659. return;
  660. }
  661. hInterfaceKey = SetupDiCreateDeviceInterfaceRegKey(hDevInfo,
  662. &InterfaceData,
  663. 0,
  664. KEY_SET_VALUE,
  665. NULL,
  666. NULL);
  667. if (hInterfaceKey == INVALID_HANDLE_VALUE) {
  668. DeskLogError(LogSevInformation, IDS_SETUPLOG_MSG_104);
  669. return;
  670. }
  671. for (LogicalDevice = 0;
  672. LogicalDevice < LogicalDevicesCount;
  673. ++LogicalDevice) {
  674. _tcscpy(Buffer, SZ_VU_LOGICAL);
  675. _stprintf(Buffer + _tcslen(Buffer), TEXT("%d"), LogicalDevice);
  676. if (RegOpenKeyEx(hPhysicalDeviceKey,
  677. Buffer,
  678. 0,
  679. KEY_READ,
  680. &hLogicalDeviceKey) != ERROR_SUCCESS) {
  681. //
  682. // We can not go on with this physical device
  683. // The LogicalDevices order is important for DualView
  684. //
  685. DeskLogError(LogSevInformation, IDS_SETUPLOG_MSG_116);
  686. break;
  687. }
  688. _stprintf(Buffer, TEXT("%d"), LogicalDevice);
  689. if (RegCreateKeyEx(hInterfaceKey,
  690. Buffer,
  691. 0,
  692. NULL,
  693. REG_OPTION_NON_VOLATILE,
  694. KEY_WRITE,
  695. NULL,
  696. &hInterfaceLogicalDeviceKey,
  697. NULL) != ERROR_SUCCESS) {
  698. //
  699. // We can not go on with this physical device
  700. // The LogicalDevices order is important for DualView
  701. //
  702. DeskLogError(LogSevInformation, IDS_SETUPLOG_MSG_105, LogicalDevice);
  703. RegCloseKey(hLogicalDeviceKey);
  704. break;
  705. }
  706. //
  707. // Use preferred mode?
  708. //
  709. cb = sizeof(XResolution);
  710. if (RegQueryValueEx(hLogicalDeviceKey,
  711. SZ_VU_X_RESOLUTION,
  712. 0,
  713. NULL,
  714. (PBYTE)&XResolution,
  715. &cb) != ERROR_SUCCESS) {
  716. XResolution = DEFAULT_XRESOLUTION;
  717. }
  718. cb = sizeof(YResolution);
  719. if (RegQueryValueEx(hLogicalDeviceKey,
  720. SZ_VU_Y_RESOLUTION,
  721. 0,
  722. NULL,
  723. (PBYTE)&YResolution,
  724. &cb) != ERROR_SUCCESS) {
  725. YResolution = DEFAULT_YRESOLUTION;
  726. }
  727. UsePreferredMode = ((XResolution < MIN_XRESOLUTION) ||
  728. (YResolution < MIN_YRESOLUTION));
  729. RegSetValueEx(hInterfaceLogicalDeviceKey,
  730. SZ_VU_PREFERRED_MODE,
  731. 0,
  732. REG_DWORD,
  733. (PBYTE)&UsePreferredMode,
  734. sizeof(UsePreferredMode));
  735. if (UsePreferredMode) {
  736. DeskLogError(LogSevInformation,
  737. IDS_SETUPLOG_MSG_130);
  738. } else {
  739. //
  740. // AttachedToDesktop
  741. //
  742. cb = sizeof(AttachedToDesktop);
  743. if (RegQueryValueEx(hLogicalDeviceKey,
  744. SZ_VU_ATTACHED_TO_DESKTOP,
  745. 0,
  746. NULL,
  747. (PBYTE)&AttachedToDesktop,
  748. &cb) == ERROR_SUCCESS) {
  749. if (RegSetValueEx(hInterfaceLogicalDeviceKey,
  750. SZ_VU_ATTACHED_TO_DESKTOP,
  751. 0,
  752. REG_DWORD,
  753. (PBYTE)&AttachedToDesktop,
  754. sizeof(AttachedToDesktop)) == ERROR_SUCCESS) {
  755. DeskLogError(LogSevInformation,
  756. IDS_SETUPLOG_MSG_117,
  757. AttachedToDesktop);
  758. }
  759. }
  760. //
  761. // RelativeX
  762. //
  763. cb = sizeof(RelativeX);
  764. if (RegQueryValueEx(hLogicalDeviceKey,
  765. SZ_VU_RELATIVE_X,
  766. 0,
  767. NULL,
  768. (PBYTE)&RelativeX,
  769. &cb) == ERROR_SUCCESS) {
  770. if (RegSetValueEx(hInterfaceLogicalDeviceKey,
  771. SZ_VU_RELATIVE_X,
  772. 0,
  773. REG_DWORD,
  774. (PBYTE)&RelativeX,
  775. sizeof(RelativeX)) == ERROR_SUCCESS) {
  776. DeskLogError(LogSevInformation,
  777. IDS_SETUPLOG_MSG_118,
  778. RelativeX);
  779. }
  780. }
  781. //
  782. // RelativeY
  783. //
  784. cb = sizeof(RelativeY);
  785. if (RegQueryValueEx(hLogicalDeviceKey,
  786. SZ_VU_RELATIVE_Y,
  787. 0,
  788. NULL,
  789. (PBYTE)&RelativeY,
  790. &cb) == ERROR_SUCCESS) {
  791. if (RegSetValueEx(hInterfaceLogicalDeviceKey,
  792. SZ_VU_RELATIVE_Y,
  793. 0,
  794. REG_DWORD,
  795. (PBYTE)&RelativeY,
  796. sizeof(RelativeY)) == ERROR_SUCCESS) {
  797. DeskLogError(LogSevInformation,
  798. IDS_SETUPLOG_MSG_119,
  799. RelativeY);
  800. }
  801. }
  802. //
  803. // BitsPerPel
  804. //
  805. cb = sizeof(BitsPerPel);
  806. if (RegQueryValueEx(hLogicalDeviceKey,
  807. SZ_VU_BITS_PER_PEL,
  808. 0,
  809. NULL,
  810. (PBYTE)&BitsPerPel,
  811. &cb) == ERROR_SUCCESS) {
  812. if (RegSetValueEx(hInterfaceLogicalDeviceKey,
  813. SZ_VU_BITS_PER_PEL,
  814. 0,
  815. REG_DWORD,
  816. (PBYTE)&BitsPerPel,
  817. sizeof(BitsPerPel)) == ERROR_SUCCESS) {
  818. DeskLogError(LogSevInformation,
  819. IDS_SETUPLOG_MSG_120,
  820. BitsPerPel);
  821. }
  822. }
  823. //
  824. // XResolution
  825. //
  826. if (RegSetValueEx(hInterfaceLogicalDeviceKey,
  827. SZ_VU_X_RESOLUTION,
  828. 0,
  829. REG_DWORD,
  830. (PBYTE)&XResolution,
  831. sizeof(XResolution)) == ERROR_SUCCESS) {
  832. DeskLogError(LogSevInformation,
  833. IDS_SETUPLOG_MSG_121,
  834. XResolution);
  835. }
  836. //
  837. // dwYResolution
  838. //
  839. if (RegSetValueEx(hInterfaceLogicalDeviceKey,
  840. SZ_VU_Y_RESOLUTION,
  841. 0,
  842. REG_DWORD,
  843. (PBYTE)&YResolution,
  844. sizeof(YResolution)) == ERROR_SUCCESS) {
  845. DeskLogError(LogSevInformation,
  846. IDS_SETUPLOG_MSG_122,
  847. YResolution);
  848. }
  849. //
  850. // dwVRefresh
  851. //
  852. cb = sizeof(VRefresh);
  853. if (RegQueryValueEx(hLogicalDeviceKey,
  854. SZ_VU_VREFRESH,
  855. 0,
  856. NULL,
  857. (PBYTE)&VRefresh,
  858. &cb) == ERROR_SUCCESS) {
  859. if (RegSetValueEx(hInterfaceLogicalDeviceKey,
  860. SZ_VU_VREFRESH,
  861. 0,
  862. REG_DWORD,
  863. (PBYTE)&VRefresh,
  864. sizeof(VRefresh)) == ERROR_SUCCESS) {
  865. DeskLogError(LogSevInformation,
  866. IDS_SETUPLOG_MSG_123,
  867. VRefresh);
  868. }
  869. }
  870. //
  871. // Flags
  872. //
  873. cb = sizeof(Flags);
  874. if (RegQueryValueEx(hLogicalDeviceKey,
  875. SZ_VU_FLAGS,
  876. 0,
  877. NULL,
  878. (PBYTE)&Flags,
  879. &cb) == ERROR_SUCCESS) {
  880. if (RegSetValueEx(hInterfaceLogicalDeviceKey,
  881. SZ_VU_FLAGS,
  882. 0,
  883. REG_DWORD,
  884. (PBYTE)&Flags,
  885. sizeof(Flags)) == ERROR_SUCCESS) {
  886. DeskLogError(LogSevInformation,
  887. IDS_SETUPLOG_MSG_124,
  888. Flags);
  889. }
  890. }
  891. }
  892. //
  893. // Migrate the hardware acceleration and the pruning mode
  894. //
  895. MigrateDeviceKeySettings(hDevInfo,
  896. pDevInfoData,
  897. hLogicalDeviceKey,
  898. LogicalDevice);
  899. RegCloseKey(hLogicalDeviceKey);
  900. RegCloseKey(hInterfaceLogicalDeviceKey);
  901. }
  902. RegCloseKey(hInterfaceKey);
  903. }
  904. VOID
  905. MigrateDeviceKeySettings(
  906. HDEVINFO hDevInfo,
  907. PSP_DEVINFO_DATA pDevInfoData,
  908. HKEY hLogicalDeviceKey,
  909. DWORD Index
  910. )
  911. {
  912. HKEY hkPnP = (HKEY)INVALID_HANDLE_VALUE;
  913. HKEY hkDevice = (HKEY)INVALID_HANDLE_VALUE;
  914. LPTSTR pBuffer = NULL;
  915. DWORD dwSize, len, cb;
  916. DWORD HwAcceleration, PruningMode;
  917. //
  918. // Open the PnP key
  919. //
  920. hkPnP = SetupDiOpenDevRegKey(hDevInfo,
  921. pDevInfoData,
  922. DICS_FLAG_GLOBAL,
  923. 0,
  924. DIREG_DEV,
  925. KEY_READ);
  926. if (hkPnP == INVALID_HANDLE_VALUE) {
  927. DeskLogError(LogSevInformation,
  928. IDS_SETUPLOG_MSG_127,
  929. TEXT("SetupDiOpenDevRegKey"));
  930. goto Fallout;
  931. }
  932. //
  933. // Try to get the GUID from the PnP key
  934. //
  935. dwSize = 0;
  936. if (RegQueryValueEx(hkPnP,
  937. SZ_GUID,
  938. 0,
  939. NULL,
  940. NULL,
  941. &dwSize) != ERROR_SUCCESS) {
  942. DeskLogError(LogSevInformation,
  943. IDS_SETUPLOG_MSG_127,
  944. TEXT("RegQueryValueEx"));
  945. goto Fallout;
  946. }
  947. len = _tcslen(SZ_VIDEO_DEVICES);
  948. pBuffer = (LPTSTR)LocalAlloc(LPTR,
  949. dwSize + (len + 6) * sizeof(TCHAR));
  950. if (pBuffer == NULL) {
  951. DeskLogError(LogSevInformation,
  952. IDS_SETUPLOG_MSG_127,
  953. TEXT("LocalAlloc"));
  954. goto Fallout;
  955. }
  956. _tcscpy(pBuffer, SZ_VIDEO_DEVICES);
  957. if (RegQueryValueEx(hkPnP,
  958. SZ_GUID,
  959. 0,
  960. NULL,
  961. (PBYTE)(pBuffer + len),
  962. &dwSize) != ERROR_SUCCESS) {
  963. DeskLogError(LogSevInformation,
  964. IDS_SETUPLOG_MSG_127,
  965. TEXT("RegQueryValueEx"));
  966. goto Fallout;
  967. }
  968. _stprintf(pBuffer + _tcslen(pBuffer), L"\\%04d", Index);
  969. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  970. pBuffer,
  971. 0,
  972. KEY_WRITE,
  973. &hkDevice) != ERROR_SUCCESS) {
  974. DeskLogError(LogSevInformation,
  975. IDS_SETUPLOG_MSG_127,
  976. TEXT("RegOpenKeyEx"));
  977. hkDevice = (HKEY)INVALID_HANDLE_VALUE;
  978. goto Fallout;
  979. }
  980. //
  981. // Hardware acceleration
  982. //
  983. cb = sizeof(HwAcceleration);
  984. if (RegQueryValueEx(hLogicalDeviceKey,
  985. SZ_HW_ACCELERATION,
  986. 0,
  987. NULL,
  988. (PBYTE)&HwAcceleration,
  989. &cb) == ERROR_SUCCESS) {
  990. RegSetValueEx(hkDevice,
  991. SZ_HW_ACCELERATION,
  992. 0,
  993. REG_DWORD,
  994. (PBYTE)&HwAcceleration,
  995. sizeof(HwAcceleration));
  996. }
  997. //
  998. // Pruning mode
  999. //
  1000. cb = sizeof(PruningMode);
  1001. if (RegQueryValueEx(hLogicalDeviceKey,
  1002. SZ_PRUNNING_MODE,
  1003. 0,
  1004. NULL,
  1005. (PBYTE)&PruningMode,
  1006. &cb) == ERROR_SUCCESS) {
  1007. RegSetValueEx(hkDevice,
  1008. SZ_PRUNNING_MODE,
  1009. 0,
  1010. REG_DWORD,
  1011. (PBYTE)&PruningMode,
  1012. sizeof(PruningMode));
  1013. }
  1014. Fallout:
  1015. if (hkPnP != INVALID_HANDLE_VALUE) {
  1016. RegCloseKey(hkPnP);
  1017. }
  1018. if (pBuffer != NULL) {
  1019. LocalFree(pBuffer);
  1020. }
  1021. if (hkDevice != INVALID_HANDLE_VALUE) {
  1022. RegCloseKey(hkDevice);
  1023. }
  1024. }
  1025. ///////////////////////////////////////////////////////////////////////////////
  1026. ///////////////////////////////////////////////////////////////////////////////
  1027. ///////////////////////////////////////////////////////////////////////////////
  1028. ///////////////////////////////////////////////////////////////////////////////
  1029. ///////////////////////////////////////////////////////////////////////////////
  1030. ///////////////////////////////////////////////////////////////////////////////
  1031. // type constants for DrawArrow
  1032. #define AW_TOP 1 // top
  1033. #define AW_BOTTOM 2 // bottom
  1034. #define AW_LEFT 3 // left
  1035. #define AW_RIGHT 4 // right
  1036. #define CCH_MAX_STRING 256
  1037. typedef struct _NEW_DESKTOP_PARAM {
  1038. LPDEVMODE lpdevmode;
  1039. LPTSTR pwszDevice;
  1040. DWORD dwTimeout;
  1041. } NEW_DESKTOP_PARAM, *PNEW_DESKTOP_PARAM;
  1042. // table of resolutions that we show off.
  1043. // if the resolution is larger, then we show that one too.
  1044. typedef struct tagRESTAB {
  1045. INT xRes;
  1046. INT yRes;
  1047. COLORREF crColor; // color to paint this resolution
  1048. } RESTAB;
  1049. RESTAB ResTab[] ={
  1050. { 1600, 1200, RGB(255,0,0)},
  1051. { 1280, 1024, RGB(0,255,0)},
  1052. { 1152, 900, RGB(0,0,255)},
  1053. { 1024, 768, RGB(255,0,0)},
  1054. { 800, 600, RGB(0,255,0)},
  1055. // 640x480 or 640x400 handled specially
  1056. { 0, 0, 0} // end of table
  1057. };
  1058. DWORD WINAPI
  1059. ApplyNowThd(
  1060. LPVOID lpThreadParameter
  1061. );
  1062. void
  1063. DrawBmp(
  1064. HDC hDC
  1065. );
  1066. VOID
  1067. LabelResolution(
  1068. HDC hDC,
  1069. INT xmin,
  1070. INT ymin,
  1071. INT xmax,
  1072. INT ymax
  1073. );
  1074. static VOID
  1075. PaintRect(
  1076. HDC hDC,
  1077. INT lowx,
  1078. INT lowy,
  1079. INT highx,
  1080. INT highy,
  1081. COLORREF rgb,
  1082. UINT idString
  1083. );
  1084. VOID
  1085. DrawArrows(
  1086. HDC hDC,
  1087. INT xRes,
  1088. INT yRes
  1089. );
  1090. static VOID
  1091. LabelRect(
  1092. HDC hDC,
  1093. PRECT pRect,
  1094. UINT idString
  1095. );
  1096. static VOID
  1097. DrawArrow(
  1098. HDC hDC,
  1099. INT type,
  1100. INT xPos,
  1101. INT yPos,
  1102. COLORREF crPenColor
  1103. );
  1104. VOID
  1105. MakeRect(
  1106. PRECT pRect,
  1107. INT xmin,
  1108. INT ymin,
  1109. INT xmax,
  1110. INT ymax
  1111. );
  1112. DWORD
  1113. DisplayTestSettingsW(
  1114. LPDEVMODEW lpDevMode,
  1115. LPWSTR pwszDevice,
  1116. DWORD dwTimeout
  1117. )
  1118. {
  1119. HANDLE hThread;
  1120. DWORD idThread;
  1121. DWORD bTest;
  1122. NEW_DESKTOP_PARAM desktopParam;
  1123. if (!lpDevMode || !pwszDevice)
  1124. return FALSE;
  1125. if (dwTimeout == 0)
  1126. dwTimeout = NORMAL_TIMEOUT;
  1127. desktopParam.lpdevmode = lpDevMode;
  1128. desktopParam.pwszDevice = pwszDevice;
  1129. desktopParam.dwTimeout = dwTimeout;
  1130. hThread = CreateThread(NULL,
  1131. 4096,
  1132. ApplyNowThd,
  1133. (LPVOID) &desktopParam,
  1134. SYNCHRONIZE | THREAD_QUERY_INFORMATION,
  1135. &idThread
  1136. );
  1137. WaitForSingleObject(hThread, INFINITE);
  1138. GetExitCodeThread(hThread, &bTest);
  1139. CloseHandle(hThread);
  1140. return bTest;
  1141. }
  1142. DWORD WINAPI
  1143. ApplyNowThd(
  1144. LPVOID lpThreadParameter
  1145. )
  1146. {
  1147. PNEW_DESKTOP_PARAM lpDesktopParam = (PNEW_DESKTOP_PARAM) lpThreadParameter;
  1148. HDESK hdsk = NULL;
  1149. HDESK hdskDefault = NULL;
  1150. BOOL bTest = FALSE;
  1151. HDC hdc;
  1152. //
  1153. // HACK:
  1154. // We need to make a USER call before calling the desktop stuff so we can
  1155. // sure our threads internal data structure are associated with the default
  1156. // desktop.
  1157. // Otherwise USER has problems closing the desktop with our thread on it.
  1158. //
  1159. GetSystemMetrics(SM_CXSCREEN);
  1160. //
  1161. // Create the desktop
  1162. //
  1163. hdskDefault = GetThreadDesktop(GetCurrentThreadId());
  1164. if (hdskDefault != NULL) {
  1165. hdsk = CreateDesktop(TEXT("Display.Cpl Desktop"),
  1166. lpDesktopParam->pwszDevice,
  1167. lpDesktopParam->lpdevmode,
  1168. 0,
  1169. MAXIMUM_ALLOWED,
  1170. NULL);
  1171. if (hdsk != NULL) {
  1172. //
  1173. // use the desktop for this thread
  1174. //
  1175. if (SetThreadDesktop(hdsk)) {
  1176. hdc = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
  1177. if (hdc) {
  1178. DrawBmp(hdc);
  1179. DeleteDC(hdc);
  1180. bTest = TRUE;
  1181. }
  1182. //
  1183. // Sleep for some seconds so you have time to look at the screen.
  1184. //
  1185. Sleep(lpDesktopParam->dwTimeout);
  1186. }
  1187. }
  1188. //
  1189. // Reset the thread to the right desktop
  1190. //
  1191. SetThreadDesktop(hdskDefault);
  1192. SwitchDesktop(hdskDefault);
  1193. //
  1194. // Can only close the desktop after we have switched to the new one.
  1195. //
  1196. if (hdsk != NULL) {
  1197. CloseDesktop(hdsk);
  1198. }
  1199. }
  1200. ExitThread((DWORD) bTest);
  1201. return 0;
  1202. }
  1203. /****************************************************************************
  1204. FUNCTION: DrawBmp
  1205. PURPOSE: Show off a fancy screen so the user has some idea
  1206. of what will be seen given this resolution, colour
  1207. depth and vertical refresh rate. Note that we do not
  1208. try to simulate the font sizes.
  1209. ****************************************************************************/
  1210. void
  1211. DrawBmp(
  1212. HDC hDC
  1213. )
  1214. {
  1215. INT nBpp; // bits per pixel
  1216. INT nWidth; // width of screen in pixels
  1217. INT nHeight; // height of screen in pixels
  1218. INT xUsed,yUsed; // amount of x and y to use for dense bitmap
  1219. INT dx,dy; // delta x and y for color bars
  1220. RECT rct; // rectangle for passing bounds
  1221. HFONT hPrevFont=0; // previous font in DC
  1222. HFONT hNewFont; // new font if possible
  1223. HPEN hPrevPen; // previous pen handle
  1224. INT x,y,i;
  1225. INT off; // offset in dx units
  1226. hNewFont = (HFONT)NULL;
  1227. if (hNewFont) // if no font, use old
  1228. hPrevFont= (HFONT) SelectObject(hDC, hNewFont);
  1229. // get surface information
  1230. nBpp= GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES);
  1231. nWidth= GetDeviceCaps(hDC, HORZRES);
  1232. nHeight= GetDeviceCaps(hDC, VERTRES);
  1233. // background for everything is yellow.
  1234. PaintRect(hDC, 0, 0, nWidth, nHeight, RGB(255,255,0), 0);
  1235. LabelResolution( hDC, 0,0,nWidth, nHeight );
  1236. // Background for various resolutions
  1237. // biggest ones first
  1238. for(i = 0; ResTab[i].xRes !=0; i++) {
  1239. // Only draw if it will show
  1240. //if ((nWidth >= ResTab[i].xRes) | ( nHeight>=ResTab[i].yRes ) )
  1241. if ((nWidth >= ResTab[i].xRes) || (nHeight >= ResTab[i].yRes)) {
  1242. PaintRect(hDC, 0, 0, ResTab[i].xRes, ResTab[i].yRes, ResTab[i].crColor, 0);
  1243. LabelResolution(hDC, 0, 0, ResTab[i].xRes, ResTab[i].yRes);
  1244. }
  1245. }
  1246. // color bars - only in standard vga area
  1247. xUsed= min(nWidth, 640); // only use vga width
  1248. yUsed= min(nHeight, 480); // could be 400 on some boards
  1249. dx = xUsed / 2;
  1250. dy = yUsed / 6;
  1251. PaintRect(hDC, 0, 0, dx, dy*1, RGB(255,0,0), IDS_COLOR_RED);
  1252. PaintRect(hDC, 0, dy*1, dx, dy*2, RGB(0,255,0), IDS_COLOR_GREEN);
  1253. PaintRect(hDC, 0, dy*2, dx, dy*3, RGB(0,0,255), IDS_COLOR_BLUE);
  1254. PaintRect(hDC, 0, dy*3, dx, dy*4, RGB(255,255,0), IDS_COLOR_YELLOW);
  1255. PaintRect(hDC, 0, dy*4, dx, dy*5, RGB(255,0,255), IDS_COLOR_MAGENTA);
  1256. PaintRect(hDC, 0, dy*5, dx, yUsed, RGB(0,255,255), IDS_COLOR_CYAN);
  1257. // gradations of colors for true color detection
  1258. for (x = dx; x < xUsed; x++) {
  1259. int level;
  1260. level = 255 - (256 * (x-dx)) / dx;
  1261. PaintRect(hDC, x, dy*0, x+1, dy*1, RGB(level,0,0 ), 0);
  1262. PaintRect(hDC, x, dy*1, x+1, dy*2, RGB(0,level,0 ), 0);
  1263. PaintRect(hDC, x, dy*2, x+1, dy*3, RGB(0,0,level ), 0);
  1264. PaintRect(hDC, x, dy*5, x+1, dy*6, RGB(level,level,level), 0);
  1265. }
  1266. MakeRect(&rct, dx, 0, dx * 2, dy * 1);
  1267. LabelRect(hDC, &rct, IDS_RED_SHADES);
  1268. MakeRect(&rct, dx, dy, dx * 2, dy * 2);
  1269. LabelRect(hDC, &rct, IDS_GREEN_SHADES);
  1270. MakeRect(&rct, dx, 2 * dy, dx * 2, dy * 3);
  1271. LabelRect(hDC, &rct, IDS_BLUE_SHADES);
  1272. MakeRect(&rct, dx, 5 * dy, dx * 2, dy * 6);
  1273. LabelRect(hDC, &rct, IDS_GRAY_SHADES);
  1274. // horizontal lines for interlace detection
  1275. off = 3;
  1276. PaintRect(hDC, dx, dy*off, xUsed, dy * (off+1), RGB(255,255,255), 0); // white
  1277. hPrevPen = (HPEN) SelectObject(hDC, GetStockObject(BLACK_PEN));
  1278. for (y = dy * off; y < dy * (off+1); y = y+2) {
  1279. MoveToEx(hDC, dx, y, NULL);
  1280. LineTo( hDC, dx * 2, y);
  1281. }
  1282. SelectObject(hDC, hPrevPen);
  1283. MakeRect(&rct, dx, dy * off, dx * 2, dy * (off+1));
  1284. LabelRect(hDC, &rct, IDS_PATTERN_HORZ);
  1285. // vertical lines for bad dac detection
  1286. off = 4;
  1287. PaintRect(hDC, dx, dy * off, xUsed,dy * (off+1), RGB(255,255,255), 0); // white
  1288. hPrevPen= (HPEN) SelectObject(hDC, GetStockObject(BLACK_PEN));
  1289. for (x = dx; x < xUsed; x = x+2) {
  1290. MoveToEx(hDC, x, dy * off, NULL);
  1291. LineTo( hDC, x, dy * (off+1));
  1292. }
  1293. SelectObject(hDC, hPrevPen);
  1294. MakeRect(&rct, dx, dy * off, dx * 2, dy * (off+1));
  1295. LabelRect(hDC, &rct, IDS_PATTERN_VERT);
  1296. DrawArrows(hDC, nWidth, nHeight);
  1297. LabelResolution(hDC, 0, 0, xUsed, yUsed);
  1298. // delete created font if one was created
  1299. if (hPrevFont) {
  1300. hPrevFont = (HFONT) SelectObject(hDC, hPrevFont);
  1301. DeleteObject(hPrevFont);
  1302. }
  1303. }
  1304. /****************************************************************************
  1305. FUNCTION: LabelResolution
  1306. PURPOSE: Labels the resolution in a form a user may understand.
  1307. FEATURE: We could label vertically too.
  1308. ****************************************************************************/
  1309. VOID
  1310. LabelResolution(
  1311. HDC hDC,
  1312. INT xmin,
  1313. INT ymin,
  1314. INT xmax,
  1315. INT ymax
  1316. )
  1317. {
  1318. TCHAR szRes[120]; // text for resolution
  1319. TCHAR szFmt[CCH_MAX_STRING]; // format string
  1320. SIZE size;
  1321. INT iStatus;
  1322. iStatus = LoadString(hInstance, ID_DSP_TXT_XBYY /* remove IDS_RESOLUTION_FMT */, szFmt, ARRAYSIZE(szFmt) );
  1323. if (!iStatus || iStatus == sizeof(szFmt)) {
  1324. lstrcpy(szFmt,TEXT("%d x %d")); // make sure we get something
  1325. }
  1326. wsprintf(szRes, szFmt, xmax, ymax);
  1327. SetBkMode(hDC, TRANSPARENT);
  1328. SetTextColor(hDC, RGB(0,0,0));
  1329. GetTextExtentPoint32(hDC, szRes, lstrlen(szRes), &size);
  1330. // Text near bottom of screen ~10 pixels from bottom
  1331. TextOut(hDC, xmax/2 - size.cx/2, ymax - 10-size.cy, szRes, lstrlen(szRes));
  1332. }
  1333. /****************************************************************************
  1334. FUNCTION: PaintRect
  1335. PURPOSE: Color in a rectangle and label it.
  1336. ****************************************************************************/
  1337. static VOID
  1338. PaintRect(
  1339. HDC hDC, // DC to paint
  1340. INT lowx, // coordinates describing rectangle to fill
  1341. INT lowy, //
  1342. INT highx, //
  1343. INT highy, //
  1344. COLORREF rgb, // color to fill in rectangle with
  1345. UINT idString // resource ID to use to label or 0 is none
  1346. )
  1347. {
  1348. RECT rct;
  1349. HBRUSH hBrush;
  1350. MakeRect(&rct, lowx, lowy, highx, highy);
  1351. hBrush = CreateSolidBrush(rgb);
  1352. if (hBrush)
  1353. {
  1354. FillRect(hDC, &rct, hBrush);
  1355. DeleteObject(hBrush);
  1356. }
  1357. LabelRect(hDC, &rct, idString);
  1358. }
  1359. /****************************************************************************
  1360. FUNCTION: DrawArrows
  1361. PURPOSE: Draw all the arrows showing edges of resolution.
  1362. ****************************************************************************/
  1363. VOID
  1364. DrawArrows(
  1365. HDC hDC,
  1366. INT xRes,
  1367. INT yRes
  1368. )
  1369. {
  1370. INT dx,dy;
  1371. INT x,y;
  1372. COLORREF color= RGB(0,0,0); // color of arrow
  1373. dx= xRes/8;
  1374. dy= yRes/8;
  1375. for (x = 0; x < xRes; x += dx) {
  1376. DrawArrow(hDC, AW_TOP, dx/2+x, 0, color);
  1377. DrawArrow(hDC, AW_BOTTOM, dx/2+x, yRes-1, color);
  1378. }
  1379. for (y = 0; y < yRes; y += dy) {
  1380. DrawArrow(hDC, AW_LEFT, 0, dy/2+y, color);
  1381. DrawArrow(hDC, AW_RIGHT, xRes-1, dy/2+y, color);
  1382. }
  1383. }
  1384. /****************************************************************************
  1385. FUNCTION: LabelRect
  1386. PURPOSE: Label a rectangle with centered text given resource ID.
  1387. ****************************************************************************/
  1388. static VOID
  1389. LabelRect(
  1390. HDC hDC,
  1391. PRECT pRect,
  1392. UINT idString
  1393. )
  1394. {
  1395. UINT iStatus;
  1396. INT xStart, yStart;
  1397. SIZE size; // for size of string
  1398. TCHAR szMsg[CCH_MAX_STRING];
  1399. if (idString == 0) // make it easy to ignore call
  1400. return;
  1401. SetBkMode(hDC, OPAQUE);
  1402. SetBkColor(hDC, RGB(0,0,0));
  1403. SetTextColor(hDC, RGB(255,255,255));
  1404. // center
  1405. xStart = (pRect->left + pRect->right) / 2;
  1406. yStart = (pRect->top + pRect->bottom) / 2;
  1407. iStatus = LoadString(hInstance, idString, szMsg, ARRAYSIZE(szMsg));
  1408. if (!iStatus) {
  1409. return; // can't find string - print nothing
  1410. }
  1411. GetTextExtentPoint32(hDC, szMsg, lstrlen(szMsg), &size);
  1412. TextOut(hDC, xStart-size.cx/2, yStart-size.cy/2, szMsg, lstrlen(szMsg));
  1413. }
  1414. /****************************************************************************
  1415. FUNCTION: DrawArrow
  1416. PURPOSE: Draw one arrow in a given color.
  1417. ****************************************************************************/
  1418. static VOID
  1419. DrawArrow(
  1420. HDC hDC,
  1421. INT type,
  1422. INT xPos,
  1423. INT yPos,
  1424. COLORREF crPenColor
  1425. )
  1426. {
  1427. INT shaftlen=30; // length of arrow shaft
  1428. INT headlen=15; // height or width of arrow head (not length)
  1429. HPEN hPen, hPrevPen = NULL; // pens
  1430. INT x,y;
  1431. INT xdir, ydir; // directions of x and y (1,-1)
  1432. hPen= CreatePen( PS_SOLID, 1, crPenColor );
  1433. if( hPen )
  1434. hPrevPen= (HPEN) SelectObject( hDC, hPen );
  1435. MoveToEx( hDC, xPos, yPos, NULL );
  1436. xdir= ydir= 1; // defaults
  1437. switch( type )
  1438. {
  1439. case AW_BOTTOM:
  1440. ydir= -1;
  1441. case AW_TOP:
  1442. LineTo(hDC, xPos, yPos+ydir*shaftlen);
  1443. for( x=0; x<3; x++ )
  1444. {
  1445. MoveToEx( hDC, xPos, yPos+ydir*x, NULL );
  1446. LineTo( hDC, xPos-(headlen-x), yPos+ydir*headlen );
  1447. MoveToEx( hDC, xPos, yPos+ydir*x, NULL );
  1448. LineTo( hDC, xPos+(headlen-x), yPos+ydir*headlen );
  1449. }
  1450. break;
  1451. case AW_RIGHT:
  1452. xdir= -1;
  1453. case AW_LEFT:
  1454. LineTo( hDC, xPos + xdir*shaftlen, yPos );
  1455. for( y=0; y<3; y++ )
  1456. {
  1457. MoveToEx( hDC, xPos + xdir*y, yPos, NULL );
  1458. LineTo( hDC, xPos + xdir*headlen, yPos+(headlen-y));
  1459. MoveToEx( hDC, xPos + xdir*y, yPos, NULL );
  1460. LineTo( hDC, xPos + xdir*headlen, yPos-(headlen-y));
  1461. }
  1462. break;
  1463. }
  1464. if( hPrevPen )
  1465. SelectObject( hDC, hPrevPen );
  1466. if (hPen)
  1467. DeleteObject(hPen);
  1468. }
  1469. /****************************************************************************
  1470. FUNCTION: MakeRect
  1471. PURPOSE: Fill in RECT structure given contents.
  1472. ****************************************************************************/
  1473. VOID
  1474. MakeRect(
  1475. PRECT pRect,
  1476. INT xmin,
  1477. INT ymin,
  1478. INT xmax,
  1479. INT ymax
  1480. )
  1481. {
  1482. pRect->left= xmin;
  1483. pRect->right= xmax;
  1484. pRect->bottom= ymin;
  1485. pRect->top= ymax;
  1486. }