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.

2290 lines
65 KiB

  1. /**************************************************************************\
  2. * Module Name: settings.cpp
  3. *
  4. * Contains Implementation of the CDisplaySettings class who is in charge of
  5. * the settings of a single display. This is the data base class who does the
  6. * real change display settings work
  7. *
  8. * Copyright (c) Microsoft Corp. 1992-1998 All Rights Reserved
  9. *
  10. \**************************************************************************/
  11. #include "priv.h"
  12. #include "DisplaySettings.h"
  13. #include "ntreg.hxx"
  14. extern int AskDynaCDS(HWND hDlg);
  15. INT_PTR CALLBACK KeepNewDlgProc(HWND hDlg, UINT message , WPARAM wParam, LPARAM lParam);
  16. UINT g_cfDisplayDevice = 0;
  17. UINT g_cfDisplayName = 0;
  18. UINT g_cfDisplayDeviceID = 0;
  19. UINT g_cfMonitorDevice = 0;
  20. UINT g_cfMonitorName = 0;
  21. UINT g_cfMonitorDeviceID = 0;
  22. UINT g_cfExtensionInterface = 0;
  23. UINT g_cfDisplayDeviceKey = 0;
  24. UINT g_cfDisplayStateFlags = 0;
  25. UINT g_cfDisplayPruningMode = 0;
  26. #define TF_DISPLAYSETTINGS 0
  27. /*****************************************************************\
  28. *
  29. * helper routine
  30. *
  31. \*****************************************************************/
  32. int CDisplaySettings::_InsertSortedDwords(
  33. int val1,
  34. int val2,
  35. int cval,
  36. int **ppval)
  37. {
  38. int *oldpval = *ppval;
  39. int *tmppval;
  40. int i;
  41. for (i=0; i<cval; i++)
  42. {
  43. tmppval = (*ppval) + (i * 2);
  44. if (*tmppval == val1)
  45. {
  46. if (*(tmppval + 1) == val2)
  47. {
  48. return cval;
  49. }
  50. else if (*(tmppval + 1) > val2)
  51. {
  52. break;
  53. }
  54. }
  55. else if (*tmppval > val1)
  56. {
  57. break;
  58. }
  59. }
  60. TraceMsg(TF_FUNC,"_InsertSortedDword, vals = %d %d, cval = %d, index = %d", val1, val2, cval, i);
  61. *ppval = (int *) LocalAlloc(LPTR, (cval + 1) * 2 * sizeof(DWORD));
  62. if (*ppval)
  63. {
  64. //
  65. // Insert the items at the right location in the array
  66. //
  67. if (oldpval) {
  68. CopyMemory(*ppval,
  69. oldpval,
  70. i * 2 * sizeof(DWORD));
  71. }
  72. *(*ppval + (i * 2)) = val1;
  73. *(*ppval + (i * 2) + 1) = val2;
  74. if (oldpval) {
  75. CopyMemory((*ppval) + 2 * (i + 1),
  76. oldpval+ (i * 2),
  77. (cval-i) * 2 * sizeof(DWORD));
  78. LocalFree(oldpval);
  79. }
  80. return (cval + 1);
  81. }
  82. return 0;
  83. }
  84. /*****************************************************************\
  85. *
  86. * debug routine
  87. *
  88. \*****************************************************************/
  89. void CDisplaySettings::_Dump_CDisplaySettings(BOOL bAll)
  90. {
  91. TraceMsg(TF_DUMP_CSETTINGS,"Dump of CDisplaySettings structure");
  92. TraceMsg(TF_DUMP_CSETTINGS,"\t _DisplayDevice = %s", _pDisplayDevice->DeviceName);
  93. TraceMsg(TF_DUMP_CSETTINGS,"\t _cpdm = %d", _cpdm );
  94. TraceMsg(TF_DUMP_CSETTINGS,"\t _apdm = %08lx", _apdm );
  95. TraceMsg(TF_DUMP_CSETTINGS,"\t OrgResolution = %d, %d", _ORGXRES, _ORGYRES );
  96. TraceMsg(TF_DUMP_CSETTINGS,"\t _ptOrgPos = %d, %d", _ptOrgPos.x ,_ptOrgPos.y);
  97. TraceMsg(TF_DUMP_CSETTINGS,"\t OrgColor = %d", _ORGCOLOR );
  98. TraceMsg(TF_DUMP_CSETTINGS,"\t OrgFrequency = %d", _ORGFREQ );
  99. TraceMsg(TF_DUMP_CSETTINGS,"\t _pOrgDevmode = %08lx", _pOrgDevmode );
  100. TraceMsg(TF_DUMP_CSETTINGS,"\t _fOrgAttached = %d", _fOrgAttached );
  101. TraceMsg(TF_DUMP_CSETTINGS,"\t CurResolution = %d, %d", _CURXRES, _CURYRES );
  102. TraceMsg(TF_DUMP_CSETTINGS,"\t _ptCurPos = %d, %d", _ptCurPos.x ,_ptCurPos.y);
  103. TraceMsg(TF_DUMP_CSETTINGS,"\t CurColor = %d", _CURCOLOR );
  104. TraceMsg(TF_DUMP_CSETTINGS,"\t CurFrequency = %d", _CURFREQ );
  105. TraceMsg(TF_DUMP_CSETTINGS,"\t _pCurDevmode = %08lx", _pCurDevmode );
  106. TraceMsg(TF_DUMP_CSETTINGS,"\t _fCurAttached = %d", _fCurAttached );
  107. TraceMsg(TF_DUMP_CSETTINGS,"\t _fUsingDefault = %d", _fUsingDefault );
  108. TraceMsg(TF_DUMP_CSETTINGS,"\t _fPrimary = %d", _fPrimary );
  109. TraceMsg(TF_DUMP_CSETTINGS,"\t _cRef = %d", _cRef );
  110. if (bAll)
  111. {
  112. _Dump_CDevmodeList();
  113. }
  114. }
  115. void CDisplaySettings::_Dump_CDevmodeList(VOID)
  116. {
  117. ULONG i;
  118. for (i=0; _apdm && (i<_cpdm); i++)
  119. {
  120. LPDEVMODE lpdm = (_apdm + i)->lpdm;
  121. TraceMsg(TF_DUMP_CSETTINGS,"\t\t mode %d, %08lx, Flags %08lx, X=%d Y=%d C=%d F=%d O=%d FO=%d",
  122. i, lpdm, (_apdm + i)->dwFlags,
  123. lpdm->dmPelsWidth, lpdm->dmPelsHeight, lpdm->dmBitsPerPel, lpdm->dmDisplayFrequency,
  124. lpdm->dmDisplayOrientation, lpdm->dmDisplayFixedOutput);
  125. }
  126. }
  127. void CDisplaySettings::_Dump_CDevmode(LPDEVMODE pdm)
  128. {
  129. TraceMsg(TF_DUMP_DEVMODE," Size = %d", pdm->dmSize);
  130. TraceMsg(TF_DUMP_DEVMODE," Fields = %08lx", pdm->dmFields);
  131. TraceMsg(TF_DUMP_DEVMODE," XPosition = %d", pdm->dmPosition.x);
  132. TraceMsg(TF_DUMP_DEVMODE," YPosition = %d", pdm->dmPosition.y);
  133. TraceMsg(TF_DUMP_DEVMODE," XResolution = %d", pdm->dmPelsWidth);
  134. TraceMsg(TF_DUMP_DEVMODE," YResolution = %d", pdm->dmPelsHeight);
  135. TraceMsg(TF_DUMP_DEVMODE," Bpp = %d", pdm->dmBitsPerPel);
  136. TraceMsg(TF_DUMP_DEVMODE," Frequency = %d", pdm->dmDisplayFrequency);
  137. TraceMsg(TF_DUMP_DEVMODE," Flags = %d", pdm->dmDisplayFlags);
  138. TraceMsg(TF_DUMP_DEVMODE," XPanning = %d", pdm->dmPanningWidth);
  139. TraceMsg(TF_DUMP_DEVMODE," YPanning = %d", pdm->dmPanningHeight);
  140. TraceMsg(TF_DUMP_DEVMODE," DPI = %d", pdm->dmLogPixels);
  141. TraceMsg(TF_DUMP_DEVMODE," DriverExtra = %d", pdm->dmDriverExtra);
  142. TraceMsg(TF_DUMP_DEVMODE," Orientation = %d", pdm->dmDisplayOrientation);
  143. TraceMsg(TF_DUMP_DEVMODE," FixedOutput = %d", pdm->dmDisplayFixedOutput);
  144. if (pdm->dmDriverExtra)
  145. {
  146. TraceMsg(TF_DUMP_CSETTINGS,"\t - %08lx %08lx",
  147. *(PULONG)(((PUCHAR)pdm)+pdm->dmSize),
  148. *(PULONG)(((PUCHAR)pdm)+pdm->dmSize + 4));
  149. }
  150. }
  151. //
  152. // Lets perform the following operations on the list
  153. //
  154. // (1) Remove identical modes
  155. // (2) Remove 16 color modes for which there is a 256
  156. // color equivalent.
  157. // (3) Remove modes with any dimension less than 640x480
  158. //
  159. void CDisplaySettings::_FilterModes()
  160. {
  161. DWORD i, j;
  162. LPDEVMODE pdm, pdm2;
  163. PMODEARRAY pMode, pMode2;
  164. for (i = 0; _apdm && i < _cpdm; i++)
  165. {
  166. pMode = _apdm + i;
  167. pdm = pMode->lpdm;
  168. // Skip any invalid modes
  169. if (pMode->dwFlags & MODE_INVALID)
  170. {
  171. continue;
  172. }
  173. //
  174. // If any of the following conditions are true, then we want to
  175. // remove the current mode.
  176. //
  177. // Remove any modes that are too small
  178. if (pdm->dmPelsHeight < 480 || pdm->dmPelsWidth < 640)
  179. {
  180. TraceMsg(TF_DUMP_CSETTINGS,"_FilterModes: Mode %d - resolution too small", i);
  181. pMode->dwFlags |= MODE_INVALID;
  182. continue;
  183. }
  184. // Remove any modes that would change the orientation
  185. if (_bFilterOrientation)
  186. {
  187. if (pdm->dmFields & DM_DISPLAYORIENTATION &&
  188. pdm->dmDisplayOrientation != _dwOrientation)
  189. {
  190. pMode->dwFlags |= MODE_INVALID;
  191. TraceMsg(TF_DUMP_CSETTINGS,"_FilterModes: Mode %d - Wrong Orientation", i);
  192. continue;
  193. }
  194. }
  195. // Remove any modes that would change fixed output unless our current mode is
  196. // native resolution
  197. if (_bFilterFixedOutput && _dwFixedOutput != DMDFO_DEFAULT)
  198. {
  199. if (pdm->dmFields & DM_DISPLAYFIXEDOUTPUT &&
  200. pdm->dmDisplayFixedOutput != _dwFixedOutput)
  201. {
  202. pMode->dwFlags |= MODE_INVALID;
  203. TraceMsg(TF_DUMP_CSETTINGS,"_FilterModes: Mode %d - Wrong FixedOutput", i);
  204. continue;
  205. }
  206. }
  207. // Remove any duplicate modes
  208. for (j = i + 1; j < _cpdm; j++)
  209. {
  210. pMode2 = _apdm + j;
  211. pdm2 = pMode2->lpdm;
  212. if (!(pMode2->dwFlags & MODE_INVALID) &&
  213. pdm2->dmBitsPerPel == pdm->dmBitsPerPel &&
  214. pdm2->dmPelsWidth == pdm->dmPelsWidth &&
  215. pdm2->dmPelsHeight == pdm->dmPelsHeight &&
  216. pdm2->dmDisplayFrequency == pdm->dmDisplayFrequency)
  217. {
  218. TraceMsg(TF_DUMP_CSETTINGS,"_FilterModes: Mode %d - Duplicate Mode", i);
  219. pMode2->dwFlags |= MODE_INVALID;
  220. }
  221. }
  222. }
  223. }
  224. //
  225. // _AddDevMode method
  226. //
  227. // This method builds the index lists for the matrix. There is one
  228. // index list for each axes of the three dimemsional matrix of device
  229. // modes.
  230. //
  231. // The entry is also automatically added to the linked list of modes if
  232. // it is not alreay present in the list.
  233. //
  234. BOOL CDisplaySettings::_AddDevMode(LPDEVMODE lpdm)
  235. {
  236. if (lpdm)
  237. {
  238. PMODEARRAY newapdm, tempapdm;
  239. //
  240. // Set the height for the test of the 1152 mode
  241. //
  242. if (lpdm->dmPelsWidth == 1152) {
  243. // Set1152Mode(lpdm->dmPelsHeight);
  244. }
  245. newapdm = (PMODEARRAY) LocalAlloc(LPTR, (_cpdm + 1) * sizeof(MODEARRAY));
  246. if (newapdm)
  247. {
  248. CopyMemory(newapdm, _apdm, _cpdm * sizeof(MODEARRAY));
  249. (newapdm + _cpdm)->dwFlags &= ~MODE_INVALID;
  250. (newapdm + _cpdm)->dwFlags |= MODE_RAW;
  251. (newapdm + _cpdm)->lpdm = lpdm;
  252. }
  253. tempapdm = _apdm;
  254. _apdm = newapdm;
  255. _cpdm++;
  256. if (tempapdm)
  257. {
  258. LocalFree(tempapdm);
  259. }
  260. }
  261. return TRUE;
  262. }
  263. //
  264. // Return a list of Resolutions supported, given a color depth
  265. //
  266. int CDisplaySettings::GetResolutionList(
  267. int Color,
  268. PPOINT *ppRes)
  269. {
  270. DWORD i;
  271. int cRes = 0;
  272. int *pResTmp = NULL;
  273. LPDEVMODE pdm;
  274. *ppRes = NULL;
  275. for (i = 0; _apdm && (i < _cpdm); i++)
  276. {
  277. if(!_IsModeVisible(i))
  278. {
  279. continue;
  280. }
  281. if(!_IsModePreferred(i))
  282. {
  283. continue;
  284. }
  285. pdm = (_apdm + i)->lpdm;
  286. if ((Color == -1) ||
  287. (Color == (int)pdm->dmBitsPerPel))
  288. {
  289. cRes = _InsertSortedDwords(pdm->dmPelsWidth,
  290. pdm->dmPelsHeight,
  291. cRes,
  292. &pResTmp);
  293. }
  294. }
  295. *ppRes = (PPOINT) pResTmp;
  296. return cRes;
  297. }
  298. //
  299. //
  300. // Return a list of color depths supported
  301. //
  302. int CDisplaySettings::GetColorList(
  303. LPPOINT Res,
  304. PLONGLONG *ppColor)
  305. {
  306. DWORD i;
  307. int cColor = 0;
  308. int *pColorTmp = NULL;
  309. LPDEVMODE pdm;
  310. for (i = 0; _apdm && (i < _cpdm); i++)
  311. {
  312. if(!_IsModeVisible(i))
  313. {
  314. continue;
  315. }
  316. if(!_IsModePreferred(i))
  317. {
  318. continue;
  319. }
  320. pdm = (_apdm + i)->lpdm;
  321. if ((Res == NULL) ||
  322. (Res->x == -1) ||
  323. (Res->y == -1) ||
  324. (Res->x == (int)pdm->dmPelsWidth) ||
  325. (Res->y == (int)pdm->dmPelsHeight))
  326. {
  327. cColor = _InsertSortedDwords(pdm->dmBitsPerPel,
  328. 0,
  329. cColor,
  330. &pColorTmp);
  331. }
  332. }
  333. *ppColor = (PLONGLONG) pColorTmp;
  334. return cColor;
  335. }
  336. int CDisplaySettings::GetFrequencyList(int Color, LPPOINT Res, PLONGLONG *ppFreq)
  337. {
  338. DWORD i;
  339. int cFreq = 0;
  340. int *pFreqTmp = NULL;
  341. LPDEVMODE pdm;
  342. POINT res;
  343. if (Color == -1) {
  344. Color = _CURCOLOR;
  345. }
  346. if (Res == NULL)
  347. {
  348. MAKEXYRES(&res, _CURXRES, _CURYRES);
  349. }
  350. else
  351. {
  352. res = *Res;
  353. }
  354. for (i = 0; _apdm && (i < _cpdm); i++)
  355. {
  356. if(!_IsModeVisible(i))
  357. {
  358. continue;
  359. }
  360. pdm = (_apdm + i)->lpdm;
  361. if (res.x == (int)pdm->dmPelsWidth &&
  362. res.y == (int)pdm->dmPelsHeight &&
  363. Color == (int)pdm->dmBitsPerPel)
  364. {
  365. cFreq = _InsertSortedDwords(pdm->dmDisplayFrequency,
  366. 0,
  367. cFreq,
  368. &pFreqTmp);
  369. }
  370. }
  371. *ppFreq = (PLONGLONG) pFreqTmp;
  372. return cFreq;
  373. }
  374. void CDisplaySettings::SetCurFrequency(int Frequency)
  375. {
  376. LPDEVMODE pdm;
  377. LPDEVMODE pdmMatch = NULL;
  378. ULONG i;
  379. for (i = 0; _apdm && (i < _cpdm); i++)
  380. {
  381. if(!_IsModeVisible(i))
  382. {
  383. continue;
  384. }
  385. pdm = (_apdm + i)->lpdm;
  386. //
  387. // Find the exact match.
  388. //
  389. if (_CURCOLOR == (int) pdm->dmBitsPerPel &&
  390. _CURXRES == (int) pdm->dmPelsWidth &&
  391. _CURYRES == (int) pdm->dmPelsHeight &&
  392. Frequency == (int) pdm->dmDisplayFrequency)
  393. {
  394. pdmMatch = pdm;
  395. break;
  396. }
  397. }
  398. //
  399. // We should always make a match because the list of frequencies shown to
  400. // the user is only for the current color & resolution
  401. //
  402. ASSERT(pdmMatch);
  403. if (pdmMatch) {
  404. _SetCurrentValues(pdmMatch);
  405. }
  406. }
  407. LPDEVMODE CDisplaySettings::GetCurrentDevMode(void)
  408. {
  409. ULONG dmSize = _pCurDevmode->dmSize + _pCurDevmode->dmDriverExtra;
  410. PDEVMODE pdevmode = (LPDEVMODE) LocalAlloc(LPTR, dmSize);
  411. if (pdevmode) {
  412. CopyMemory(pdevmode, _pCurDevmode, dmSize);
  413. }
  414. return pdevmode;
  415. }
  416. void CDisplaySettings::_SetCurrentValues(LPDEVMODE lpdm)
  417. {
  418. _pCurDevmode = lpdm;
  419. //
  420. // Don't save the other fields (like position) as they are programmed by
  421. // the UI separately.
  422. //
  423. // This should only save hardware specific fields.
  424. //
  425. TraceMsg(TF_DUMP_CSETTINGS,"");
  426. TraceMsg(TF_DUMP_CSETTINGS,"_SetCurrentValues complete");
  427. _Dump_CDisplaySettings(FALSE);
  428. }
  429. BOOL CDisplaySettings::_PerfectMatch(LPDEVMODE lpdm)
  430. {
  431. for (DWORD i = 0; _apdm && (i < _cpdm); i++)
  432. {
  433. if(!_IsModeVisible(i))
  434. {
  435. continue;
  436. }
  437. if ((_apdm + i)->lpdm == lpdm)
  438. {
  439. _SetCurrentValues((_apdm + i)->lpdm);
  440. TraceMsg(TF_DISPLAYSETTINGS, "_PerfectMatch -- return TRUE");
  441. return TRUE;
  442. }
  443. }
  444. TraceMsg(TF_DISPLAYSETTINGS, "_PerfectMatch -- return FALSE");
  445. return FALSE;
  446. }
  447. BOOL CDisplaySettings::_ExactMatch(LPDEVMODE lpdm, BOOL bForceVisible)
  448. {
  449. LPDEVMODE pdm;
  450. ULONG i;
  451. for (i = 0; _apdm && (i < _cpdm); i++)
  452. {
  453. pdm = (_apdm + i)->lpdm;
  454. if (
  455. ((lpdm->dmFields & DM_BITSPERPEL) &&
  456. (pdm->dmBitsPerPel != lpdm->dmBitsPerPel))
  457. ||
  458. ((lpdm->dmFields & DM_PELSWIDTH) &&
  459. (pdm->dmPelsWidth != lpdm->dmPelsWidth))
  460. ||
  461. ((lpdm->dmFields & DM_PELSHEIGHT) &&
  462. (pdm->dmPelsHeight != lpdm->dmPelsHeight))
  463. ||
  464. ((lpdm->dmFields & DM_DISPLAYFREQUENCY) &&
  465. (pdm->dmDisplayFrequency != lpdm->dmDisplayFrequency))
  466. )
  467. {
  468. continue;
  469. }
  470. if (!_IsModeVisible(i))
  471. {
  472. if (bForceVisible &&
  473. ((((_apdm + i)->dwFlags) & MODE_INVALID) == 0) &&
  474. _bIsPruningOn &&
  475. ((((_apdm + i)->dwFlags) & MODE_RAW) == MODE_RAW))
  476. {
  477. (_apdm + i)->dwFlags &= ~MODE_RAW;
  478. }
  479. else
  480. {
  481. continue;
  482. }
  483. }
  484. _SetCurrentValues(pdm);
  485. TraceMsg(TF_DISPLAYSETTINGS, "_ExactMatch -- return TRUE");
  486. return TRUE;
  487. }
  488. TraceMsg(TF_DISPLAYSETTINGS, "_ExactMatch -- return FALSE");
  489. return FALSE;
  490. }
  491. // JoelGros defined a feature where we prefer to give the user
  492. // a color depth of at least 32-bit, or as close to that as the
  493. // display supports. Bryan Starbuck (BryanSt) 3/9/2000
  494. #define MAX_PREFERED_COLOR_DEPTH 32
  495. void CDisplaySettings::_BestMatch(LPPOINT Res, int Color, IN BOOL fAutoSetColorDepth)
  496. {
  497. // -1 means match loosely, based on current _xxx value
  498. LPDEVMODE pdm;
  499. LPDEVMODE pdmMatch = NULL;
  500. ULONG i;
  501. for (i = 0; _apdm && (i < _cpdm); i++)
  502. {
  503. if(!_IsModeVisible(i))
  504. {
  505. continue;
  506. }
  507. pdm = (_apdm + i)->lpdm;
  508. // Take care of exact matches
  509. if ((Color != -1) &&
  510. (Color != (int)pdm->dmBitsPerPel))
  511. {
  512. continue;
  513. }
  514. if ((Res != NULL) &&
  515. (Res->x != -1) &&
  516. ( (Res->x != (int)pdm->dmPelsWidth) ||
  517. (Res->y != (int)pdm->dmPelsHeight)) )
  518. {
  519. continue;
  520. }
  521. // Find Best Match
  522. if (pdmMatch == NULL)
  523. {
  524. pdmMatch = pdm;
  525. }
  526. // Find best Color.
  527. if (Color == -1) // Do they want best color matching?
  528. {
  529. if (fAutoSetColorDepth)
  530. {
  531. // This will use the "auto-set a good color depth" feature.
  532. // The best match color depth will not equal the current color depth if
  533. // we are going to need to work closer and closer to our desired color depth.
  534. // (We may never reach it because the user may just have increased the resolution
  535. // so the current color depth isn't supported)
  536. // We prefer keep increasing the color depth to at least the current color depth.
  537. // That may not be possible if that depth isn't supported at this resolution.
  538. // We also would like to keep increasing it until we hit MAX_PREFERED_COLOR_DEPTH
  539. // because colors of at least that deep benefit users.
  540. // Do we need to decrease the color depth? Yes if
  541. if (((int)pdmMatch->dmBitsPerPel > _CURCOLOR) && // the match is more than the current, and
  542. ((int)pdmMatch->dmBitsPerPel > MAX_PREFERED_COLOR_DEPTH)) // the match is more than the prefered max
  543. {
  544. // We will want to decrease it if this entry is smaller than our match.
  545. if ((int)pdm->dmBitsPerPel < (int)pdmMatch->dmBitsPerPel)
  546. {
  547. pdmMatch = pdm;
  548. }
  549. }
  550. else
  551. {
  552. // We want to increase it if:
  553. if (((int)pdm->dmBitsPerPel > (int)pdmMatch->dmBitsPerPel) && // this entry is larger than our match, and
  554. ((int)pdm->dmBitsPerPel <= max(_CURCOLOR, MAX_PREFERED_COLOR_DEPTH))) // this doesn't take us over our prefered max or current depth (which ever is higher).
  555. {
  556. pdmMatch = pdm;
  557. }
  558. }
  559. }
  560. else
  561. {
  562. // This falls back to the old behavior.
  563. if ((int)pdmMatch->dmBitsPerPel > _CURCOLOR)
  564. {
  565. if ((int)pdm->dmBitsPerPel < (int)pdmMatch->dmBitsPerPel)
  566. {
  567. pdmMatch = pdm;
  568. }
  569. }
  570. else
  571. {
  572. if (((int)pdm->dmBitsPerPel > (int)pdmMatch->dmBitsPerPel) &&
  573. ((int)pdm->dmBitsPerPel <= _CURCOLOR))
  574. {
  575. pdmMatch = pdm;
  576. }
  577. }
  578. }
  579. }
  580. // Find best Resolution.
  581. if (((Res == NULL) || (Res->x == -1)) &&
  582. (((int)pdmMatch->dmPelsWidth != _CURXRES) ||
  583. ((int)pdmMatch->dmPelsHeight != _CURYRES)))
  584. {
  585. if (((int)pdmMatch->dmPelsWidth > _CURXRES) ||
  586. (((int)pdmMatch->dmPelsWidth == _CURXRES) &&
  587. ((int)pdmMatch->dmPelsHeight > _CURYRES)))
  588. {
  589. if (((int)pdm->dmPelsWidth < (int)pdmMatch->dmPelsWidth) ||
  590. (((int)pdm->dmPelsWidth == (int)pdmMatch->dmPelsWidth) &&
  591. ((int)pdm->dmPelsHeight < (int)pdmMatch->dmPelsHeight)))
  592. {
  593. pdmMatch = pdm;
  594. }
  595. }
  596. else
  597. {
  598. if (((int)pdm->dmPelsWidth > (int)pdmMatch->dmPelsWidth) ||
  599. (((int)pdm->dmPelsWidth == (int)pdmMatch->dmPelsWidth) &&
  600. ((int)pdm->dmPelsHeight > (int)pdmMatch->dmPelsHeight)))
  601. {
  602. if (((int)pdm->dmPelsWidth <= _CURXRES) ||
  603. (((int)pdm->dmPelsWidth == _CURXRES) &&
  604. ((int)pdm->dmPelsHeight <= _CURYRES)))
  605. {
  606. pdmMatch = pdm;
  607. }
  608. }
  609. }
  610. }
  611. // Find best Frequency.
  612. if (((int)pdmMatch->dmDisplayFrequency != _CURFREQ) &&
  613. (!((Res == NULL) &&
  614. ((int)pdmMatch->dmPelsWidth == _CURXRES) &&
  615. ((int)pdmMatch->dmPelsHeight == _CURYRES) &&
  616. (((int)pdm->dmPelsWidth != _CURXRES) ||
  617. ((int)pdm->dmPelsHeight != _CURYRES)))) &&
  618. (!((Color == -1) &&
  619. ((int)pdmMatch->dmBitsPerPel == _CURCOLOR) &&
  620. ((int)pdm->dmBitsPerPel != _CURCOLOR))))
  621. {
  622. if ((int)pdmMatch->dmDisplayFrequency > _CURFREQ)
  623. {
  624. if ((int)pdm->dmDisplayFrequency < (int)pdmMatch->dmDisplayFrequency)
  625. {
  626. pdmMatch = pdm;
  627. }
  628. }
  629. else
  630. {
  631. if (((int)pdm->dmDisplayFrequency > (int)pdmMatch->dmDisplayFrequency) &&
  632. ((int)pdm->dmDisplayFrequency <= _CURFREQ))
  633. {
  634. pdmMatch = pdm;
  635. }
  636. }
  637. }
  638. }
  639. _SetCurrentValues(pdmMatch);
  640. }
  641. BOOL CDisplaySettings::GetMonitorName(LPTSTR pszName, DWORD cchSize)
  642. {
  643. DISPLAY_DEVICE ddTmp;
  644. DWORD cAttachedMonitors = 0, nMonitor = 0;
  645. ZeroMemory(&ddTmp, sizeof(ddTmp));
  646. ddTmp.cb = sizeof(DISPLAY_DEVICE);
  647. while (EnumDisplayDevices(_pDisplayDevice->DeviceName, nMonitor, &ddTmp, 0))
  648. {
  649. if (ddTmp.StateFlags & DISPLAY_DEVICE_ATTACHED)
  650. {
  651. ++cAttachedMonitors;
  652. if (cAttachedMonitors > 1)
  653. break;
  654. // Single monitor
  655. StrCpyN(pszName, (LPTSTR)ddTmp.DeviceString, cchSize);
  656. }
  657. ++nMonitor;
  658. ZeroMemory(&ddTmp, sizeof(ddTmp));
  659. ddTmp.cb = sizeof(DISPLAY_DEVICE);
  660. }
  661. if (cAttachedMonitors == 0)
  662. {
  663. // No monitors
  664. LoadString(HINST_THISDLL, IDS_UNKNOWNMONITOR, pszName, cchSize);
  665. }
  666. else if (cAttachedMonitors > 1)
  667. {
  668. // Multiple monitors
  669. LoadString(HINST_THISDLL, IDS_MULTIPLEMONITORS, pszName, cchSize);
  670. }
  671. return (cAttachedMonitors != 0);
  672. }
  673. BOOL CDisplaySettings::GetMonitorDevice(LPTSTR pszDevice)
  674. {
  675. DISPLAY_DEVICE ddTmp;
  676. ZeroMemory(&ddTmp, sizeof(ddTmp));
  677. ddTmp.cb = sizeof(DISPLAY_DEVICE);
  678. if (EnumDisplayDevices(_pDisplayDevice->DeviceName, 0, &ddTmp, 0))
  679. {
  680. lstrcpy(pszDevice, (LPTSTR)ddTmp.DeviceName);
  681. return TRUE;
  682. }
  683. return FALSE;
  684. }
  685. STDMETHODIMP CDisplaySettings::GetData(FORMATETC *pfmtetc, STGMEDIUM *pstgmed)
  686. {
  687. HRESULT hr;
  688. ASSERT(this);
  689. ASSERT(pfmtetc);
  690. ASSERT(pstgmed);
  691. // Ignore pfmtetc.ptd. All supported data formats are device-independent.
  692. ZeroMemory(pstgmed, SIZEOF(*pstgmed));
  693. if ((hr = QueryGetData(pfmtetc)) == S_OK)
  694. {
  695. LPTSTR pszOut = NULL;
  696. TCHAR szMonitorName[130];
  697. TCHAR szMonitorDevice[40];
  698. if (pfmtetc->cfFormat == g_cfExtensionInterface)
  699. {
  700. //
  701. // Get the array of information back to the device
  702. //
  703. // Allocate a buffer large enough to store all of the information
  704. //
  705. PDESK_EXTENSION_INTERFACE pInterface;
  706. pInterface = (PDESK_EXTENSION_INTERFACE)
  707. GlobalAlloc(GPTR, sizeof(DESK_EXTENSION_INTERFACE));
  708. if (pInterface)
  709. {
  710. CRegistrySettings * RegSettings = new CRegistrySettings(_pDisplayDevice->DeviceKey);
  711. if (RegSettings)
  712. {
  713. pInterface->cbSize = sizeof(DESK_EXTENSION_INTERFACE);
  714. pInterface->pContext = this;
  715. pInterface->lpfnEnumAllModes = CDisplaySettings::_lpfnEnumAllModes;
  716. pInterface->lpfnSetSelectedMode = CDisplaySettings::_lpfnSetSelectedMode;
  717. pInterface->lpfnGetSelectedMode = CDisplaySettings::_lpfnGetSelectedMode;
  718. pInterface->lpfnSetPruningMode = CDisplaySettings::_lpfnSetPruningMode;
  719. pInterface->lpfnGetPruningMode = CDisplaySettings::_lpfnGetPruningMode;
  720. RegSettings->GetHardwareInformation(&pInterface->Info);
  721. pstgmed->tymed = TYMED_HGLOBAL;
  722. pstgmed->hGlobal = pInterface;
  723. pstgmed->pUnkForRelease = NULL;
  724. hr = S_OK;
  725. delete RegSettings;
  726. }
  727. }
  728. else
  729. {
  730. hr = E_OUTOFMEMORY;
  731. }
  732. }
  733. else if (pfmtetc->cfFormat == g_cfMonitorDeviceID)
  734. {
  735. //
  736. //! This code is broken. It must be removed.
  737. //
  738. /*
  739. DISPLAY_DEVICE ddTmp;
  740. BOOL fKnownMonitor;
  741. ZeroMemory(&ddTmp, sizeof(ddTmp));
  742. ddTmp.cb = sizeof(DISPLAY_DEVICE);
  743. fKnownMonitor = EnumDisplayDevices(_pDisplayDevice->DeviceName, 0, &ddTmp, 0);
  744. hr = GetDevInstID((LPTSTR)(fKnownMonitor ? ddTmp.DeviceKey : TEXT("")), pstgmed);
  745. */
  746. hr = E_UNEXPECTED;
  747. }
  748. else if (pfmtetc->cfFormat == g_cfDisplayStateFlags)
  749. {
  750. DWORD* pdwStateFlags = (DWORD*)GlobalAlloc(GPTR, sizeof(DWORD));
  751. if (pdwStateFlags)
  752. {
  753. *pdwStateFlags = _pDisplayDevice->StateFlags;
  754. pstgmed->tymed = TYMED_HGLOBAL;
  755. pstgmed->hGlobal = pdwStateFlags;
  756. pstgmed->pUnkForRelease = NULL;
  757. hr = S_OK;
  758. }
  759. else
  760. {
  761. hr = E_OUTOFMEMORY;
  762. }
  763. }
  764. else if (pfmtetc->cfFormat == g_cfDisplayPruningMode)
  765. {
  766. BYTE* pPruningMode = (BYTE*)GlobalAlloc(GPTR, sizeof(BYTE));
  767. if (pPruningMode)
  768. {
  769. *pPruningMode = (BYTE)(_bCanBePruned && _bIsPruningOn ? 1 : 0);
  770. pstgmed->tymed = TYMED_HGLOBAL;
  771. pstgmed->hGlobal = pPruningMode;
  772. pstgmed->pUnkForRelease = NULL;
  773. hr = S_OK;
  774. }
  775. else
  776. {
  777. hr = E_OUTOFMEMORY;
  778. }
  779. }
  780. else if (pfmtetc->cfFormat == g_cfDisplayDeviceID)
  781. {
  782. {
  783. CRegistrySettings *pRegSettings = new CRegistrySettings(_pDisplayDevice->DeviceKey);
  784. if (pRegSettings)
  785. {
  786. pszOut = pRegSettings->GetDeviceInstanceId();
  787. hr = CopyDataToStorage(pstgmed, pszOut);
  788. delete pRegSettings;
  789. }
  790. else
  791. {
  792. hr = E_OUTOFMEMORY;
  793. }
  794. }
  795. }
  796. else
  797. {
  798. if (pfmtetc->cfFormat == g_cfMonitorName)
  799. {
  800. GetMonitorName(szMonitorName, ARRAYSIZE(szMonitorName));
  801. pszOut = szMonitorName;
  802. }
  803. else if (pfmtetc->cfFormat == g_cfMonitorDevice)
  804. {
  805. GetMonitorDevice(szMonitorDevice);
  806. pszOut = szMonitorDevice;
  807. }
  808. else if (pfmtetc->cfFormat == g_cfDisplayDevice)
  809. {
  810. pszOut = (LPTSTR)_pDisplayDevice->DeviceName;
  811. }
  812. else if (pfmtetc->cfFormat == g_cfDisplayDeviceKey)
  813. {
  814. pszOut = (LPTSTR)_pDisplayDevice->DeviceKey;
  815. }
  816. else
  817. {
  818. ASSERT(pfmtetc->cfFormat == g_cfDisplayName);
  819. pszOut = (LPTSTR)_pDisplayDevice->DeviceString;
  820. }
  821. hr = CopyDataToStorage(pstgmed, pszOut);
  822. }
  823. }
  824. return(hr);
  825. }
  826. STDMETHODIMP CDisplaySettings::CopyDataToStorage(STGMEDIUM *pstgmed, LPTSTR pszOut)
  827. {
  828. HRESULT hr = E_UNEXPECTED;
  829. int cch;
  830. if (NULL != pszOut)
  831. {
  832. cch = lstrlen(pszOut) + 1;
  833. LPWSTR pwszDevice = (LPWSTR)GlobalAlloc(GPTR, cch * SIZEOF(WCHAR));
  834. if (pwszDevice)
  835. {
  836. //
  837. // We always return UNICODE string
  838. //
  839. #ifdef UNICODE
  840. lstrcpy(pwszDevice, pszOut);
  841. #else
  842. int cchConverted = MultiByteToWideChar(CP_ACP, 0, pszOut , -1, pwszDevice, cch);
  843. ASSERT(cchConverted == cch);
  844. #endif
  845. pstgmed->tymed = TYMED_HGLOBAL;
  846. pstgmed->hGlobal = pwszDevice;
  847. pstgmed->pUnkForRelease = NULL;
  848. hr = S_OK;
  849. }
  850. else
  851. {
  852. hr = E_OUTOFMEMORY;
  853. }
  854. }
  855. return hr;
  856. }
  857. STDMETHODIMP CDisplaySettings::GetDataHere(FORMATETC *pfmtetc, STGMEDIUM *pstgpmed)
  858. {
  859. ZeroMemory(pfmtetc, SIZEOF(pfmtetc));
  860. return E_NOTIMPL;
  861. }
  862. //
  863. // Check that all the parameters to the interface are appropriately
  864. //
  865. STDMETHODIMP CDisplaySettings::QueryGetData(FORMATETC *pfmtetc)
  866. {
  867. CLIPFORMAT cfFormat;
  868. if (pfmtetc->dwAspect != DVASPECT_CONTENT)
  869. {
  870. return DV_E_DVASPECT;
  871. }
  872. if ((pfmtetc->tymed & TYMED_HGLOBAL) == 0)
  873. {
  874. return DV_E_TYMED;
  875. }
  876. cfFormat = pfmtetc->cfFormat;
  877. if ((cfFormat != g_cfDisplayDevice) &&
  878. (cfFormat != g_cfDisplayName) &&
  879. (cfFormat != g_cfDisplayDeviceID) &&
  880. (cfFormat != g_cfMonitorDevice) &&
  881. (cfFormat != g_cfMonitorName) &&
  882. (cfFormat != g_cfMonitorDeviceID) &&
  883. (cfFormat != g_cfExtensionInterface) &&
  884. (cfFormat != g_cfDisplayDeviceKey) &&
  885. (cfFormat != g_cfDisplayStateFlags) &&
  886. (cfFormat != g_cfDisplayPruningMode))
  887. {
  888. return DV_E_FORMATETC;
  889. }
  890. if (pfmtetc->lindex != -1)
  891. {
  892. return DV_E_LINDEX;
  893. }
  894. return S_OK;
  895. }
  896. STDMETHODIMP CDisplaySettings::GetCanonicalFormatEtc(FORMATETC *pfmtetcIn, FORMATETC *pfmtetcOut)
  897. {
  898. HRESULT hr;
  899. ASSERT(pfmtetcIn);
  900. ASSERT(pfmtetcOut);
  901. hr = QueryGetData(pfmtetcIn);
  902. if (hr == S_OK)
  903. {
  904. *pfmtetcOut = *pfmtetcIn;
  905. if (pfmtetcIn->ptd == NULL)
  906. hr = DATA_S_SAMEFORMATETC;
  907. else
  908. {
  909. pfmtetcIn->ptd = NULL;
  910. ASSERT(hr == S_OK);
  911. }
  912. }
  913. else
  914. ZeroMemory(pfmtetcOut, SIZEOF(*pfmtetcOut));
  915. return(hr);
  916. }
  917. STDMETHODIMP CDisplaySettings::SetData(FORMATETC *pfmtetc, STGMEDIUM *pstgmed, BOOL bRelease)
  918. {
  919. return E_NOTIMPL;
  920. }
  921. STDMETHODIMP CDisplaySettings::EnumFormatEtc(DWORD dwDirFlags, IEnumFORMATETC ** ppiefe)
  922. {
  923. HRESULT hr;
  924. ASSERT(ppiefe);
  925. *ppiefe = NULL;
  926. if (dwDirFlags == DATADIR_GET)
  927. {
  928. FORMATETC rgfmtetc[] =
  929. {
  930. { (CLIPFORMAT)g_cfDisplayDevice, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
  931. { (CLIPFORMAT)g_cfDisplayName, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
  932. { (CLIPFORMAT)g_cfMonitorDevice, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
  933. { (CLIPFORMAT)g_cfMonitorName, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
  934. { (CLIPFORMAT)g_cfExtensionInterface, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
  935. { (CLIPFORMAT)g_cfDisplayDeviceID, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
  936. { (CLIPFORMAT)g_cfMonitorDeviceID, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
  937. { (CLIPFORMAT)g_cfDisplayDeviceKey, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
  938. { (CLIPFORMAT)g_cfDisplayStateFlags, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
  939. { (CLIPFORMAT)g_cfDisplayPruningMode, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
  940. };
  941. hr = SHCreateStdEnumFmtEtc(ARRAYSIZE(rgfmtetc), rgfmtetc, ppiefe);
  942. }
  943. else
  944. hr = E_NOTIMPL;
  945. return(hr);
  946. }
  947. STDMETHODIMP CDisplaySettings::DAdvise(FORMATETC *pfmtetc, DWORD dwAdviseFlags, IAdviseSink * piadvsink, DWORD * pdwConnection)
  948. {
  949. ASSERT(pfmtetc);
  950. ASSERT(pdwConnection);
  951. *pdwConnection = 0;
  952. return OLE_E_ADVISENOTSUPPORTED;
  953. }
  954. STDMETHODIMP CDisplaySettings::DUnadvise(DWORD dwConnection)
  955. {
  956. return OLE_E_ADVISENOTSUPPORTED;
  957. }
  958. STDMETHODIMP CDisplaySettings::EnumDAdvise(IEnumSTATDATA ** ppiesd)
  959. {
  960. ASSERT(ppiesd);
  961. *ppiesd = NULL;
  962. return OLE_E_ADVISENOTSUPPORTED;
  963. }
  964. void CDisplaySettings::_InitClipboardFormats()
  965. {
  966. if (g_cfDisplayDevice == 0)
  967. g_cfDisplayDevice = RegisterClipboardFormat(DESKCPLEXT_DISPLAY_DEVICE);
  968. if (g_cfDisplayDeviceID == 0)
  969. g_cfDisplayDeviceID = RegisterClipboardFormat(DESKCPLEXT_DISPLAY_ID);
  970. if (g_cfDisplayName == 0)
  971. g_cfDisplayName = RegisterClipboardFormat(DESKCPLEXT_DISPLAY_NAME);
  972. if (g_cfMonitorDevice == 0)
  973. g_cfMonitorDevice = RegisterClipboardFormat(DESKCPLEXT_MONITOR_DEVICE);
  974. if (g_cfMonitorDeviceID == 0)
  975. g_cfMonitorDeviceID = RegisterClipboardFormat(DESKCPLEXT_MONITOR_ID);
  976. if (g_cfMonitorName == 0)
  977. g_cfMonitorName = RegisterClipboardFormat(DESKCPLEXT_MONITOR_NAME);
  978. if (g_cfExtensionInterface == 0)
  979. g_cfExtensionInterface = RegisterClipboardFormat(DESKCPLEXT_INTERFACE);
  980. if (g_cfDisplayDeviceKey == 0)
  981. g_cfDisplayDeviceKey = RegisterClipboardFormat(DESKCPLEXT_DISPLAY_DEVICE_KEY);
  982. if (g_cfDisplayStateFlags == 0)
  983. g_cfDisplayStateFlags = RegisterClipboardFormat(DESKCPLEXT_DISPLAY_STATE_FLAGS);
  984. if (g_cfDisplayPruningMode == 0)
  985. g_cfDisplayPruningMode = RegisterClipboardFormat(DESKCPLEXT_PRUNING_MODE);
  986. }
  987. HRESULT CDisplaySettings::QueryInterface(REFIID riid, LPVOID * ppvObj)
  988. {
  989. static const QITAB qit[] = {
  990. QITABENT(CDisplaySettings, IDataObject),
  991. QITABENT(CDisplaySettings, IDisplaySettings),
  992. { 0 },
  993. };
  994. return QISearch(this, qit, riid, ppvObj);
  995. }
  996. ULONG CDisplaySettings::AddRef()
  997. {
  998. return InterlockedIncrement(&_cRef);
  999. }
  1000. ULONG CDisplaySettings::Release()
  1001. {
  1002. if (InterlockedDecrement(&_cRef))
  1003. return _cRef;
  1004. delete this;
  1005. return 0;
  1006. }
  1007. STDMETHODIMP_(LPDEVMODEW)
  1008. CDisplaySettings::_lpfnEnumAllModes(
  1009. LPVOID pContext,
  1010. DWORD iMode)
  1011. {
  1012. DWORD cCount = 0;
  1013. DWORD i;
  1014. CDisplaySettings *pSettings = (CDisplaySettings *) pContext;
  1015. for (i = 0; pSettings->_apdm && (i < pSettings->_cpdm); i++)
  1016. {
  1017. // Don't show invalid modes or raw modes if pruning is on;
  1018. if(!_IsModeVisible(pSettings, i))
  1019. {
  1020. continue;
  1021. }
  1022. if (cCount == iMode)
  1023. {
  1024. return (pSettings->_apdm + i)->lpdm;
  1025. }
  1026. cCount++;
  1027. }
  1028. return NULL;
  1029. }
  1030. STDMETHODIMP_(BOOL)
  1031. CDisplaySettings::_lpfnSetSelectedMode(
  1032. LPVOID pContext,
  1033. LPDEVMODEW lpdm)
  1034. {
  1035. CDisplaySettings *pSettings = (CDisplaySettings *) pContext;
  1036. return pSettings->_PerfectMatch(lpdm);
  1037. }
  1038. STDMETHODIMP_(LPDEVMODEW)
  1039. CDisplaySettings::_lpfnGetSelectedMode(
  1040. LPVOID pContext
  1041. )
  1042. {
  1043. CDisplaySettings *pSettings = (CDisplaySettings *) pContext;
  1044. return pSettings->_pCurDevmode;
  1045. }
  1046. STDMETHODIMP_(VOID)
  1047. CDisplaySettings::_lpfnSetPruningMode(
  1048. LPVOID pContext,
  1049. BOOL bIsPruningOn)
  1050. {
  1051. CDisplaySettings *pSettings = (CDisplaySettings *) pContext;
  1052. pSettings->SetPruningMode(bIsPruningOn);
  1053. }
  1054. STDMETHODIMP_(VOID)
  1055. CDisplaySettings::_lpfnGetPruningMode(
  1056. LPVOID pContext,
  1057. BOOL* pbCanBePruned,
  1058. BOOL* pbIsPruningReadOnly,
  1059. BOOL* pbIsPruningOn)
  1060. {
  1061. CDisplaySettings *pSettings = (CDisplaySettings *) pContext;
  1062. pSettings->GetPruningMode(pbCanBePruned,
  1063. pbIsPruningReadOnly,
  1064. pbIsPruningOn);
  1065. }
  1066. // If any attached device is at 640x480, we want to force small font
  1067. BOOL CDisplaySettings::IsSmallFontNecessary()
  1068. {
  1069. if (_fOrgAttached || _fCurAttached)
  1070. {
  1071. //
  1072. // Force Small fonts at 640x480
  1073. //
  1074. if (_CURXRES < 800 || _CURYRES < 600)
  1075. return TRUE;
  1076. }
  1077. return FALSE;
  1078. }
  1079. // Constructor for CDisplaySettings
  1080. //
  1081. // (gets called when ever a CDisplaySettings object is created)
  1082. //
  1083. CDisplaySettings::CDisplaySettings()
  1084. : _cRef(1)
  1085. , _cpdm(0)
  1086. , _apdm(0)
  1087. , _hPruningRegKey(NULL)
  1088. , _bCanBePruned(FALSE)
  1089. , _bIsPruningReadOnly(TRUE)
  1090. , _bIsPruningOn(FALSE)
  1091. , _pOrgDevmode(NULL)
  1092. , _pCurDevmode(NULL)
  1093. , _fOrgAttached(FALSE)
  1094. , _fCurAttached(FALSE)
  1095. , _bFilterOrientation(FALSE)
  1096. , _bFilterFixedOutput(FALSE)
  1097. {
  1098. SetRectEmpty(&_rcPreview);
  1099. }
  1100. //
  1101. // Destructor
  1102. //
  1103. CDisplaySettings::~CDisplaySettings() {
  1104. TraceMsg(TF_DISPLAYSETTINGS, "**** Destructing %s", _pDisplayDevice->DeviceName);
  1105. if (_apdm)
  1106. {
  1107. while(_cpdm--)
  1108. {
  1109. LocalFree((_apdm + _cpdm)->lpdm);
  1110. }
  1111. LocalFree(_apdm);
  1112. _apdm = NULL;
  1113. }
  1114. _cpdm = 0;
  1115. if(NULL != _hPruningRegKey)
  1116. RegCloseKey(_hPruningRegKey);
  1117. }
  1118. //
  1119. // _SetFilterOptions -- determine if display modes should be filtered
  1120. // by orientation and/or fixed output (centered/stretched)
  1121. //
  1122. void CDisplaySettings::_SetFilterOptions(LPCTSTR pszDeviceName, LPDEVMODEW pdevmode)
  1123. {
  1124. BOOL bCurrent = FALSE;
  1125. BOOL bRegistry = FALSE;
  1126. // See if we need to filter modes by orientation and/or stretched/centered
  1127. ZeroMemory(pdevmode, sizeof(DEVMODE));
  1128. pdevmode->dmSize = sizeof(DEVMODE);
  1129. bCurrent = EnumDisplaySettingsExWrap(pszDeviceName,
  1130. ENUM_CURRENT_SETTINGS,
  1131. pdevmode,
  1132. 0);
  1133. if (!bCurrent)
  1134. {
  1135. TraceMsg(TF_DUMP_CSETTINGS, "_SetFilterOptions -- No Current Mode. Try to use registry settings.");
  1136. bRegistry = EnumDisplaySettingsExWrap(pszDeviceName,
  1137. ENUM_REGISTRY_SETTINGS,
  1138. pdevmode,
  1139. 0);
  1140. }
  1141. if (bCurrent || bRegistry)
  1142. {
  1143. if (pdevmode->dmFields & DM_DISPLAYORIENTATION)
  1144. {
  1145. _bFilterOrientation = TRUE;
  1146. _dwOrientation = pdevmode->dmDisplayOrientation;
  1147. TraceMsg(TF_DUMP_CSETTINGS, "Filtering modes on orientation %d", _dwOrientation);
  1148. }
  1149. if (pdevmode->dmFields & DM_DISPLAYFIXEDOUTPUT)
  1150. {
  1151. _bFilterFixedOutput = TRUE;
  1152. _dwFixedOutput = pdevmode->dmDisplayFixedOutput;
  1153. TraceMsg(TF_DUMP_CSETTINGS, "Filtering modes on fixed output %d", _dwFixedOutput);
  1154. }
  1155. }
  1156. else
  1157. {
  1158. TraceMsg(TF_DUMP_CSETTINGS, "_SetFilterOptions -- No settings, forcing default");
  1159. _bFilterOrientation = TRUE;
  1160. _dwOrientation = DMDO_DEFAULT;
  1161. }
  1162. TraceMsg(TF_DUMP_CSETTINGS, "Filter mode settings for: %s", pszDeviceName);
  1163. TraceMsg(TF_DUMP_CSETTINGS, " _bFilterOrientation: %d, _dwOrientation: %d", _bFilterOrientation, _dwOrientation);
  1164. TraceMsg(TF_DUMP_CSETTINGS, " _bFilterFixedOutput: %d, _dwFixedOutput: %d", _bFilterFixedOutput, _dwFixedOutput);
  1165. }
  1166. //
  1167. // InitSettings -- Enumerate the settings, and build the mode list when
  1168. //
  1169. BOOL CDisplaySettings::InitSettings(LPDISPLAY_DEVICE pDisplay)
  1170. {
  1171. BOOL fReturn = FALSE;
  1172. LPDEVMODE pdevmode = (LPDEVMODE) LocalAlloc(LPTR, (sizeof(DEVMODE) + 0xFFFF));
  1173. if (pdevmode)
  1174. {
  1175. ULONG i = 0;
  1176. BOOL bCurrent = FALSE;
  1177. BOOL bRegistry = FALSE;
  1178. BOOL bExact = FALSE;
  1179. fReturn = TRUE;
  1180. // Set the cached values for modes.
  1181. MAKEXYRES(&_ptCurPos, 0, 0);
  1182. _fCurAttached = FALSE;
  1183. _pCurDevmode = NULL;
  1184. // Save the display name
  1185. ASSERT(pDisplay);
  1186. _pDisplayDevice = pDisplay;
  1187. TraceMsg(TF_GENERAL, "Initializing CDisplaySettings for %s", _pDisplayDevice->DeviceName);
  1188. // Pruning Mode
  1189. _bCanBePruned = ((_pDisplayDevice->StateFlags & DISPLAY_DEVICE_MODESPRUNED) != 0);
  1190. _bIsPruningReadOnly = TRUE;
  1191. _bIsPruningOn = FALSE;
  1192. if (_bCanBePruned)
  1193. {
  1194. _bIsPruningOn = TRUE; // if can be pruned, by default pruning is on
  1195. GetDeviceRegKey(_pDisplayDevice->DeviceKey, &_hPruningRegKey, &_bIsPruningReadOnly);
  1196. if (_hPruningRegKey)
  1197. {
  1198. DWORD dwIsPruningOn = 1;
  1199. DWORD cb = sizeof(dwIsPruningOn);
  1200. RegQueryValueEx(_hPruningRegKey,
  1201. SZ_PRUNNING_MODE,
  1202. NULL,
  1203. NULL,
  1204. (LPBYTE)&dwIsPruningOn,
  1205. &cb);
  1206. _bIsPruningOn = (dwIsPruningOn != 0);
  1207. }
  1208. }
  1209. // See if we need to filter modes by orientation and/or stretched/centered
  1210. _SetFilterOptions(_pDisplayDevice->DeviceName, pdevmode);
  1211. // Lets generate a list with all the possible modes.
  1212. ZeroMemory(pdevmode, sizeof(DEVMODE));
  1213. pdevmode->dmSize = sizeof(DEVMODE);
  1214. // Enum the raw list of modes
  1215. while (EnumDisplaySettingsExWrap(_pDisplayDevice->DeviceName, i++, pdevmode, EDS_RAWMODE))
  1216. {
  1217. WORD dmsize = pdevmode->dmSize + pdevmode->dmDriverExtra;
  1218. LPDEVMODE lpdm = (LPDEVMODE) LocalAlloc(LPTR, dmsize);
  1219. if (lpdm)
  1220. {
  1221. CopyMemory(lpdm, pdevmode, dmsize);
  1222. _AddDevMode(lpdm);
  1223. }
  1224. pdevmode->dmDriverExtra = 0;
  1225. }
  1226. // Filter the list of modes
  1227. _FilterModes();
  1228. if(_bCanBePruned)
  1229. {
  1230. // Enum pruned list of modes
  1231. i = 0;
  1232. _bCanBePruned = FALSE;
  1233. while (EnumDisplaySettingsExWrap(_pDisplayDevice->DeviceName, i++, pdevmode, 0))
  1234. {
  1235. if(_MarkMode(pdevmode))
  1236. _bCanBePruned = TRUE; // at least one non-raw mode
  1237. pdevmode->dmDriverExtra = 0;
  1238. }
  1239. if(!_bCanBePruned)
  1240. {
  1241. _bIsPruningReadOnly = TRUE;
  1242. _bIsPruningOn = FALSE;
  1243. }
  1244. }
  1245. // Debug
  1246. _Dump_CDisplaySettings(TRUE);
  1247. // Get the current mode
  1248. ZeroMemory(pdevmode,sizeof(DEVMODE));
  1249. pdevmode->dmSize = sizeof(DEVMODE);
  1250. bCurrent = EnumDisplaySettingsExWrap(_pDisplayDevice->DeviceName,
  1251. ENUM_CURRENT_SETTINGS,
  1252. pdevmode,
  1253. 0);
  1254. if (!bCurrent)
  1255. {
  1256. TraceMsg(TF_DISPLAYSETTINGS, "InitSettings -- No Current Mode. Try to use registry settings.");
  1257. ZeroMemory(pdevmode,sizeof(DEVMODE));
  1258. pdevmode->dmSize = sizeof(DEVMODE);
  1259. bRegistry = EnumDisplaySettingsExWrap(_pDisplayDevice->DeviceName,
  1260. ENUM_REGISTRY_SETTINGS,
  1261. pdevmode,
  1262. 0);
  1263. }
  1264. // Set the default values based on registry or current settings.
  1265. if (bCurrent || bRegistry)
  1266. {
  1267. // Check if this DEVMODE is in the list
  1268. TraceMsg(TF_FUNC, "Devmode for Exact Matching");
  1269. _Dump_CDevmode(pdevmode);
  1270. TraceMsg(TF_FUNC, "");
  1271. // If the current mode is not in the list of modes supported by
  1272. // the monitor, we want to show it anyway.
  1273. //
  1274. // Consider the following scenario: the user sets the display
  1275. // to 1024x768 and after that it goes to DevManager and selects
  1276. // a monitor type that can not do that mode. When the user
  1277. // reopens the applet the current mode will be pruned out.
  1278. // In such a case we want the current mode to be visible.
  1279. bExact = _ExactMatch(pdevmode, TRUE);
  1280. if (!bExact && bCurrent)
  1281. {
  1282. // If the current mode is not in the list, we may have a problem.
  1283. }
  1284. // Is attached?
  1285. if(bCurrent)
  1286. {
  1287. _fOrgAttached = _fCurAttached = ((pdevmode->dmFields & DM_POSITION) ? 1 : 0);
  1288. }
  1289. // Set the original values
  1290. if (bExact == TRUE)
  1291. {
  1292. MAKEXYRES(&_ptCurPos, pdevmode->dmPosition.x, pdevmode->dmPosition.y);
  1293. ConfirmChangeSettings();
  1294. }
  1295. }
  1296. // If we have no modes, return FALSE.
  1297. if (_cpdm == 0)
  1298. {
  1299. FmtMessageBox(ghwndPropSheet,
  1300. MB_ICONEXCLAMATION,
  1301. MSG_CONFIGURATION_PROBLEM,
  1302. MSG_INVALID_OLD_DISPLAY_DRIVER);
  1303. fReturn = FALSE;
  1304. }
  1305. else
  1306. {
  1307. // If there were no current values, set some now
  1308. // But don't confirm them ...
  1309. if (bExact == FALSE)
  1310. {
  1311. TraceMsg(TF_DISPLAYSETTINGS, "InitSettings -- No Current OR Registry Mode");
  1312. i = 0;
  1313. // Try setting any mode as the current.
  1314. while (_apdm && (_PerfectMatch((_apdm + i++)->lpdm) == FALSE))
  1315. {
  1316. if (i > _cpdm)
  1317. {
  1318. FmtMessageBox(ghwndPropSheet,
  1319. MB_ICONEXCLAMATION,
  1320. MSG_CONFIGURATION_PROBLEM,
  1321. MSG_INVALID_OLD_DISPLAY_DRIVER);
  1322. fReturn = FALSE;
  1323. break;
  1324. }
  1325. }
  1326. if (fReturn && _fCurAttached)
  1327. {
  1328. MAKEXYRES(&_ptCurPos, _pCurDevmode->dmPosition.x, _pCurDevmode->dmPosition.y);
  1329. }
  1330. }
  1331. if (fReturn)
  1332. {
  1333. // Export our interfaces for extended properly pages.
  1334. _InitClipboardFormats();
  1335. // Final debug output
  1336. TraceMsg(TF_DUMP_CSETTINGS," InitSettings successful - current values :");
  1337. _Dump_CDisplaySettings(FALSE);
  1338. }
  1339. }
  1340. LocalFree(pdevmode);
  1341. }
  1342. return TRUE;
  1343. }
  1344. // SaveSettings
  1345. //
  1346. // Writes the new display parameters to the proper place in the
  1347. // registry.
  1348. int CDisplaySettings::SaveSettings(DWORD dwSet)
  1349. {
  1350. int iResult = 0;
  1351. if (_pCurDevmode)
  1352. {
  1353. // Make a copy of the current devmode
  1354. ULONG dmSize = _pCurDevmode->dmSize + _pCurDevmode->dmDriverExtra;
  1355. PDEVMODE pdevmode = (LPDEVMODE) LocalAlloc(LPTR, dmSize);
  1356. if (pdevmode)
  1357. {
  1358. CopyMemory(pdevmode, _pCurDevmode, dmSize);
  1359. // Save all of the new values out to the registry
  1360. // Resolution color bits and frequency
  1361. //
  1362. // We always have to set DM_POSITION when calling the API.
  1363. // In order to remove a device from the desktop, what actually needs
  1364. // to be done is provide an empty rectangle.
  1365. pdevmode->dmFields |= DM_POSITION;
  1366. if (!_fCurAttached)
  1367. {
  1368. pdevmode->dmPelsWidth = 0;
  1369. pdevmode->dmPelsHeight = 0;
  1370. }
  1371. else
  1372. {
  1373. pdevmode->dmPosition.x = _ptCurPos.x;
  1374. pdevmode->dmPosition.y = _ptCurPos.y;
  1375. }
  1376. TraceMsg(TF_GENERAL, "SaveSettings:: Display: %s", _pDisplayDevice->DeviceName);
  1377. _Dump_CDevmode(pdevmode);
  1378. // These calls have NORESET flag set so that it only goes to
  1379. // change the registry settings, it does not refresh the display
  1380. // If EnumDisplaySettings was called with EDS_RAWMODE, we need CDS_RAWMODE below.
  1381. // Otherwise, it's harmless.
  1382. iResult = ChangeDisplaySettingsEx(_pDisplayDevice->DeviceName,
  1383. pdevmode,
  1384. NULL,
  1385. CDS_RAWMODE | dwSet | ( _fPrimary ? CDS_SET_PRIMARY : 0),
  1386. NULL);
  1387. if (iResult < 0)
  1388. {
  1389. TraceMsg(TF_DISPLAYSETTINGS, "**** SaveSettings:: ChangeDisplaySettingsEx not successful on %s", _pDisplayDevice->DeviceName);
  1390. }
  1391. LocalFree(pdevmode);
  1392. }
  1393. }
  1394. return iResult;
  1395. }
  1396. HRESULT CDisplaySettings::GetDevInstID(LPTSTR lpszDeviceKey, STGMEDIUM *pstgmed)
  1397. {
  1398. HRESULT hr = E_FAIL;
  1399. return hr;
  1400. }
  1401. void ConvertStrToToken(LPTSTR pszString, DWORD cchSize)
  1402. {
  1403. while (pszString[0])
  1404. {
  1405. if (TEXT('\\') == pszString[0])
  1406. {
  1407. pszString[0] = TEXT(':');
  1408. }
  1409. pszString++;
  1410. }
  1411. }
  1412. HRESULT CDisplaySettings::_GetRegKey(LPDEVMODE pDevmode, int * pnIndex, LPTSTR pszRegKey, DWORD cchSize,
  1413. LPTSTR pszRegValue, DWORD cchValueSize)
  1414. {
  1415. HRESULT hr = E_FAIL;
  1416. DISPLAY_DEVICE ddMonitor = {0};
  1417. ddMonitor.cb = sizeof(ddMonitor);
  1418. if (pDevmode && pDevmode->dmDeviceName && _pDisplayDevice &&
  1419. EnumDisplayDevices(_pDisplayDevice->DeviceName, *pnIndex, &ddMonitor, 0))
  1420. {
  1421. TCHAR szMonitor[MAX_PATH];
  1422. TCHAR szVideoAdapter[MAX_PATH];
  1423. StrCpyN(szMonitor, ddMonitor.DeviceID, ARRAYSIZE(szMonitor));
  1424. StrCpyN(szVideoAdapter, _pDisplayDevice->DeviceID, ARRAYSIZE(szVideoAdapter));
  1425. ConvertStrToToken(szMonitor, ARRAYSIZE(szMonitor));
  1426. ConvertStrToToken(szVideoAdapter, ARRAYSIZE(szVideoAdapter));
  1427. wnsprintf(pszRegKey, cchSize, TEXT("%s\\%s\\%s,%d\\%dx%d x %dHz"), SZ_CP_SETTINGS_VIDEO,
  1428. szVideoAdapter, szMonitor, *pnIndex, pDevmode->dmPelsWidth, pDevmode->dmPelsHeight,
  1429. pDevmode->dmDisplayFrequency);
  1430. wnsprintf(pszRegValue, cchValueSize, TEXT("%d bpp"), pDevmode->dmBitsPerPel);
  1431. hr = S_OK;
  1432. }
  1433. return hr;
  1434. }
  1435. BOOL CDisplaySettings::ConfirmChangeSettings()
  1436. {
  1437. // Succeeded, so, reset the original settings
  1438. _ptOrgPos = _ptCurPos;
  1439. _pOrgDevmode = _pCurDevmode;
  1440. _fOrgAttached = _fCurAttached;
  1441. // Now write the results to the registry so we know this is safe and can use it later.
  1442. TCHAR szRegKey[2*MAX_PATH];
  1443. TCHAR szRegValue[20];
  1444. int nIndex = 0;
  1445. while (SUCCEEDED(_GetRegKey(_pCurDevmode, &nIndex, szRegKey, ARRAYSIZE(szRegKey), szRegValue, ARRAYSIZE(szRegValue))))
  1446. {
  1447. HKEY hKey;
  1448. if (SUCCEEDED(HrRegCreateKeyEx(HKEY_LOCAL_MACHINE, szRegKey, 0, NULL,
  1449. REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL)))
  1450. {
  1451. RegCloseKey(hKey);
  1452. }
  1453. HrRegSetDWORD(HKEY_LOCAL_MACHINE, szRegKey, szRegValue, 1);
  1454. nIndex++;
  1455. }
  1456. return TRUE;
  1457. }
  1458. BOOL CDisplaySettings::IsKnownSafe(void)
  1459. {
  1460. TCHAR szRegKey[2*MAX_PATH];
  1461. TCHAR szRegValue[20];
  1462. BOOL fIsSafe = FALSE;
  1463. int nIndex = 0;
  1464. while (SUCCEEDED(_GetRegKey(_pCurDevmode, &nIndex, szRegKey, ARRAYSIZE(szRegKey), szRegValue, ARRAYSIZE(szRegValue))))
  1465. {
  1466. fIsSafe = HrRegGetDWORD(HKEY_LOCAL_MACHINE, szRegKey, szRegValue, 0);
  1467. if (!fIsSafe)
  1468. {
  1469. break;
  1470. }
  1471. nIndex++;
  1472. }
  1473. // TODO: In blackcomb, just return TRUE as long as long as we were able to prune the list. If we could prune the list,
  1474. // then the driver dudes where able to get PnP IDs from the video cards (adapters) and monitors, so the list of
  1475. // supported modes should be accurate. If not, the drivers guys (ErickS) will fix. -BryanSt
  1476. return fIsSafe;
  1477. }
  1478. int CDisplaySettings::RestoreSettings()
  1479. {
  1480. //
  1481. // Test failed, so restore the old settings, only restore the color and resolution
  1482. // information, and do restore the monitor position and its attached status
  1483. // Although this function is currently only called when restoring resolution
  1484. // the user could have changed position, then resolution and then clicked 'Apply,'
  1485. // in which case we want to revert position as well.
  1486. //
  1487. int iResult = DISP_CHANGE_SUCCESSFUL;
  1488. PDEVMODE pdevmode;
  1489. //
  1490. // If this display was originally turned off, don't bother
  1491. //
  1492. if ((_pOrgDevmode != NULL) &&
  1493. //(_pOrgDevmode != _pCurDevmode))
  1494. ((_pOrgDevmode != _pCurDevmode) || (_ptOrgPos.x != _ptCurPos.x) || (_ptOrgPos.y != _ptCurPos.y) ))
  1495. {
  1496. iResult = DISP_CHANGE_NOTUPDATED;
  1497. // Make a copy of the original devmode
  1498. ULONG dmSize = _pOrgDevmode->dmSize + _pOrgDevmode->dmDriverExtra;
  1499. pdevmode = (LPDEVMODE) LocalAlloc(LPTR, dmSize);
  1500. if (pdevmode)
  1501. {
  1502. CopyMemory(pdevmode, _pOrgDevmode, dmSize);
  1503. pdevmode->dmFields |= DM_POSITION;
  1504. pdevmode->dmPosition.x = _ptOrgPos.x;
  1505. pdevmode->dmPosition.y = _ptOrgPos.y;
  1506. if (!_fOrgAttached)
  1507. {
  1508. pdevmode->dmPelsWidth = 0;
  1509. pdevmode->dmPelsHeight = 0;
  1510. }
  1511. TraceMsg(TF_GENERAL, "RestoreSettings:: Display: %s", _pDisplayDevice->DeviceName);
  1512. _Dump_CDevmode(pdevmode);
  1513. // If EnumDisplaySettings was called with EDS_RAWMODE, we need CDS_RAWMODE below.
  1514. // Otherwise, it's harmless.
  1515. iResult = ChangeDisplaySettingsEx(_pDisplayDevice->DeviceName,
  1516. pdevmode,
  1517. NULL,
  1518. CDS_RAWMODE | CDS_UPDATEREGISTRY | CDS_NORESET | ( _fPrimary ? CDS_SET_PRIMARY : 0),
  1519. NULL);
  1520. if (iResult < 0 )
  1521. {
  1522. TraceMsg(TF_DISPLAYSETTINGS, "**** RestoreSettings:: ChangeDisplaySettingsEx not successful on %s", _pDisplayDevice->DeviceName);
  1523. ASSERT(FALSE);
  1524. LocalFree(pdevmode);
  1525. return iResult;
  1526. }
  1527. else
  1528. {
  1529. // Succeeded, so, reset the original settings
  1530. _ptCurPos = _ptOrgPos;
  1531. _pCurDevmode = _pOrgDevmode;
  1532. _fCurAttached = _fOrgAttached;
  1533. if(_bCanBePruned && !_bIsPruningReadOnly && _bIsPruningOn && _IsCurDevmodeRaw())
  1534. SetPruningMode(FALSE);
  1535. }
  1536. LocalFree(pdevmode);
  1537. }
  1538. }
  1539. return iResult;
  1540. }
  1541. BOOL CDisplaySettings::_IsModeVisible(int i)
  1542. {
  1543. return _IsModeVisible(this, i);
  1544. }
  1545. BOOL CDisplaySettings::_IsModeVisible(CDisplaySettings* pSettings, int i)
  1546. {
  1547. ASSERT(pSettings);
  1548. if (!pSettings->_apdm)
  1549. {
  1550. return FALSE;
  1551. }
  1552. // (the mode is valid) AND
  1553. // ((pruning mode is off) OR (mode is not raw))
  1554. return ((!((pSettings->_apdm + i)->dwFlags & MODE_INVALID)) &&
  1555. ((!pSettings->_bIsPruningOn) ||
  1556. (!((pSettings->_apdm + i)->dwFlags & MODE_RAW))
  1557. )
  1558. );
  1559. }
  1560. BOOL CDisplaySettings::_IsModePreferred(int i)
  1561. {
  1562. LPDEVMODE pDevMode = ((PMODEARRAY)(_apdm + i))->lpdm;
  1563. if (_pCurDevmode == pDevMode)
  1564. return TRUE;
  1565. BOOL bLandscape = (pDevMode->dmPelsWidth >= pDevMode->dmPelsHeight);
  1566. TraceMsg(TF_DUMP_CSETTINGS, "_IsModePreferred: %d x %d - landscape mode: %d",
  1567. pDevMode->dmPelsWidth, pDevMode->dmPelsHeight, bLandscape);
  1568. // (the mode is valid) AND
  1569. // ((pruning mode is off) OR (mode is not raw))
  1570. return (pDevMode->dmBitsPerPel >= 15 &&
  1571. ((bLandscape && pDevMode->dmPelsWidth >= 800 && pDevMode->dmPelsHeight >= 600) ||
  1572. (!bLandscape && pDevMode->dmPelsWidth >= 600 && pDevMode->dmPelsHeight >= 800)));
  1573. }
  1574. BOOL CDisplaySettings::_MarkMode(LPDEVMODE lpdm)
  1575. {
  1576. LPDEVMODE pdm;
  1577. ULONG i;
  1578. BOOL bMark = FALSE;
  1579. for (i = 0; _apdm && (i < _cpdm); i++)
  1580. {
  1581. if (!((_apdm + i)->dwFlags & MODE_INVALID))
  1582. {
  1583. pdm = (_apdm + i)->lpdm;
  1584. if (
  1585. ((lpdm->dmFields & DM_BITSPERPEL) &&
  1586. (pdm->dmBitsPerPel == lpdm->dmBitsPerPel))
  1587. &&
  1588. ((lpdm->dmFields & DM_PELSWIDTH) &&
  1589. (pdm->dmPelsWidth == lpdm->dmPelsWidth))
  1590. &&
  1591. ((lpdm->dmFields & DM_PELSHEIGHT) &&
  1592. (pdm->dmPelsHeight == lpdm->dmPelsHeight))
  1593. &&
  1594. ((lpdm->dmFields & DM_DISPLAYFREQUENCY) &&
  1595. (pdm->dmDisplayFrequency == lpdm->dmDisplayFrequency))
  1596. )
  1597. {
  1598. (_apdm + i)->dwFlags &= ~MODE_RAW;
  1599. bMark = TRUE;
  1600. }
  1601. }
  1602. }
  1603. return bMark;
  1604. }
  1605. BOOL CDisplaySettings::_IsCurDevmodeRaw()
  1606. {
  1607. LPDEVMODE pdm;
  1608. ULONG i;
  1609. BOOL bCurrentAndPruned = FALSE;
  1610. for (i = 0; _apdm && (i < _cpdm); i++)
  1611. {
  1612. if (!((_apdm + i)->dwFlags & MODE_INVALID) &&
  1613. ((_apdm + i)->dwFlags & MODE_RAW))
  1614. {
  1615. pdm = (_apdm + i)->lpdm;
  1616. if (
  1617. ((_pCurDevmode->dmFields & DM_BITSPERPEL) &&
  1618. (pdm->dmBitsPerPel == _pCurDevmode->dmBitsPerPel))
  1619. &&
  1620. ((_pCurDevmode->dmFields & DM_PELSWIDTH) &&
  1621. (pdm->dmPelsWidth == _pCurDevmode->dmPelsWidth))
  1622. &&
  1623. ((_pCurDevmode->dmFields & DM_PELSHEIGHT) &&
  1624. (pdm->dmPelsHeight == _pCurDevmode->dmPelsHeight))
  1625. &&
  1626. ((_pCurDevmode->dmFields & DM_DISPLAYFREQUENCY) &&
  1627. (pdm->dmDisplayFrequency == _pCurDevmode->dmDisplayFrequency))
  1628. )
  1629. {
  1630. bCurrentAndPruned = TRUE;
  1631. break;
  1632. }
  1633. }
  1634. }
  1635. return bCurrentAndPruned;
  1636. }
  1637. DISPLAY_DEVICE dd;
  1638. HRESULT CDisplaySettings::SetMonitor(DWORD dwMonitor)
  1639. {
  1640. ZeroMemory(&dd, sizeof(DISPLAY_DEVICE));
  1641. dd.cb = sizeof(DISPLAY_DEVICE);
  1642. DWORD dwMon = 0;
  1643. for (DWORD dwCount = 0; EnumDisplayDevices(NULL, dwCount, &dd, 0); dwCount++)
  1644. {
  1645. if (!(dd.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER))
  1646. {
  1647. if (dwMon == dwMonitor)
  1648. {
  1649. InitSettings(&dd);
  1650. _fPrimary = (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE);
  1651. return S_OK;
  1652. }
  1653. dwMon++;
  1654. }
  1655. }
  1656. return E_INVALIDARG;
  1657. }
  1658. HRESULT CDisplaySettings::GetModeCount(DWORD* pdwCount, BOOL fOnlyPreferredModes)
  1659. {
  1660. DWORD cCount = 0;
  1661. for (DWORD i = 0; _apdm && (i < _cpdm); i++)
  1662. {
  1663. // Don't show invalid modes or raw modes if pruning is on;
  1664. if(!_IsModeVisible(i))
  1665. {
  1666. continue;
  1667. }
  1668. if(fOnlyPreferredModes && (!_IsModePreferred(i)))
  1669. {
  1670. continue;
  1671. }
  1672. cCount++;
  1673. }
  1674. *pdwCount = cCount;
  1675. return S_OK;
  1676. }
  1677. HRESULT CDisplaySettings::GetMode(DWORD dwMode, BOOL fOnlyPreferredModes, DWORD* pdwWidth, DWORD* pdwHeight, DWORD* pdwColor)
  1678. {
  1679. DWORD cCount = 0;
  1680. for (DWORD i = 0; _apdm && (i < _cpdm); i++)
  1681. {
  1682. // Don't show invalid modes or raw modes if pruning is on;
  1683. if(!_IsModeVisible(i))
  1684. {
  1685. continue;
  1686. }
  1687. if(fOnlyPreferredModes && (!_IsModePreferred(i)))
  1688. {
  1689. continue;
  1690. }
  1691. if (cCount == dwMode)
  1692. {
  1693. LPDEVMODE lpdm = (_apdm + i)->lpdm;
  1694. *pdwWidth = lpdm->dmPelsWidth;
  1695. *pdwHeight = lpdm->dmPelsHeight;
  1696. *pdwColor = lpdm->dmBitsPerPel;
  1697. return S_OK;
  1698. }
  1699. cCount++;
  1700. }
  1701. return E_INVALIDARG;
  1702. }
  1703. DEVMODE dm;
  1704. HRESULT CDisplaySettings::SetSelectedMode(HWND hwnd, DWORD dwWidth, DWORD dwHeight, DWORD dwColor, BOOL* pfApplied, DWORD dwFlags)
  1705. {
  1706. dm.dmBitsPerPel = dwColor;
  1707. dm.dmPelsWidth = dwWidth;
  1708. dm.dmPelsHeight = dwHeight;
  1709. dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
  1710. *pfApplied = FALSE;
  1711. POINT res = {dwWidth, dwHeight};
  1712. PLONGLONG freq = NULL;
  1713. int cFreq = GetFrequencyList(dwColor, &res, &freq);
  1714. if (cFreq)
  1715. {
  1716. dm.dmFields |= DM_DISPLAYFREQUENCY;
  1717. // Default to lowest frequency
  1718. dm.dmDisplayFrequency = (DWORD)freq[0];
  1719. // Try to find a good frequency
  1720. for (int i = cFreq - 1; i >= 0; i--)
  1721. {
  1722. if ((freq[i] >= 60) && (freq[i] <= 72))
  1723. {
  1724. dm.dmDisplayFrequency = (DWORD)freq[i];
  1725. }
  1726. }
  1727. }
  1728. LocalFree(freq);
  1729. ULONG dmSize = _pCurDevmode->dmSize + _pCurDevmode->dmDriverExtra;
  1730. PDEVMODE pOldDevMode = (LPDEVMODE) LocalAlloc(LPTR, dmSize);
  1731. if (pOldDevMode)
  1732. {
  1733. CopyMemory(pOldDevMode, _pCurDevmode, dmSize);
  1734. if (_ExactMatch(&dm, FALSE))
  1735. {
  1736. // Verify that the mode actually works
  1737. if (SaveSettings(CDS_TEST) == DISP_CHANGE_SUCCESSFUL)
  1738. {
  1739. // Update the registry to specify the new display settings
  1740. if (SaveSettings(CDS_UPDATEREGISTRY | CDS_NORESET) == DISP_CHANGE_SUCCESSFUL)
  1741. {
  1742. // Refresh the display info from the registry, if you update directly ChangeDisplaySettings will do weird things in the fringe cases
  1743. if (ChangeDisplaySettings(NULL, CDS_RAWMODE) == DISP_CHANGE_SUCCESSFUL)
  1744. {
  1745. if (IsKnownSafe())
  1746. {
  1747. // No need to warn, this is known to be a good value.
  1748. *pfApplied = TRUE;
  1749. }
  1750. else
  1751. {
  1752. INT_PTR iRet = DialogBoxParam(HINST_THISDLL,
  1753. MAKEINTRESOURCE((dwFlags & DS_BACKUPDISPLAYCPL) ? DLG_KEEPNEW2 : DLG_KEEPNEW3),
  1754. hwnd,
  1755. KeepNewDlgProc,
  1756. (dwFlags & DS_BACKUPDISPLAYCPL) ? 15 : 30);
  1757. if ((IDYES == iRet) || (IDOK == iRet))
  1758. {
  1759. *pfApplied = TRUE;
  1760. }
  1761. else
  1762. {
  1763. if (_ExactMatch(pOldDevMode, FALSE))
  1764. {
  1765. SaveSettings(CDS_UPDATEREGISTRY | CDS_NORESET);
  1766. ChangeDisplaySettings(NULL, CDS_RAWMODE);
  1767. }
  1768. if (dwFlags & DS_BACKUPDISPLAYCPL)
  1769. {
  1770. // Use shellexecuteex to run the display CPL
  1771. SHELLEXECUTEINFO shexinfo = {0};
  1772. shexinfo.cbSize = sizeof (shexinfo);
  1773. shexinfo.fMask = SEE_MASK_FLAG_NO_UI;
  1774. shexinfo.nShow = SW_SHOWNORMAL;
  1775. shexinfo.lpFile = L"desk.cpl";
  1776. ShellExecuteEx(&shexinfo);
  1777. }
  1778. }
  1779. }
  1780. }
  1781. }
  1782. }
  1783. }
  1784. LocalFree(pOldDevMode);
  1785. }
  1786. return S_OK;
  1787. }
  1788. HRESULT CDisplaySettings::GetSelectedMode(DWORD* pdwWidth, DWORD* pdwHeight, DWORD* pdwColor)
  1789. {
  1790. if (pdwWidth && pdwHeight && pdwColor)
  1791. {
  1792. if (_pCurDevmode)
  1793. {
  1794. *pdwWidth = _pCurDevmode->dmPelsWidth;
  1795. *pdwHeight = _pCurDevmode->dmPelsHeight;
  1796. *pdwColor = _pCurDevmode->dmBitsPerPel;
  1797. return S_OK;
  1798. }
  1799. else
  1800. {
  1801. return E_FAIL;
  1802. }
  1803. }
  1804. else
  1805. {
  1806. return E_INVALIDARG;
  1807. }
  1808. }
  1809. HRESULT CDisplaySettings::GetAttached(BOOL* pfAttached)
  1810. {
  1811. if (pfAttached)
  1812. {
  1813. *pfAttached = _fCurAttached;
  1814. return S_OK;
  1815. }
  1816. else
  1817. return E_INVALIDARG;
  1818. }
  1819. HRESULT CDisplaySettings::SetPruningMode(BOOL fIsPruningOn)
  1820. {
  1821. ASSERT (_bCanBePruned && !_bIsPruningReadOnly);
  1822. if (_bCanBePruned &&
  1823. !_bIsPruningReadOnly &&
  1824. ((fIsPruningOn != 0) != _bIsPruningOn))
  1825. {
  1826. _bIsPruningOn = (fIsPruningOn != 0);
  1827. DWORD dwIsPruningOn = (DWORD)_bIsPruningOn;
  1828. RegSetValueEx(_hPruningRegKey,
  1829. SZ_PRUNNING_MODE,
  1830. NULL,
  1831. REG_DWORD,
  1832. (LPBYTE) &dwIsPruningOn,
  1833. sizeof(dwIsPruningOn));
  1834. //
  1835. // handle the special case when we pruned out the current mode
  1836. //
  1837. if(_bIsPruningOn && _IsCurDevmodeRaw())
  1838. {
  1839. //
  1840. // switch to the closest mode
  1841. //
  1842. _BestMatch(NULL, -1, TRUE);
  1843. }
  1844. }
  1845. return S_OK;
  1846. }
  1847. HRESULT CDisplaySettings::GetPruningMode(BOOL* pfCanBePruned, BOOL* pfIsPruningReadOnly, BOOL* pfIsPruningOn)
  1848. {
  1849. if (pfCanBePruned && pfIsPruningReadOnly && pfIsPruningOn)
  1850. {
  1851. *pfCanBePruned = _bCanBePruned;
  1852. *pfIsPruningReadOnly = _bIsPruningReadOnly;
  1853. *pfIsPruningOn = _bIsPruningOn;
  1854. return S_OK;
  1855. }
  1856. else
  1857. {
  1858. return E_INVALIDARG;
  1859. }
  1860. }
  1861. HRESULT CDisplaySettings_CreateInstance(IN IUnknown * punkOuter, IN REFIID riid, OUT LPVOID * ppvObj)
  1862. {
  1863. HRESULT hr = E_INVALIDARG;
  1864. if (!punkOuter && ppvObj)
  1865. {
  1866. CDisplaySettings * pThis = new CDisplaySettings();
  1867. *ppvObj = NULL;
  1868. if (pThis)
  1869. {
  1870. hr = pThis->QueryInterface(riid, ppvObj);
  1871. pThis->Release();
  1872. }
  1873. else
  1874. {
  1875. hr = E_OUTOFMEMORY;
  1876. }
  1877. }
  1878. return hr;
  1879. }