Leaked source code of windows server 2003
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.

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