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.

254 lines
8.7 KiB

  1. //#include "cabinet.h"
  2. #include "priv.h"
  3. #include <regstr.h>
  4. #include <atlcom.h>
  5. #include <shguidp.h>
  6. #include <shlguid.h>
  7. typedef struct
  8. {
  9. DWORD dwWidth;
  10. DWORD dwHeight;
  11. DWORD dwColor;
  12. BOOL fAvailable;
  13. } SCREENMODE;
  14. class ATL_NO_VTABLE CScreenResFixer :
  15. public CComObjectRootEx<CComSingleThreadModel>,
  16. public CComCoClass<CScreenResFixer, &CLSID_ScreenResFixer>,
  17. public IContextMenu,
  18. public IScreenResFixer
  19. {
  20. public:
  21. CScreenResFixer() {}
  22. virtual ~CScreenResFixer() {}
  23. DECLARE_NOT_AGGREGATABLE(CScreenResFixer)
  24. BEGIN_COM_MAP(CScreenResFixer)
  25. COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu)
  26. COM_INTERFACE_ENTRY(IScreenResFixer)
  27. END_COM_MAP()
  28. // *** IContextMenu methods ***
  29. STDMETHODIMP QueryContextMenu(HMENU hmenu, UINT iIndexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) { return E_NOTIMPL; }
  30. STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO lpici);
  31. STDMETHODIMP GetCommandString(UINT_PTR idCmd, UINT uType, UINT *pRes, LPSTR pszName, UINT cchMax) { return E_NOTIMPL; }
  32. private:
  33. int _PickScreenResolution(SCREENMODE* modes, int cModes);
  34. HRESULT _FixScreenResolution(BOOL fShowDisplayCPL);
  35. };
  36. // *** IContextMenu methods ***
  37. STDMETHODIMP CScreenResFixer::InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
  38. {
  39. WCHAR szTitle[256];
  40. HRESULT hr;
  41. szTitle[0] = 0;
  42. LoadString(HINST_THISDLL, IDS_SCREENRESFIXER_TITLE, szTitle, ARRAYSIZE(szTitle));
  43. BOOL fOK = FALSE;
  44. if (lpici)
  45. {
  46. WCHAR szText[512];
  47. szText[0] = 0;
  48. LoadString(HINST_THISDLL, IDS_SCREENRESFIXER_TEXT, szText, ARRAYSIZE(szText));
  49. fOK = (IDYES == SHMessageBoxCheck(NULL, szText, szTitle, MB_YESNO, 0, TEXT("ScreenCheck")));
  50. }
  51. else
  52. {
  53. WCHAR szText[512];
  54. szText[0] = 0;
  55. LoadString(HINST_THISDLL, IDS_SCREENRESFIXER_ALTTEXT, szText, ARRAYSIZE(szText));
  56. fOK = (IDOK == MessageBox(NULL, szText, szTitle, MB_OK));
  57. }
  58. if (fOK)
  59. {
  60. hr = _FixScreenResolution(!(lpici == NULL));
  61. }
  62. else
  63. {
  64. // If the user checked "Don't show me again" then force this setting into HKLM, so that it doesn't
  65. // show up for any users
  66. if (!SHRegGetBoolUSValue(REGSTR_PATH_EXPLORER TEXT("\\DontShowMeThisDialogAgain"), TEXT("ScreenCheck"), FALSE, TRUE))
  67. {
  68. SHRegSetUSValueW(REGSTR_PATH_EXPLORER TEXT("\\DontShowMeThisDialogAgain"), TEXT("ScreenCheck"), REG_SZ, L"no", sizeof(L"no"), SHREGSET_HKLM);
  69. }
  70. hr = S_OK;
  71. }
  72. // Now that the user finished with their screen resolution, tell the Start Menu
  73. // it's okay to pop up.
  74. HWND hwndTray = FindWindow(TEXT(WNDCLASS_TRAYNOTIFY), NULL);
  75. if (hwndTray)
  76. PostMessage(hwndTray, RegisterWindowMessage(TEXT("Welcome Finished")), 0, 0);
  77. return hr;
  78. }
  79. int CScreenResFixer::_PickScreenResolution(SCREENMODE* modes, int cModes)
  80. {
  81. static const struct {
  82. int iMinWidth;
  83. int iMinHeight;
  84. int iMaxWidth;
  85. int iMaxHeight;
  86. int iIdealColor;
  87. }
  88. picker[] =
  89. {
  90. { 800, 600, 1024, 768, 32 },
  91. { 800, 600, 1024, 768, 24 },
  92. { 800, 600, 1024, 768, -1 },
  93. { 1024, 768, -1, -1, 32 },
  94. { 1024, 768, -1, -1, 24 },
  95. { 1024, 768, -1, -1, -1 },
  96. };
  97. for (int i = 0; i < ARRAYSIZE(picker); i++)
  98. {
  99. // Try for Ideal Color in given resolution range
  100. for (int iMode = 0; iMode < cModes; iMode++)
  101. {
  102. if ((modes[iMode].fAvailable) &&
  103. (modes[iMode].dwWidth >= (DWORD)picker[i].iMinWidth) &&
  104. (modes[iMode].dwHeight >= (DWORD)picker[i].iMinHeight))
  105. {
  106. if ((picker[i].iMaxWidth == -1) ||
  107. ((modes[iMode].dwWidth < (DWORD)picker[i].iMaxWidth) &&
  108. (modes[iMode].dwHeight < (DWORD)picker[i].iMaxHeight)))
  109. {
  110. if (((picker[i].iIdealColor == -1) && (modes[iMode].dwColor >= 15)) ||
  111. (modes[iMode].dwColor == (DWORD)picker[i].iIdealColor))
  112. {
  113. return iMode;
  114. }
  115. }
  116. }
  117. }
  118. }
  119. return -1;
  120. }
  121. void UpdateRecycleBinInfo()
  122. {
  123. static const LPTSTR lpszSubkey = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ScreenResFixer");
  124. static const LPTSTR lpszValue = TEXT("AdjustRecycleBinPosition");
  125. //Read if the we have done it once already.
  126. DWORD dwAdjustPos = 0; //Assume that Recycle-bin has been already positioned.
  127. DWORD dwSize = sizeof(dwAdjustPos);
  128. SHRegGetUSValue(lpszSubkey, lpszValue, NULL, &dwAdjustPos, &dwSize, FALSE, &dwAdjustPos, dwSize);
  129. // 0 => Recycle-bin hasn't been positioned because of resolution fixer.
  130. // 1 => Recycle-bin needs to be repositioned. It has't happened yet!
  131. // 2 => Recycle-bin has already been re-positioned. Nothing needs to be done here!
  132. if(dwAdjustPos == 0)
  133. {
  134. // 0 => Recycle-bin hasn't been positioned because of resolution fixer.
  135. // So, we need to change the settings sothat when desktop.cpp responds to res change,
  136. // it will position the recycle-bin.
  137. dwAdjustPos = 1;
  138. SHRegSetUSValue(lpszSubkey, lpszValue, REG_DWORD, &dwAdjustPos, sizeof(dwAdjustPos), SHREGSET_HKCU | SHREGSET_FORCE_HKCU);
  139. }
  140. }
  141. HRESULT CScreenResFixer::_FixScreenResolution(BOOL fShowDisplayCPL)
  142. {
  143. IDisplaySettings * pds;
  144. HRESULT hr = CoCreateInstance(CLSID_DisplaySettings, NULL, CLSCTX_INPROC_SERVER,
  145. IID_PPV_ARG(IDisplaySettings, &pds));
  146. if (SUCCEEDED(hr))
  147. {
  148. for (DWORD dwMon = 0; SUCCEEDED(pds->SetMonitor(dwMon)); dwMon++)
  149. {
  150. BOOL fAttached = FALSE;
  151. hr = pds->GetAttached(&fAttached);
  152. if (SUCCEEDED(hr) && fAttached)
  153. {
  154. DWORD dwWidth, dwHeight, dwColor;
  155. hr = pds->GetSelectedMode(&dwWidth, &dwHeight, &dwColor);
  156. if (SUCCEEDED(hr) && ((dwWidth < 800) || (dwHeight < 600) || (dwColor < 15)))
  157. {
  158. DWORD cModes = 0;
  159. hr = pds->GetModeCount(&cModes, TRUE);
  160. if (SUCCEEDED( hr ) && (cModes > 0))
  161. {
  162. SCREENMODE* modes = new SCREENMODE[cModes];
  163. if (modes)
  164. {
  165. for (DWORD i = 0; i < cModes; i++)
  166. {
  167. hr = pds->GetMode(i, TRUE, &modes[i].dwWidth, &modes[i].dwHeight, &modes[i].dwColor);
  168. modes[i].fAvailable = SUCCEEDED(hr) && ((i <= 0) ||
  169. (modes[i].dwWidth != modes[i-1].dwWidth) ||
  170. (modes[i].dwHeight != modes[i-1].dwHeight) ||
  171. (modes[i].dwColor != modes[i-1].dwColor));
  172. }
  173. int iMode = _PickScreenResolution(modes, cModes);
  174. if (iMode != -1)
  175. {
  176. static BOOL fRecycleBinInfoUpdated = FALSE; //to begin with!
  177. //We are about to change the mode. Make a note in registry
  178. if(!fRecycleBinInfoUpdated)
  179. {
  180. UpdateRecycleBinInfo();
  181. fRecycleBinInfoUpdated = TRUE;
  182. }
  183. BOOL fApplied = FALSE;
  184. pds->SetSelectedMode(NULL, modes[iMode].dwWidth, modes[iMode].dwHeight, modes[iMode].dwColor, &fApplied, fShowDisplayCPL ? DS_BACKUPDISPLAYCPL : 0);
  185. if (!fApplied)
  186. {
  187. hr = E_FAIL;
  188. }
  189. }
  190. delete [] modes;
  191. modes = NULL;
  192. }
  193. else
  194. {
  195. hr = E_OUTOFMEMORY;
  196. }
  197. }
  198. }
  199. }
  200. }
  201. }
  202. return hr;
  203. }
  204. HRESULT CScreenResFixer_CreateInstance(IN IUnknown * punkOuter, IN REFIID riid, OUT LPVOID * ppvObj)
  205. {
  206. HRESULT hr = E_INVALIDARG;
  207. if (!punkOuter && ppvObj)
  208. {
  209. CComObject<CScreenResFixer> * pThis = new CComObject<CScreenResFixer>();
  210. *ppvObj = NULL;
  211. if (pThis)
  212. {
  213. hr = pThis->QueryInterface(riid, ppvObj);
  214. }
  215. else
  216. {
  217. hr = E_OUTOFMEMORY;
  218. }
  219. }
  220. return hr;
  221. }