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.

5469 lines
171 KiB

  1. /*****************************************************************************\
  2. FILE: SettingsPg.cpp
  3. DESCRIPTION:
  4. This code will display a "Settings" tab in the
  5. "Display Properties" dialog
  6. BryanSt 1/05/2001 Updated and Converted to C++
  7. Copyright (C) Microsoft Corp 1993-2001. All rights reserved.
  8. \*****************************************************************************/
  9. #include "priv.h"
  10. #include "SettingsPg.h"
  11. #include "DisplaySettings.h"
  12. #include "shlobjp.h"
  13. #include "shlwapi.h"
  14. #include "ntreg.hxx"
  15. #include "AdvAppearPg.h"
  16. #include <tchar.h>
  17. #include <dbt.h>
  18. #include <oleacc.h>
  19. #include <devguid.h>
  20. #define EIS_NOT_INVALID 0x00000001
  21. #define EIS_EXEC_INVALID_NEW_DRIVER 0x00000002
  22. #define EIS_EXEC_INVALID_DEFAULT_DISPLAY_MODE 0x00000003
  23. #define EIS_EXEC_INVALID_DISPLAY_DRIVER 0x00000004
  24. #define EIS_EXEC_INVALID_OLD_DISPLAY_DRIVER 0x00000005
  25. #define EIS_EXEC_INVALID_16COLOR_DISPLAY_MODE 0x00000006
  26. #define EIS_EXEC_INVALID_DISPLAY_MODE 0x00000007
  27. #define EIS_EXEC_INVALID_CONFIGURATION 0x00000008
  28. #define EIS_EXEC_INVALID_DISPLAY_DEVICE 0x00000009
  29. LRESULT CALLBACK MonitorWindowProc(HWND hwnd, UINT msg,WPARAM wParam,LPARAM lParam);
  30. LRESULT CALLBACK SliderSubWndProc (HWND hwndSlider, UINT uMsg, WPARAM wParam, LPARAM lParam, WPARAM uID, ULONG_PTR dwRefData);
  31. int ComputeNumberOfDisplayDevices();
  32. BOOL MakeMonitorBitmap(int w, int h, LPCTSTR sz, HBITMAP *pBitmap, HBITMAP *pMaskBitmap, int cx, int cy, BOOL fSelected);
  33. typedef struct _APPEXT {
  34. TCHAR szKeyName[MAX_PATH];
  35. TCHAR szDefaultValue[MAX_PATH];
  36. struct _APPEXT* pNext;
  37. } APPEXT, *PAPPEXT;
  38. VOID CheckForDuplicateAppletExtensions(HKEY hkDriver);
  39. VOID DeskAESnapshot(HKEY hkExtensions, PAPPEXT* ppAppExt);
  40. VOID DeskAECleanup(PAPPEXT pAppExt);
  41. VOID DeskAEDelete(PTCHAR szDeleteFrom, PTCHAR mszExtensionsToRemove);
  42. #define SELECTION_THICKNESS 4
  43. #define MONITOR_BORDER 1
  44. #define REGSTR_VAL_SAFEBOOT TEXT("System\\CurrentControlSet\\Control\\SafeBoot\\Option")
  45. // Maximum number of monitors supported.
  46. #define MONITORS_MAX 10
  47. #define PREVIEWAREARATIO 2
  48. #define MM_REDRAWPREVIEW (WM_USER + 1)
  49. #define MM_MONITORMOVED (WM_USER + 2)
  50. #define ToolTip_Activate(hTT, activate) \
  51. SendMessage(hTT, TTM_ACTIVATE, (WPARAM) activate, (LPARAM) 0)
  52. #define ToolTip_AddTool(hTT, lpti) \
  53. SendMessage(hTT, TTM_ADDTOOL, (WPARAM) 0, (LPARAM) (lpti))
  54. #define ToolTip_DelTool(hTT, lpti) \
  55. SendMessage(hTT, TTM_DELTOOL, (WPARAM) 0, (LPARAM) (lpti))
  56. #define ToolTip_GetCurrentTool(hTT, lpti) \
  57. SendMessage(hTT, TTM_GETCURRENTTOOL, (WPARAM) 0, (LPARAM) (lpti))
  58. #define ToolTip_RelayEvent(hTT, _msg, h, m, wp, lp) \
  59. _msg.hwnd = h; _msg.message = m; _msg.wParam = wp; _msg.lParam = lp;\
  60. SendMessage(hTT, TTM_RELAYEVENT, (WPARAM) 0, (LPARAM) &_msg);
  61. #define ToolTip_SetDelayTime(hTT, d, t) \
  62. SendMessage(hTT, TTM_SETDELAYTIME, (WPARAM) d, (LPARAM)MAKELONG((t), 0))
  63. #define ToolTip_SetToolInfo(hTT, lpti) \
  64. SendMessage(hTT, TTM_SETTOOLINFO, (WPARAM) 0, (LPARAM) (lpti))
  65. #define ToolTip_TrackActivate(hTT, bActivate, lpti) \
  66. SendMessage(hTT, TTM_TRACKACTIVATE, (WPARAM) (bActivate), (LPARAM) (lpti))
  67. #define ToolTip_TrackPosition(hTT, x, y) \
  68. SendMessage(hTT, TTM_TRACKPOSITION, (WPARAM) 0, (LPARAM) MAKELONG((x), (y)))
  69. #define ToolTip_Update(hTT) \
  70. SendMessage(hTT, TTM_UPDATE, (WPARAM) 0, (LPARAM) 0)
  71. VOID
  72. CDECL
  73. TRACE(
  74. PCTSTR pszMsg,
  75. ...
  76. )
  77. /*++
  78. Outputs a message to the setup log. Prepends "desk.cpl " to the strings and
  79. appends the correct newline chars (\r\n)==
  80. --*/
  81. {
  82. TCHAR ach[1024+40]; // Largest path plus extra
  83. va_list vArgs;
  84. va_start(vArgs, pszMsg);
  85. StringCchVPrintf(ach, ARRAYSIZE(ach), pszMsg, vArgs);
  86. va_end(vArgs);
  87. OutputDebugString(ach);
  88. }
  89. #ifdef _WIN64
  90. //
  91. // GetDlgItem and GetDlgCtrlID don't support INT_PTR's,
  92. // so we have to do it manually.
  93. // Fortunately, GetWindowLongPtr(GWLP_ID) actually returns a full 64-bit
  94. // value instead of truncating at 32-bits.
  95. //
  96. #define GetDlgCtrlIDP(hwnd) GetWindowLongPtr(hwnd, GWLP_ID)
  97. HWND GetDlgItemP(HWND hDlg, INT_PTR id)
  98. {
  99. HWND hwndChild = GetWindow(hDlg, GW_CHILD);
  100. while (hwndChild && GetDlgCtrlIDP(hwndChild) != id)
  101. hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
  102. return hwndChild;
  103. }
  104. #else
  105. #define GetDlgItemP GetDlgItem
  106. #define GetDlgCtrlIDP GetDlgCtrlID
  107. #endif
  108. //
  109. // display devices
  110. //
  111. typedef struct _multimon_device {
  112. //
  113. // Main class for settings
  114. //
  115. CDisplaySettings * pds;
  116. //
  117. // Color and resolution information cache
  118. // Rebuild when modes are enumerated.
  119. //
  120. int cColors;
  121. PLONGLONG ColorList;
  122. int cResolutions;
  123. PPOINT ResolutionList;
  124. ULONG ComboBoxItem;
  125. DISPLAY_DEVICE DisplayDevice;
  126. ULONG DisplayIndex;
  127. POINT Snap;
  128. HDC hdc;
  129. //
  130. // Image information.
  131. //
  132. int w,h;
  133. HIMAGELIST himl;
  134. int iImage;
  135. BOOLEAN bTracking;
  136. HWND hwndFlash; //Flash window.
  137. } MULTIMON_DEVICE, *PMULTIMON_DEVICE;
  138. #define GetDlgCtrlDevice(hwnd) ((PMULTIMON_DEVICE)GetDlgCtrlIDP(hwnd))
  139. BOOL gfFlashWindowRegistered = FALSE;
  140. HWND ghwndToolTipTracking;
  141. HWND ghwndToolTipPopup;
  142. HWND ghwndPropSheet;
  143. void AddTrackingToolTip(PMULTIMON_DEVICE pDevice, HWND hwnd);
  144. void RemoveTrackingToolTip(HWND hwnd);
  145. void AddPopupToolTip(HWND hwndC);
  146. void RemovePopupToolTip(HWND hwndC);
  147. extern int AskDynaCDS(HWND hDlg);
  148. extern int GetDisplayCPLPreference(LPCTSTR szRegVal);
  149. extern void SetDisplayCPLPreference(LPCTSTR szRegVal, int val);
  150. // Prototype for CreateStdAccessibleProxy.
  151. // A and W versions are available - pClassName can be ANSI or UNICODE
  152. // string. This is a TCHAR-style prototype, but you can do a A or W
  153. // specific one if desired.
  154. typedef HRESULT (WINAPI *PFNCREATESTDACCESSIBLEPROXY) (
  155. HWND hWnd,
  156. LPTSTR pClassName,
  157. LONG idObject,
  158. REFIID riid,
  159. void ** ppvObject
  160. );
  161. // Same for LresultFromObject...
  162. typedef LRESULT (WINAPI *PFNLRESULTFROMOBJECT)(
  163. REFIID riid,
  164. WPARAM wParam,
  165. LPUNKNOWN punk
  166. );
  167. PRIVATE PFNCREATESTDACCESSIBLEPROXY s_pfnCreateStdAccessibleProxy = NULL;
  168. PRIVATE PFNLRESULTFROMOBJECT s_pfnLresultFromObject = NULL;
  169. BOOL g_fAttemptedOleAccLoad ;
  170. HMODULE g_hOleAcc;
  171. //-----------------------------------------------------------------------------
  172. static const DWORD sc_MultiMonitorHelpIds[] =
  173. {
  174. IDC_SCREENSAMPLE, IDH_DISPLAY_SETTINGS_MONITOR_GRAPHIC,
  175. IDC_MULTIMONHELP, IDH_DISPLAY_SETTINGS_MONITOR_GRAPHIC,
  176. IDC_DISPLAYDESK, IDH_DISPLAY_SETTINGS_MONITOR_GRAPHIC,
  177. IDC_DISPLAYLABEL, IDH_DISPLAY_SETTINGS_DISPLAY_LIST,
  178. IDC_DISPLAYLIST, IDH_DISPLAY_SETTINGS_DISPLAY_LIST,
  179. IDC_DISPLAYTEXT, IDH_DISPLAY_SETTINGS_DISPLAY_LIST,
  180. IDC_COLORGROUPBOX, IDH_DISPLAY_SETTINGS_COLORBOX,
  181. IDC_COLORBOX, IDH_DISPLAY_SETTINGS_COLORBOX,
  182. IDC_COLORSAMPLE, IDH_DISPLAY_SETTINGS_COLORBOX,
  183. IDC_RESGROUPBOX, IDH_DISPLAY_SETTINGS_SCREENAREA,
  184. IDC_SCREENSIZE, IDH_DISPLAY_SETTINGS_SCREENAREA,
  185. IDC_RES_LESS, IDH_DISPLAY_SETTINGS_SCREENAREA,
  186. IDC_RES_MORE, IDH_DISPLAY_SETTINGS_SCREENAREA,
  187. IDC_RESXY, IDH_DISPLAY_SETTINGS_SCREENAREA,
  188. IDC_DISPLAYUSEME, IDH_DISPLAY_SETTINGS_EXTEND_DESKTOP_CHECKBOX,
  189. IDC_DISPLAYPRIME, IDH_DISPLAY_SETTINGS_USE_PRIMARY_CHECKBOX,
  190. IDC_IDENTIFY, IDH_DISPLAY_SETTINGS_IDENTIFY_BUTTON,
  191. IDC_TROUBLESHOOT, IDH_DISPLAY_SETTINGS_TROUBLE_BUTTON,
  192. IDC_DISPLAYPROPERTIES, IDH_DISPLAY_SETTINGS_ADVANCED_BUTTON,
  193. 0, 0
  194. };
  195. class CAccessibleWrapper: public IAccessible
  196. {
  197. // We need to do our own refcounting for this wrapper object
  198. LONG m_cRef;
  199. // Need ptr to the IAccessible
  200. IAccessible * m_pAcc;
  201. HWND m_hwnd;
  202. public:
  203. CAccessibleWrapper( HWND hwnd, IAccessible * pAcc );
  204. virtual ~CAccessibleWrapper(void);
  205. // IUnknown
  206. // (We do our own ref counting)
  207. virtual STDMETHODIMP QueryInterface(REFIID riid, void** ppv);
  208. virtual STDMETHODIMP_(ULONG) AddRef();
  209. virtual STDMETHODIMP_(ULONG) Release();
  210. // IDispatch
  211. virtual STDMETHODIMP GetTypeInfoCount(UINT* pctinfo);
  212. virtual STDMETHODIMP GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo);
  213. virtual STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR** rgszNames, UINT cNames,
  214. LCID lcid, DISPID* rgdispid);
  215. virtual STDMETHODIMP Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags,
  216. DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo,
  217. UINT* puArgErr);
  218. // IAccessible
  219. virtual STDMETHODIMP get_accParent(IDispatch ** ppdispParent);
  220. virtual STDMETHODIMP get_accChildCount(long* pChildCount);
  221. virtual STDMETHODIMP get_accChild(VARIANT varChild, IDispatch ** ppdispChild);
  222. virtual STDMETHODIMP get_accName(VARIANT varChild, BSTR* pszName);
  223. virtual STDMETHODIMP get_accValue(VARIANT varChild, BSTR* pszValue);
  224. virtual STDMETHODIMP get_accDescription(VARIANT varChild, BSTR* pszDescription);
  225. virtual STDMETHODIMP get_accRole(VARIANT varChild, VARIANT *pvarRole);
  226. virtual STDMETHODIMP get_accState(VARIANT varChild, VARIANT *pvarState);
  227. virtual STDMETHODIMP get_accHelp(VARIANT varChild, BSTR* pszHelp);
  228. virtual STDMETHODIMP get_accHelpTopic(BSTR* pszHelpFile, VARIANT varChild, long* pidTopic);
  229. virtual STDMETHODIMP get_accKeyboardShortcut(VARIANT varChild, BSTR* pszKeyboardShortcut);
  230. virtual STDMETHODIMP get_accFocus(VARIANT * pvarFocusChild);
  231. virtual STDMETHODIMP get_accSelection(VARIANT * pvarSelectedChildren);
  232. virtual STDMETHODIMP get_accDefaultAction(VARIANT varChild, BSTR* pszDefaultAction);
  233. virtual STDMETHODIMP accSelect(long flagsSel, VARIANT varChild);
  234. virtual STDMETHODIMP accLocation(long* pxLeft, long* pyTop, long* pcxWidth, long* pcyHeight, VARIANT varChild);
  235. virtual STDMETHODIMP accNavigate(long navDir, VARIANT varStart, VARIANT * pvarEndUpAt);
  236. virtual STDMETHODIMP accHitTest(long xLeft, long yTop, VARIANT * pvarChildAtPoint);
  237. virtual STDMETHODIMP accDoDefaultAction(VARIANT varChild);
  238. virtual STDMETHODIMP put_accName(VARIANT varChild, BSTR szName);
  239. virtual STDMETHODIMP put_accValue(VARIANT varChild, BSTR pszValue);
  240. };
  241. CAccessibleWrapper::CAccessibleWrapper( HWND hwnd, IAccessible * pAcc )
  242. : m_cRef( 1 ),
  243. m_pAcc( pAcc ),
  244. m_hwnd( hwnd )
  245. {
  246. ASSERT( m_pAcc );
  247. m_pAcc->AddRef();
  248. }
  249. CAccessibleWrapper::~CAccessibleWrapper()
  250. {
  251. m_pAcc->Release();
  252. }
  253. // IUnknown
  254. // Implement refcounting ourselves
  255. // Also implement QI ourselves, so that we return a ptr back to the wrapper.
  256. STDMETHODIMP CAccessibleWrapper::QueryInterface(REFIID riid, void** ppv)
  257. {
  258. *ppv = NULL;
  259. if ((riid == IID_IUnknown) ||
  260. (riid == IID_IDispatch) ||
  261. (riid == IID_IAccessible))
  262. {
  263. *ppv = (IAccessible *) this;
  264. }
  265. else
  266. return(E_NOINTERFACE);
  267. AddRef();
  268. return(NOERROR);
  269. }
  270. STDMETHODIMP_(ULONG) CAccessibleWrapper::AddRef()
  271. {
  272. return InterlockedIncrement(&m_cRef);
  273. }
  274. STDMETHODIMP_(ULONG) CAccessibleWrapper::Release()
  275. {
  276. ASSERT( 0 != m_cRef );
  277. ULONG cRef = InterlockedDecrement(&m_cRef);
  278. if ( 0 == cRef )
  279. {
  280. delete this;
  281. }
  282. return cRef;
  283. }
  284. // IDispatch
  285. // - pass all through m_pAcc
  286. STDMETHODIMP CAccessibleWrapper::GetTypeInfoCount(UINT* pctinfo)
  287. {
  288. return m_pAcc->GetTypeInfoCount(pctinfo);
  289. }
  290. STDMETHODIMP CAccessibleWrapper::GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo)
  291. {
  292. return m_pAcc->GetTypeInfo(itinfo, lcid, pptinfo);
  293. }
  294. STDMETHODIMP CAccessibleWrapper::GetIDsOfNames(REFIID riid, OLECHAR** rgszNames, UINT cNames,
  295. LCID lcid, DISPID* rgdispid)
  296. {
  297. return m_pAcc->GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
  298. }
  299. STDMETHODIMP CAccessibleWrapper::Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags,
  300. DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo,
  301. UINT* puArgErr)
  302. {
  303. return m_pAcc->Invoke(dispidMember, riid, lcid, wFlags,
  304. pdispparams, pvarResult, pexcepinfo,
  305. puArgErr);
  306. }
  307. // IAccessible
  308. // - pass all through m_pAcc
  309. STDMETHODIMP CAccessibleWrapper::get_accParent(IDispatch ** ppdispParent)
  310. {
  311. return m_pAcc->get_accParent(ppdispParent);
  312. }
  313. STDMETHODIMP CAccessibleWrapper::get_accChildCount(long* pChildCount)
  314. {
  315. return m_pAcc->get_accChildCount(pChildCount);
  316. }
  317. STDMETHODIMP CAccessibleWrapper::get_accChild(VARIANT varChild, IDispatch ** ppdispChild)
  318. {
  319. return m_pAcc->get_accChild(varChild, ppdispChild);
  320. }
  321. STDMETHODIMP CAccessibleWrapper::get_accName(VARIANT varChild, BSTR* pszName)
  322. {
  323. return m_pAcc->get_accName(varChild, pszName);
  324. }
  325. STDMETHODIMP CAccessibleWrapper::get_accValue(VARIANT varChild, BSTR* pszValue)
  326. {
  327. // varChild.lVal specifies which sub-part of the component
  328. // is being queried.
  329. // CHILDID_SELF (0) specifies the overall component - other
  330. // non-0 values specify a child.
  331. // In a trackbar, CHILDID_SELF refers to the overall trackbar
  332. // (which is what we want), whereas other values refer to the
  333. // sub-components - the actual slider 'thumb', and the 'page
  334. // up/page down' areas to the left/right of it.
  335. if( varChild.vt == VT_I4 && varChild.lVal == CHILDID_SELF )
  336. {
  337. HWND hDlg;
  338. TCHAR achRes[120];
  339. hDlg = GetParent( m_hwnd );
  340. SendDlgItemMessage(hDlg, IDC_RESXY, WM_GETTEXT, 120, (LPARAM)achRes);
  341. *pszValue = SysAllocString( achRes );
  342. return S_OK;
  343. }
  344. else
  345. {
  346. // Pass requests about the sub-components to the
  347. // 'original' IAccessible for us).
  348. return m_pAcc->get_accValue(varChild, pszValue);
  349. }
  350. }
  351. STDMETHODIMP CAccessibleWrapper::get_accDescription(VARIANT varChild, BSTR* pszDescription)
  352. {
  353. return m_pAcc->get_accDescription(varChild, pszDescription);
  354. }
  355. STDMETHODIMP CAccessibleWrapper::get_accRole(VARIANT varChild, VARIANT *pvarRole)
  356. {
  357. return m_pAcc->get_accRole(varChild, pvarRole);
  358. }
  359. STDMETHODIMP CAccessibleWrapper::get_accState(VARIANT varChild, VARIANT *pvarState)
  360. {
  361. return m_pAcc->get_accState(varChild, pvarState);
  362. }
  363. STDMETHODIMP CAccessibleWrapper::get_accHelp(VARIANT varChild, BSTR* pszHelp)
  364. {
  365. return m_pAcc->get_accHelp(varChild, pszHelp);
  366. }
  367. STDMETHODIMP CAccessibleWrapper::get_accHelpTopic(BSTR* pszHelpFile, VARIANT varChild, long* pidTopic)
  368. {
  369. return m_pAcc->get_accHelpTopic(pszHelpFile, varChild, pidTopic);
  370. }
  371. STDMETHODIMP CAccessibleWrapper::get_accKeyboardShortcut(VARIANT varChild, BSTR* pszKeyboardShortcut)
  372. {
  373. return m_pAcc->get_accKeyboardShortcut(varChild, pszKeyboardShortcut);
  374. }
  375. STDMETHODIMP CAccessibleWrapper::get_accFocus(VARIANT * pvarFocusChild)
  376. {
  377. return m_pAcc->get_accFocus(pvarFocusChild);
  378. }
  379. STDMETHODIMP CAccessibleWrapper::get_accSelection(VARIANT * pvarSelectedChildren)
  380. {
  381. return m_pAcc->get_accSelection(pvarSelectedChildren);
  382. }
  383. STDMETHODIMP CAccessibleWrapper::get_accDefaultAction(VARIANT varChild, BSTR* pszDefaultAction)
  384. {
  385. return m_pAcc->get_accDefaultAction(varChild, pszDefaultAction);
  386. }
  387. STDMETHODIMP CAccessibleWrapper::accSelect(long flagsSel, VARIANT varChild)
  388. {
  389. return m_pAcc->accSelect(flagsSel, varChild);
  390. }
  391. STDMETHODIMP CAccessibleWrapper::accLocation(long* pxLeft, long* pyTop, long* pcxWidth, long* pcyHeight, VARIANT varChild)
  392. {
  393. return m_pAcc->accLocation(pxLeft, pyTop, pcxWidth, pcyHeight, varChild);
  394. }
  395. STDMETHODIMP CAccessibleWrapper::accNavigate(long navDir, VARIANT varStart, VARIANT * pvarEndUpAt)
  396. {
  397. return m_pAcc->accNavigate(navDir, varStart, pvarEndUpAt);
  398. }
  399. STDMETHODIMP CAccessibleWrapper::accHitTest(long xLeft, long yTop, VARIANT * pvarChildAtPoint)
  400. {
  401. return m_pAcc->accHitTest(xLeft, yTop, pvarChildAtPoint);
  402. }
  403. STDMETHODIMP CAccessibleWrapper::accDoDefaultAction(VARIANT varChild)
  404. {
  405. return m_pAcc->accDoDefaultAction(varChild);
  406. }
  407. STDMETHODIMP CAccessibleWrapper::put_accName(VARIANT varChild, BSTR szName)
  408. {
  409. return m_pAcc->put_accName(varChild, szName);
  410. }
  411. STDMETHODIMP CAccessibleWrapper::put_accValue(VARIANT varChild, BSTR pszValue)
  412. {
  413. return m_pAcc->put_accValue(varChild, pszValue);
  414. }
  415. class CSettingsPage : public CObjectWithSite,
  416. public CObjectCLSID,
  417. public IMultiMonConfig,
  418. public IPropertyBag,
  419. public IBasePropPage
  420. {
  421. friend int ComputeNumberOfDisplayDevices();
  422. friend int DisplaySaveSettings(PVOID pContext, HWND hwnd);
  423. private:
  424. // Data Section
  425. PMULTIMON_DEVICE _pCurDevice;
  426. PMULTIMON_DEVICE _pPrimaryDevice;
  427. // HWND for the main window
  428. HWND _hDlg;
  429. HWND _hwndDesk;
  430. HWND _hwndList;
  431. // union of all monitor RECTs
  432. RECT _rcDesk;
  433. // ref count
  434. LONG _cRef;
  435. LONG _nInApply;
  436. // how to translate to preview size
  437. int _DeskScale;
  438. POINT _DeskOff;
  439. UINT _InSetInfo;
  440. ULONG _NumDevices;
  441. HBITMAP _hbmScrSample;
  442. HBITMAP _hbmMonitor;
  443. HIMAGELIST _himl;
  444. DWORD _dwInvalidMode;
  445. // UI variables
  446. int _iColor;
  447. int _iResolution;
  448. BOOL _bBadDriver : 1;
  449. BOOL _bNoAttach : 1;
  450. BOOL _bDirty : 1;
  451. MULTIMON_DEVICE _Devices[MONITORS_MAX];
  452. // Private functions
  453. void _DeskToPreview(LPRECT in, LPRECT out);
  454. void _OffsetPreviewToDesk(HWND hwndC, LPRECT prcNewPreview, LPRECT prcOldPreview, LPRECT out);
  455. BOOL _QueryForceSmallFont();
  456. void _SetPreviewScreenSize(int HRes, int VRes, int iOrgXRes, int iOrgYRes);
  457. void _CleanupRects(HWND hwndP);
  458. void _ConfirmPositions();
  459. void _DoAdvancedSettingsSheet();
  460. BOOL _HandleHScroll(HWND hwndSB, int iCode, int iPos);
  461. void _RedrawDeskPreviews();
  462. void _OnAdvancedClicked();
  463. BOOL _InitDisplaySettings(BOOL bExport);
  464. int _EnumerateAllDisplayDevices(); //Enumerates and returns the number of devices.
  465. void _DestroyMultimonDevice(PMULTIMON_DEVICE pDevice);
  466. void _DestroyDisplaySettings();
  467. void _InitUI();
  468. void _UpdateUI(BOOL fAutoSetColorDepth = TRUE, int FocusToCtrlID = 0);
  469. LPTSTR _FormatMessageInvoke(LPCTSTR pcszFormat, va_list *argList);
  470. LPTSTR _FormatMessageWrap(LPCTSTR pcszFormat, ...);
  471. void _GetDisplayName(PMULTIMON_DEVICE pDevice, LPTSTR pszDisplay, DWORD cchSize);
  472. int _SaveDisplaySettings(DWORD dwSet);
  473. void _ForwardToChildren(UINT message, WPARAM wParam, LPARAM lParam);
  474. static BOOL _CanSkipWarningBecauseKnownSafe(CDisplaySettings *rgpds[], ULONG numDevices);
  475. static BOOL _AnyChange(CDisplaySettings *rgpds[], ULONG numDevices);
  476. static BOOL _IsSingleToMultimonChange(CDisplaySettings *rgpds[],
  477. ULONG numDevices);
  478. static int _DisplaySaveSettings(CDisplaySettings *rgpds[],
  479. ULONG numDevices,
  480. HWND hDlg);
  481. static int _SaveSettings(CDisplaySettings *rgpds[],
  482. ULONG numDevices,
  483. HWND hDlg,
  484. DWORD dwSet);
  485. BOOL _AreExtraMonitorsDisabledOnPersonal();
  486. BOOL _InitMessage();
  487. void _vPreExecMode();
  488. void _vPostExecMode();
  489. public:
  490. CSettingsPage();
  491. static BOOL RegisterPreviewWindowClass(WNDPROC pfnWndProc);
  492. // *** IUnknown methods ***
  493. STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj);
  494. STDMETHODIMP_(ULONG) AddRef(void);
  495. STDMETHODIMP_(ULONG) Release(void);
  496. // *** IMultiMonConfig methods ***
  497. STDMETHOD ( Initialize ) ( HWND hwndHost, WNDPROC pfnWndProc, DWORD dwReserved);
  498. STDMETHOD ( GetNumberOfMonitors ) (int * pCMon, DWORD dwReserved);
  499. STDMETHOD ( GetMonitorData) (int iMonitor, MonitorData * pmd, DWORD dwReserved);
  500. STDMETHOD ( Paint) (THIS_ int iMonitor, DWORD dwReserved);
  501. // *** IShellPropSheetExt ***
  502. virtual STDMETHODIMP AddPages(IN LPFNSVADDPROPSHEETPAGE pfnAddPage, IN LPARAM lParam);
  503. virtual STDMETHODIMP ReplacePage(IN EXPPS uPageID, IN LPFNSVADDPROPSHEETPAGE pfnReplaceWith, IN LPARAM lParam);
  504. // *** IObjectWithSite ***
  505. virtual STDMETHODIMP SetSite(IUnknown *punkSite);
  506. // *** IPropertyBag ***
  507. virtual STDMETHODIMP Read(IN LPCOLESTR pszPropName, IN VARIANT * pVar, IN IErrorLog *pErrorLog);
  508. virtual STDMETHODIMP Write(IN LPCOLESTR pszPropName, IN VARIANT *pVar);
  509. // *** IBasePropPage ***
  510. virtual STDMETHODIMP GetAdvancedDialog(OUT IAdvancedDialog ** ppAdvDialog);
  511. virtual STDMETHODIMP OnApply(IN PROPPAGEONAPPLY oaAction);
  512. BOOL InitMultiMonitorDlg(HWND hDlg);
  513. PMULTIMON_DEVICE GetCurDevice(){return _pCurDevice;};
  514. int GetNumberOfAttachedDisplays();
  515. void UpdateActiveDisplay(PMULTIMON_DEVICE pDevice, BOOL bRepaint = TRUE);
  516. BOOL HandleMonitorChange(HWND hwndP, BOOL bMainDlg, BOOL bRepaint = TRUE);
  517. void SetDirty(BOOL bDirty=TRUE);
  518. BOOL SetPrimary(PMULTIMON_DEVICE pDevice);
  519. BOOL SetMonAttached(PMULTIMON_DEVICE pDevice, BOOL bSetAttached,
  520. BOOL bForce, HWND hwnd);
  521. HWND GetCurDeviceHwnd() { return GetDlgItemP(_hwndDesk, (INT_PTR) _pCurDevice);};
  522. ULONG GetNumDevices() { return _NumDevices;};
  523. BOOL QueryNoAttach() { return _bNoAttach;};
  524. BOOL IsDirty() { return _bDirty;};
  525. void GetMonitorPosition(PMULTIMON_DEVICE pDevice, HWND hwndP, PPOINT ptPos);
  526. static INT_PTR CALLBACK SettingsDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
  527. LRESULT CALLBACK WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
  528. IThemeUIPages* _pThemeUI;
  529. };
  530. CSettingsPage::CSettingsPage() : _cRef(1), CObjectCLSID(&PPID_Settings)
  531. {
  532. ASSERT(_pCurDevice == NULL);
  533. ASSERT(_pPrimaryDevice == NULL);
  534. ASSERT(_DeskScale == 0);
  535. ASSERT(_InSetInfo == 0);
  536. ASSERT(_NumDevices == 0);
  537. ASSERT(IsRectEmpty(&_rcDesk));
  538. ASSERT(_bNoAttach == FALSE);
  539. ASSERT(_bDirty == FALSE);
  540. _nInApply = 0;
  541. };
  542. void CSettingsPage::_DestroyMultimonDevice(PMULTIMON_DEVICE pDevice)
  543. {
  544. ASSERT(pDevice->pds);
  545. pDevice->pds->Release();
  546. pDevice->pds = NULL;
  547. if(pDevice->hwndFlash)
  548. {
  549. DestroyWindow(pDevice->hwndFlash);
  550. pDevice->hwndFlash = NULL;
  551. }
  552. if (pDevice->hdc) {
  553. DeleteDC(pDevice->hdc);
  554. pDevice->hdc = NULL;
  555. }
  556. if (pDevice->ResolutionList) {
  557. LocalFree(pDevice->ResolutionList);
  558. pDevice->ResolutionList = NULL;
  559. }
  560. if (pDevice->ColorList) {
  561. LocalFree(pDevice->ColorList);
  562. pDevice->ColorList = NULL;
  563. }
  564. }
  565. void CSettingsPage::_DestroyDisplaySettings()
  566. {
  567. ULONG iDevice;
  568. HWND hwndC;
  569. ASSERT(_NumDevices);
  570. TraceMsg(TF_GENERAL, "DestroyDisplaySettings: %d devices", _NumDevices);
  571. // We are about to destroy the _Devices below. Pointerts to these devices are used as the
  572. // CtrlIDs for the monitor windows. So, we need destroy the monitor windows first;
  573. // otherwise, if the monitor windows are destroyed later, they try to use these invalid
  574. // pDevice in FlashText. (pDevice->hwndFlash will fault).
  575. hwndC = GetWindow(_hwndDesk, GW_CHILD);
  576. while (hwndC)
  577. {
  578. RemoveTrackingToolTip(hwndC);
  579. RemovePopupToolTip(hwndC);
  580. DestroyWindow(hwndC);
  581. hwndC = GetWindow(_hwndDesk, GW_CHILD);
  582. }
  583. // Now, we can destroy the _Devices safely.
  584. for (iDevice = 0; iDevice < _NumDevices; iDevice++) {
  585. _DestroyMultimonDevice(_Devices + iDevice);
  586. // Note: pds is destroyed and set to zero already in the above call.
  587. //delete _Devices[iDevice].pds;
  588. //_Devices[iDevice].pds = 0;
  589. }
  590. if (_himl) {
  591. ImageList_Destroy(_himl);
  592. _himl = NULL;
  593. }
  594. DestroyWindow(ghwndToolTipTracking);
  595. DestroyWindow(ghwndToolTipPopup);
  596. ghwndToolTipTracking = NULL;
  597. ghwndToolTipPopup = NULL;
  598. TraceMsg(TF_GENERAL, "DestroyDisplaySettings: Finished destroying all devices");
  599. }
  600. //
  601. // deterines if the applet is in detect mode.
  602. //
  603. //
  604. // Called to put up initial messages that need to appear above the dialog
  605. // box
  606. //
  607. BOOL CSettingsPage::_InitMessage()
  608. {
  609. {
  610. //
  611. // _bBadDriver will be set when we fail to build the list of modes,
  612. // or something else failed during initialization.
  613. //
  614. // In almost every case, we should already know about this situation
  615. // based on our boot code.
  616. // However, if this is a new situation, just report a "bad driver"
  617. //
  618. DWORD dwExecMode;
  619. if (_pThemeUI && (SUCCEEDED(_pThemeUI->GetExecMode(&dwExecMode))))
  620. {
  621. if (_bBadDriver)
  622. {
  623. ASSERT(dwExecMode == EM_INVALID_MODE);
  624. _pThemeUI->SetExecMode(EM_INVALID_MODE);
  625. dwExecMode = EM_INVALID_MODE;
  626. _dwInvalidMode = EIS_EXEC_INVALID_DISPLAY_DRIVER;
  627. }
  628. if (dwExecMode == EM_INVALID_MODE)
  629. {
  630. DWORD Mesg;
  631. switch(_dwInvalidMode) {
  632. case EIS_EXEC_INVALID_NEW_DRIVER:
  633. Mesg = MSG_INVALID_NEW_DRIVER;
  634. break;
  635. case EIS_EXEC_INVALID_DEFAULT_DISPLAY_MODE:
  636. Mesg = MSG_INVALID_DEFAULT_DISPLAY_MODE;
  637. break;
  638. case EIS_EXEC_INVALID_DISPLAY_DRIVER:
  639. Mesg = MSG_INVALID_DISPLAY_DRIVER;
  640. break;
  641. case EIS_EXEC_INVALID_OLD_DISPLAY_DRIVER:
  642. Mesg = MSG_INVALID_OLD_DISPLAY_DRIVER;
  643. break;
  644. case EIS_EXEC_INVALID_16COLOR_DISPLAY_MODE:
  645. Mesg = MSG_INVALID_16COLOR_DISPLAY_MODE;
  646. break;
  647. case EIS_EXEC_INVALID_DISPLAY_MODE:
  648. Mesg = MSG_INVALID_DISPLAY_MODE;
  649. {
  650. //
  651. // If we are in safe mode, then we will get to here when
  652. // we initially log in. We are in forced VGA mode, so there
  653. // is no real error here. Emulate a click on the OK button
  654. // and everybody is happy.
  655. //
  656. HKEY hSafe;
  657. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  658. REGSTR_VAL_SAFEBOOT,
  659. 0,
  660. KEY_READ,
  661. &hSafe) == ERROR_SUCCESS) {
  662. //
  663. // If we ever care about the actual safe mode, the value
  664. // is nameed "OptionValue"
  665. //
  666. RegCloseKey(hSafe);
  667. PropSheet_PressButton(GetParent(_hDlg), PSBTN_OK);
  668. return TRUE;
  669. }
  670. }
  671. break;
  672. case EIS_EXEC_INVALID_CONFIGURATION:
  673. default:
  674. Mesg = MSG_INVALID_CONFIGURATION;
  675. break;
  676. }
  677. FmtMessageBox(_hDlg,
  678. MB_ICONEXCLAMATION,
  679. MSG_CONFIGURATION_PROBLEM,
  680. Mesg);
  681. //
  682. // For a bad display driver or old display driver, let's send the
  683. // user straight to the installation dialog.
  684. //
  685. if ((_dwInvalidMode == EIS_EXEC_INVALID_OLD_DISPLAY_DRIVER) ||
  686. (_dwInvalidMode == EIS_EXEC_INVALID_DISPLAY_DRIVER))
  687. {
  688. ASSERT(FALSE);
  689. }
  690. }
  691. }
  692. }
  693. return TRUE;
  694. }
  695. VOID CSettingsPage::_vPreExecMode()
  696. {
  697. HKEY hkey;
  698. //
  699. // This function sets up the execution mode of the applet.
  700. // There are four vlid modes.
  701. //
  702. // EXEC_NORMAL - When the apple is launched from the control panel
  703. //
  704. // EXEC_INVALID_MODE is exactly the same as for NORMAL except we will
  705. // not mark the current mode as tested so the user has
  706. // to at least test a mode
  707. //
  708. // EXEC_DETECT - When the applet is launched normally, but a detect was
  709. // done on the previous boot (the key in the registry is
  710. // set)
  711. //
  712. // EXEC_SETUP - When we launch the applet in setup mode from setup (Both
  713. // the registry key is set and the setup flag is passed in).
  714. //
  715. //
  716. // These two keys should only be checked \ deleted if the machine has been
  717. // rebooted and the detect \ new display has actually happened.
  718. // So we will look for the RebootNecessary key (a volatile key) and if
  719. // it is not present, then we can delete the key. Otherwise, the reboot
  720. // has not happened, and we keep the key
  721. //
  722. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  723. SZ_REBOOT_NECESSARY,
  724. 0,
  725. KEY_READ | KEY_WRITE,
  726. &hkey) != ERROR_SUCCESS) {
  727. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  728. SZ_DETECT_DISPLAY,
  729. 0,
  730. KEY_READ | KEY_WRITE,
  731. &hkey) == ERROR_SUCCESS) {
  732. //
  733. // NOTE: This key is also set when EXEC_SETUP is being run.
  734. //
  735. DWORD dwExecMode;
  736. if (_pThemeUI && (SUCCEEDED(_pThemeUI->GetExecMode(&dwExecMode))))
  737. {
  738. if (dwExecMode == EM_NORMAL) {
  739. _pThemeUI->SetExecMode(EM_DETECT);
  740. } else {
  741. //
  742. // If we are in setup mode, we also check the extra values
  743. // under DetectDisplay that control the unattended installation.
  744. //
  745. ASSERT(dwExecMode == EM_SETUP);
  746. }
  747. }
  748. RegCloseKey(hkey);
  749. }
  750. //
  751. // Check for a new driver being installed
  752. //
  753. DWORD dwExecMode;
  754. if (_pThemeUI && (SUCCEEDED(_pThemeUI->GetExecMode(&dwExecMode))))
  755. {
  756. if ( (dwExecMode == EM_NORMAL) &&
  757. (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  758. SZ_NEW_DISPLAY,
  759. 0,
  760. KEY_READ | KEY_WRITE,
  761. &hkey) == ERROR_SUCCESS) ) {
  762. _pThemeUI->SetExecMode(EM_INVALID_MODE);
  763. _dwInvalidMode = EIS_EXEC_INVALID_NEW_DRIVER;
  764. RegCloseKey(hkey);
  765. }
  766. }
  767. RegDeleteKey(HKEY_LOCAL_MACHINE,
  768. SZ_DETECT_DISPLAY);
  769. RegDeleteKey(HKEY_LOCAL_MACHINE,
  770. SZ_NEW_DISPLAY);
  771. }
  772. {
  773. LPTSTR psz = NULL;
  774. LPTSTR pszInv = NULL;
  775. DWORD dwExecMode;
  776. if (_pThemeUI && (SUCCEEDED(_pThemeUI->GetExecMode(&dwExecMode))))
  777. {
  778. switch(dwExecMode) {
  779. case EM_NORMAL:
  780. psz = TEXT("Normal Execution mode");
  781. break;
  782. case EM_DETECT:
  783. psz = TEXT("Detection Execution mode");
  784. break;
  785. case EM_SETUP:
  786. psz = TEXT("Setup Execution mode");
  787. break;
  788. case EM_INVALID_MODE:
  789. psz = TEXT("Invalid Mode Execution mode");
  790. switch(_dwInvalidMode) {
  791. case EIS_EXEC_INVALID_NEW_DRIVER:
  792. pszInv = TEXT("Invalid new driver");
  793. break;
  794. default:
  795. pszInv = TEXT("*** Invalid *** Invalid mode");
  796. break;
  797. }
  798. break;
  799. default:
  800. psz = TEXT("*** Invalid *** Execution mode");
  801. break;
  802. }
  803. if (dwExecMode == EM_INVALID_MODE)
  804. {
  805. TraceMsg(TF_FUNC, "\t\t sub invalid mode : %ws", pszInv);
  806. }
  807. }
  808. TraceMsg(TF_FUNC, "\n\n", psz);
  809. }
  810. }
  811. VOID CSettingsPage::_vPostExecMode() {
  812. HKEY hkey;
  813. DWORD cb;
  814. DWORD data;
  815. //
  816. // Check for various invalid configurations
  817. //
  818. DWORD dwExecMode;
  819. if (_pThemeUI && (SUCCEEDED(_pThemeUI->GetExecMode(&dwExecMode))))
  820. {
  821. if ( (dwExecMode == EM_NORMAL) &&
  822. (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  823. SZ_INVALID_DISPLAY,
  824. 0,
  825. KEY_READ | KEY_WRITE,
  826. &hkey) == ERROR_SUCCESS) ) {
  827. _pThemeUI->SetExecMode(EM_INVALID_MODE);
  828. //
  829. // Check for these fields in increasing order of "badness" or
  830. // "detail" so that the *worst* error is the one remaining in the
  831. // _dwInvalidMode variable once all the checks are done.
  832. //
  833. cb = sizeof(data);
  834. if (RegQueryValueEx(hkey,
  835. TEXT("DefaultMode"),
  836. NULL,
  837. NULL,
  838. (LPBYTE)(&data),
  839. &cb) == ERROR_SUCCESS)
  840. {
  841. _dwInvalidMode = EIS_EXEC_INVALID_DEFAULT_DISPLAY_MODE;
  842. }
  843. cb = sizeof(data);
  844. if (RegQueryValueEx(hkey,
  845. TEXT("BadMode"),
  846. NULL,
  847. NULL,
  848. (LPBYTE)(&data),
  849. &cb) == ERROR_SUCCESS)
  850. {
  851. _dwInvalidMode = EIS_EXEC_INVALID_DISPLAY_MODE;
  852. }
  853. cb = sizeof(data);
  854. if (RegQueryValueEx(hkey,
  855. TEXT("16ColorMode"),
  856. NULL,
  857. NULL,
  858. (LPBYTE)(&data),
  859. &cb) == ERROR_SUCCESS)
  860. {
  861. _dwInvalidMode = EIS_EXEC_INVALID_16COLOR_DISPLAY_MODE;
  862. }
  863. cb = sizeof(data);
  864. if (RegQueryValueEx(hkey,
  865. TEXT("InvalidConfiguration"),
  866. NULL,
  867. NULL,
  868. (LPBYTE)(&data),
  869. &cb) == ERROR_SUCCESS)
  870. {
  871. _dwInvalidMode = EIS_EXEC_INVALID_CONFIGURATION;
  872. }
  873. cb = sizeof(data);
  874. if (RegQueryValueEx(hkey,
  875. TEXT("MissingDisplayDriver"),
  876. NULL,
  877. NULL,
  878. (LPBYTE)(&data),
  879. &cb) == ERROR_SUCCESS)
  880. {
  881. _dwInvalidMode = EIS_EXEC_INVALID_DISPLAY_DRIVER;
  882. }
  883. //
  884. // This last case will be set in addition to the previous one in the
  885. // case where the driver was an old driver linking to winsvr.dll
  886. // and we can not load it.
  887. //
  888. cb = sizeof(data);
  889. if (RegQueryValueEx(hkey,
  890. TEXT("OldDisplayDriver"),
  891. NULL,
  892. NULL,
  893. (LPBYTE)(&data),
  894. &cb) == ERROR_SUCCESS)
  895. {
  896. _dwInvalidMode = EIS_EXEC_INVALID_OLD_DISPLAY_DRIVER;
  897. }
  898. RegCloseKey(hkey);
  899. }
  900. }
  901. //
  902. // Delete all of these bad configuration keys since we only want the
  903. // user to see the message once.
  904. //
  905. RegDeleteKey(HKEY_LOCAL_MACHINE,
  906. SZ_INVALID_DISPLAY);
  907. {
  908. LPTSTR psz = NULL;
  909. LPTSTR pszInv = NULL;
  910. DWORD dwExecMode;
  911. if (_pThemeUI && (SUCCEEDED(_pThemeUI->GetExecMode(&dwExecMode))))
  912. {
  913. if (dwExecMode == EM_INVALID_MODE)
  914. {
  915. switch (_dwInvalidMode)
  916. {
  917. case EIS_EXEC_INVALID_DEFAULT_DISPLAY_MODE:
  918. pszInv = TEXT("Default mode being used");
  919. break;
  920. case EIS_EXEC_INVALID_DISPLAY_DRIVER:
  921. pszInv = TEXT("Invalid Display Driver");
  922. break;
  923. case EIS_EXEC_INVALID_OLD_DISPLAY_DRIVER:
  924. pszInv = TEXT("Old Display Driver");
  925. break;
  926. case EIS_EXEC_INVALID_16COLOR_DISPLAY_MODE:
  927. pszInv = TEXT("16 color mode not supported");
  928. break;
  929. case EIS_EXEC_INVALID_DISPLAY_MODE:
  930. pszInv = TEXT("Invalid display mode");
  931. break;
  932. case EIS_EXEC_INVALID_CONFIGURATION:
  933. pszInv = TEXT("Invalid configuration");
  934. break;
  935. default:
  936. psz = TEXT("*** Invalid *** Invalid mode");
  937. break;
  938. }
  939. TraceMsg(TF_FUNC, "\t\t sub invlid mode : %ws", pszInv);
  940. TraceMsg(TF_FUNC, "\n\n", psz);
  941. }
  942. }
  943. }
  944. }
  945. //-----------------------------------------------------------------------------
  946. //-----------------------------------------------------------------------------
  947. void CSettingsPage::_DeskToPreview(LPRECT in, LPRECT out)
  948. {
  949. out->left = _DeskOff.x + MulDiv(in->left - _rcDesk.left,_DeskScale,1000);
  950. out->top = _DeskOff.y + MulDiv(in->top - _rcDesk.top, _DeskScale,1000);
  951. out->right = _DeskOff.x + MulDiv(in->right - _rcDesk.left,_DeskScale,1000);
  952. out->bottom = _DeskOff.y + MulDiv(in->bottom - _rcDesk.top, _DeskScale,1000);
  953. }
  954. //-----------------------------------------------------------------------------
  955. //-----------------------------------------------------------------------------
  956. void CSettingsPage::_OffsetPreviewToDesk(HWND hwndC, LPRECT prcNewPreview, LPRECT prcOldPreview, LPRECT out)
  957. {
  958. int x = 0, y = 0;
  959. int dtLeft, dtRight, dtTop, dtBottom;
  960. int nTotal;
  961. HWND hwndT;
  962. RECT rcC, rcT, rcPosT;
  963. BOOL bx = FALSE, by = FALSE;
  964. PMULTIMON_DEVICE pDeviceT;
  965. dtLeft = prcNewPreview->left - prcOldPreview->left;
  966. dtRight = prcNewPreview->right - prcOldPreview->right;
  967. dtTop = prcNewPreview->top - prcOldPreview->top;
  968. dtBottom = prcNewPreview->bottom - prcOldPreview->bottom;
  969. nTotal = abs(dtLeft) + abs(dtRight) + abs(dtTop) + abs(dtBottom);
  970. if (nTotal == 0) {
  971. return;
  972. } else if (nTotal > 2) {
  973. //
  974. // walk all other windows and snap our window to them
  975. //
  976. GetWindowRect(hwndC, &rcC);
  977. for (hwndT = GetWindow(hwndC, GW_HWNDFIRST);
  978. (hwndT && (!bx || !by));
  979. hwndT = GetWindow(hwndT, GW_HWNDNEXT))
  980. {
  981. if (hwndT == hwndC)
  982. continue;
  983. GetWindowRect(hwndT, &rcT);
  984. pDeviceT = GetDlgCtrlDevice(hwndT);
  985. if (pDeviceT) {
  986. pDeviceT->pds->GetCurPosition(&rcPosT);
  987. if (!bx) {
  988. bx = TRUE;
  989. if (rcC.left == rcT.left) {
  990. x = rcPosT.left - out->left;
  991. } else if (rcC.left == rcT.right) {
  992. x = rcPosT.right - out->left;
  993. } else if (rcC.right == rcT.left) {
  994. x = rcPosT.left - out->right;
  995. } else if (rcC.right == rcT.right) {
  996. x = rcPosT.right - out->right;
  997. } else {
  998. bx = FALSE;
  999. }
  1000. }
  1001. if (!by) {
  1002. by = TRUE;
  1003. if (rcC.top == rcT.top) {
  1004. y = rcPosT.top - out->top;
  1005. } else if (rcC.top == rcT.bottom) {
  1006. y = rcPosT.bottom - out->top;
  1007. } else if (rcC.bottom == rcT.top) {
  1008. y = rcPosT.top - out->bottom;
  1009. } else if (rcC.bottom == rcT.bottom) {
  1010. y = rcPosT.bottom - out->bottom;
  1011. } else {
  1012. by = FALSE;
  1013. }
  1014. }
  1015. }
  1016. }
  1017. if (!bx) {
  1018. x = _rcDesk.left + MulDiv(prcNewPreview->left - _DeskOff.x,1000,_DeskScale);
  1019. x = x - out->left;
  1020. }
  1021. if (!by) {
  1022. y = _rcDesk.top + MulDiv(prcNewPreview->top - _DeskOff.y,1000,_DeskScale);
  1023. y = y - out->top;
  1024. }
  1025. } else {
  1026. x = dtLeft * 8;
  1027. y = dtTop * 8;
  1028. }
  1029. OffsetRect(out, x, y);
  1030. }
  1031. //-----------------------------------------------------------------------------
  1032. int CSettingsPage::_SaveSettings(CDisplaySettings *rgpds[], ULONG numDevices, HWND hDlg, DWORD dwSet)
  1033. {
  1034. int iRet = 0;
  1035. ULONG iDevice;
  1036. for (iDevice = 0; iDevice < numDevices; iDevice++)
  1037. {
  1038. // PERF - we should only save the settings for devices that have
  1039. // changed.
  1040. if (rgpds[iDevice])
  1041. {
  1042. int iResult = rgpds[iDevice]->SaveSettings(dwSet);
  1043. if (iResult != DISP_CHANGE_SUCCESSFUL)
  1044. {
  1045. if (iResult == DISP_CHANGE_RESTART)
  1046. {
  1047. iRet = iResult;
  1048. continue;
  1049. }
  1050. else
  1051. {
  1052. FmtMessageBox(hDlg,
  1053. MB_ICONEXCLAMATION,
  1054. IDS_CHANGE_SETTINGS,
  1055. IDS_CHANGESETTINGS_FAILED);
  1056. ASSERT(iResult < 0);
  1057. return iResult;
  1058. }
  1059. }
  1060. }
  1061. }
  1062. return iRet;
  1063. }
  1064. INT_PTR CALLBACK KeepNewDlgProc(HWND hDlg, UINT message , WPARAM wParam, LPARAM lParam)
  1065. {
  1066. UINT_PTR idTimer = 0;
  1067. HICON hicon;
  1068. TCHAR szRevert[100];
  1069. TCHAR szString[120];
  1070. switch(message)
  1071. {
  1072. case WM_INITDIALOG:
  1073. hicon = LoadIcon(NULL, IDI_QUESTION);
  1074. if (hicon)
  1075. SendDlgItemMessage(hDlg, IDC_BIGICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hicon);
  1076. LoadString(HINST_THISDLL, IDS_REVERTBACK, szRevert, ARRAYSIZE(szRevert));
  1077. StringCchPrintf(szString, ARRAYSIZE(szString), szRevert, lParam);
  1078. SetDlgItemText(hDlg, IDC_COUNTDOWN, szString);
  1079. idTimer = SetTimer(hDlg, lParam, 1000, NULL);
  1080. SetFocus(GetDlgItem(hDlg, IDNO));
  1081. // FALSE so that the focus set above is kept
  1082. return FALSE;
  1083. case WM_DESTROY:
  1084. // raymondc - this code is dead; idTimer is initialized to zero
  1085. // fortunately, timers are automatically killed at window destruction
  1086. // if (idTimer)
  1087. // KillTimer(hDlg, idTimer);
  1088. hicon = (HICON)SendDlgItemMessage(hDlg, IDC_BIGICON, STM_GETIMAGE, IMAGE_ICON, 0);
  1089. if (hicon)
  1090. DestroyIcon(hicon);
  1091. break;
  1092. case WM_TIMER:
  1093. KillTimer(hDlg, wParam);
  1094. LoadString(HINST_THISDLL, IDS_REVERTBACK, szRevert, ARRAYSIZE(szRevert));
  1095. StringCchPrintf(szString, ARRAYSIZE(szString), szRevert, wParam - 1);
  1096. SetDlgItemText(hDlg, IDC_COUNTDOWN, szString);
  1097. idTimer = SetTimer(hDlg, wParam - 1, 1000, NULL);
  1098. if (wParam == 1)
  1099. EndDialog(hDlg, IDNO);
  1100. break;
  1101. case WM_COMMAND:
  1102. EndDialog(hDlg, wParam);
  1103. break;
  1104. default:
  1105. return FALSE;
  1106. }
  1107. return TRUE;
  1108. }
  1109. int CSettingsPage::GetNumberOfAttachedDisplays()
  1110. {
  1111. int nDisplays = 0;
  1112. for (ULONG iDevice = 0; iDevice < _NumDevices; iDevice++)
  1113. {
  1114. if (_Devices[iDevice].pds->IsAttached())
  1115. nDisplays++;
  1116. }
  1117. return nDisplays;
  1118. }
  1119. BOOL CSettingsPage::_IsSingleToMultimonChange(CDisplaySettings *rgpds[],
  1120. ULONG numDevices)
  1121. {
  1122. int nAttached = 0;
  1123. int nOrgAttached = 0;
  1124. for (ULONG iDevice = 0;
  1125. (iDevice < numDevices) && (nOrgAttached <= 1);
  1126. iDevice++)
  1127. {
  1128. if (rgpds[iDevice]->IsOrgAttached())
  1129. nOrgAttached++;
  1130. if (rgpds[iDevice]->IsAttached())
  1131. nAttached++;
  1132. }
  1133. return ((nOrgAttached <= 1) && (nAttached > 1));
  1134. }
  1135. BOOL CSettingsPage::_AnyChange(CDisplaySettings *rgpds[], ULONG numDevices)
  1136. {
  1137. for (ULONG iDevice = 0; iDevice < numDevices; iDevice++)
  1138. {
  1139. if (rgpds[iDevice]->IsAttached() && rgpds[iDevice]->bIsModeChanged())
  1140. {
  1141. return TRUE;
  1142. }
  1143. }
  1144. return FALSE;
  1145. }
  1146. BOOL CSettingsPage::_CanSkipWarningBecauseKnownSafe(CDisplaySettings *rgpds[], ULONG numDevices)
  1147. {
  1148. BOOL fSafe = TRUE;
  1149. for (ULONG iDevice = 0; iDevice < numDevices; iDevice++)
  1150. {
  1151. if (rgpds[iDevice] && !rgpds[iDevice]->IsKnownSafe())
  1152. {
  1153. fSafe = FALSE;
  1154. break;
  1155. }
  1156. }
  1157. return fSafe;
  1158. }
  1159. BOOL CSettingsPage::_QueryForceSmallFont()
  1160. {
  1161. for (ULONG iDevice = 0; iDevice < _NumDevices; iDevice++)
  1162. {
  1163. if ((_Devices[iDevice].pds->IsAttached()) &&
  1164. (!_Devices[iDevice].pds->IsSmallFontNecessary()))
  1165. {
  1166. return FALSE;
  1167. }
  1168. }
  1169. return TRUE;
  1170. }
  1171. LPTSTR CSettingsPage::_FormatMessageInvoke(LPCTSTR pcszFormat, va_list *argList)
  1172. {
  1173. LPTSTR pszOutput;
  1174. if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
  1175. pcszFormat,
  1176. 0, 0,
  1177. reinterpret_cast<LPTSTR>(&pszOutput), 0,
  1178. argList) == 0)
  1179. {
  1180. pszOutput = NULL;
  1181. }
  1182. return(pszOutput);
  1183. }
  1184. LPTSTR CSettingsPage::_FormatMessageWrap(LPCTSTR pcszFormat, ...)
  1185. {
  1186. LPTSTR pszOutput;
  1187. va_list argList;
  1188. va_start(argList, pcszFormat);
  1189. pszOutput = _FormatMessageInvoke(pcszFormat, &argList);
  1190. va_end(argList);
  1191. return(pszOutput);
  1192. }
  1193. void CSettingsPage::_GetDisplayName(PMULTIMON_DEVICE pDevice, LPTSTR pszDisplay, DWORD cchSize)
  1194. {
  1195. LPTSTR pszFormattedOutput;
  1196. TCHAR szMonitor[140];
  1197. TCHAR szDisplayFormat[40];
  1198. LoadString(HINST_THISDLL, IDS_DISPLAYFORMAT, szDisplayFormat, ARRAYSIZE(szDisplayFormat));
  1199. pDevice->pds->GetMonitorName(szMonitor, ARRAYSIZE(szMonitor));
  1200. pszFormattedOutput = _FormatMessageWrap(szDisplayFormat,
  1201. pDevice->DisplayIndex,
  1202. szMonitor,
  1203. pDevice->DisplayDevice.DeviceString);
  1204. StringCchCopy(pszDisplay, cchSize, pszFormattedOutput);
  1205. LocalFree(pszFormattedOutput);
  1206. }
  1207. void CSettingsPage::_OnAdvancedClicked()
  1208. {
  1209. BOOL bCanBePruned, bIsPruningReadOnly;
  1210. BOOL bBeforeIsPruningOn, bAfterIsPruningOn;
  1211. if (_pCurDevice && _pCurDevice->pds)
  1212. {
  1213. _pCurDevice->pds->GetPruningMode(&bCanBePruned,
  1214. &bIsPruningReadOnly,
  1215. &bBeforeIsPruningOn);
  1216. _DoAdvancedSettingsSheet();
  1217. if (bCanBePruned && !bIsPruningReadOnly)
  1218. {
  1219. _pCurDevice->pds->GetPruningMode(&bCanBePruned,
  1220. &bIsPruningReadOnly,
  1221. &bAfterIsPruningOn);
  1222. if (bBeforeIsPruningOn != bAfterIsPruningOn)
  1223. {
  1224. // pruning mode has changed - update the UI
  1225. _InitUI();
  1226. _UpdateUI();
  1227. }
  1228. }
  1229. }
  1230. }
  1231. //-----------------------------------------------------------------------------
  1232. void CSettingsPage::_DoAdvancedSettingsSheet()
  1233. {
  1234. if (_pCurDevice && _pCurDevice->pds)
  1235. {
  1236. PROPSHEETHEADER psh;
  1237. HPROPSHEETPAGE rPages[MAX_PAGES];
  1238. PROPSHEETPAGE psp;
  1239. HPSXA hpsxa = NULL;
  1240. HPSXA hpsxaOEM = NULL;
  1241. HPSXA hpsxaAdapter = NULL;
  1242. HPSXA* phpsxaChildren = NULL;
  1243. INT_PTR iResult = 0;
  1244. TCHAR szDisplay[140 + 256 + 20]; //Monitor-name and Adapter Properties.
  1245. TCHAR szMonitor[140];
  1246. TCHAR szDisplayFormat[35];
  1247. GENERAL_ADVDLG_INITPARAMS generalInitParams = {0};
  1248. // Create the "Monitor-name and Adapter-name properties" string to be used as the title for these
  1249. // property sheets.
  1250. LoadString(HINST_THISDLL, IDS_ADVDIALOGTITLE, szDisplayFormat, ARRAYSIZE(szDisplayFormat));
  1251. _pCurDevice->pds->GetMonitorName(szMonitor, ARRAYSIZE(szMonitor));
  1252. StringCchPrintf(szDisplay, ARRAYSIZE(szDisplay), szDisplayFormat, szMonitor, _pCurDevice->DisplayDevice.DeviceString);
  1253. generalInitParams.fFoceSmallFont = _QueryForceSmallFont();
  1254. generalInitParams.punkSite = _punkSite; // They don't get a ref because their property dialog appears and goes away before this function returns.
  1255. psh.dwSize = sizeof(psh);
  1256. psh.dwFlags = PSH_PROPTITLE;
  1257. psh.hwndParent = GetParent(_hDlg);
  1258. psh.hInstance = HINST_THISDLL;
  1259. psh.pszCaption = szDisplay;
  1260. psh.nPages = 0;
  1261. psh.nStartPage = 0;
  1262. psh.phpage = rPages;
  1263. psp.dwSize = sizeof(psp);
  1264. psp.dwFlags = PSP_DEFAULT;
  1265. psp.hInstance = HINST_THISDLL;
  1266. psp.pfnDlgProc = GeneralPageProc;
  1267. psp.pszTemplate = MAKEINTRESOURCE(DLG_GENERAL);
  1268. psp.lParam = (LPARAM)&generalInitParams;
  1269. rPages[psh.nPages] = CreatePropertySheetPage(&psp);
  1270. if (rPages[psh.nPages])
  1271. psh.nPages++;
  1272. IDataObject * pdo = NULL;
  1273. _pCurDevice->pds->QueryInterface(IID_IDataObject, (LPVOID *) &pdo);
  1274. CRegistrySettings RegSettings(_pCurDevice->DisplayDevice.DeviceKey);
  1275. HKEY hkDriver = RegSettings.OpenDrvRegKey();
  1276. if (hkDriver != INVALID_HANDLE_VALUE)
  1277. {
  1278. CheckForDuplicateAppletExtensions(hkDriver);
  1279. }
  1280. //
  1281. // load the generic (non hardware specific) extensions
  1282. //
  1283. if( ( hpsxa = SHCreatePropSheetExtArrayEx( HKEY_LOCAL_MACHINE, REGSTR_PATH_CONTROLSFOLDER TEXT("\\Device"), 8, pdo) ) != NULL )
  1284. {
  1285. SHAddFromPropSheetExtArray( hpsxa, _AddDisplayPropSheetPage, (LPARAM)&psh );
  1286. }
  1287. //
  1288. // Load the hardware-specific extensions
  1289. //
  1290. // NOTE it is very important to load the OEM extensions *after* the
  1291. // generic extensions some HW extensions expect to be the last tabs
  1292. // in the propsheet (right before the settings tab)
  1293. //
  1294. // FEATURE - we may need a way to NOT load the vendor extensions in case
  1295. // they break our applet.
  1296. //
  1297. if( ( hpsxaOEM = SHCreatePropSheetExtArrayEx( HKEY_LOCAL_MACHINE, REGSTR_PATH_CONTROLSFOLDER TEXT("\\Display"), 8, pdo) ) != NULL )
  1298. {
  1299. SHAddFromPropSheetExtArray( hpsxaOEM, _AddDisplayPropSheetPage, (LPARAM)&psh );
  1300. }
  1301. //
  1302. // Load the applet extensions for the adapter
  1303. //
  1304. if (hkDriver != INVALID_HANDLE_VALUE)
  1305. {
  1306. if( ( hpsxaAdapter = SHCreatePropSheetExtArrayEx( hkDriver, TEXT("Display"), 8, pdo) ) != NULL )
  1307. {
  1308. SHAddFromPropSheetExtArray( hpsxaAdapter, _AddDisplayPropSheetPage, (LPARAM)&psh );
  1309. }
  1310. RegCloseKey(hkDriver);
  1311. }
  1312. //
  1313. // Load the applet extensions for the adapter child devices (e.g. monitors)
  1314. //
  1315. DEVINST devInstAdapter, devInstMonitor;
  1316. DWORD cChildDevices = 0, nChild, index;
  1317. HDEVINFO hDevMonitors = INVALID_HANDLE_VALUE;
  1318. SP_DEVINFO_DATA DevInfoData;
  1319. HKEY hkMonitor;
  1320. BOOL bMonitors = FALSE;
  1321. LPTSTR szAdapterInstanceID = RegSettings.GetDeviceInstanceId();
  1322. if (szAdapterInstanceID != NULL)
  1323. {
  1324. if (CM_Locate_DevNodeW(&devInstAdapter, szAdapterInstanceID, 0) == CR_SUCCESS)
  1325. {
  1326. //
  1327. // Get the number of child devices
  1328. //
  1329. cChildDevices = 0;
  1330. if (CM_Get_Child(&devInstMonitor, devInstAdapter, 0) == CR_SUCCESS)
  1331. {
  1332. do
  1333. {
  1334. cChildDevices++;
  1335. }
  1336. while (CM_Get_Sibling(&devInstMonitor, devInstMonitor, 0) == CR_SUCCESS);
  1337. }
  1338. //
  1339. // Allocate the memory
  1340. //
  1341. if (cChildDevices > 0)
  1342. {
  1343. phpsxaChildren = (HPSXA*)LocalAlloc(LPTR, cChildDevices * sizeof(HPSXA));
  1344. hDevMonitors = SetupDiGetClassDevs((LPGUID)&GUID_DEVCLASS_MONITOR,
  1345. NULL,
  1346. NULL,
  1347. 0);
  1348. }
  1349. //
  1350. // Load the applet extensions
  1351. //
  1352. if ((phpsxaChildren != NULL) &&
  1353. (hDevMonitors != INVALID_HANDLE_VALUE))
  1354. {
  1355. nChild = 0;
  1356. if (CM_Get_Child(&devInstMonitor, devInstAdapter, 0) == CR_SUCCESS)
  1357. {
  1358. do
  1359. {
  1360. DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  1361. index = 0;
  1362. while (SetupDiEnumDeviceInfo(hDevMonitors,
  1363. index,
  1364. &DevInfoData)) {
  1365. if (DevInfoData.DevInst == devInstMonitor) {
  1366. hkMonitor = SetupDiOpenDevRegKey(hDevMonitors,
  1367. &DevInfoData,
  1368. DICS_FLAG_GLOBAL,
  1369. 0,
  1370. DIREG_DRV ,
  1371. KEY_WRITE | KEY_READ);
  1372. if (hkMonitor != INVALID_HANDLE_VALUE)
  1373. {
  1374. if ((phpsxaChildren[nChild] = SHCreatePropSheetExtArrayEx(hkMonitor,
  1375. TEXT("Display"),
  1376. 8,
  1377. pdo)) != NULL)
  1378. {
  1379. bMonitors = TRUE;
  1380. SHAddFromPropSheetExtArray(phpsxaChildren[nChild],
  1381. _AddDisplayPropSheetPage,
  1382. (LPARAM)&psh);
  1383. }
  1384. RegCloseKey(hkMonitor);
  1385. }
  1386. break;
  1387. }
  1388. DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  1389. index++;
  1390. }
  1391. nChild++;
  1392. }
  1393. while ((nChild < cChildDevices) &&
  1394. (CM_Get_Sibling(&devInstMonitor, devInstMonitor, 0) == CR_SUCCESS));
  1395. }
  1396. }
  1397. }
  1398. }
  1399. //
  1400. // add a fake settings page to fool OEM extensions (must be last)
  1401. //
  1402. if (hpsxa || hpsxaOEM || hpsxaAdapter || bMonitors)
  1403. {
  1404. AddFakeSettingsPage(_pThemeUI, &psh);
  1405. }
  1406. if (psh.nPages)
  1407. {
  1408. iResult = PropertySheet(&psh);
  1409. }
  1410. _GetDisplayName(_pCurDevice, szDisplay, ARRAYSIZE(szDisplay));
  1411. if (_NumDevices == 1)
  1412. {
  1413. //Set the name of the primary in the static text
  1414. //strip the first token off (this is the number we dont want it)
  1415. TCHAR *pch;
  1416. for (pch=szDisplay; *pch && *pch != TEXT(' '); pch++);
  1417. for (;*pch && *pch == TEXT(' '); pch++);
  1418. SetDlgItemText(_hDlg, IDC_DISPLAYTEXT, pch);
  1419. }
  1420. else
  1421. {
  1422. ComboBox_DeleteString(_hwndList, _pCurDevice->ComboBoxItem);
  1423. ComboBox_InsertString(_hwndList, _pCurDevice->ComboBoxItem, szDisplay);
  1424. ComboBox_SetItemData(_hwndList, _pCurDevice->ComboBoxItem, (DWORD_PTR)_pCurDevice);
  1425. ComboBox_SetCurSel(_hwndList, _pCurDevice->ComboBoxItem);
  1426. }
  1427. if( hpsxa )
  1428. SHDestroyPropSheetExtArray( hpsxa );
  1429. if( hpsxaOEM )
  1430. SHDestroyPropSheetExtArray( hpsxaOEM );
  1431. if( hpsxaAdapter )
  1432. SHDestroyPropSheetExtArray( hpsxaAdapter );
  1433. if (phpsxaChildren != NULL)
  1434. {
  1435. for (nChild = 0; nChild < cChildDevices; nChild++) {
  1436. if (phpsxaChildren[nChild] != NULL)
  1437. {
  1438. SHDestroyPropSheetExtArray(phpsxaChildren[nChild]);
  1439. }
  1440. }
  1441. LocalFree(phpsxaChildren);
  1442. }
  1443. if (hDevMonitors != INVALID_HANDLE_VALUE)
  1444. {
  1445. SetupDiDestroyDeviceInfoList(hDevMonitors);
  1446. }
  1447. if (pdo)
  1448. pdo->Release();
  1449. if ((iResult == ID_PSRESTARTWINDOWS) || (iResult == ID_PSREBOOTSYSTEM))
  1450. {
  1451. PropSheet_CancelToClose(GetParent(_hDlg));
  1452. if (iResult == ID_PSREBOOTSYSTEM)
  1453. PropSheet_RebootSystem(ghwndPropSheet);
  1454. else
  1455. PropSheet_RestartWindows(ghwndPropSheet);
  1456. }
  1457. //
  1458. // APPCOMPAT
  1459. // Reset the dirty flag based on what the extensions did.
  1460. //
  1461. //
  1462. // Reset the controls in case someone changed the selected mode.
  1463. //
  1464. UpdateActiveDisplay(NULL);
  1465. }
  1466. }
  1467. //-----------------------------------------------------------------------------
  1468. void CSettingsPage::UpdateActiveDisplay(PMULTIMON_DEVICE pDevice, BOOL bRepaint /*=TRUE*/)
  1469. {
  1470. if (_pCurDevice && _pCurDevice->pds)
  1471. {
  1472. HWND hwndC;
  1473. _InSetInfo++;
  1474. if (pDevice == NULL)
  1475. pDevice = (PMULTIMON_DEVICE)ComboBox_GetItemData(_hwndList, ComboBox_GetCurSel(_hwndList));
  1476. else
  1477. ComboBox_SetCurSel(_hwndList, pDevice->ComboBoxItem);
  1478. if (pDevice && pDevice != (PMULTIMON_DEVICE)CB_ERR)
  1479. {
  1480. hwndC = GetCurDeviceHwnd();
  1481. // The Current Device has changed, so, force recreating the bitmap the next time
  1482. // we paint the monitor on the preview window.
  1483. _pCurDevice->w = pDevice->w = 0;
  1484. _pCurDevice = pDevice;
  1485. if (hwndC)
  1486. RedrawWindow(hwndC, NULL, NULL, RDW_ERASE | RDW_INVALIDATE);
  1487. hwndC = GetCurDeviceHwnd();
  1488. if (hwndC)
  1489. RedrawWindow(hwndC, NULL, NULL, RDW_ERASE | RDW_INVALIDATE);
  1490. if(_NumDevices > 1)
  1491. {
  1492. // Update the two check box windows
  1493. CheckDlgButton(_hDlg, IDC_DISPLAYPRIME, _pCurDevice->pds->IsPrimary());
  1494. EnableWindow(GetDlgItem(_hDlg, IDC_DISPLAYPRIME),
  1495. _pCurDevice->pds->IsAttached() &&
  1496. !_pCurDevice->pds->IsRemovable() &&
  1497. !_pCurDevice->pds->IsPrimary());
  1498. CheckDlgButton(_hDlg, IDC_DISPLAYUSEME, _pCurDevice->pds->IsAttached());
  1499. EnableWindow(GetDlgItem(_hDlg, IDC_DISPLAYUSEME),
  1500. !_bNoAttach && !_pCurDevice->pds->IsPrimary());
  1501. }
  1502. // Reset the values for the list boxes, and then repaint it
  1503. if(bRepaint)
  1504. {
  1505. _InitUI();
  1506. _UpdateUI(FALSE /*fAutoSetColorDepth*/);
  1507. }
  1508. }
  1509. else
  1510. {
  1511. // No display device !
  1512. TraceMsg(TF_WARNING, "**** UpdateActiveDisplay: No display device!!!!");
  1513. ASSERT(FALSE);
  1514. }
  1515. _InSetInfo--;
  1516. }
  1517. }
  1518. // ---------------------------------------------------------------------------
  1519. // Initialize the resolution and color UI widgets
  1520. //
  1521. void CSettingsPage::_InitUI()
  1522. {
  1523. if (_pCurDevice && _pCurDevice->pds)
  1524. {
  1525. int i;
  1526. int Color;
  1527. // Update the Color list
  1528. TraceMsg(TF_FUNC, "_InitUI() -- Color list");
  1529. SendDlgItemMessage(_hDlg, IDC_COLORBOX, CB_RESETCONTENT, 0, 0);
  1530. if (_pCurDevice->ColorList)
  1531. {
  1532. LocalFree(_pCurDevice->ColorList);
  1533. _pCurDevice->ColorList = NULL;
  1534. }
  1535. _pCurDevice->cColors = _pCurDevice->pds->GetColorList(NULL, &_pCurDevice->ColorList);
  1536. for (i = 0; i < _pCurDevice->cColors; i++)
  1537. {
  1538. TCHAR achColor[50];
  1539. DWORD idColor = ID_DSP_TXT_TRUECOLOR32;
  1540. Color = (int) *(_pCurDevice->ColorList + i);
  1541. //
  1542. // convert bit count to number of colors and make it a string
  1543. //
  1544. switch (Color)
  1545. {
  1546. case 32: idColor = ID_DSP_TXT_TRUECOLOR32; break;
  1547. case 24: idColor = ID_DSP_TXT_TRUECOLOR24; break;
  1548. case 16: idColor = ID_DSP_TXT_16BIT_COLOR; break;
  1549. case 15: idColor = ID_DSP_TXT_15BIT_COLOR; break;
  1550. case 8: idColor = ID_DSP_TXT_8BIT_COLOR; break;
  1551. case 4: idColor = ID_DSP_TXT_4BIT_COLOR; break;
  1552. default:
  1553. ASSERT(FALSE);
  1554. }
  1555. LoadString(HINST_THISDLL, idColor, achColor, ARRAYSIZE(achColor));
  1556. SendDlgItemMessage(_hDlg, IDC_COLORBOX, CB_INSERTSTRING, i, (LPARAM)achColor);
  1557. }
  1558. //
  1559. // Update the screen Size List
  1560. //
  1561. TraceMsg(TF_FUNC, "_InitUI() -- Screen Size list");
  1562. if (_pCurDevice->ResolutionList)
  1563. {
  1564. LocalFree(_pCurDevice->ResolutionList);
  1565. _pCurDevice->ResolutionList = NULL;
  1566. }
  1567. _pCurDevice->cResolutions =
  1568. _pCurDevice->pds->GetResolutionList(-1, &_pCurDevice->ResolutionList);
  1569. SendDlgItemMessage(_hDlg, IDC_SCREENSIZE, TBM_SETRANGE, TRUE,
  1570. MAKELONG(0, _pCurDevice->cResolutions - 1));
  1571. TraceMsg(TF_FUNC, "_InitUI() -- Res MaxRange = %d", _pCurDevice->cResolutions - 1);
  1572. // Reset the indices since they are no longer valid
  1573. _iResolution = -1;
  1574. _iColor = -1;
  1575. }
  1576. }
  1577. // ---------------------------------------------------------------------------
  1578. // Update the resolution and color UI widgets
  1579. //
  1580. void CSettingsPage::_UpdateUI(BOOL fAutoSetColorDepth, int FocusToCtrlID)
  1581. {
  1582. if (_pCurDevice && _pCurDevice->pds)
  1583. {
  1584. int i;
  1585. POINT Res;
  1586. int Color;
  1587. BOOL bRepaint;
  1588. // Get the current values
  1589. _pCurDevice->pds->GetCurResolution(&Res);
  1590. Color = _pCurDevice->pds->GetCurColor();
  1591. // Update the color listbox
  1592. TraceMsg(TF_FUNC, "_UpdateUI() -- Set Color %d", Color);
  1593. for (i=0; i<_pCurDevice->cColors; i++)
  1594. {
  1595. if (Color == (int) *(_pCurDevice->ColorList + i))
  1596. {
  1597. TraceMsg(TF_FUNC, "_UpdateUI() -- Set Color index %d", i);
  1598. if (_iColor == i)
  1599. {
  1600. TraceMsg(TF_FUNC, "_UpdateUI() -- Set Color index %d - is current", i);
  1601. break;
  1602. }
  1603. HBITMAP hbm, hbmOld;
  1604. int iBitmap = IDB_COLOR4DITHER;
  1605. HDC hdc = GetDC(NULL);
  1606. int bpp = GetDeviceCaps(hdc, PLANES) * GetDeviceCaps(hdc, BITSPIXEL);
  1607. SendDlgItemMessage(_hDlg, IDC_COLORBOX, CB_SETCURSEL, i, 0);
  1608. if (Color <= 4)
  1609. iBitmap = IDB_COLOR4;
  1610. else if (bpp >= 16)
  1611. {
  1612. if (Color <= 8)
  1613. iBitmap = IDB_COLOR8;
  1614. else if (Color <= 16)
  1615. iBitmap = IDB_COLOR16;
  1616. else
  1617. iBitmap = IDB_COLOR24;
  1618. }
  1619. ReleaseDC(NULL, hdc);
  1620. hbm = (HBITMAP)LoadImage(HINST_THISDLL, MAKEINTRESOURCE(iBitmap), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
  1621. if (hbm)
  1622. {
  1623. hbmOld = (HBITMAP) SendDlgItemMessage(_hDlg, IDC_COLORSAMPLE, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hbm);
  1624. if (hbmOld)
  1625. {
  1626. DeleteObject(hbmOld);
  1627. }
  1628. }
  1629. _iColor = i;
  1630. break;
  1631. }
  1632. }
  1633. if (i == _pCurDevice->cColors)
  1634. {
  1635. TraceMsg(TF_ERROR, "_UpdateUI -- !!! inconsistent color list !!!");
  1636. }
  1637. TraceMsg(TF_FUNC, "_UpdateUI() -- Set Resolution %d %d", Res.x, Res.y);
  1638. // Update the resolution string
  1639. {
  1640. TCHAR achStr[80];
  1641. TCHAR achRes[120];
  1642. LoadString(HINST_THISDLL, ID_DSP_TXT_XBYY, achStr, ARRAYSIZE(achStr));
  1643. StringCchPrintf(achRes, ARRAYSIZE(achRes), achStr, Res.x, Res.y);
  1644. SendDlgItemMessage(_hDlg, IDC_RESXY, WM_SETTEXT, 0, (LPARAM)achRes);
  1645. }
  1646. // Update the resolution slider
  1647. for (i=0; i<_pCurDevice->cResolutions; i++)
  1648. {
  1649. if ( (Res.x == (*(_pCurDevice->ResolutionList + i)).x) &&
  1650. (Res.y == (*(_pCurDevice->ResolutionList + i)).y) )
  1651. {
  1652. TraceMsg(TF_FUNC, "_UpdateUI() -- Set Resolution index %d", i);
  1653. if (_iResolution == i)
  1654. {
  1655. TraceMsg(TF_FUNC, "_UpdateUI() -- Set Resolution index %d - is current", i);
  1656. break;
  1657. }
  1658. SendDlgItemMessage(_hDlg, IDC_SCREENSIZE, TBM_SETPOS, TRUE, i);
  1659. break;
  1660. }
  1661. }
  1662. if (i == _pCurDevice->cResolutions)
  1663. {
  1664. TraceMsg(TF_ERROR, "_UpdateUI -- !!! inconsistent color list !!!");
  1665. }
  1666. bRepaint = (i != _iResolution);
  1667. _iResolution = i;
  1668. // If the resolution has changed, we have to repaint the preview window
  1669. // Set the focus back to the trackbar after the repaint so any further
  1670. // kb events will be send to it rather than the preview window
  1671. if (bRepaint) {
  1672. SendMessage(_hDlg, MM_REDRAWPREVIEW, 0, 0);
  1673. }
  1674. if (FocusToCtrlID != 0) {
  1675. SetFocus(GetDlgItem(_hDlg, FocusToCtrlID));
  1676. }
  1677. }
  1678. }
  1679. //----------------------------------------------------------------------------
  1680. //
  1681. // SetPrimary()
  1682. //
  1683. //----------------------------------------------------------------------------
  1684. BOOL
  1685. CSettingsPage::SetPrimary(
  1686. PMULTIMON_DEVICE pDevice)
  1687. {
  1688. //
  1689. // Check if state is already set.
  1690. //
  1691. if (pDevice == _pPrimaryDevice)
  1692. {
  1693. pDevice->pds->SetPrimary(TRUE);
  1694. return TRUE;
  1695. }
  1696. ASSERT(pDevice->pds->IsAttached());
  1697. _pPrimaryDevice->pds->SetPrimary(FALSE);
  1698. pDevice->pds->SetPrimary(TRUE);
  1699. _pPrimaryDevice = pDevice;
  1700. SetDirty();
  1701. return TRUE;
  1702. }
  1703. //----------------------------------------------------------------------------
  1704. //
  1705. // SetMonAttached()
  1706. //
  1707. //----------------------------------------------------------------------------
  1708. BOOL
  1709. CSettingsPage::SetMonAttached(
  1710. PMULTIMON_DEVICE pDevice,
  1711. BOOL bSetAttached,
  1712. BOOL bForce,
  1713. HWND hwnd)
  1714. {
  1715. if (pDevice->pds->IsAttached() == bSetAttached)
  1716. {
  1717. return TRUE;
  1718. }
  1719. if (bSetAttached)
  1720. {
  1721. //
  1722. // Make sure this device actually has a rectangle.
  1723. // If it does not (not configured in the registry, then we need
  1724. // to put up a popup and ask the user to configure the device.
  1725. //
  1726. if (hwnd)
  1727. {
  1728. //
  1729. // Check to see if we should ask the user about enabling this device
  1730. //
  1731. if (bForce == FALSE)
  1732. {
  1733. TCHAR szTurnItOn[400];
  1734. TCHAR szTurnOnTitleFormat[30];
  1735. TCHAR szTurnOnTitle[110];
  1736. LPTSTR pstr = szTurnItOn;
  1737. DWORD chSize = ARRAYSIZE(szTurnItOn);
  1738. LoadString(HINST_THISDLL, IDS_TURNONTITLE, szTurnOnTitleFormat, ARRAYSIZE(szTurnOnTitleFormat));
  1739. StringCchPrintf(szTurnOnTitle, ARRAYSIZE(szTurnOnTitle), szTurnOnTitleFormat, pDevice->DisplayIndex);
  1740. if (GetNumberOfAttachedDisplays() == 1)
  1741. {
  1742. LoadString(HINST_THISDLL, IDS_TURNONMSG, szTurnItOn, ARRAYSIZE(szTurnItOn));
  1743. pstr += lstrlen(szTurnItOn);
  1744. chSize -= lstrlen(szTurnItOn);
  1745. }
  1746. LoadString(HINST_THISDLL, IDS_TURNITON, pstr, chSize);
  1747. if (ShellMessageBox(HINST_THISDLL, hwnd, szTurnItOn, szTurnOnTitle,
  1748. MB_YESNO | MB_ICONINFORMATION) != IDYES)
  1749. {
  1750. return FALSE;
  1751. }
  1752. }
  1753. }
  1754. pDevice->pds->SetAttached(TRUE);
  1755. }
  1756. else // (bSetAttached == FALSE)
  1757. {
  1758. //
  1759. // Can't detach if we have only one device or it's the primary.
  1760. // The UI should disable this situation
  1761. //
  1762. if ((GetNumberOfAttachedDisplays() == 1) ||
  1763. pDevice->pds->IsPrimary())
  1764. {
  1765. ASSERT(FALSE);
  1766. }
  1767. pDevice->pds->SetAttached(FALSE);
  1768. }
  1769. SetDirty();
  1770. return TRUE;
  1771. }
  1772. //----------------------------------------------------------------------------
  1773. //
  1774. // SetDirty
  1775. //
  1776. //----------------------------------------------------------------------------
  1777. void CSettingsPage::SetDirty(BOOL bDirty)
  1778. {
  1779. _bDirty = bDirty;
  1780. if (_bDirty)
  1781. {
  1782. EnableApplyButton(_hDlg);
  1783. }
  1784. }
  1785. //-----------------------------------------------------------------------------
  1786. void CSettingsPage::_CleanupRects(HWND hwndP)
  1787. {
  1788. int n;
  1789. HWND hwndC;
  1790. DWORD arcDev[MONITORS_MAX];
  1791. RECT arc[MONITORS_MAX];
  1792. DWORD iArcPrimary = 0;
  1793. RECT rc;
  1794. RECT rcU;
  1795. int i;
  1796. RECT rcPrev;
  1797. int sx,sy;
  1798. int x,y;
  1799. //
  1800. // get the positions of all the windows
  1801. //
  1802. n = 0;
  1803. for (ULONG iDevice = 0; iDevice < _NumDevices; iDevice++)
  1804. {
  1805. PMULTIMON_DEVICE pDevice = &_Devices[iDevice];
  1806. hwndC = GetDlgItemP(hwndP, (INT_PTR) pDevice);
  1807. if (hwndC != NULL)
  1808. {
  1809. RECT rcPos;
  1810. RECT rcPreview;
  1811. TraceMsg(TF_GENERAL, "_CleanupRects start Device %08lx, Dev = %d, hwnd = %08lx",
  1812. pDevice, iDevice, hwndC);
  1813. ShowWindow(hwndC, SW_SHOW);
  1814. GetWindowRect(hwndC, &arc[n]);
  1815. MapWindowPoints(NULL, hwndP, (POINT FAR*)&arc[n], 2);
  1816. pDevice->pds->GetCurPosition(&rcPos);
  1817. pDevice->pds->GetPreviewPosition(&rcPreview);
  1818. _OffsetPreviewToDesk(hwndC, &arc[n], &rcPreview, &rcPos);
  1819. arc[n] = rcPos;
  1820. arcDev[n] = iDevice;
  1821. // TEMP
  1822. // For non-atached devices, make sure they end up to the right
  1823. // Eventually, non-attached devices should be showed aligned on the
  1824. // right hand side of the window.
  1825. if (!pDevice->pds->IsAttached())
  1826. {
  1827. OffsetRect(&arc[n], 10000, 0);
  1828. }
  1829. if (pDevice->pds->IsPrimary())
  1830. {
  1831. TraceMsg(TF_GENERAL, "_CleanupRects primary Device %08lx", pDevice);
  1832. iArcPrimary = n;
  1833. }
  1834. n++;
  1835. }
  1836. }
  1837. //
  1838. // cleanup the rects
  1839. //
  1840. AlignRects(arc, n, iArcPrimary, CUDR_NORMAL);
  1841. //
  1842. // Get the union.
  1843. //
  1844. SetRectEmpty(&rcU);
  1845. for (i=0; i<n; i++)
  1846. UnionRect(&rcU, &rcU, &arc[i]);
  1847. GetClientRect(hwndP, &rcPrev);
  1848. //
  1849. // only rescale if the new desk hangs outside the preview area.
  1850. // or is too small
  1851. //
  1852. _DeskToPreview(&rcU, &rc);
  1853. x = ((rcPrev.right - rcPrev.left)-(rc.right - rc.left))/2;
  1854. y = ((rcPrev.bottom - rcPrev.top) -(rc.bottom - rc.top))/2;
  1855. if (rcU.left < 0 || rcU.top < 0 || x < 0 || y < 0 ||
  1856. rcU.right > rcPrev.right || rcU.bottom > rcPrev.bottom ||
  1857. (x > (rcPrev.right-rcPrev.left)/8 &&
  1858. y > (rcPrev.bottom-rcPrev.top)/8))
  1859. {
  1860. _rcDesk = rcU;
  1861. sx = MulDiv(rcPrev.right - rcPrev.left - 16,1000,_rcDesk.right - _rcDesk.left);
  1862. sy = MulDiv(rcPrev.bottom - rcPrev.top - 16,1000,_rcDesk.bottom - _rcDesk.top);
  1863. _DeskScale = min(sx,sy) * 2 / 3;
  1864. _DeskToPreview(&_rcDesk, &rc);
  1865. _DeskOff.x = ((rcPrev.right - rcPrev.left)-(rc.right - rc.left))/2;
  1866. _DeskOff.y = ((rcPrev.bottom - rcPrev.top) -(rc.bottom - rc.top))/2;
  1867. }
  1868. //
  1869. // Show all the windows and save them all to the devmode.
  1870. //
  1871. for (i=0; i < n; i++)
  1872. {
  1873. RECT rcPos;
  1874. POINT ptPos;
  1875. _Devices[arcDev[i]].pds->GetCurPosition(&rcPos);
  1876. hwndC = GetDlgItemP(hwndP, (INT_PTR) &_Devices[arcDev[i]]);
  1877. _DeskToPreview(&arc[i], &rc);
  1878. rc.right = MulDiv(RECTWIDTH(rcPos), _DeskScale, 1000);
  1879. rc.bottom = MulDiv(RECTHEIGHT(rcPos), _DeskScale, 1000);
  1880. TraceMsg(TF_GENERAL, "_CleanupRects set Dev = %d, hwnd = %08lx", arcDev[i], hwndC);
  1881. TraceMsg(TF_GENERAL, "_CleanupRects window pos %d,%d,%d,%d", rc.left, rc.top, rc.right, rc.bottom);
  1882. SetWindowPos(hwndC,
  1883. NULL,
  1884. rc.left,
  1885. rc.top,
  1886. rc.right,
  1887. rc.bottom,
  1888. SWP_NOZORDER);
  1889. rc.right += rc.left;
  1890. rc.bottom += rc.top;
  1891. _Devices[arcDev[i]].pds->SetPreviewPosition(&rc);
  1892. ptPos.x = arc[i].left;
  1893. ptPos.y = arc[i].top;
  1894. _Devices[arcDev[i]].pds->SetCurPosition(&ptPos);
  1895. }
  1896. TraceMsg(TF_GENERAL, "");
  1897. }
  1898. void CSettingsPage::_ConfirmPositions()
  1899. {
  1900. ASSERT (_NumDevices > 1);
  1901. PMULTIMON_DEVICE pDevice;
  1902. ULONG iDevice;
  1903. for (iDevice = 0; iDevice < _NumDevices; iDevice++)
  1904. {
  1905. pDevice = &_Devices[iDevice];
  1906. if (pDevice->pds->IsOrgAttached())
  1907. {
  1908. RECT rcOrg, rcCur;
  1909. pDevice->pds->GetCurPosition(&rcCur);
  1910. pDevice->pds->GetOrgPosition(&rcOrg);
  1911. if ((rcCur.left != rcOrg.left) ||
  1912. (rcCur.top != rcOrg.top))
  1913. {
  1914. POINT ptOrg;
  1915. ptOrg.x = rcCur.left;
  1916. ptOrg.y = rcCur.top;
  1917. pDevice->pds->SetOrgPosition(&ptOrg);
  1918. SetDirty(TRUE);
  1919. }
  1920. }
  1921. }
  1922. }
  1923. void CSettingsPage::GetMonitorPosition(PMULTIMON_DEVICE pDevice, HWND hwndP, PPOINT ptPos)
  1924. {
  1925. int iPrimary = 0;
  1926. HWND hwndC;
  1927. RECT rcPos;
  1928. RECT rcPreview;
  1929. RECT arc[MONITORS_MAX];
  1930. int i;
  1931. for (ULONG iDevice = 0; iDevice < _NumDevices; iDevice++)
  1932. {
  1933. PMULTIMON_DEVICE pDevice = &_Devices[iDevice];
  1934. hwndC = GetDlgItemP(hwndP, (INT_PTR) pDevice);
  1935. ASSERT(hwndC);
  1936. GetWindowRect(hwndC, &arc[iDevice]);
  1937. MapWindowPoints(NULL, hwndP, (POINT FAR*)&arc[iDevice], 2);
  1938. pDevice->pds->GetCurPosition(&rcPos);
  1939. pDevice->pds->GetPreviewPosition(&rcPreview);
  1940. _OffsetPreviewToDesk(hwndC, &arc[iDevice], &rcPreview, &rcPos);
  1941. arc[iDevice] = rcPos;
  1942. if (pDevice->pds->IsPrimary()) {
  1943. iPrimary = iDevice;
  1944. }
  1945. }
  1946. AlignRects(arc, iDevice, iPrimary, CUDR_NORMAL);
  1947. i = (int)(pDevice - _Devices);
  1948. ptPos->x = arc[i].left;
  1949. ptPos->y = arc[i].top;
  1950. }
  1951. BOOL CSettingsPage::HandleMonitorChange(HWND hwndP, BOOL bMainDlg, BOOL bRepaint /*=TRUE*/)
  1952. {
  1953. if (!bMainDlg && _InSetInfo)
  1954. return FALSE;
  1955. SetDirty();
  1956. if (bMainDlg)
  1957. BringWindowToTop(hwndP);
  1958. _CleanupRects(GetParent(hwndP));
  1959. UpdateActiveDisplay(_pCurDevice, bRepaint);
  1960. return TRUE;
  1961. }
  1962. BOOL CSettingsPage::RegisterPreviewWindowClass(WNDPROC pfnWndProc)
  1963. {
  1964. TraceMsg(TF_GENERAL, "InitMultiMonitorDlg\n");
  1965. WNDCLASS cls;
  1966. cls.hCursor = LoadCursor(NULL,IDC_ARROW);
  1967. cls.hIcon = NULL;
  1968. cls.lpszMenuName = NULL;
  1969. cls.lpszClassName = TEXT("Monitor32");
  1970. cls.hbrBackground = (HBRUSH)(COLOR_DESKTOP + 1);
  1971. cls.hInstance = HINST_THISDLL;
  1972. cls.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
  1973. cls.lpfnWndProc = pfnWndProc;
  1974. cls.cbWndExtra = sizeof(LPVOID);
  1975. cls.cbClsExtra = 0;
  1976. return RegisterClass(&cls);
  1977. }
  1978. LRESULT CALLBACK DeskWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, UINT_PTR uID, DWORD_PTR dwRefData);
  1979. // This function is called from desk.c; Hence extern "C".
  1980. // This function is needed to determine if we need to use the single monitor's dialog
  1981. // or multi-monitor's dialog template at the time of starting the control panel applet.
  1982. int ComputeNumberOfDisplayDevices(void)
  1983. {
  1984. int iNumberOfDevices = 0;
  1985. CSettingsPage * pMultiMon = new CSettingsPage;
  1986. if (pMultiMon)
  1987. {
  1988. int iDevice;
  1989. // Enumerate all display devices to count the number of valid devices.
  1990. iNumberOfDevices = pMultiMon->_EnumerateAllDisplayDevices();
  1991. // Now that we have the number of devices, let's cleanup the device settings we
  1992. // created in the process of enumerating above.
  1993. for (iDevice = 0; iDevice < iNumberOfDevices; iDevice++)
  1994. pMultiMon->_DestroyMultimonDevice(&pMultiMon->_Devices[iDevice]);
  1995. // Let's clean up the MultiMon we allocated earlier.
  1996. pMultiMon->Release();
  1997. }
  1998. return iNumberOfDevices;
  1999. }
  2000. int ComputeNumberOfMonitorsFast(BOOL fFastDetect)
  2001. {
  2002. int nVideoCards = 0;
  2003. int nIndex;
  2004. DISPLAY_DEVICE dispDevice = {0};
  2005. dispDevice.cb = sizeof(dispDevice);
  2006. for (nIndex = 0; EnumDisplayDevices(NULL, nIndex, &dispDevice, 0); nIndex++)
  2007. {
  2008. // Fast Detect means the caller only cares if there are more than 1.
  2009. if (fFastDetect && (nVideoCards > 1))
  2010. {
  2011. break;
  2012. }
  2013. dispDevice.cb = sizeof(dispDevice);
  2014. if (!(dispDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER))
  2015. {
  2016. nVideoCards++;
  2017. }
  2018. }
  2019. return nVideoCards;
  2020. }
  2021. BOOL CSettingsPage::_InitDisplaySettings(BOOL bExport)
  2022. {
  2023. HWND hwndC;
  2024. int iItem;
  2025. LONG iPrimeDevice = 0;
  2026. TCHAR ach[128];
  2027. PMULTIMON_DEVICE pDevice;
  2028. RECT rcPrimary;
  2029. HCURSOR hcur;
  2030. _InSetInfo = 1;
  2031. hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
  2032. //
  2033. // Reset all the data so we can reinitialize the applet.
  2034. //
  2035. {
  2036. ComboBox_ResetContent(_hwndList);
  2037. SetRectEmpty(&_rcDesk);
  2038. hwndC = GetWindow(_hwndDesk, GW_CHILD);
  2039. while (hwndC)
  2040. {
  2041. RemoveTrackingToolTip(hwndC);
  2042. RemovePopupToolTip(hwndC);
  2043. DestroyWindow(hwndC);
  2044. hwndC = GetWindow(_hwndDesk, GW_CHILD);
  2045. }
  2046. ShowWindow(_hwndDesk, SW_HIDE);
  2047. if (_himl != NULL)
  2048. {
  2049. ImageList_Destroy(_himl);
  2050. _himl = NULL;
  2051. }
  2052. //
  2053. // Clear out all the devices.
  2054. //
  2055. for (ULONG iDevice = 0; iDevice < _NumDevices; iDevice++) {
  2056. pDevice = _Devices + iDevice;
  2057. _DestroyMultimonDevice(pDevice);
  2058. ZeroMemory(pDevice, sizeof(*pDevice));
  2059. }
  2060. ZeroMemory(_Devices + _NumDevices,
  2061. sizeof(_Devices) - sizeof(MULTIMON_DEVICE) * _NumDevices);
  2062. _NumDevices = 0;
  2063. }
  2064. //
  2065. // Enumerate all the devices in the system.
  2066. //
  2067. // Note: This function computes the _NumDevices.
  2068. _EnumerateAllDisplayDevices();
  2069. if (_NumDevices == 0)
  2070. {
  2071. ASSERT(0);
  2072. return FALSE;
  2073. }
  2074. // Because we are getting the registry values, the current state of
  2075. // the registry may be inconsistent with that of the system:
  2076. //
  2077. // EmumDisplayDevices will return the active primary in the
  2078. // system, which may be different than the actual primary marked in the
  2079. // registry
  2080. BOOL bTmpDevicePrimary = FALSE;
  2081. ULONG iDevice;
  2082. _pPrimaryDevice = NULL;
  2083. for (iDevice = 0; iDevice < _NumDevices; iDevice++)
  2084. {
  2085. // First, we can pick any monitor that is attached as the primary.
  2086. if (_Devices[iDevice].pds->IsAttached())
  2087. {
  2088. if ((_pPrimaryDevice == NULL) &&
  2089. !_Devices[iDevice].pds->IsRemovable())
  2090. {
  2091. _pPrimaryDevice = &_Devices[iDevice];
  2092. TraceMsg(TF_GENERAL, "InitDisplaySettings: primary found %d\n", iDevice);
  2093. }
  2094. // If the DISPLAY_DEVICE structure tells us this is the primary,
  2095. // Pick this one.
  2096. if (_Devices[iDevice].DisplayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
  2097. {
  2098. if (bTmpDevicePrimary)
  2099. {
  2100. ASSERT(FALSE);
  2101. }
  2102. else
  2103. {
  2104. _pPrimaryDevice = &_Devices[iDevice];
  2105. bTmpDevicePrimary = TRUE;
  2106. TraceMsg(TF_GENERAL, "InitDisplaySettings: Tmp DEVICE_PRIMARY found %d", iDevice);
  2107. }
  2108. // Check that the position should really be 0,0
  2109. RECT pos;
  2110. _Devices[iDevice].pds->GetCurPosition(&pos);
  2111. if ((pos.left == 0) &&
  2112. (pos.top == 0))
  2113. {
  2114. _pPrimaryDevice = &_Devices[iDevice];
  2115. TraceMsg(TF_GENERAL, "InitDisplaySettings: Best DEVICE_PRIMARY found %d", iDevice);
  2116. }
  2117. else
  2118. {
  2119. ASSERT(FALSE);
  2120. TraceMsg(TF_GENERAL, "InitDisplaySettings: PRIMARY is not at 0,0");
  2121. }
  2122. }
  2123. }
  2124. }
  2125. if (_pPrimaryDevice == NULL)
  2126. {
  2127. TraceMsg(TF_GENERAL, "InitDisplaySettings: NO Attached devices !!!");
  2128. // We must be running setup.
  2129. // Pick the first non-removable device as the primary.
  2130. for (iDevice = 0; iDevice < _NumDevices; iDevice++)
  2131. {
  2132. if (!_Devices[iDevice].pds->IsRemovable())
  2133. {
  2134. _pPrimaryDevice = &_Devices[iDevice];
  2135. break;
  2136. }
  2137. }
  2138. if (_pPrimaryDevice == NULL)
  2139. {
  2140. ASSERT(FALSE);
  2141. TraceMsg(TF_GENERAL, "InitDisplaySettings: All devices are removable !!!");
  2142. _pPrimaryDevice = &_Devices[0];
  2143. }
  2144. }
  2145. _pCurDevice = _pPrimaryDevice;
  2146. //
  2147. // Reset the primary's variables to make sure it is a properly formated
  2148. // primary entry.
  2149. //
  2150. SetMonAttached(_pPrimaryDevice, TRUE, TRUE, NULL);
  2151. SetPrimary(_pPrimaryDevice);
  2152. _pPrimaryDevice->pds->GetCurPosition(&rcPrimary);
  2153. //
  2154. // compute the max image size needed for a monitor bitmap
  2155. //
  2156. // NOTE this must be the max size the images will *ever*
  2157. // be we cant just take the current max size.
  2158. // we use the client window size, a child monitor cant be larger than this.
  2159. //
  2160. RECT rcDesk;
  2161. GetClientRect(_hwndDesk, &rcDesk);
  2162. int cxImage = rcDesk.right;
  2163. int cyImage = rcDesk.bottom;
  2164. //
  2165. // Create a temporary monitor bitmap
  2166. //
  2167. HBITMAP hbm = NULL;
  2168. MakeMonitorBitmap(cxImage, cyImage, NULL, &hbm, NULL, cxImage, cyImage, FALSE);
  2169. //
  2170. // Go through all the devices one last time to create the windows
  2171. //
  2172. for (iDevice = 0; iDevice < _NumDevices; iDevice++)
  2173. {
  2174. TCHAR szDisplay[256];
  2175. pDevice = &_Devices[iDevice];
  2176. MonitorData md = {0};
  2177. RECT rcPos;
  2178. LPVOID pWindowData = (LPVOID)this;
  2179. pDevice->DisplayIndex = iDevice + 1;
  2180. _GetDisplayName(pDevice, szDisplay, ARRAYSIZE(szDisplay));
  2181. iItem = ComboBox_AddString(_hwndList, szDisplay);
  2182. pDevice->ComboBoxItem = iItem;
  2183. ComboBox_SetItemData(_hwndList,
  2184. iItem,
  2185. (DWORD_PTR)pDevice);
  2186. //
  2187. // If the monitor is part of the desktop, show it on the screen
  2188. // otherwise keep it invisible.
  2189. //
  2190. StringCchPrintf(ach, ARRAYSIZE(ach), TEXT("%d"), iDevice + 1);
  2191. // Set the selection
  2192. //
  2193. if (pDevice == _pPrimaryDevice)
  2194. {
  2195. iPrimeDevice = iDevice;
  2196. }
  2197. if (!pDevice->pds->IsAttached())
  2198. {
  2199. // By default set the unattached monitors to the right of the primary monitor
  2200. POINT ptPos = {rcPrimary.right, rcPrimary.top};
  2201. pDevice->pds->SetCurPosition(&ptPos);
  2202. }
  2203. pDevice->pds->GetCurPosition(&rcPos);
  2204. if (bExport)
  2205. {
  2206. md.dwSize = sizeof(MonitorData);
  2207. if ( pDevice->pds->IsPrimary() )
  2208. md.dwStatus |= MD_PRIMARY;
  2209. if ( pDevice->pds->IsAttached() )
  2210. md.dwStatus |= MD_ATTACHED;
  2211. md.rcPos = rcPos;
  2212. pWindowData = &md;
  2213. }
  2214. if (_himl == NULL)
  2215. {
  2216. UINT flags = ILC_COLORDDB | ILC_MASK;
  2217. _himl = ImageList_Create(cxImage, cyImage, flags, _NumDevices, 1);
  2218. ASSERT(_himl);
  2219. ImageList_SetBkColor(_himl, GetSysColor(COLOR_APPWORKSPACE));
  2220. }
  2221. pDevice->w = -1;
  2222. pDevice->h = -1;
  2223. pDevice->himl = _himl;
  2224. pDevice->iImage = ImageList_AddMasked(_himl, hbm, CLR_DEFAULT);
  2225. TraceMsg(TF_GENERAL, "InitDisplaySettings: Creating preview windows %s at %d %d %d %d",
  2226. ach, rcPos.left, rcPos.top, rcPos.right, rcPos.bottom);
  2227. // HACK! Use pDevice as its own id. Doesn't work on Win64.
  2228. hwndC = CreateWindowEx(
  2229. 0,
  2230. TEXT("Monitor32"), ach,
  2231. WS_CLIPSIBLINGS | WS_VISIBLE | WS_CHILD,
  2232. rcPos.left, rcPos.top, RECTWIDTH(rcPos), RECTHEIGHT(rcPos),
  2233. _hwndDesk,
  2234. (HMENU)pDevice,
  2235. HINST_THISDLL,
  2236. pWindowData);
  2237. ASSERT(hwndC);
  2238. AddTrackingToolTip(pDevice, hwndC);
  2239. AddPopupToolTip(hwndC);
  2240. }
  2241. ToolTip_Activate(ghwndToolTipPopup, TRUE);
  2242. ToolTip_SetDelayTime(ghwndToolTipPopup, TTDT_INITIAL, 1000);
  2243. ToolTip_SetDelayTime(ghwndToolTipPopup, TTDT_RESHOW, 1000);
  2244. // nuke the temp monitor bitmap.
  2245. if (hbm)
  2246. DeleteObject(hbm);
  2247. //
  2248. // Set the primary device as the current device
  2249. //
  2250. ComboBox_SetCurSel(_hwndList, iPrimeDevice);
  2251. // Initialize all the constants and the settings fields
  2252. _DeskScale = 1000;
  2253. _DeskOff.x = 0;
  2254. _DeskOff.y = 0;
  2255. _CleanupRects(_hwndDesk);
  2256. // Now: depends on whether we have a multimon system, change the UI
  2257. if (_NumDevices == 1)
  2258. {
  2259. HWND hwndDisable;
  2260. hwndDisable = GetDlgItem(_hDlg, IDC_MULTIMONHELP);
  2261. ShowWindow(hwndDisable, SW_HIDE);
  2262. ShowWindow(_hwndDesk, SW_HIDE);
  2263. // set up bitmaps for sample screen
  2264. _hbmScrSample = LoadMonitorBitmap( TRUE ); // let them do the desktop
  2265. SendDlgItemMessage(_hDlg, IDC_SCREENSAMPLE, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)_hbmScrSample);
  2266. // get a base copy of the bitmap for when the "internals" change
  2267. _hbmMonitor = LoadMonitorBitmap( FALSE ); // we'll do the desktop
  2268. //Hide the combo box, keep the static text
  2269. ShowWindow(_hwndList, SW_HIDE);
  2270. //Set the name of the primary in the static text
  2271. //strip the first token off (this is the number we dont want it)
  2272. TCHAR *pch, szDisplay[MAX_PATH];
  2273. _GetDisplayName(_pPrimaryDevice, szDisplay, ARRAYSIZE(szDisplay));
  2274. for (pch=szDisplay; *pch && *pch != TEXT(' '); pch++);
  2275. for (;*pch && *pch == TEXT(' '); pch++);
  2276. SetDlgItemText(_hDlg, IDC_DISPLAYTEXT, pch);
  2277. // Hide the check boxes
  2278. // Single monitors use a different dialog template now!
  2279. hwndDisable = GetDlgItem(_hDlg, IDC_DISPLAYPRIME);
  2280. if(hwndDisable)
  2281. ShowWindow(hwndDisable, SW_HIDE);
  2282. hwndDisable = GetDlgItem(_hDlg, IDC_DISPLAYUSEME);
  2283. if(hwndDisable)
  2284. ShowWindow(hwndDisable, SW_HIDE);
  2285. }
  2286. else if (_NumDevices > 0)
  2287. {
  2288. //Hide the static text, keep the combo box
  2289. ShowWindow(GetDlgItem(_hDlg, IDC_DISPLAYTEXT), SW_HIDE);
  2290. // Hide the Multimon version of the preview objects
  2291. ShowWindow(GetDlgItem(_hDlg, IDC_SCREENSAMPLE), SW_HIDE);
  2292. // In case of multiple devices, subclass the _hwndDesk window for key board support
  2293. SetWindowSubclass(_hwndDesk, DeskWndProc, 0, (DWORD_PTR)this);
  2294. ShowWindow(_hwndDesk, SW_SHOW);
  2295. }
  2296. //
  2297. // Paint the UI.
  2298. //
  2299. UpdateActiveDisplay(_pCurDevice);
  2300. //
  2301. // Reset the cursor and leave
  2302. //
  2303. SetCursor(hcur);
  2304. _InSetInfo--;
  2305. return TRUE;
  2306. }
  2307. //
  2308. // This function enumerates all the devices and returns the number of
  2309. // devices found in the system.
  2310. //
  2311. int CSettingsPage::_EnumerateAllDisplayDevices()
  2312. {
  2313. PMULTIMON_DEVICE pDevice;
  2314. int iEnum;
  2315. BOOL fSuccess;
  2316. ULONG dwVgaPrimary = 0xFFFFFFFF;
  2317. //
  2318. // Enumerate all the devices in the system.
  2319. //
  2320. for (iEnum = 0; _NumDevices < MONITORS_MAX; iEnum++)
  2321. {
  2322. pDevice = &_Devices[_NumDevices];
  2323. ZeroMemory(&(pDevice->DisplayDevice), sizeof(pDevice->DisplayDevice));
  2324. pDevice->DisplayDevice.cb = sizeof(pDevice->DisplayDevice);
  2325. fSuccess = EnumDisplayDevices(NULL, iEnum, &pDevice->DisplayDevice, 0);
  2326. TraceMsg(TF_GENERAL, "Device %d ", iEnum);
  2327. TraceMsg(TF_GENERAL, "cb %d ", pDevice->DisplayDevice.cb);
  2328. TraceMsg(TF_GENERAL, "DeviceName %ws ", pDevice->DisplayDevice.DeviceName);
  2329. TraceMsg(TF_GENERAL, "DeviceString %ws", pDevice->DisplayDevice.DeviceString);
  2330. TraceMsg(TF_GENERAL, "StateFlags %08lx", pDevice->DisplayDevice.StateFlags);
  2331. // ignore device's we cant create a DC for.
  2332. if (!fSuccess)
  2333. {
  2334. TraceMsg(TF_GENERAL, "End of list\n");
  2335. break;
  2336. }
  2337. // We won't even include the MIRRORING drivers in the list for
  2338. // now.
  2339. if (pDevice->DisplayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER)
  2340. {
  2341. TraceMsg(TF_GENERAL, "Mirroring driver - skip it\n");
  2342. continue;
  2343. }
  2344. // dump the device software key
  2345. TraceMsg(TF_GENERAL, "DeviceKey %s", pDevice->DisplayDevice.DeviceKey);
  2346. // Create the settings for this device
  2347. pDevice->pds = new CDisplaySettings();
  2348. if (pDevice->pds)
  2349. {
  2350. if (pDevice->pds->InitSettings(&pDevice->DisplayDevice))
  2351. {
  2352. // Determine if the VGA is the primary.
  2353. // This will only happen for SETUP or BASEVIDEO
  2354. //
  2355. // We want to delete this device later on if we have others.
  2356. if (pDevice->DisplayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
  2357. {
  2358. CRegistrySettings crv(&pDevice->DisplayDevice.DeviceKey[0]);
  2359. LPTSTR pszMini = crv.GetMiniPort();
  2360. // If VGA is active, then go to pass 2.
  2361. // Otherwise, let's try to use this device
  2362. //
  2363. if (pszMini && (!lstrcmpi(TEXT("vga"), pszMini)))
  2364. {
  2365. TraceMsg(TF_GENERAL, "EnumDevices - VGA primary\n");
  2366. dwVgaPrimary = _NumDevices;
  2367. }
  2368. }
  2369. // Add it to the list.
  2370. _NumDevices++;
  2371. }
  2372. else
  2373. {
  2374. pDevice->pds->Release();
  2375. pDevice->pds = NULL;
  2376. }
  2377. }
  2378. }
  2379. //
  2380. // If the primary VGA is not needed, remove it.
  2381. //
  2382. if ((dwVgaPrimary != 0xFFFFFFFF) &&
  2383. (_NumDevices >= 2))
  2384. {
  2385. TraceMsg(TF_GENERAL, "REMOVE primary VGA device\n");
  2386. _Devices[dwVgaPrimary].pds->Release();
  2387. _Devices[dwVgaPrimary].pds = NULL;
  2388. _NumDevices--;
  2389. _Devices[dwVgaPrimary] = _Devices[_NumDevices];
  2390. }
  2391. return(_NumDevices); //Return the number of devices.
  2392. }
  2393. //-----------------------------------------------------------------------------
  2394. BOOL CSettingsPage::InitMultiMonitorDlg(HWND hDlg)
  2395. {
  2396. HWND hwndSlider;
  2397. BOOL fSucceeded;
  2398. _hDlg = hDlg;
  2399. _hwndDesk = GetDlgItem(_hDlg, IDC_DISPLAYDESK);
  2400. _hwndList = GetDlgItem(_hDlg, IDC_DISPLAYLIST);
  2401. hwndSlider = GetDlgItem(hDlg, IDC_SCREENSIZE);
  2402. ASSERT(hwndSlider != NULL);
  2403. fSucceeded = SetWindowSubclass(hwndSlider, SliderSubWndProc, 0, NULL);
  2404. ASSERT(fSucceeded);
  2405. // Determine in what mode we are running the applet before getting information
  2406. _vPreExecMode();
  2407. // Create a tooltip window
  2408. ghwndToolTipTracking = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, TEXT(""),
  2409. WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT,
  2410. CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL,
  2411. HINST_THISDLL, NULL);
  2412. ghwndToolTipPopup = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, TEXT(""),
  2413. WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT,
  2414. CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL,
  2415. HINST_THISDLL, NULL);
  2416. RegisterPreviewWindowClass(&MonitorWindowProc);
  2417. _InitDisplaySettings(FALSE);
  2418. if (_NumDevices > 1)
  2419. _ConfirmPositions();
  2420. if (ClassicGetSystemMetrics(SM_REMOTESESSION)) {
  2421. EnableWindow(GetDlgItem(_hDlg, IDC_DISPLAYPROPERTIES), FALSE);
  2422. }
  2423. // Determine if any errors showed up during enumerations and initialization
  2424. _vPostExecMode();
  2425. // Now tell the user what we found out during initialization
  2426. // Errors, or what we found during detection
  2427. PostMessage(hDlg, MSG_DSP_SETUP_MESSAGE, 0, 0);
  2428. // Since this could have taken a very long time, just make us visible
  2429. // if another app (like progman) came up.
  2430. ShowWindow(hDlg, SW_SHOW);
  2431. return TRUE;
  2432. }
  2433. LRESULT CALLBACK DeskWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam, UINT_PTR uID, DWORD_PTR dwRefData)
  2434. {
  2435. CSettingsPage * pcmm = (CSettingsPage *)dwRefData;
  2436. HWND hwndC;
  2437. RECT rcPos;
  2438. BOOL bMoved = TRUE;
  2439. int iMonitor, nMoveUnit;
  2440. switch(message)
  2441. {
  2442. case WM_GETDLGCODE:
  2443. return DLGC_WANTCHARS | DLGC_WANTARROWS;
  2444. case WM_KILLFOCUS:
  2445. RedrawWindow(hDlg, NULL, NULL, RDW_INVALIDATE);
  2446. break;
  2447. case WM_MOUSEMOVE: {
  2448. MSG mmsg;
  2449. ToolTip_RelayEvent(ghwndToolTipPopup, mmsg, hDlg, message, wParam, lParam);
  2450. }
  2451. break;
  2452. case WM_PAINT:
  2453. if (GetFocus() != hDlg)
  2454. break;
  2455. return(DefSubclassProc(hDlg, message, wParam, lParam));
  2456. break;
  2457. case WM_LBUTTONDOWN:
  2458. SetFocus(hDlg);
  2459. break;
  2460. case WM_KEYDOWN:
  2461. nMoveUnit = ((GetKeyState(VK_CONTROL) & 0x8000) ? 1 : 3);
  2462. hwndC = pcmm->GetCurDeviceHwnd();
  2463. GetWindowRect(hwndC, &rcPos);
  2464. MapWindowRect(NULL, hDlg, &rcPos);
  2465. switch(wParam)
  2466. {
  2467. case VK_LEFT:
  2468. MoveWindow(hwndC, rcPos.left - nMoveUnit, rcPos.top, RECTWIDTH(rcPos), RECTHEIGHT(rcPos), TRUE);
  2469. break;
  2470. case VK_RIGHT:
  2471. MoveWindow(hwndC, rcPos.left + nMoveUnit, rcPos.top, RECTWIDTH(rcPos), RECTHEIGHT(rcPos), TRUE);
  2472. break;
  2473. case VK_UP:
  2474. MoveWindow(hwndC, rcPos.left, rcPos.top - nMoveUnit, RECTWIDTH(rcPos), RECTHEIGHT(rcPos), TRUE);
  2475. break;
  2476. case VK_DOWN:
  2477. MoveWindow(hwndC, rcPos.left, rcPos.top + nMoveUnit, RECTWIDTH(rcPos), RECTHEIGHT(rcPos), TRUE);
  2478. break;
  2479. default:
  2480. bMoved = FALSE;
  2481. break;
  2482. }
  2483. if (bMoved)
  2484. {
  2485. pcmm->HandleMonitorChange(hwndC, FALSE, FALSE);
  2486. if (IsWindowVisible(ghwndToolTipPopup)) {
  2487. ToolTip_Update(ghwndToolTipPopup);
  2488. }
  2489. }
  2490. break;
  2491. case WM_CHAR:
  2492. if (wParam >= TEXT('0') && wParam <= TEXT('9') && pcmm) {
  2493. iMonitor = (TCHAR)wParam - TEXT('0');
  2494. if ((iMonitor == 0) && (pcmm->GetNumDevices() >= 10))
  2495. {
  2496. iMonitor = 10;
  2497. }
  2498. if ((iMonitor > 0) && ((ULONG)iMonitor <= pcmm->GetNumDevices()))
  2499. {
  2500. HWND hwndList = GetDlgItem(GetParent(hDlg), IDC_DISPLAYLIST);
  2501. ComboBox_SetCurSel(hwndList, iMonitor - 1);
  2502. pcmm->UpdateActiveDisplay(NULL);
  2503. return 0;
  2504. }
  2505. }
  2506. break;
  2507. case WM_DESTROY:
  2508. RemoveWindowSubclass(hDlg, DeskWndProc, 0);
  2509. break;
  2510. default:
  2511. break;
  2512. }
  2513. return DefSubclassProc(hDlg, message, wParam, lParam);
  2514. }
  2515. //-----------------------------------------------------------------------------
  2516. //
  2517. // Callback functions PropertySheet can use
  2518. //
  2519. INT_PTR CALLBACK CSettingsPage::SettingsDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  2520. {
  2521. CSettingsPage * pcmm = (CSettingsPage *) GetWindowLongPtr(hDlg, DWLP_USER);
  2522. switch (message)
  2523. {
  2524. case WM_INITDIALOG:
  2525. {
  2526. PROPSHEETPAGE * pPropSheetPage = (PROPSHEETPAGE *) lParam;
  2527. if (pPropSheetPage)
  2528. {
  2529. SetWindowLongPtr(hDlg, DWLP_USER, pPropSheetPage->lParam);
  2530. pcmm = (CSettingsPage *)pPropSheetPage->lParam;
  2531. }
  2532. if (pcmm)
  2533. {
  2534. SetWindowLongPtr(hDlg, DWLP_USER, (LPARAM)pcmm);
  2535. ghwndPropSheet = GetParent(hDlg);
  2536. SetWindowLong(ghwndPropSheet,
  2537. GWL_STYLE,
  2538. GetWindowLong(ghwndPropSheet, GWL_STYLE) | WS_CLIPCHILDREN);
  2539. if (pcmm->InitMultiMonitorDlg(hDlg))
  2540. {
  2541. //
  2542. // if we have a invalid mode force the user to Apply
  2543. //
  2544. DWORD dwExecMode;
  2545. if (pcmm->_pThemeUI && (SUCCEEDED(pcmm->_pThemeUI->GetExecMode(&dwExecMode))))
  2546. {
  2547. if (dwExecMode == EM_INVALID_MODE)
  2548. pcmm->SetDirty();
  2549. }
  2550. return TRUE;
  2551. }
  2552. else
  2553. return FALSE;
  2554. }
  2555. }
  2556. break;
  2557. case WM_DESTROY:
  2558. if (pcmm)
  2559. {
  2560. pcmm->WndProc(message, wParam, lParam);
  2561. SetWindowLongPtr(hDlg, DWLP_USER, NULL);
  2562. }
  2563. if(gfFlashWindowRegistered)
  2564. {
  2565. gfFlashWindowRegistered = FALSE;
  2566. UnregisterClass(TEXT("MonitorNumber32"), HINST_THISDLL);
  2567. }
  2568. break;
  2569. default:
  2570. if (pcmm)
  2571. return pcmm->WndProc(message, wParam, lParam);
  2572. break;
  2573. }
  2574. return FALSE;
  2575. }
  2576. void CSettingsPage::_SetPreviewScreenSize(int HRes, int VRes, int iOrgXRes, int iOrgYRes)
  2577. {
  2578. HBITMAP hbmOld, hbmOld2;
  2579. HBRUSH hbrOld;
  2580. HDC hdcMem, hdcMem2;
  2581. // stretching the taskbar could get messy, we'll only do the desktop
  2582. int mon_dy = MON_DY - MON_TRAY;
  2583. // init to identical extents
  2584. SIZE dSrc = { MON_DX, mon_dy };
  2585. SIZE dDst = { MON_DX, mon_dy };
  2586. // set up a work area to play in
  2587. if (!_hbmMonitor || !_hbmScrSample)
  2588. return;
  2589. HDC hdc = GetDC(NULL);
  2590. hdcMem = CreateCompatibleDC(hdc);
  2591. hdcMem2 = CreateCompatibleDC(hdc);
  2592. ReleaseDC(NULL, hdc);
  2593. if (!hdcMem2 || !hdcMem)
  2594. return;
  2595. hbmOld2 = (HBITMAP)SelectObject(hdcMem2, _hbmScrSample);
  2596. hbmOld = (HBITMAP)SelectObject(hdcMem, _hbmMonitor);
  2597. // see if we need to shrink either aspect of the image
  2598. if (HRes > iOrgXRes || VRes > iOrgYRes)
  2599. {
  2600. // make sure the uncovered area will be seamless with the desktop
  2601. RECT rc = { MON_X, MON_Y, MON_X + MON_DX, MON_Y + mon_dy };
  2602. HBRUSH hbr = CreateSolidBrush(GetPixel( hdcMem, MON_X + 1, MON_Y + 1 ));
  2603. if (hbr)
  2604. {
  2605. FillRect(hdcMem2, &rc, hbr);
  2606. DeleteObject(hbr);
  2607. }
  2608. }
  2609. // stretch the image to reflect the new resolution
  2610. if( HRes > iOrgXRes )
  2611. dDst.cx = MulDiv( MON_DX, iOrgXRes, HRes );
  2612. else if( HRes < iOrgXRes )
  2613. dSrc.cx = MulDiv( MON_DX, HRes, iOrgXRes );
  2614. if( VRes > iOrgYRes )
  2615. dDst.cy = MulDiv( mon_dy, iOrgYRes, VRes );
  2616. else if( VRes < iOrgYRes )
  2617. dSrc.cy = MulDiv( mon_dy, VRes, iOrgYRes );
  2618. SetStretchBltMode( hdcMem2, COLORONCOLOR );
  2619. StretchBlt( hdcMem2, MON_X, MON_Y, dDst.cx, dDst.cy,
  2620. hdcMem, MON_X, MON_Y, dSrc.cx, dSrc.cy, SRCCOPY);
  2621. // now fill the new image's desktop with the possibly-dithered brush
  2622. // the top right corner seems least likely to be hit by the stretch...
  2623. hbrOld = (HBRUSH)SelectObject( hdcMem2, GetSysColorBrush( COLOR_DESKTOP ) );
  2624. ExtFloodFill(hdcMem2, MON_X + MON_DX - 2, MON_Y+1,
  2625. GetPixel(hdcMem2, MON_X + MON_DX - 2, MON_Y+1), FLOODFILLSURFACE);
  2626. // clean up after ourselves
  2627. SelectObject( hdcMem2, hbrOld );
  2628. SelectObject( hdcMem2, hbmOld2 );
  2629. DeleteObject( hdcMem2 );
  2630. SelectObject( hdcMem, hbmOld );
  2631. DeleteObject( hdcMem );
  2632. }
  2633. void CSettingsPage::_RedrawDeskPreviews()
  2634. {
  2635. if (_NumDevices > 1)
  2636. {
  2637. _CleanupRects(_hwndDesk);
  2638. RedrawWindow(_hwndDesk, NULL, NULL, RDW_ALLCHILDREN | RDW_ERASE | RDW_INVALIDATE);
  2639. }
  2640. else if (_pCurDevice && _pCurDevice->pds)
  2641. {
  2642. RECT rcPos, rcOrgPos;
  2643. _pCurDevice->pds->GetCurPosition(&rcPos);
  2644. _pCurDevice->pds->GetOrgPosition(&rcOrgPos);
  2645. _SetPreviewScreenSize(RECTWIDTH(rcPos), RECTHEIGHT(rcPos), RECTWIDTH(rcOrgPos), RECTHEIGHT(rcOrgPos));
  2646. // only invalidate the "screen" part of the monitor bitmap
  2647. rcPos.left = MON_X;
  2648. rcPos.top = MON_Y;
  2649. rcPos.right = MON_X + MON_DX + 2; // fudge (trust me)
  2650. rcPos.bottom = MON_Y + MON_DY + 1; // fudge (trust me)
  2651. InvalidateRect(GetDlgItem(_hDlg, IDC_SCREENSAMPLE), &rcPos, FALSE);
  2652. }
  2653. }
  2654. int DisplaySaveSettings(PVOID pContext, HWND hwnd)
  2655. {
  2656. CDisplaySettings *rgpds[1];
  2657. rgpds[0] = (CDisplaySettings*) pContext;
  2658. if(rgpds[0]->bIsModeChanged())
  2659. return CSettingsPage::_DisplaySaveSettings(rgpds, 1, hwnd);
  2660. else
  2661. return DISP_CHANGE_SUCCESSFUL;
  2662. }
  2663. int CSettingsPage::_DisplaySaveSettings(CDisplaySettings *rgpds[], ULONG numDevices, HWND hDlg)
  2664. {
  2665. BOOL bReboot = FALSE;
  2666. BOOL bTest = FALSE;
  2667. int iSave;
  2668. ULONG iDevice;
  2669. POINT ptCursorSave;
  2670. // Test the new settings first
  2671. iSave = _SaveSettings(rgpds, numDevices, hDlg, CDS_TEST);
  2672. if (iSave < DISP_CHANGE_SUCCESSFUL)
  2673. {
  2674. FmtMessageBox(hDlg,
  2675. MB_ICONEXCLAMATION,
  2676. IDS_CHANGE_SETTINGS,
  2677. IDS_SETTINGS_INVALID);
  2678. return iSave;
  2679. }
  2680. int iDynaResult;
  2681. // Ask first and then change the settings.
  2682. if (!bReboot &&
  2683. (_AnyChange(rgpds, numDevices) ||
  2684. _IsSingleToMultimonChange(rgpds, numDevices)))
  2685. {
  2686. iDynaResult = AskDynaCDS(hDlg);
  2687. if (iDynaResult == -1)
  2688. {
  2689. return DISP_CHANGE_NOTUPDATED;
  2690. }
  2691. else if (iDynaResult == 0)
  2692. {
  2693. bReboot = TRUE;
  2694. }
  2695. }
  2696. if (!bReboot && _AnyChange(rgpds, numDevices) &&
  2697. !_CanSkipWarningBecauseKnownSafe(rgpds, numDevices))
  2698. {
  2699. bTest = TRUE;
  2700. }
  2701. // Save the settings to the registry.
  2702. iSave = _SaveSettings(rgpds, numDevices, hDlg, CDS_UPDATEREGISTRY | CDS_NORESET);
  2703. if (iSave < DISP_CHANGE_SUCCESSFUL)
  2704. {
  2705. // NOTE
  2706. // If we get NOT_UPDATED, this mean security may be turned on.
  2707. // We could still try to do the dynamic change.
  2708. // This only works in single mon ...
  2709. if (iSave == DISP_CHANGE_NOTUPDATED)
  2710. {
  2711. FmtMessageBox(hDlg,
  2712. MB_ICONEXCLAMATION,
  2713. IDS_CHANGE_SETTINGS,
  2714. IDS_SETTINGS_CANNOT_SAVE);
  2715. }
  2716. else
  2717. {
  2718. FmtMessageBox(hDlg,
  2719. MB_ICONEXCLAMATION,
  2720. IDS_CHANGE_SETTINGS,
  2721. IDS_SETTINGS_FAILED_SAVE);
  2722. }
  2723. // Restore the settings to their original state
  2724. for (iDevice = 0; iDevice < numDevices; iDevice++)
  2725. {
  2726. rgpds[iDevice]->RestoreSettings();
  2727. }
  2728. _SaveSettings(rgpds, numDevices, hDlg, CDS_UPDATEREGISTRY | CDS_NORESET);
  2729. return iSave;
  2730. }
  2731. if (bReboot)
  2732. {
  2733. iSave = DISP_CHANGE_RESTART;
  2734. }
  2735. // Try to change the mode dynamically if it was requested
  2736. GetCursorPos(&ptCursorSave);
  2737. if (iSave == DISP_CHANGE_SUCCESSFUL)
  2738. {
  2739. // If EnumDisplaySettings was called with EDS_RAWMODE, we need CDS_RAWMODE below.
  2740. // Otherwise, it's harmless.
  2741. iSave = ChangeDisplaySettings(NULL, CDS_RAWMODE);
  2742. //We post a message to ourselves to destroy it later.
  2743. // Check the return from the dynamic mode switch.
  2744. if (iSave < 0)
  2745. {
  2746. DWORD dwMessage =
  2747. ((iSave == DISP_CHANGE_BADDUALVIEW) ? IDS_CHANGESETTINGS_BADDUALVIEW
  2748. : IDS_DYNAMIC_CHANGESETTINGS_FAILED);
  2749. FmtMessageBox(hDlg,
  2750. MB_ICONEXCLAMATION,
  2751. IDS_CHANGE_SETTINGS,
  2752. dwMessage);
  2753. }
  2754. else if (iSave == DISP_CHANGE_SUCCESSFUL)
  2755. {
  2756. // Set the cursor to where it was before we changed the display
  2757. // (ie, if we changed a 2ndary monitor, the cursor would have been
  2758. // placed on the primary after the application of the change, move
  2759. // it back to the 2ndary monitor. If the change failed, we are
  2760. // just placing the cursor back to it orig pos
  2761. SetCursorPos(ptCursorSave.x, ptCursorSave.y);
  2762. // Determine what to do based on the return code.
  2763. if (bTest && (IDYES != DialogBoxParam(HINST_THISDLL,
  2764. MAKEINTRESOURCE(DLG_KEEPNEW),
  2765. GetParent(hDlg),
  2766. KeepNewDlgProc, 15)))
  2767. {
  2768. iSave = DISP_CHANGE_NOTUPDATED;
  2769. }
  2770. }
  2771. }
  2772. // Determine what to do based on the return code.
  2773. if (iSave >= DISP_CHANGE_SUCCESSFUL)
  2774. {
  2775. // Confirm the settings
  2776. for (iDevice = 0; iDevice < numDevices; iDevice++)
  2777. {
  2778. rgpds[iDevice]->ConfirmChangeSettings();
  2779. }
  2780. }
  2781. else
  2782. {
  2783. // Restore the settings to their original state
  2784. for (iDevice = 0; iDevice < numDevices; iDevice++)
  2785. {
  2786. rgpds[iDevice]->RestoreSettings();
  2787. }
  2788. //DLI: This last function call will actually go refresh the whole desktop
  2789. // If EnumDisplaySettings was called with EDS_RAWMODE, we need CDS_RAWMODE below.
  2790. // Otherwise, it's harmless.
  2791. ChangeDisplaySettings(NULL, CDS_RAWMODE);
  2792. }
  2793. return iSave;
  2794. }
  2795. //-----------------------------------------------------------------------------
  2796. //
  2797. // Resolution slider
  2798. //
  2799. CSettingsPage::_HandleHScroll(HWND hwndTB, int iCode, int iPos)
  2800. {
  2801. if (_pCurDevice && _pCurDevice->pds)
  2802. {
  2803. int iRes = _iResolution;
  2804. int cRes = (int)SendMessage(hwndTB, TBM_GETRANGEMAX, TRUE, 0);
  2805. TraceMsg(TF_FUNC, "_HandleHScroll: MaxRange = %d, iRes = %d, iPos = %d", cRes, iRes, iPos);
  2806. // Message box if something bad is going to happen ?
  2807. // _VerifyPrimaryMode(TRUE);
  2808. switch (iCode)
  2809. {
  2810. case TB_LINEUP:
  2811. case TB_PAGEUP:
  2812. if (iRes != 0)
  2813. iRes--;
  2814. break;
  2815. case TB_LINEDOWN:
  2816. case TB_PAGEDOWN:
  2817. if (++iRes >= cRes)
  2818. iRes = cRes;
  2819. break;
  2820. case TB_BOTTOM:
  2821. iRes = cRes;
  2822. break;
  2823. case TB_TOP:
  2824. iRes = 0;
  2825. break;
  2826. case TB_THUMBTRACK:
  2827. case TB_THUMBPOSITION:
  2828. iRes = iPos;
  2829. break;
  2830. default:
  2831. return FALSE;
  2832. }
  2833. TraceMsg(TF_FUNC, "_HandleHScroll: iRes = %d, iCode = %d", iRes, iCode);
  2834. // We only want to automatically set the color depth for the user if they
  2835. // changed the resolution. (not just set focus to the control)
  2836. BOOL fAutoSetColorDepth = (_iResolution != iRes); // iPos
  2837. _pCurDevice->pds->SetCurResolution(_pCurDevice->ResolutionList + iRes, fAutoSetColorDepth);
  2838. // Repaint the control in case they changed
  2839. _UpdateUI(TRUE /*fAutoSetColorDepth*/, IDC_SCREENSIZE);
  2840. DWORD dwExecMode;
  2841. if (_pThemeUI && (SUCCEEDED(_pThemeUI->GetExecMode(&dwExecMode))))
  2842. {
  2843. if ( (dwExecMode == EM_NORMAL) ||
  2844. (dwExecMode == EM_INVALID_MODE) ||
  2845. (dwExecMode == EM_DETECT) ) {
  2846. //
  2847. // Set the apply button if resolution has changed
  2848. //
  2849. if (_pCurDevice->pds->bIsModeChanged())
  2850. SetDirty();
  2851. return 0;
  2852. }
  2853. }
  2854. }
  2855. return TRUE;
  2856. }
  2857. void CSettingsPage::_ForwardToChildren(UINT message, WPARAM wParam, LPARAM lParam)
  2858. {
  2859. HWND hwndC = GetDlgItem(_hDlg, IDC_SCREENSIZE);
  2860. if (hwndC)
  2861. SendMessage(hwndC, message, wParam, lParam);
  2862. }
  2863. LRESULT CALLBACK CSettingsPage::WndProc(UINT message, WPARAM wParam, LPARAM lParam)
  2864. {
  2865. NMHDR FAR * lpnm;
  2866. HWND hwndC;
  2867. HWND hwndSample;
  2868. HBITMAP hbm;
  2869. switch (message)
  2870. {
  2871. case WM_NOTIFY:
  2872. lpnm = (NMHDR FAR *)lParam;
  2873. switch (lpnm->code)
  2874. {
  2875. case PSN_APPLY:
  2876. return TRUE;
  2877. default:
  2878. return FALSE;
  2879. }
  2880. break;
  2881. case WM_CTLCOLORSTATIC:
  2882. if (GetDlgCtrlID((HWND)lParam) == IDC_DISPLAYDESK)
  2883. {
  2884. return (UINT_PTR)GetSysColorBrush(COLOR_APPWORKSPACE);
  2885. }
  2886. return FALSE;
  2887. case WM_COMMAND:
  2888. switch (GET_WM_COMMAND_ID(wParam, lParam))
  2889. {
  2890. case IDC_DISPLAYPRIME:
  2891. if (!SetPrimary(_pCurDevice))
  2892. {
  2893. return FALSE;
  2894. }
  2895. hwndC = GetCurDeviceHwnd();
  2896. HandleMonitorChange(hwndC, TRUE);
  2897. break;
  2898. case IDC_DISPLAYUSEME:
  2899. // Don't pop up warning dialog box if this display is already attached
  2900. // or if there are already more than 1 display
  2901. if (!_pCurDevice ||
  2902. !SetMonAttached(_pCurDevice,
  2903. !_pCurDevice->pds->IsAttached(),
  2904. TRUE,
  2905. _hDlg))
  2906. {
  2907. return FALSE;
  2908. }
  2909. hwndC = GetCurDeviceHwnd();
  2910. HandleMonitorChange(hwndC, TRUE);
  2911. break;
  2912. case IDC_DISPLAYLIST:
  2913. switch (GET_WM_COMMAND_CMD(wParam, lParam))
  2914. {
  2915. case CBN_DBLCLK:
  2916. goto DoDeviceSettings;
  2917. case CBN_SELCHANGE:
  2918. UpdateActiveDisplay(NULL);
  2919. break;
  2920. default:
  2921. return FALSE;
  2922. }
  2923. break;
  2924. case IDC_DISPLAYPROPERTIES:
  2925. switch (GET_WM_COMMAND_CMD(wParam, lParam))
  2926. {
  2927. DoDeviceSettings:
  2928. case BN_CLICKED:
  2929. if (IsWindowEnabled(GetDlgItem(_hDlg, IDC_DISPLAYPROPERTIES)))
  2930. _OnAdvancedClicked();
  2931. break;
  2932. default:
  2933. return FALSE;
  2934. }
  2935. break;
  2936. case IDC_COLORBOX:
  2937. switch(GET_WM_COMMAND_CMD(wParam, lParam))
  2938. {
  2939. case CBN_SELCHANGE:
  2940. {
  2941. HWND hwndColorBox = GetDlgItem(_hDlg, IDC_COLORBOX);
  2942. int iClr = ComboBox_GetCurSel(hwndColorBox);
  2943. if ((iClr != CB_ERR) && _pCurDevice && _pCurDevice->pds && _pCurDevice->ColorList)
  2944. {
  2945. // Message box if something bad is going to happen ?
  2946. // _VerifyPrimaryMode(TRUE);
  2947. _pCurDevice->pds->SetCurColor((int) *(_pCurDevice->ColorList + iClr));
  2948. // Repaint the control in case they changed
  2949. _UpdateUI(TRUE /*fAutoSetColorDepth*/, IDC_COLORBOX);
  2950. }
  2951. break;
  2952. }
  2953. default:
  2954. break;
  2955. }
  2956. break;
  2957. case IDC_TROUBLESHOOT:
  2958. // Invokes the trouble shooter for the Settings tab.
  2959. {
  2960. TCHAR szCommand[MAX_PATH];
  2961. LoadString(HINST_THISDLL,IDS_TROUBLESHOOT_EXEC, szCommand, ARRAYSIZE(szCommand));
  2962. // Get location of HelpCtr.exe, which is the value in the
  2963. // HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\HELPCTR.EXE key
  2964. TCHAR szHelpCtr[MAX_PATH];
  2965. HKEY hKey = NULL;
  2966. DWORD cbHelpCtr = sizeof(szHelpCtr);
  2967. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  2968. TEXT("Microsoft\\Windows\\CurrentVersion\\App Paths\\HELPCTR.EXE"),
  2969. 0,
  2970. KEY_QUERY_VALUE,
  2971. &hKey) != ERROR_SUCCESS ||
  2972. RegQueryValueEx(hKey,
  2973. TEXT(""),
  2974. NULL,
  2975. NULL,
  2976. (LPBYTE)szHelpCtr,
  2977. &cbHelpCtr) != ERROR_SUCCESS)
  2978. {
  2979. StringCchCopy(szHelpCtr, ARRAYSIZE(szHelpCtr), TEXT("HelpCtr.exe"));
  2980. }
  2981. if (hKey)
  2982. {
  2983. RegCloseKey(hKey);
  2984. }
  2985. HrShellExecute(_hwndDesk, NULL, szHelpCtr, szCommand, NULL, SW_NORMAL);
  2986. }
  2987. break;
  2988. case IDC_IDENTIFY:
  2989. // Flashes the Text on all the monitors simultaneously
  2990. {
  2991. HWND hwndC;
  2992. //Enumerate all the monitors and flash this for each!
  2993. hwndC = GetWindow(_hwndDesk, GW_CHILD);
  2994. while (hwndC)
  2995. {
  2996. PostMessage(hwndC, WM_COMMAND, MAKEWPARAM(IDC_FLASH, 0), MAKELPARAM(0, 0));
  2997. hwndC = GetWindow(hwndC, GW_HWNDNEXT);
  2998. }
  2999. }
  3000. break;
  3001. default:
  3002. return FALSE;
  3003. }
  3004. // Enable the apply button only if we are not in setup.
  3005. DWORD dwExecMode;
  3006. if (_pThemeUI && (SUCCEEDED(_pThemeUI->GetExecMode(&dwExecMode))))
  3007. {
  3008. if ( (dwExecMode == EM_NORMAL) ||
  3009. (dwExecMode == EM_INVALID_MODE) ||
  3010. (dwExecMode == EM_DETECT) )
  3011. {
  3012. // Set the apply button if something changed
  3013. if (_pCurDevice && _pCurDevice->pds &&
  3014. _pCurDevice->pds->bIsModeChanged())
  3015. {
  3016. SetDirty();
  3017. }
  3018. }
  3019. }
  3020. break;
  3021. case WM_HSCROLL:
  3022. _HandleHScroll((HWND)lParam, (int) LOWORD(wParam), (int) HIWORD(wParam));
  3023. break;
  3024. case WM_HELP:
  3025. WinHelp((HWND)((LPHELPINFO)lParam)->hItemHandle, TEXT("display.hlp"), HELP_WM_HELP,
  3026. (DWORD_PTR)(LPTSTR)sc_MultiMonitorHelpIds);
  3027. break;
  3028. case WM_CONTEXTMENU:
  3029. WinHelp((HWND)wParam, TEXT("display.hlp"), HELP_CONTEXTMENU,
  3030. (DWORD_PTR)(LPTSTR)sc_MultiMonitorHelpIds);
  3031. break;
  3032. case WM_DISPLAYCHANGE:
  3033. case WM_WININICHANGE:
  3034. _ForwardToChildren(message, wParam, lParam);
  3035. break;
  3036. case WM_SYSCOLORCHANGE:
  3037. if (_himl)
  3038. ImageList_SetBkColor(_himl, GetSysColor(COLOR_APPWORKSPACE));
  3039. //
  3040. // Needs to be passed to all the new common controls so they repaint
  3041. // correctly using the new system colors
  3042. //
  3043. _ForwardToChildren(message, wParam, lParam);
  3044. //
  3045. // Rerender the monitor(s) bitmap(s) to reflect the new colors
  3046. //
  3047. if (_NumDevices == 1) {
  3048. // set up bitmaps for sample screen
  3049. if (_hbmScrSample && (GetObjectType(_hbmScrSample) != 0)) {
  3050. DeleteObject(_hbmScrSample);
  3051. _hbmScrSample = 0;
  3052. }
  3053. _hbmScrSample = LoadMonitorBitmap( TRUE ); // let them do the desktop
  3054. SendDlgItemMessage(_hDlg, IDC_SCREENSAMPLE, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)_hbmScrSample);
  3055. // get a base copy of the bitmap for when the "internals" change
  3056. if (_hbmMonitor && (GetObjectType(_hbmMonitor) != 0)) {
  3057. DeleteObject(_hbmMonitor);
  3058. _hbmMonitor = 0;
  3059. }
  3060. _hbmMonitor = LoadMonitorBitmap( FALSE ); // we'll do the desktop
  3061. }
  3062. else if (_NumDevices > 0)
  3063. {
  3064. HBITMAP hbm, hbmMask;
  3065. int cx, cy;
  3066. UINT iDevice;
  3067. PMULTIMON_DEVICE pDevice;
  3068. TCHAR ach[12];
  3069. // replace each monitor bitmap with one with correct colors
  3070. for (iDevice = 0; (iDevice < _NumDevices); iDevice++)
  3071. {
  3072. pDevice = &_Devices[iDevice];
  3073. if (pDevice)
  3074. {
  3075. _itot(iDevice+1,ach,10);
  3076. ImageList_GetIconSize(pDevice->himl, &cx, &cy);
  3077. MakeMonitorBitmap(pDevice->w,pDevice->h,ach,&hbm,&hbmMask,cx,cy, (pDevice == _pCurDevice));
  3078. ImageList_Replace(pDevice->himl,pDevice->iImage,hbm,hbmMask);
  3079. DeleteObject(hbm);
  3080. DeleteObject(hbmMask);
  3081. }
  3082. }
  3083. }
  3084. break;
  3085. #if 0
  3086. //
  3087. // NOTE: until video supports device interfaces, we cannot use
  3088. // WM_DEVICECHANGE to detect video changes. The default WM_DEVCHANGE
  3089. // only reports about legacy devices
  3090. //
  3091. case WM_DEVICECHANGE:
  3092. //
  3093. // Rebuild the device list if we are not currently enumerating,
  3094. // because enumerating may cause another device to come on-line
  3095. //
  3096. // We only reenumerate if a new *video* device arrives
  3097. //
  3098. if (!_InSetInfo &&
  3099. (wParam == DBT_DEVICEARRIVAL || wParam == DBT_DEVICEREMOVECOMPLETE))
  3100. {
  3101. DEV_BROADCAST_HDR *bhdr = (DEV_BROADCAST_HDR *) lParam;
  3102. // check for something else here, most likely the dev interface guid
  3103. if (bhdr->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
  3104. {
  3105. _InitDisplaySettings(FALSE);
  3106. }
  3107. }
  3108. break;
  3109. #endif
  3110. case WM_DESTROY:
  3111. TraceMsg(TF_GENERAL, "WndProc:: WM_DESTROY");
  3112. hwndSample = GetDlgItem(_hDlg, IDC_COLORSAMPLE);
  3113. hbm = (HBITMAP)SendMessage(hwndSample, STM_SETIMAGE, IMAGE_BITMAP, NULL);
  3114. if (hbm)
  3115. DeleteObject(hbm);
  3116. if (_NumDevices == 1)
  3117. {
  3118. hwndSample = GetDlgItem(_hDlg, IDC_SCREENSAMPLE);
  3119. hbm = (HBITMAP)SendMessage(hwndSample, STM_SETIMAGE, IMAGE_BITMAP, NULL);
  3120. if (hbm)
  3121. DeleteObject(hbm);
  3122. if (_hbmScrSample && (GetObjectType(_hbmScrSample) != 0))
  3123. DeleteObject(_hbmScrSample);
  3124. if (_hbmMonitor && (GetObjectType(_hbmMonitor) != 0))
  3125. DeleteObject(_hbmMonitor);
  3126. }
  3127. _DestroyDisplaySettings();
  3128. break;
  3129. case MSG_DSP_SETUP_MESSAGE:
  3130. return _InitMessage();
  3131. // MultiMonitor CPL specific messages
  3132. case MM_REDRAWPREVIEW:
  3133. _RedrawDeskPreviews();
  3134. break;
  3135. case WM_LBUTTONDBLCLK:
  3136. if (_NumDevices == 1)
  3137. {
  3138. HWND hwndSample = GetDlgItem(_hDlg, IDC_SCREENSAMPLE);
  3139. if(NULL != hwndSample)
  3140. {
  3141. POINT pt;
  3142. RECT rc;
  3143. pt.x = GET_X_LPARAM(lParam); // horizontal position of cursor
  3144. pt.y = GET_Y_LPARAM(lParam); // vertical position of cursor
  3145. GetWindowRect(hwndSample, &rc);
  3146. if(ClientToScreen(_hDlg, &pt) && PtInRect(&rc, pt))
  3147. PostMessage(_hDlg, WM_COMMAND, MAKEWPARAM(IDC_DISPLAYPROPERTIES, BN_CLICKED), (LPARAM)hwndSample);
  3148. }
  3149. break;
  3150. }
  3151. else
  3152. return FALSE;
  3153. default:
  3154. return FALSE;
  3155. }
  3156. return TRUE;
  3157. }
  3158. // IUnknown methods
  3159. HRESULT CSettingsPage::QueryInterface(REFIID riid, LPVOID * ppvObj)
  3160. {
  3161. static const QITAB qit[] = {
  3162. QITABENT(CSettingsPage, IObjectWithSite),
  3163. QITABENT(CSettingsPage, IPropertyBag),
  3164. QITABENT(CSettingsPage, IBasePropPage),
  3165. QITABENTMULTI(CSettingsPage, IShellPropSheetExt, IBasePropPage),
  3166. { 0 },
  3167. };
  3168. return QISearch(this, qit, riid, ppvObj);
  3169. }
  3170. ULONG CSettingsPage::AddRef()
  3171. {
  3172. return InterlockedIncrement(&_cRef);
  3173. }
  3174. ULONG CSettingsPage::Release()
  3175. {
  3176. ASSERT( 0 != _cRef );
  3177. ULONG cRef = InterlockedDecrement(&_cRef);
  3178. if ( 0 == cRef )
  3179. {
  3180. delete this;
  3181. }
  3182. return cRef;
  3183. }
  3184. // IMultiMonConfig methods
  3185. HRESULT CSettingsPage::Initialize(HWND hwndHost, WNDPROC pfnWndProc, DWORD dwReserved)
  3186. {
  3187. HRESULT hr = E_FAIL;
  3188. if (hwndHost && RegisterPreviewWindowClass(pfnWndProc))
  3189. {
  3190. _hwndDesk = hwndHost;
  3191. if (_InitDisplaySettings(TRUE))
  3192. hr = S_OK;
  3193. }
  3194. return hr;
  3195. }
  3196. HRESULT CSettingsPage::GetNumberOfMonitors(int * pCMon, DWORD dwReserved)
  3197. {
  3198. if (pCMon)
  3199. {
  3200. *pCMon = _NumDevices;
  3201. return S_OK;
  3202. }
  3203. return E_FAIL;
  3204. }
  3205. HRESULT CSettingsPage::GetMonitorData(int iMonitor, MonitorData * pmd, DWORD dwReserved)
  3206. {
  3207. ASSERT(pmd);
  3208. if ((pmd == NULL) || ((ULONG)iMonitor >= _NumDevices))
  3209. return ResultFromWin32(ERROR_INVALID_PARAMETER);
  3210. PMULTIMON_DEVICE pDevice = &_Devices[iMonitor];
  3211. pmd->dwSize = sizeof(MonitorData);
  3212. if ( pDevice->pds->IsPrimary() )
  3213. pmd->dwStatus |= MD_PRIMARY;
  3214. if ( pDevice->pds->IsAttached() )
  3215. pmd->dwStatus |= MD_ATTACHED;
  3216. pDevice->pds->GetCurPosition(&pmd->rcPos);
  3217. return S_OK;
  3218. }
  3219. HRESULT CSettingsPage::Paint(int iMonitor, DWORD dwReserved)
  3220. {
  3221. _RedrawDeskPreviews();
  3222. return S_OK;
  3223. }
  3224. /*----------------------------------------------------------------------------
  3225. ----------------------------------------------------------------------------*/
  3226. HFONT GetFont(LPRECT prc)
  3227. {
  3228. LOGFONT lf;
  3229. ZeroMemory(&lf, sizeof(lf));
  3230. lf.lfWeight = FW_EXTRABOLD;
  3231. lf.lfHeight = prc->bottom - prc->top;
  3232. lf.lfWidth = 0;
  3233. lf.lfPitchAndFamily = FF_SWISS;
  3234. lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
  3235. return CreateFontIndirect(&lf);
  3236. }
  3237. /*----------------------------------------------------------------------------
  3238. ----------------------------------------------------------------------------*/
  3239. #define HANG_TIME 2500
  3240. LRESULT CALLBACK BigNumberWindowProc(HWND hwnd, UINT msg,WPARAM wParam,LPARAM lParam)
  3241. {
  3242. TCHAR ach[80];
  3243. HFONT hfont;
  3244. RECT rc;
  3245. HDC hdc;
  3246. HRGN hrgnTxtA;
  3247. PAINTSTRUCT ps;
  3248. HGDIOBJ hOldPen;
  3249. HGDIOBJ hNewPen;
  3250. switch (msg)
  3251. {
  3252. case WM_CREATE:
  3253. break;
  3254. case WM_SIZE:
  3255. GetWindowText(hwnd, ach, ARRAYSIZE(ach));
  3256. GetClientRect(hwnd, &rc);
  3257. hfont = GetFont(&rc);
  3258. hdc = GetDC(hwnd);
  3259. SelectObject(hdc, hfont);
  3260. BeginPath(hdc);
  3261. SetBkMode(hdc, TRANSPARENT);
  3262. TextOut(hdc,0,0,ach,lstrlen(ach));
  3263. EndPath(hdc);
  3264. hrgnTxtA = PathToRegion(hdc);
  3265. SetWindowRgn(hwnd,hrgnTxtA,TRUE);
  3266. ReleaseDC(hwnd, hdc);
  3267. DeleteObject(hfont);
  3268. break;
  3269. case WM_TIMER:
  3270. DestroyWindow(hwnd);
  3271. return 0;
  3272. case WM_PAINT:
  3273. GetWindowText(hwnd, ach, ARRAYSIZE(ach));
  3274. GetClientRect(hwnd, &rc);
  3275. hfont = GetFont(&rc);
  3276. if (hfont)
  3277. {
  3278. hdc = BeginPaint(hwnd, &ps);
  3279. //The following paints the whole region (which is in the shape of the number) black!
  3280. PatBlt(hdc, 0, 0, rc.right, rc.bottom, BLACKNESS | NOMIRRORBITMAP);
  3281. SelectObject(hdc, hfont);
  3282. SetTextColor(hdc, 0xFFFFFF);
  3283. //Let's create a path that is the shape of the region by drawing that number.
  3284. BeginPath(hdc);
  3285. SetBkMode(hdc, TRANSPARENT);
  3286. TextOut(hdc,0,0,ach,lstrlen(ach));
  3287. EndPath(hdc);
  3288. // The above TextOut calljust created the path. Let's now actually draw the number!
  3289. // Note: We are drawing the number in white there by changing whatever painted as black
  3290. // a few moments ago!
  3291. TextOut(hdc,0,0,ach,lstrlen(ach));
  3292. //Let's create a thick black brush to paint the borders of the number we just drew!
  3293. hNewPen = CreatePen(PS_INSIDEFRAME, 4, 0x0); //Black Color
  3294. if (hNewPen)
  3295. {
  3296. hOldPen = SelectObject(hdc, hNewPen);
  3297. //Draw the border of the white number with the thick black brush!
  3298. StrokePath(hdc);
  3299. SelectObject(hdc, hOldPen);
  3300. DeleteObject(hNewPen);
  3301. }
  3302. EndPaint(hwnd, &ps);
  3303. DeleteObject(hfont);
  3304. }
  3305. break;
  3306. }
  3307. return DefWindowProc(hwnd,msg,wParam,lParam);
  3308. }
  3309. int Bail()
  3310. {
  3311. POINT pt;
  3312. POINT pt0;
  3313. DWORD time0;
  3314. DWORD d;
  3315. d = GetDoubleClickTime();
  3316. time0 = GetMessageTime();
  3317. pt0.x = (int)(short)LOWORD(GetMessagePos());
  3318. pt0.y = (int)(short)HIWORD(GetMessagePos());
  3319. if (GetTickCount()-time0 > d)
  3320. return 2;
  3321. if (!((GetAsyncKeyState(VK_LBUTTON) | GetAsyncKeyState(VK_RBUTTON)) & 0x8000))
  3322. return 1;
  3323. GetCursorPos(&pt);
  3324. if ((pt.y - pt0.y) > 2 || (pt.y - pt0.y) < -2)
  3325. return 1;
  3326. if ((pt.x - pt0.x) > 2 || (pt.x - pt0.x) < -2)
  3327. return 1;
  3328. return 0;
  3329. }
  3330. void FlashText(HWND hDlg, PMULTIMON_DEVICE pDevice, LPCTSTR sz, LPRECT prc, BOOL fWait)
  3331. {
  3332. HFONT hfont;
  3333. SIZE size;
  3334. HDC hdc;
  3335. int i;
  3336. if (!pDevice->pds->IsOrgAttached())
  3337. return;
  3338. if (pDevice->hwndFlash && IsWindow(pDevice->hwndFlash))
  3339. {
  3340. DestroyWindow(pDevice->hwndFlash);
  3341. pDevice->hwndFlash = NULL;
  3342. }
  3343. if (sz == NULL)
  3344. return;
  3345. if (fWait)
  3346. {
  3347. while ((i=Bail()) == 0)
  3348. ;
  3349. if (i == 1)
  3350. return;
  3351. }
  3352. hdc = GetDC(NULL);
  3353. hfont = GetFont(prc);
  3354. SelectObject(hdc, hfont);
  3355. if (!GetTextExtentPoint(hdc, sz, lstrlen(sz), &size))
  3356. {
  3357. size.cx = 0;
  3358. size.cy = 0;
  3359. }
  3360. ReleaseDC(NULL, hdc);
  3361. DeleteObject(hfont);
  3362. if (!gfFlashWindowRegistered)
  3363. {
  3364. WNDCLASS cls;
  3365. cls.hCursor = LoadCursor(NULL,IDC_ARROW);
  3366. cls.hIcon = NULL;
  3367. cls.lpszMenuName = NULL;
  3368. cls.lpszClassName = TEXT("MonitorNumber32");
  3369. cls.hbrBackground = (HBRUSH)(COLOR_DESKTOP + 1);
  3370. cls.hInstance = HINST_THISDLL;
  3371. cls.style = CS_VREDRAW | CS_HREDRAW;
  3372. cls.lpfnWndProc = BigNumberWindowProc;
  3373. cls.cbWndExtra = 0;
  3374. cls.cbClsExtra = 0;
  3375. RegisterClass(&cls);
  3376. gfFlashWindowRegistered = TRUE;
  3377. }
  3378. pDevice->hwndFlash = CreateWindowEx(
  3379. WS_EX_TOPMOST | WS_EX_TOOLWINDOW, //WS_BORDER,
  3380. TEXT("MonitorNumber32"), sz,
  3381. WS_POPUP,
  3382. (prc->right + prc->left - size.cx)/2,
  3383. (prc->bottom + prc->top - size.cy)/2,
  3384. size.cx,
  3385. size.cy,
  3386. hDlg, //Set the dialog as the parent sothat we get back the activation after flash window goes away!
  3387. NULL,
  3388. HINST_THISDLL,
  3389. NULL);
  3390. if (pDevice->hwndFlash)
  3391. {
  3392. ShowWindow(pDevice->hwndFlash, SW_SHOW);
  3393. UpdateWindow(pDevice->hwndFlash);
  3394. SetTimer(pDevice->hwndFlash, 1, HANG_TIME, NULL);
  3395. }
  3396. }
  3397. void DrawMonitorNum(HDC hdc, int w, int h, LPCTSTR sz, BOOL fDrawBackground=TRUE)
  3398. {
  3399. HFONT hfont;
  3400. HFONT hfontT;
  3401. RECT rc;
  3402. COLORREF rgb;
  3403. COLORREF rgbDesk;
  3404. SetRect(&rc, 0, 0, w, h);
  3405. rgb = GetSysColor(COLOR_CAPTIONTEXT);
  3406. rgbDesk = GetSysColor(COLOR_DESKTOP);
  3407. if (fDrawBackground)
  3408. FillRect(hdc, &rc, GetSysColorBrush (COLOR_DESKTOP));
  3409. InflateRect(&rc, -(MON_X*w / MON_W)>> 1, -(MON_Y*h/ MON_H));
  3410. if (rgbDesk == rgb)
  3411. rgb = GetSysColor(COLOR_WINDOWTEXT);
  3412. if (rgbDesk == rgb)
  3413. rgb = rgbDesk ^ 0x00FFFFFF;
  3414. SetTextColor(hdc, rgb);
  3415. hfont = GetFont(&rc);
  3416. if (hfont)
  3417. {
  3418. hfontT = (HFONT)SelectObject(hdc, hfont);
  3419. SetTextAlign(hdc, TA_CENTER | TA_TOP);
  3420. SetBkMode(hdc, TRANSPARENT);
  3421. ExtTextOut(hdc, (rc.left+rc.right)/2, rc.top, 0, NULL, sz, lstrlen(sz), NULL);
  3422. SelectObject(hdc, hfontT);
  3423. DeleteObject(hfont);
  3424. }
  3425. }
  3426. void AddTrackingToolTip(PMULTIMON_DEVICE pDevice, HWND hwnd)
  3427. {
  3428. TOOLINFO ti;
  3429. TCHAR location[16];
  3430. RECT rcPos;
  3431. //
  3432. // New tool Tip
  3433. //
  3434. pDevice->pds->GetCurPosition(&rcPos);
  3435. StringCchPrintf(location, ARRAYSIZE(location), TEXT("%d, %d"), rcPos.left, rcPos.top);
  3436. GetWindowRect(hwnd, &rcPos);
  3437. ti.cbSize = sizeof(TOOLINFO);
  3438. ti.uFlags = TTF_TRACK;
  3439. ti.hwnd = hwnd;
  3440. ti.uId = (UINT_PTR) pDevice;
  3441. ti.hinst = HINST_THISDLL;
  3442. ti.lpszText = location;
  3443. ti.rect.left = rcPos.left + 2;
  3444. ti.rect.top = rcPos.top + 2;
  3445. ti.rect.right = rcPos.right - 2;// ti.rect.left + 10;
  3446. ti.rect.bottom = rcPos.bottom - 2; // ti.rect.top + 10;
  3447. ToolTip_AddTool(ghwndToolTipTracking, &ti);
  3448. pDevice->bTracking = FALSE;
  3449. TraceMsg(TF_GENERAL, "Added TOOLTIP hwnd %08lx, uId %08lx\n", ti.hwnd, ti.uId);
  3450. return;
  3451. }
  3452. void RemoveTrackingToolTip(HWND hwnd)
  3453. {
  3454. TOOLINFO ti;
  3455. ZeroMemory(&ti, sizeof(ti));
  3456. ti.cbSize = sizeof(ti);
  3457. ti.hwnd = hwnd;
  3458. ti.uId = (UINT_PTR) GetDlgCtrlDevice(hwnd);
  3459. ToolTip_DelTool(ghwndToolTipTracking, &ti);
  3460. }
  3461. BOOLEAN TrackToolTip(PMULTIMON_DEVICE pDevice, HWND hwnd, BOOL bTrack)
  3462. {
  3463. TOOLINFO ti;
  3464. BOOLEAN oldTracking;
  3465. ZeroMemory(&ti, sizeof(ti));
  3466. ti.cbSize = sizeof(ti);
  3467. ti.hwnd = hwnd;
  3468. ti.uId = (UINT_PTR) pDevice;
  3469. oldTracking = pDevice->bTracking;
  3470. pDevice->bTracking = (BOOLEAN)bTrack;
  3471. ToolTip_TrackActivate(ghwndToolTipTracking, bTrack, &ti);
  3472. TraceMsg(TF_GENERAL, "Track TOOLTIP hwnd %08lx, uId %08lx\n", ti.hwnd, ti.uId);
  3473. return oldTracking;
  3474. }
  3475. void AddPopupToolTip(HWND hwndC)
  3476. {
  3477. TOOLINFO ti;
  3478. //
  3479. // New tool Tip
  3480. //
  3481. ti.cbSize = sizeof(TOOLINFO);
  3482. ti.uFlags = TTF_IDISHWND | TTF_SUBCLASS | TTF_CENTERTIP;
  3483. ti.hwnd = hwndC;
  3484. ti.uId = (UINT_PTR) hwndC;
  3485. ti.hinst = HINST_THISDLL;
  3486. GetWindowRect(hwndC, &ti.rect);
  3487. ti.lpszText = LPSTR_TEXTCALLBACK;
  3488. ToolTip_AddTool(ghwndToolTipPopup, &ti);
  3489. }
  3490. void RemovePopupToolTip(HWND hwndC)
  3491. {
  3492. TOOLINFO ti;
  3493. ZeroMemory(&ti, sizeof(ti));
  3494. ti.cbSize = sizeof(ti);
  3495. ti.hwnd = hwndC;
  3496. ti.uId = (UINT_PTR) hwndC;
  3497. ToolTip_DelTool(ghwndToolTipPopup, &ti);
  3498. }
  3499. BOOL MakeMonitorBitmap(int w, int h, LPCTSTR sz, HBITMAP *pBitmap, HBITMAP *pMaskBitmap, int cx, int cy, BOOL fSelected)
  3500. {
  3501. HDC hdc; // work dc
  3502. HDC hdcS; // screen dc
  3503. ASSERT(w <= cx);
  3504. ASSERT(h <= cy);
  3505. *pBitmap = NULL;
  3506. hdcS = GetDC(NULL);
  3507. hdc = CreateCompatibleDC(hdcS);
  3508. if (hdc)
  3509. {
  3510. HDC hdcT; // another work dc
  3511. hdcT = CreateCompatibleDC(hdcS);
  3512. if (hdcT)
  3513. {
  3514. HBITMAP hbm; // 128x128 bitmap we will return
  3515. HBITMAP hbmT = NULL;// bitmap loaded from resource
  3516. HBITMAP hbmM = NULL;// mask bitmap
  3517. HDC hdcM = NULL;// another work dc
  3518. RECT rc;
  3519. if (pMaskBitmap)
  3520. hdcM = CreateCompatibleDC(hdcS);
  3521. hbm = CreateCompatibleBitmap(hdcS, cx, cy);
  3522. if (hbm)
  3523. {
  3524. hbmT = CreateCompatibleBitmap(hdcS, w, h);
  3525. if(pMaskBitmap)
  3526. hbmM = CreateBitmap(cx,cy,1,1,NULL);
  3527. ReleaseDC(NULL,hdcS);
  3528. if (hbmT)
  3529. {
  3530. SelectObject(hdc, hbm);
  3531. SelectObject(hdcT,hbmT);
  3532. if (pMaskBitmap && hdcM)
  3533. SelectObject(hdcM, hbmM);
  3534. }
  3535. *pBitmap = hbm;
  3536. }
  3537. // Make sure the color of the borders (selection & normal) is different than the background color.
  3538. HBRUSH hbrDiff = NULL;
  3539. BOOL bNeedDiff = ((fSelected &&
  3540. (GetSysColor(COLOR_APPWORKSPACE) == GetSysColor(COLOR_HIGHLIGHT))) ||
  3541. (GetSysColor(COLOR_APPWORKSPACE) == GetSysColor(COLOR_BTNHIGHLIGHT)));
  3542. if(bNeedDiff)
  3543. {
  3544. DWORD rgbDiff = ((GetSysColor(COLOR_ACTIVEBORDER) != GetSysColor(COLOR_APPWORKSPACE))
  3545. ? GetSysColor(COLOR_ACTIVEBORDER)
  3546. : GetSysColor(COLOR_APPWORKSPACE) ^ 0x00FFFFFF);
  3547. hbrDiff = CreateSolidBrush(rgbDiff);
  3548. }
  3549. // Fill it with the selection color or the background color.
  3550. SetRect(&rc, 0, 0, w, h);
  3551. FillRect(hdcT, &rc,
  3552. (fSelected ? ((GetSysColor(COLOR_APPWORKSPACE) != GetSysColor(COLOR_HIGHLIGHT))
  3553. ? GetSysColorBrush(COLOR_HIGHLIGHT)
  3554. : hbrDiff)
  3555. : GetSysColorBrush(COLOR_APPWORKSPACE)));
  3556. InflateRect(&rc, -SELECTION_THICKNESS, -SELECTION_THICKNESS);
  3557. FillRect(hdcT, &rc,
  3558. ((GetSysColor(COLOR_APPWORKSPACE) != GetSysColor(COLOR_BTNHIGHLIGHT))
  3559. ? GetSysColorBrush(COLOR_BTNHIGHLIGHT)
  3560. : hbrDiff));
  3561. if (hbrDiff)
  3562. {
  3563. DeleteObject(hbrDiff);
  3564. hbrDiff = NULL;
  3565. }
  3566. InflateRect(&rc, -MONITOR_BORDER, -MONITOR_BORDER);
  3567. FillRect(hdcT, &rc, GetSysColorBrush(COLOR_DESKTOP));
  3568. // fill bitmap with transparent color
  3569. SetBkColor(hdc,GetSysColor(COLOR_APPWORKSPACE));
  3570. SetRect(&rc, 0, 0, cx, cy);
  3571. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
  3572. // copy bitmap to upper-left of bitmap
  3573. BitBlt(hdc,0,0,w,h,hdcT,0,0,SRCCOPY);
  3574. // draw the monitor number, if provided, in the bitmap (in the right place)
  3575. if (sz)
  3576. DrawMonitorNum(hdc, w, h, sz, FALSE);
  3577. // make mask, if needed.
  3578. if (pMaskBitmap && hdcM)
  3579. {
  3580. BitBlt(hdcM,0,0,cx,cy,hdc,0,0,SRCCOPY);
  3581. *pMaskBitmap = hbmM;
  3582. }
  3583. if (hbmT)
  3584. DeleteObject(hbmT);
  3585. if (pMaskBitmap && hdcM)
  3586. DeleteDC(hdcM);
  3587. DeleteDC(hdcT);
  3588. }
  3589. DeleteDC(hdc);
  3590. }
  3591. return TRUE;
  3592. }
  3593. //
  3594. // SnapMonitorRect
  3595. //
  3596. // called while the user is moving a monitor window (WM_MOVING)
  3597. // if the CTRL key is not down we will snap the window rect
  3598. // to the edge of one of the other monitors.
  3599. //
  3600. // this is done so the user can easily align monitors
  3601. //
  3602. // NOTE pDevice->Snap must be initialized to 0,0 in WM_ENTERSIZEMOVE
  3603. //
  3604. void SnapMonitorRect(PMULTIMON_DEVICE pDevice, HWND hwnd, RECT *prc)
  3605. {
  3606. HWND hwndT;
  3607. int d;
  3608. RECT rcT;
  3609. RECT rc;
  3610. //
  3611. // allow the user to move the window anywhere when the CTRL key is down
  3612. //
  3613. if (GetKeyState(VK_CONTROL) & 0x8000)
  3614. return;
  3615. //
  3616. // macros to help in alignment
  3617. //
  3618. #define SNAP_DX 6
  3619. #define SNAP_DY 6
  3620. #define SNAPX(f,x) \
  3621. d = rcT.x - rc.f; if (abs(d) <= SNAP_DX) rc.left+=d, rc.right+=d;
  3622. #define SNAPY(f,y) \
  3623. d = rcT.y - rc.f; if (abs(d) <= SNAP_DY) rc.top+=d, rc.bottom+=d;
  3624. //
  3625. // get current rect and offset it by the amount we have corrected
  3626. // it so far (this alignes the rect with the position of the mouse)
  3627. //
  3628. rc = *prc;
  3629. OffsetRect(&rc, pDevice->Snap.x, pDevice->Snap.y);
  3630. //
  3631. // walk all other windows and snap our window to them
  3632. //
  3633. for (hwndT = GetWindow(hwnd, GW_HWNDFIRST); hwndT;
  3634. hwndT = GetWindow(hwndT, GW_HWNDNEXT))
  3635. {
  3636. if (hwndT == hwnd)
  3637. continue;
  3638. GetWindowRect(hwndT, &rcT);
  3639. InflateRect(&rcT,SNAP_DX,SNAP_DY);
  3640. if (IntersectRect(&rcT, &rcT, &rc))
  3641. {
  3642. GetWindowRect(hwndT, &rcT);
  3643. SNAPX(right,left); SNAPY(bottom,top);
  3644. SNAPX(right,right); SNAPY(bottom,bottom);
  3645. SNAPX(left,left); SNAPY(top,top);
  3646. SNAPX(left,right); SNAPY(top,bottom);
  3647. }
  3648. }
  3649. //
  3650. // adjust the amount we have snap'ed so far, and return the new rect
  3651. //
  3652. pDevice->Snap.x += prc->left - rc.left;
  3653. pDevice->Snap.y += prc->top - rc.top;
  3654. *prc = rc;
  3655. }
  3656. WPARAM GetKeyStates()
  3657. {
  3658. WPARAM wParam = 0x0;
  3659. if (GetKeyState(VK_CONTROL) & 0x8000)
  3660. wParam |= MK_CONTROL;
  3661. if (GetKeyState(VK_LBUTTON) & 0x8000)
  3662. wParam |= MK_LBUTTON;
  3663. if (GetKeyState(VK_MBUTTON) & 0x8000)
  3664. wParam |= MK_MBUTTON;
  3665. if (GetKeyState(VK_RBUTTON) & 0x8000)
  3666. wParam |= MK_RBUTTON;
  3667. if (GetKeyState(VK_SHIFT) & 0x8000)
  3668. wParam |= MK_SHIFT;
  3669. return wParam;
  3670. }
  3671. LRESULT CALLBACK MonitorWindowProc(HWND hwnd, UINT msg,WPARAM wParam,LPARAM lParam)
  3672. {
  3673. TOOLINFO ti;
  3674. PAINTSTRUCT ps;
  3675. HDC hdc;
  3676. RECT rc;
  3677. int w,h;
  3678. TCHAR ach[80];
  3679. PMULTIMON_DEVICE pDevice;
  3680. HWND hDlg = GetParent(GetParent(hwnd));
  3681. RECT rcPos;
  3682. MSG mmsg;
  3683. CSettingsPage * pcmm = (CSettingsPage *) GetWindowLongPtr(hwnd, 0);
  3684. switch (msg)
  3685. {
  3686. case WM_CREATE:
  3687. ASSERT(((LPCREATESTRUCT)lParam)->lpCreateParams);
  3688. SetWindowLongPtr(hwnd, 0, (LONG_PTR)((LPCREATESTRUCT)lParam)->lpCreateParams);
  3689. break;
  3690. case WM_NCCREATE:
  3691. // turn off RTL_MIRRORED_WINDOW in GWL_EXSTYLE
  3692. SHSetWindowBits(hwnd, GWL_EXSTYLE, RTL_MIRRORED_WINDOW, 0);
  3693. break;
  3694. case WM_NCHITTEST:
  3695. //
  3696. // return HTCAPTION so that we can get the ENTERSIZEMOVE message.
  3697. //
  3698. pDevice = GetDlgCtrlDevice(hwnd);
  3699. // Let disabled monitors move
  3700. if (pDevice) // if (pDevice && pDevice->pds->IsAttached())
  3701. return HTCAPTION;
  3702. break;
  3703. case WM_NCLBUTTONDBLCLK:
  3704. FlashText(hDlg, GetDlgCtrlDevice(hwnd), NULL,NULL,FALSE);
  3705. PostMessage(hDlg, WM_COMMAND, MAKEWPARAM(IDC_DISPLAYPROPERTIES, BN_CLICKED), (LPARAM)hwnd );
  3706. break;
  3707. case WM_CHILDACTIVATE:
  3708. if (GetFocus() != GetParent(hwnd)) {
  3709. SetFocus(GetParent(hwnd));
  3710. }
  3711. break;
  3712. case WM_HELP:
  3713. WinHelp((HWND)((LPHELPINFO)lParam)->hItemHandle, TEXT("display.hlp"), HELP_WM_HELP,
  3714. (DWORD_PTR)(LPTSTR)sc_MultiMonitorHelpIds);
  3715. break;
  3716. case WM_CONTEXTMENU:
  3717. WinHelp((HWND)wParam, TEXT("display.hlp"), HELP_CONTEXTMENU,
  3718. (DWORD_PTR)(LPTSTR)sc_MultiMonitorHelpIds);
  3719. break;
  3720. case WM_COMMAND:
  3721. switch (GET_WM_COMMAND_ID(wParam, lParam))
  3722. {
  3723. case IDC_DISPLAYPRIME:
  3724. case IDC_DISPLAYUSEME:
  3725. case IDC_DISPLAYPROPERTIES:
  3726. PostMessage(hDlg, WM_COMMAND, wParam, lParam);
  3727. break;
  3728. case IDC_FLASH:
  3729. pDevice = GetDlgCtrlDevice(hwnd);
  3730. pDevice->pds->GetOrgPosition(&rcPos);
  3731. if (!IsRectEmpty(&rcPos))
  3732. {
  3733. GetWindowText(hwnd, ach, ARRAYSIZE(ach));
  3734. FlashText(hDlg, pDevice, ach, &rcPos, FALSE);
  3735. }
  3736. break;
  3737. }
  3738. break;
  3739. case WM_INITMENUPOPUP:
  3740. pDevice = GetDlgCtrlDevice(hwnd);
  3741. CheckMenuItem((HMENU)wParam, IDC_DISPLAYUSEME,
  3742. pDevice->pds->IsAttached() ? MF_CHECKED : MF_UNCHECKED);
  3743. CheckMenuItem((HMENU)wParam, IDC_DISPLAYPRIME,
  3744. pDevice->pds->IsPrimary() ? MF_CHECKED : MF_UNCHECKED);
  3745. // until I figure out how to render on a non attached monitor, just
  3746. // disable the menu item
  3747. EnableMenuItem((HMENU)wParam, IDC_FLASH,
  3748. pDevice->pds->IsAttached() ? MF_ENABLED : MF_GRAYED);
  3749. EnableMenuItem((HMENU)wParam, IDC_DISPLAYPROPERTIES,
  3750. IsWindowEnabled(GetDlgItem(GetParent(GetParent(hwnd)), IDC_DISPLAYPROPERTIES)) ?
  3751. MF_ENABLED : MF_GRAYED);
  3752. EnableMenuItem((HMENU)wParam, IDC_DISPLAYUSEME,
  3753. pDevice->pds->IsPrimary() ? MF_GRAYED : MF_ENABLED);
  3754. EnableMenuItem((HMENU)wParam, IDC_DISPLAYPRIME,
  3755. ((pDevice->pds->IsAttached() &&
  3756. !pDevice->pds->IsRemovable() &&
  3757. !pDevice->pds->IsPrimary()) ?
  3758. MF_ENABLED : MF_GRAYED));
  3759. SetMenuDefaultItem((HMENU)wParam, IDC_DISPLAYPROPERTIES, MF_BYCOMMAND);
  3760. break;
  3761. case WM_NCMOUSEMOVE:
  3762. ToolTip_RelayEvent(ghwndToolTipPopup, mmsg, NULL, WM_MOUSEMOVE, GetKeyStates(), lParam);
  3763. break;
  3764. case WM_NCMBUTTONDOWN:
  3765. ToolTip_RelayEvent(ghwndToolTipPopup, mmsg, NULL, WM_MBUTTONDOWN, GetKeyStates(), lParam);
  3766. break;
  3767. case WM_NCMBUTTONUP:
  3768. ToolTip_RelayEvent(ghwndToolTipPopup, mmsg, NULL, WM_MBUTTONUP, GetKeyStates(), lParam);
  3769. break;
  3770. case WM_NCRBUTTONDOWN:
  3771. ToolTip_RelayEvent(ghwndToolTipPopup, mmsg, NULL, WM_RBUTTONDOWN, GetKeyStates(), lParam);
  3772. pDevice = GetDlgCtrlDevice(hwnd);
  3773. if (pDevice && pcmm)
  3774. {
  3775. HMENU hmenu;
  3776. POINT pt;
  3777. hmenu = LoadMenu(HINST_THISDLL, MAKEINTRESOURCE(MENU_MONITOR));
  3778. if (hmenu)
  3779. {
  3780. pcmm->UpdateActiveDisplay(pDevice);
  3781. GetCursorPos(&pt);
  3782. TrackPopupMenu(GetSubMenu(hmenu,0), TPM_RIGHTBUTTON,
  3783. pt.x, pt.y, 0, hwnd, NULL);
  3784. DestroyMenu(hmenu);
  3785. }
  3786. }
  3787. break;
  3788. case WM_NCRBUTTONUP:
  3789. ToolTip_RelayEvent(ghwndToolTipPopup, mmsg, NULL, WM_RBUTTONUP, GetKeyStates(), lParam);
  3790. break;
  3791. case WM_NCLBUTTONDOWN:
  3792. //TraceMsg(TF_FUNC, "WM_NCLBUTTONDOWN");
  3793. // don't relay the message here because we want to keep the tool tip
  3794. // active until they start moving the monitor. This click might just
  3795. // be for selection
  3796. // ToolTip_RelayEvent(ghwndToolTipPopup, mmsg, hDlg, WM_LBUTTONDOWN, GetKeyStates(), lParam);
  3797. BringWindowToTop(hwnd);
  3798. pDevice = GetDlgCtrlDevice(hwnd);
  3799. if (pcmm)
  3800. pcmm->UpdateActiveDisplay(pDevice);
  3801. pDevice->pds->GetOrgPosition(&rcPos);
  3802. if (!IsRectEmpty(&rcPos))
  3803. {
  3804. GetWindowText(hwnd, ach, ARRAYSIZE(ach));
  3805. FlashText(hDlg, pDevice, ach, &rcPos, TRUE);
  3806. }
  3807. break;
  3808. case WM_NOTIFY:
  3809. switch (((NMHDR FAR *)lParam)->code)
  3810. {
  3811. case TTN_NEEDTEXT:
  3812. pDevice = GetDlgCtrlDevice(hwnd);
  3813. if (pDevice->pds->IsPrimary())
  3814. {
  3815. LoadString(HINST_THISDLL, IDS_PRIMARY,
  3816. ((LPNMTTDISPINFO)lParam)->szText,
  3817. ARRAYSIZE(((LPNMTTDISPINFO)lParam)->szText) );
  3818. }
  3819. else if (!pDevice->pds->IsAttached())
  3820. {
  3821. LoadString(HINST_THISDLL, IDS_NOTATTACHED,
  3822. ((LPNMTTDISPINFO)lParam)->szText,
  3823. ARRAYSIZE(((LPNMTTDISPINFO)lParam)->szText) );
  3824. }
  3825. else
  3826. {
  3827. TCHAR szSecondary[32];
  3828. LoadString(HINST_THISDLL, IDS_SECONDARY, szSecondary, ARRAYSIZE(szSecondary));
  3829. pDevice->pds->GetCurPosition(&rcPos);
  3830. StringCchPrintf(((LPNMTTDISPINFO)lParam)->szText, ARRAYSIZE(((LPNMTTDISPINFO)lParam)->szText), TEXT("%s (%d, %d)"), szSecondary, rcPos.left, rcPos.top);
  3831. }
  3832. break;
  3833. default:
  3834. break;
  3835. }
  3836. break;
  3837. case WM_ENTERSIZEMOVE:
  3838. //TraceMsg(TF_FUNC, "WM_ENTERSIZEMOVE");
  3839. // relay a mouse up to clean the information tooltip
  3840. ToolTip_RelayEvent(ghwndToolTipPopup, mmsg, NULL, WM_LBUTTONDOWN, GetKeyStates(), lParam);
  3841. pDevice = GetDlgCtrlDevice(hwnd);
  3842. pDevice->Snap.x = 0;
  3843. pDevice->Snap.y = 0;
  3844. FlashText(hDlg, pDevice, NULL,NULL,FALSE);
  3845. break;
  3846. case WM_MOVING:
  3847. //TraceMsg(TF_FUNC, "WM_MOVING");
  3848. pDevice = GetDlgCtrlDevice(hwnd);
  3849. SnapMonitorRect(pDevice, hwnd, (RECT*)lParam);
  3850. ZeroMemory(&ti, sizeof(ti));
  3851. ti.cbSize = sizeof(ti);
  3852. if (!pDevice->bTracking) {
  3853. ToolTip_TrackPosition(ghwndToolTipTracking,
  3854. ((LPRECT)lParam)->left+2,
  3855. ((LPRECT)lParam)->top+2);
  3856. TrackToolTip(pDevice, hwnd, TRUE);
  3857. }
  3858. if (ToolTip_GetCurrentTool(ghwndToolTipTracking, &ti) && pcmm)
  3859. {
  3860. TCHAR location[16];
  3861. POINT pt;
  3862. pcmm->GetMonitorPosition(pDevice, GetParent(hwnd), &pt);
  3863. StringCchPrintf(location, ARRAYSIZE(location), TEXT("%d, %d"), pt.x, pt.y);
  3864. ti.lpszText = location;
  3865. ti.rect.left = ((RECT*)lParam)->left + 2;
  3866. ti.rect.top = ((RECT*)lParam)->top + 2;
  3867. ti.rect.right = ti.rect.left + 10;
  3868. ti.rect.bottom = ti.rect.top + 10;
  3869. ToolTip_SetToolInfo(ghwndToolTipTracking, &ti);
  3870. ToolTip_TrackPosition(ghwndToolTipTracking, ti.rect.left, ti.rect.top);
  3871. // SendMessage(ghwndToolTip, TTM_UPDATE, 0, 0);
  3872. }
  3873. break;
  3874. case WM_EXITSIZEMOVE:
  3875. //TraceMsg(TF_FUNC, "WM_EXITSIZEMOVE");
  3876. pDevice = GetDlgCtrlDevice(hwnd);
  3877. TrackToolTip(pDevice, hwnd, FALSE);
  3878. //
  3879. // We don't want to pop up any dialogs here because the modal size
  3880. // loop is still active (it eats any mouse movements and the dialogs
  3881. // can't be moved by the user).
  3882. //
  3883. PostMessage(hwnd, MM_MONITORMOVED, 0, 0);
  3884. break;
  3885. case MM_MONITORMOVED:
  3886. pDevice = GetDlgCtrlDevice(hwnd);
  3887. if (pcmm)
  3888. {
  3889. //
  3890. // If the user moved the monitor, see if they want to attach it
  3891. //
  3892. if (!pcmm->QueryNoAttach() && pDevice && !pDevice->pds->IsAttached())
  3893. {
  3894. if (pcmm->SetMonAttached(pDevice, TRUE, FALSE, hwnd))
  3895. {
  3896. pcmm->UpdateActiveDisplay(pDevice);
  3897. }
  3898. }
  3899. pcmm->HandleMonitorChange(hwnd, FALSE);
  3900. }
  3901. RedrawWindow(GetParent(hwnd), NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN);
  3902. return TRUE;
  3903. case WM_DESTROY:
  3904. FlashText(hDlg, GetDlgCtrlDevice(hwnd), NULL,NULL,FALSE);
  3905. SetWindowLong(hwnd, 0, NULL);
  3906. break;
  3907. case WM_ERASEBKGND:
  3908. //GetClientRect(hwnd, &rc);
  3909. //FillRect((HDC)wParam, &rc, GetSysColorBrush(COLOR_APPWORKSPACE));
  3910. return 0L;
  3911. case WM_PAINT:
  3912. hdc = BeginPaint(hwnd,&ps);
  3913. GetWindowText(hwnd, ach, ARRAYSIZE(ach));
  3914. GetClientRect(hwnd, &rc);
  3915. w = rc.right;
  3916. h = rc.bottom;
  3917. pDevice = GetDlgCtrlDevice(hwnd);
  3918. BOOL fSelected = (pcmm ? (BOOL)(pDevice == pcmm->GetCurDevice()) : FALSE);
  3919. if (pDevice->w != w || pDevice->h != h)
  3920. {
  3921. HBITMAP hbm, hbmMask;
  3922. int cx,cy;
  3923. pDevice->w = w;
  3924. pDevice->h = h;
  3925. ImageList_GetIconSize(pDevice->himl, &cx, &cy);
  3926. MakeMonitorBitmap(w,h,ach,&hbm,&hbmMask,cx,cy, fSelected);
  3927. ImageList_Replace(pDevice->himl,pDevice->iImage,hbm,hbmMask);
  3928. DeleteObject(hbm);
  3929. DeleteObject(hbmMask);
  3930. }
  3931. if (!pDevice->pds->IsAttached())
  3932. {
  3933. FillRect(hdc, &rc, GetSysColorBrush(COLOR_APPWORKSPACE));
  3934. if (pcmm && fSelected)
  3935. {
  3936. ImageList_DrawEx(pDevice->himl,pDevice->iImage,hdc,0,0,w,h,
  3937. CLR_DEFAULT,CLR_DEFAULT,ILD_BLEND25);
  3938. }
  3939. else
  3940. {
  3941. ImageList_DrawEx(pDevice->himl,pDevice->iImage,hdc,0,0,w,h,
  3942. CLR_DEFAULT,CLR_NONE,ILD_BLEND50);
  3943. }
  3944. }
  3945. else
  3946. {
  3947. ImageList_DrawEx(pDevice->himl,pDevice->iImage,hdc,0,0,w,h,
  3948. CLR_DEFAULT,CLR_DEFAULT,ILD_IMAGE);
  3949. }
  3950. EndPaint(hwnd,&ps);
  3951. return 0L;
  3952. }
  3953. return DefWindowProc(hwnd,msg,wParam,lParam);
  3954. }
  3955. LRESULT CALLBACK SliderSubWndProc (HWND hwndSlider, UINT uMsg, WPARAM wParam, LPARAM lParam, WPARAM uID, ULONG_PTR dwRefData)
  3956. {
  3957. ASSERT(uID == 0);
  3958. ASSERT(dwRefData == 0);
  3959. switch (uMsg)
  3960. {
  3961. case WM_GETOBJECT:
  3962. if ( lParam == OBJID_CLIENT )
  3963. {
  3964. // At this point we will try to load oleacc and get the functions
  3965. // we need.
  3966. if (!g_fAttemptedOleAccLoad)
  3967. {
  3968. g_fAttemptedOleAccLoad = TRUE;
  3969. ASSERT(s_pfnCreateStdAccessibleProxy == NULL);
  3970. ASSERT(s_pfnLresultFromObject == NULL);
  3971. g_hOleAcc = LoadLibrary(TEXT("OLEACC"));
  3972. if (g_hOleAcc != NULL)
  3973. {
  3974. s_pfnCreateStdAccessibleProxy = (PFNCREATESTDACCESSIBLEPROXY)
  3975. GetProcAddress(g_hOleAcc, "CreateStdAccessibleProxyW");
  3976. s_pfnLresultFromObject = (PFNLRESULTFROMOBJECT)
  3977. GetProcAddress(g_hOleAcc, "LresultFromObject");
  3978. }
  3979. if (s_pfnLresultFromObject == NULL || s_pfnCreateStdAccessibleProxy == NULL)
  3980. {
  3981. if (g_hOleAcc)
  3982. {
  3983. // No point holding on to Oleacc since we can't use it.
  3984. FreeLibrary(g_hOleAcc);
  3985. g_hOleAcc = NULL;
  3986. }
  3987. s_pfnLresultFromObject = NULL;
  3988. s_pfnCreateStdAccessibleProxy = NULL;
  3989. }
  3990. }
  3991. if (g_hOleAcc && s_pfnCreateStdAccessibleProxy && s_pfnLresultFromObject)
  3992. {
  3993. IAccessible *pAcc = NULL;
  3994. HRESULT hr;
  3995. // Create default slider proxy.
  3996. hr = s_pfnCreateStdAccessibleProxy(
  3997. hwndSlider,
  3998. TEXT("msctls_trackbar32"),
  3999. OBJID_CLIENT,
  4000. IID_IAccessible,
  4001. (void **)&pAcc
  4002. );
  4003. if (SUCCEEDED(hr) && pAcc)
  4004. {
  4005. // now wrap it up in our customized wrapper...
  4006. IAccessible * pWrapAcc = new CAccessibleWrapper( hwndSlider, pAcc );
  4007. // Release our ref to proxy (wrapper has its own addref'd ptr)...
  4008. pAcc->Release();
  4009. if (pWrapAcc != NULL)
  4010. {
  4011. // ...and return the wrapper via LresultFromObject...
  4012. LRESULT lr = s_pfnLresultFromObject( IID_IAccessible, wParam, pWrapAcc );
  4013. // Release our interface pointer - OLEACC has its own addref to the object
  4014. pWrapAcc->Release();
  4015. // Return the lresult, which 'contains' a reference to our wrapper object.
  4016. return lr;
  4017. // All done!
  4018. }
  4019. // If it didn't work, fall through to default behavior instead.
  4020. }
  4021. }
  4022. }
  4023. break;
  4024. case WM_DESTROY:
  4025. RemoveWindowSubclass(hwndSlider, SliderSubWndProc, uID);
  4026. break;
  4027. } /* end switch */
  4028. return DefSubclassProc(hwndSlider, uMsg, wParam, lParam);
  4029. }
  4030. BOOL CSettingsPage::_AreExtraMonitorsDisabledOnPersonal(void)
  4031. {
  4032. BOOL fIsDisabled = IsOS(OS_PERSONAL);
  4033. if (fIsDisabled)
  4034. {
  4035. // POSSIBLE FUTURE REFINEMENT: Insert call to ClassicSystemParametersInfo() to see if there are video cards that we had to disable.
  4036. fIsDisabled = FALSE;
  4037. }
  4038. return fIsDisabled;
  4039. }
  4040. // *** IShellPropSheetExt ***
  4041. HRESULT CSettingsPage::AddPages(IN LPFNSVADDPROPSHEETPAGE pfnAddPage, IN LPARAM lParam)
  4042. {
  4043. HRESULT hr = S_OK;
  4044. PROPSHEETPAGE psp = {0};
  4045. psp.dwSize = sizeof(psp);
  4046. psp.hInstance = HINST_THISDLL;
  4047. psp.dwFlags = PSP_DEFAULT;
  4048. psp.lParam = (LPARAM) this;
  4049. // GetSystemMetics(SM_CMONITORS) returns only the enabled monitors. So, we need to
  4050. // enumerate ourselves to determine if this is a multimonitor scenario. We have our own
  4051. // function to do this.
  4052. // Use the appropriate dlg template for multimonitor and single monitor configs.
  4053. // if(ClassicGetSystemMetrics(SM_CMONITORS) > 1)
  4054. //
  4055. // PERF-WARNING: calling EnumDisplaySettingsEx() is a huge perf hit, so see if we can
  4056. // findout if there is only one adapter with a cheaper call.
  4057. DEBUG_CODE(DebugStartWatch());
  4058. if (!_AreExtraMonitorsDisabledOnPersonal() && (ComputeNumberOfMonitorsFast(TRUE) > 1))
  4059. {
  4060. psp.pszTemplate = MAKEINTRESOURCE(DLG_MULTIMONITOR);
  4061. }
  4062. else
  4063. {
  4064. psp.pszTemplate = MAKEINTRESOURCE(DLG_SINGLEMONITOR);
  4065. }
  4066. DEBUG_CODE(TraceMsg(TF_THEMEUI_PERF, "CSettingsPage::AddPages() took Time=%lums", DebugStopWatch()));
  4067. psp.pfnDlgProc = CSettingsPage::SettingsDlgProc;
  4068. HPROPSHEETPAGE hpsp = CreatePropertySheetPage(&psp);
  4069. if (hpsp)
  4070. {
  4071. if (pfnAddPage(hpsp, lParam))
  4072. {
  4073. hr = S_OK;
  4074. }
  4075. else
  4076. {
  4077. DestroyPropertySheetPage(hpsp);
  4078. hr = E_FAIL;
  4079. }
  4080. }
  4081. else
  4082. {
  4083. hr = E_OUTOFMEMORY;
  4084. }
  4085. return hr;
  4086. }
  4087. HRESULT CSettingsPage::ReplacePage(IN EXPPS uPageID, IN LPFNSVADDPROPSHEETPAGE pfnReplaceWith, IN LPARAM lParam)
  4088. {
  4089. return E_NOTIMPL;
  4090. }
  4091. // *** IObjectWithSite ***
  4092. HRESULT CSettingsPage::SetSite(IN IUnknown * punkSite)
  4093. {
  4094. if (_pThemeUI)
  4095. {
  4096. _pThemeUI->Release();
  4097. _pThemeUI = NULL;
  4098. }
  4099. if (punkSite)
  4100. {
  4101. punkSite->QueryInterface(IID_PPV_ARG(IThemeUIPages, &_pThemeUI));
  4102. }
  4103. return CObjectWithSite::SetSite(punkSite);
  4104. }
  4105. // *** IPropertyBag ***
  4106. HRESULT CSettingsPage::Read(IN LPCOLESTR pszPropName, IN VARIANT * pVar, IN IErrorLog *pErrorLog)
  4107. {
  4108. HRESULT hr = E_INVALIDARG;
  4109. return hr;
  4110. }
  4111. HRESULT CSettingsPage::Write(IN LPCOLESTR pszPropName, IN VARIANT *pVar)
  4112. {
  4113. HRESULT hr = E_INVALIDARG;
  4114. return hr;
  4115. }
  4116. // *** IBasePropPage ***
  4117. HRESULT CSettingsPage::GetAdvancedDialog(OUT IAdvancedDialog ** ppAdvDialog)
  4118. {
  4119. if (ppAdvDialog)
  4120. {
  4121. *ppAdvDialog = NULL;
  4122. }
  4123. return E_NOTIMPL;
  4124. }
  4125. HRESULT CSettingsPage::OnApply(IN PROPPAGEONAPPLY oaAction)
  4126. {
  4127. if (IsDirty() && !_nInApply)
  4128. {
  4129. int status;
  4130. _nInApply++;
  4131. // Apply the settings, and enable\disable the Apply button
  4132. // appropriatly.
  4133. CDisplaySettings *rgpds[MONITORS_MAX];
  4134. ULONG iDevice;
  4135. for (iDevice = 0; iDevice < _NumDevices; iDevice++) {
  4136. rgpds[iDevice] = _Devices[iDevice].pds;
  4137. }
  4138. status = _DisplaySaveSettings(rgpds, _NumDevices, _hDlg);
  4139. SetDirty(status < 0);
  4140. if (status == DISP_CHANGE_RESTART)
  4141. {
  4142. PropSheet_RestartWindows(ghwndPropSheet);
  4143. }
  4144. else if (_pCurDevice && (status == DISP_CHANGE_SUCCESSFUL))
  4145. {
  4146. UINT iDevice;
  4147. TCHAR szDeviceName[32];
  4148. ASSERT(sizeof(szDeviceName) >=
  4149. sizeof(_pCurDevice->DisplayDevice.DeviceName));
  4150. StringCchCopy(szDeviceName, ARRAYSIZE(szDeviceName), _pCurDevice->DisplayDevice.DeviceName);
  4151. _InitDisplaySettings(FALSE);
  4152. for (iDevice = 0; iDevice < _NumDevices; iDevice++)
  4153. {
  4154. if (lstrcmp(_Devices[iDevice].DisplayDevice.DeviceName, szDeviceName) == 0)
  4155. {
  4156. UpdateActiveDisplay(_Devices + iDevice);
  4157. break;
  4158. }
  4159. }
  4160. }
  4161. else
  4162. {
  4163. // Make sure the dialog stays and redraw
  4164. _InitDisplaySettings(FALSE);
  4165. UpdateActiveDisplay(NULL);
  4166. SetWindowLongPtr(_hDlg, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE);
  4167. }
  4168. _nInApply--;
  4169. }
  4170. return S_OK;
  4171. }
  4172. HRESULT CSettingsPage_CreateInstance(IN IUnknown * punkOuter, IN REFIID riid, OUT LPVOID * ppvObj)
  4173. {
  4174. HRESULT hr = E_INVALIDARG;
  4175. if (!punkOuter && ppvObj)
  4176. {
  4177. CSettingsPage * pThis = new CSettingsPage();
  4178. *ppvObj = NULL;
  4179. if (pThis)
  4180. {
  4181. hr = pThis->QueryInterface(riid, ppvObj);
  4182. pThis->Release();
  4183. }
  4184. else
  4185. {
  4186. hr = E_OUTOFMEMORY;
  4187. }
  4188. }
  4189. return hr;
  4190. }
  4191. VOID CheckForDuplicateAppletExtensions(HKEY hkDriver)
  4192. {
  4193. DWORD dwCheckForDuplicates = 0, cb = sizeof(DWORD), Len = 0;
  4194. HKEY hkExtensions = (HKEY)INVALID_HANDLE_VALUE;
  4195. PAPPEXT pAppExtTemp = NULL, pAppExt = NULL;
  4196. PTCHAR pmszAppExt = NULL;
  4197. if (RegQueryValueEx(hkDriver,
  4198. TEXT("DeskCheckForDuplicates"),
  4199. NULL,
  4200. NULL,
  4201. (LPBYTE)(&dwCheckForDuplicates),
  4202. &cb) == ERROR_SUCCESS)
  4203. {
  4204. RegDeleteValue(hkDriver, TEXT("DeskCheckForDuplicates"));
  4205. }
  4206. if (dwCheckForDuplicates != 1)
  4207. return;
  4208. if (RegOpenKeyEx(hkDriver,
  4209. TEXT("Display\\shellex\\PropertySheetHandlers"),
  4210. 0,
  4211. KEY_READ,
  4212. &hkExtensions) != ERROR_SUCCESS)
  4213. {
  4214. hkExtensions = (HKEY)INVALID_HANDLE_VALUE;
  4215. goto Fallout;
  4216. }
  4217. DeskAESnapshot(hkExtensions, &pAppExt);
  4218. if (pAppExt != NULL)
  4219. {
  4220. pAppExtTemp = pAppExt;
  4221. Len = 0;
  4222. while (pAppExtTemp)
  4223. {
  4224. Len += lstrlen(pAppExtTemp->szDefaultValue) + 1;
  4225. pAppExtTemp = pAppExtTemp->pNext;
  4226. }
  4227. DWORD cchAppExt = (Len + 1);
  4228. pmszAppExt = (PTCHAR)LocalAlloc(LPTR, cchAppExt * sizeof(TCHAR));
  4229. if (pmszAppExt != NULL)
  4230. {
  4231. pAppExtTemp = pAppExt;
  4232. Len = 0;
  4233. while (pAppExtTemp)
  4234. {
  4235. StringCchCopy(pmszAppExt + Len, cchAppExt - Len, pAppExtTemp->szDefaultValue);
  4236. Len += lstrlen(pAppExtTemp->szDefaultValue) + 1;
  4237. pAppExtTemp = pAppExtTemp->pNext;
  4238. }
  4239. DeskAEDelete(REGSTR_PATH_CONTROLSFOLDER TEXT("\\Display\\shellex\\PropertySheetHandlers"),
  4240. pmszAppExt);
  4241. DeskAEDelete(REGSTR_PATH_CONTROLSFOLDER TEXT("\\Device\\shellex\\PropertySheetHandlers"),
  4242. pmszAppExt);
  4243. LocalFree(pmszAppExt);
  4244. }
  4245. DeskAECleanup(pAppExt);
  4246. }
  4247. Fallout:
  4248. if (hkExtensions != INVALID_HANDLE_VALUE)
  4249. {
  4250. RegCloseKey(hkExtensions);
  4251. }
  4252. }
  4253. VOID
  4254. DeskAESnapshot(
  4255. HKEY hkExtensions,
  4256. PAPPEXT* ppAppExt
  4257. )
  4258. {
  4259. HKEY hkSubkey = 0;
  4260. DWORD index = 0;
  4261. DWORD ulSize = MAX_PATH;
  4262. APPEXT AppExtTemp;
  4263. PAPPEXT pAppExtBefore = NULL;
  4264. PAPPEXT pAppExtTemp = NULL;
  4265. ulSize = sizeof(AppExtTemp.szKeyName) / sizeof(TCHAR);
  4266. while (RegEnumKeyEx(hkExtensions,
  4267. index,
  4268. AppExtTemp.szKeyName,
  4269. &ulSize,
  4270. NULL,
  4271. NULL,
  4272. NULL,
  4273. NULL) == ERROR_SUCCESS) {
  4274. if (RegOpenKeyEx(hkExtensions,
  4275. AppExtTemp.szKeyName,
  4276. 0,
  4277. KEY_READ,
  4278. &hkSubkey) == ERROR_SUCCESS) {
  4279. ulSize = sizeof(AppExtTemp.szDefaultValue);
  4280. if ((RegQueryValueEx(hkSubkey,
  4281. NULL,
  4282. 0,
  4283. NULL,
  4284. (PBYTE)AppExtTemp.szDefaultValue,
  4285. &ulSize) == ERROR_SUCCESS) &&
  4286. (AppExtTemp.szDefaultValue[0] != TEXT('\0'))) {
  4287. PAPPEXT pAppExt = (PAPPEXT)LocalAlloc(LPTR, sizeof(APPEXT));
  4288. if (pAppExt != NULL) {
  4289. *pAppExt = AppExtTemp;
  4290. pAppExtBefore = pAppExtTemp = *ppAppExt;
  4291. while((pAppExtTemp != NULL) &&
  4292. (lstrcmpi(pAppExtTemp->szDefaultValue,
  4293. pAppExt->szDefaultValue) < 0)) {
  4294. pAppExtBefore = pAppExtTemp;
  4295. pAppExtTemp = pAppExtTemp->pNext;
  4296. }
  4297. if (pAppExtBefore != pAppExtTemp) {
  4298. pAppExt->pNext = pAppExtBefore->pNext;
  4299. pAppExtBefore->pNext = pAppExt;
  4300. } else {
  4301. pAppExt->pNext = *ppAppExt;
  4302. *ppAppExt = pAppExt;
  4303. }
  4304. }
  4305. }
  4306. RegCloseKey(hkSubkey);
  4307. }
  4308. ulSize = sizeof(AppExtTemp.szKeyName) / sizeof(TCHAR);
  4309. index++;
  4310. }
  4311. }
  4312. VOID
  4313. DeskAEDelete(
  4314. PTCHAR szDeleteFrom,
  4315. PTCHAR mszExtensionsToRemove
  4316. )
  4317. {
  4318. TCHAR szKeyName[MAX_PATH];
  4319. HKEY hkDeleteFrom, hkExt;
  4320. DWORD cSubKeys = 0, cbSize = 0;
  4321. TCHAR szDefaultValue[MAX_PATH];
  4322. PTCHAR szValue;
  4323. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  4324. szDeleteFrom,
  4325. 0,
  4326. KEY_READ,
  4327. &hkDeleteFrom) == ERROR_SUCCESS) {
  4328. if (RegQueryInfoKey(hkDeleteFrom,
  4329. NULL,
  4330. NULL,
  4331. NULL,
  4332. &cSubKeys,
  4333. NULL,
  4334. NULL,
  4335. NULL,
  4336. NULL,
  4337. NULL,
  4338. NULL,
  4339. NULL) == ERROR_SUCCESS) {
  4340. while (cSubKeys--) {
  4341. if (RegEnumKey(hkDeleteFrom,
  4342. cSubKeys,
  4343. szKeyName,
  4344. ARRAYSIZE(szKeyName)) == ERROR_SUCCESS) {
  4345. int iComp = -1;
  4346. if (RegOpenKeyEx(hkDeleteFrom,
  4347. szKeyName,
  4348. 0,
  4349. KEY_READ,
  4350. &hkExt) == ERROR_SUCCESS) {
  4351. cbSize = sizeof(szDefaultValue);
  4352. if ((RegQueryValueEx(hkExt,
  4353. NULL,
  4354. 0,
  4355. NULL,
  4356. (PBYTE)szDefaultValue,
  4357. &cbSize) == ERROR_SUCCESS) &&
  4358. (szDefaultValue[0] != TEXT('\0'))) {
  4359. szValue = mszExtensionsToRemove;
  4360. while (*szValue != TEXT('\0')) {
  4361. iComp = lstrcmpi(szDefaultValue, szValue);
  4362. if (iComp <= 0) {
  4363. break;
  4364. }
  4365. while (*szValue != TEXT('\0'))
  4366. szValue++;
  4367. szValue++;
  4368. }
  4369. }
  4370. RegCloseKey(hkExt);
  4371. }
  4372. if (iComp == 0) {
  4373. SHDeleteKey(hkDeleteFrom, szKeyName);
  4374. }
  4375. }
  4376. }
  4377. }
  4378. RegCloseKey(hkDeleteFrom);
  4379. }
  4380. }
  4381. VOID
  4382. DeskAECleanup(
  4383. PAPPEXT pAppExt
  4384. )
  4385. {
  4386. PAPPEXT pAppExtTemp;
  4387. while (pAppExt) {
  4388. pAppExtTemp = pAppExt->pNext;
  4389. LocalFree(pAppExt);
  4390. pAppExt = pAppExtTemp;
  4391. }
  4392. }