Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

633 lines
25 KiB

  1. #include "stdafx.h"
  2. #pragma hdrstop
  3. // 98/10/02 vtan: Multiple monitor bug fixes.
  4. // Given an old monitor layout, a new monitor layout and a component
  5. // this function makes sure that it is in the new layout using a
  6. // monitor relative scheme. It tries to preserve the position
  7. // relatively within a given monitor. If the resolution of the monitor
  8. // changes then this needs to be accounted for also.
  9. // Preserve the component within a given monitor if the monitor is the
  10. // same HMONITOR but the GDI co-ordinates change.
  11. // If the same monitor cannot be located then move the component to the
  12. // nearest monitor and position it as best on that monitor.
  13. // If all else fails then use the default component positioning
  14. // algorithm. This should never happen.
  15. // Preserve the component within a given monitor if the resolution
  16. // changes. Preserve the size of the component by MOVING the component
  17. // in the X and Y axis until the left or the top of the monitor is
  18. // reached. When either axis reaches 0 then reduce the size of the
  19. // component until it fits within the given new resolution.
  20. static const int kNameSize = 16;
  21. typedef struct
  22. {
  23. HMONITOR miHMONITOR;
  24. RECT miDisplayAreaRect,
  25. miWorkAreaRect;
  26. } tMonitorInfoRec, *tMonitorInfoPtr;
  27. typedef struct
  28. {
  29. int miaCount, miaIndex;
  30. RECT miaVirtualScreen;
  31. tMonitorInfoRec miaMonitors[1];
  32. } tMonitorInfoArrayRec, *tMonitorInfoArrayPtr;
  33. typedef struct
  34. {
  35. bool ciValidData, ciVisible, ciRepositioned;
  36. TCHAR ciName[kNameSize]; // this is not excessive but limited
  37. DWORD ciItemState;
  38. int ciType;
  39. COMPPOS ciPosition;
  40. COMPSTATEINFO ciStateInfo;
  41. } tComponentInfoRec, *tComponentInfoPtr;
  42. static tMonitorInfoArrayPtr gOldMonitorArray = NULL;
  43. static tMonitorInfoArrayPtr gNewMonitorArray = NULL;
  44. // Functions located in Dutil.cpp used for co-ordinate mapping.
  45. void SetPt (POINT& pt, LONG x, LONG y);
  46. void OffsetPt (POINT& pt, LONG dh, LONG dv);
  47. void CalculateVirtualScreen (RECT& virtualScreen);
  48. // Local function prototypes.
  49. BOOL CALLBACK MonitorCountEnumProc (HMONITOR hMonitor, HDC dc, RECT *rc, LPARAM data);
  50. BOOL CALLBACK MonitorCalculateEnumProc (HMONITOR hMonitor, HDC dc, RECT *rc, LPARAM data);
  51. HRESULT CalculateCurrentMonitorArray(void);
  52. void ApplyCurrentMonitorArray (void);
  53. bool EqualMonitorArray (tMonitorInfoArrayPtr oldMonitorArray, tMonitorInfoArrayPtr newMonitorArray);
  54. int IndexOfMonitor (tMonitorInfoArrayPtr pMIA, HMONITOR hMonitor);
  55. int IndexOfMonitor (tMonitorInfoArrayPtr pMIA, POINT& pt);
  56. int IndexOfMonitor (tMonitorInfoArrayPtr pMIA, RECT& rc);
  57. bool RepositionDesktopRect (RECT& rcComponent, tMonitorInfoArrayPtr oldMonitorArray, tMonitorInfoArrayPtr newMonitorArray);
  58. bool RepositionDesktopComponent (COMPPOS& componentPosition, COMPSTATEINFO& componentStateInfo, DWORD dwItemState);
  59. bool ReadAllComponents (HKEY hKeyDesktop, tComponentInfoPtr& pComponentInfo, DWORD& dwComponentCount);
  60. void WriteAllComponents (HKEY hKeyDesktop, tComponentInfoPtr pComponentInfo, DWORD dwComponentCount);
  61. BOOL CALLBACK MonitorCountEnumProc (HMONITOR hMonitor, HDC dc, RECT *rc, LPARAM data)
  62. // Count the number of monitors attached to the system.
  63. {
  64. int *iCounter;
  65. iCounter = reinterpret_cast<int*>(data);
  66. ++(*iCounter);
  67. return(TRUE);
  68. }
  69. BOOL CALLBACK MonitorCalculateEnumProc (HMONITOR hMonitor, HDC dc, RECT *rc, LPARAM data)
  70. // Store each monitor HMONITOR and dimensions in the array.
  71. {
  72. tMonitorInfoArrayPtr monitorArray;
  73. MONITORINFO monitorInfo;
  74. monitorArray = reinterpret_cast<tMonitorInfoArrayPtr>(data);
  75. monitorInfo.cbSize = sizeof(monitorInfo);
  76. if (GetMonitorInfo(hMonitor, &monitorInfo) != 0)
  77. {
  78. tMonitorInfoPtr pMI;
  79. pMI = &monitorArray->miaMonitors[monitorArray->miaIndex++];
  80. pMI->miHMONITOR = hMonitor;
  81. TBOOL(CopyRect(&pMI->miDisplayAreaRect, &monitorInfo.rcMonitor));
  82. TBOOL(CopyRect(&pMI->miWorkAreaRect, &monitorInfo.rcWork));
  83. }
  84. return(TRUE);
  85. }
  86. HRESULT CalculateCurrentMonitorArray(void)
  87. // Allocate and fill the monitor rectangle array.
  88. {
  89. HRESULT hr = E_OUTOFMEMORY;
  90. int iCount;
  91. iCount = 0;
  92. TBOOL(EnumDisplayMonitors(NULL, NULL, MonitorCountEnumProc, reinterpret_cast<LPARAM>(&iCount)));
  93. gNewMonitorArray = reinterpret_cast<tMonitorInfoArrayPtr>(LocalAlloc(LMEM_FIXED, sizeof(tMonitorInfoArrayRec) + ((iCount - 1) * sizeof(tMonitorInfoRec))));
  94. if (gNewMonitorArray)
  95. {
  96. gNewMonitorArray->miaCount = iCount;
  97. gNewMonitorArray->miaIndex = 0;
  98. CalculateVirtualScreen(gNewMonitorArray->miaVirtualScreen);
  99. TBOOL(EnumDisplayMonitors(NULL, NULL, MonitorCalculateEnumProc, reinterpret_cast<LPARAM>(gNewMonitorArray)));
  100. hr = S_OK;
  101. }
  102. return hr;
  103. }
  104. void ApplyCurrentMonitorArray (void)
  105. // Discard the old and save the new as current monitor
  106. // rectangle array for the next time the function is called.
  107. {
  108. if (gOldMonitorArray != NULL)
  109. (HLOCAL)LocalFree(gOldMonitorArray);
  110. gOldMonitorArray = gNewMonitorArray;
  111. gNewMonitorArray = NULL;
  112. }
  113. bool EqualMonitorArray (tMonitorInfoArrayPtr oldMonitorArray, tMonitorInfoArrayPtr newMonitorArray)
  114. {
  115. bool bResult;
  116. if (oldMonitorArray->miaCount == newMonitorArray->miaCount)
  117. {
  118. int i, iLimit;
  119. bResult = true;
  120. for (i = 0, iLimit = oldMonitorArray->miaCount; bResult && (i < iLimit); ++i)
  121. bResult &= (EqualRect(&oldMonitorArray->miaMonitors[i].miWorkAreaRect, &newMonitorArray->miaMonitors[i].miWorkAreaRect) != 0);
  122. }
  123. else
  124. bResult = false;
  125. return(bResult);
  126. }
  127. // These functions determine the index into the monitor
  128. // rectangle array of a given HMONITOR, POINT or RECT.
  129. int IndexOfMonitor (tMonitorInfoArrayPtr pMIA, HMONITOR hMonitor)
  130. {
  131. int i, iLimit, iResult;
  132. tMonitorInfoPtr pMI;
  133. iResult = -1;
  134. for (i = 0, iLimit = pMIA->miaCount, pMI = pMIA->miaMonitors; i < iLimit; ++i, ++pMI)
  135. {
  136. if (pMI->miHMONITOR == hMonitor)
  137. {
  138. iResult = i;
  139. break;
  140. }
  141. }
  142. return(iResult);
  143. }
  144. // Note that the functions that take a POINT or RECT
  145. // require the co-ordinates to be in TRIDENT co-ordinates.
  146. int IndexOfMonitor (tMonitorInfoArrayPtr pMIA, POINT& pt)
  147. {
  148. int i, iLimit, iResult;
  149. tMonitorInfoPtr pMI;
  150. POINT ptLocal;
  151. ptLocal = pt;
  152. OffsetPt(ptLocal, +pMIA->miaVirtualScreen.left, +pMIA->miaVirtualScreen.top);
  153. iResult = -1;
  154. for (i = 0, iLimit = pMIA->miaCount, pMI = pMIA->miaMonitors; i < iLimit; ++i, ++pMI)
  155. {
  156. if (PtInRect(&pMI->miDisplayAreaRect, ptLocal) != 0)
  157. {
  158. iResult = i;
  159. break;
  160. }
  161. }
  162. return(iResult);
  163. }
  164. int IndexOfMonitor (tMonitorInfoArrayPtr pMIA, RECT& rc)
  165. {
  166. int iResult;
  167. POINT pt;
  168. // 99/05/12 #338446 vtan: Try all four corners of the rectangle
  169. // to find a match.
  170. pt.x = rc.left;
  171. pt.y = rc.top;
  172. iResult = IndexOfMonitor(pMIA, pt);
  173. if (iResult < 0)
  174. {
  175. pt.x = rc.left;
  176. pt.y = rc.bottom;
  177. iResult = IndexOfMonitor(pMIA, pt);
  178. if (iResult < 0)
  179. {
  180. pt.x = rc.right;
  181. pt.y = rc.top;
  182. iResult = IndexOfMonitor(pMIA, pt);
  183. if (iResult < 0)
  184. {
  185. pt.x = rc.right;
  186. pt.y = rc.bottom;
  187. iResult = IndexOfMonitor(pMIA, pt);
  188. }
  189. }
  190. }
  191. return(iResult);
  192. }
  193. int IndexOfMonitor (tMonitorInfoArrayPtr pMIA, COMPPOS& componentPosition)
  194. {
  195. RECT rcComponent;
  196. TBOOL(SetRect(&rcComponent, componentPosition.iLeft, componentPosition.iTop, componentPosition.iLeft + componentPosition.dwWidth, componentPosition.iTop + componentPosition.dwHeight));
  197. return(IndexOfMonitor(pMIA, rcComponent));
  198. }
  199. bool RepositionDesktopRect (RECT& rcComponent, tMonitorInfoArrayPtr oldMonitorArray, tMonitorInfoArrayPtr newMonitorArray)
  200. // Reposition the component's RECT based on the logic at the
  201. // top of the source file. Used for both the component's
  202. // current position and the restored position.
  203. {
  204. bool bRepositionedComponent;
  205. int iOldMonitorIndex, iNewMonitorIndex;
  206. // This is for future expansion. The components are always
  207. // deemed to be repositioned if this function is called.
  208. bRepositionedComponent = true;
  209. // Find out if the monitor which the component was on is still
  210. // present. To do this find the index of the component in the
  211. // old monitor array, get the HMONITOR and find that in the new
  212. // monitor array.
  213. iOldMonitorIndex = IndexOfMonitor(oldMonitorArray, rcComponent);
  214. if (iOldMonitorIndex >= 0)
  215. {
  216. RECT *prcOldMonitor, *prcNewMonitor;
  217. iNewMonitorIndex = IndexOfMonitor(newMonitorArray, oldMonitorArray->miaMonitors[iOldMonitorIndex].miHMONITOR);
  218. if (iNewMonitorIndex < 0)
  219. {
  220. HMONITOR hMonitor;
  221. // The component is on a monitor that no longer exists. The only
  222. // thing to do in this case is to find the nearest monitor based
  223. // on the GDI co-ordinates and position it on that monitor.
  224. hMonitor = MonitorFromRect(&rcComponent, MONITOR_DEFAULTTONEAREST);
  225. iNewMonitorIndex = IndexOfMonitor(newMonitorArray, hMonitor);
  226. ASSERT(iNewMonitorIndex >= 0);
  227. }
  228. // If iNewMonitorIndex was already positive then the monitor which
  229. // the component was on still exists and simply mapping GDI
  230. // co-ordinates will work. Otherwise we found the nearest monitor
  231. // and mapping GDI co-ordinates also works!
  232. // This maps from the component's OLD co-ordinates in trident
  233. // co-ordinates to GDI co-ordinates. Then it maps from the GDI
  234. // co-ordinates to an OLD monitor relative co-ordinate. Then it
  235. // maps from the OLD monitor relative co-ordinates to the NEW
  236. // monitor GDI co-ordinates.
  237. prcOldMonitor = &oldMonitorArray->miaMonitors[iOldMonitorIndex].miDisplayAreaRect;
  238. prcNewMonitor = &newMonitorArray->miaMonitors[iNewMonitorIndex].miDisplayAreaRect;
  239. TBOOL(OffsetRect(&rcComponent, +oldMonitorArray->miaVirtualScreen.left, +oldMonitorArray->miaVirtualScreen.top));
  240. TBOOL(OffsetRect(&rcComponent, -prcOldMonitor->left, -prcOldMonitor->top));
  241. TBOOL(OffsetRect(&rcComponent, +prcNewMonitor->left, +prcNewMonitor->top));
  242. }
  243. else
  244. {
  245. // Component exists at an invalid location in the old monitor
  246. // layout. It may be valid in the new layout. Try this. If that
  247. // doesn't work then it doesn't exist in the old nor the new
  248. // layout. It was in no-man's land. Position it using the default
  249. // positioning system.
  250. iNewMonitorIndex = IndexOfMonitor(newMonitorArray, rcComponent);
  251. if (iNewMonitorIndex < 0)
  252. {
  253. POINT ptOrigin;
  254. COMPPOS componentPosition;
  255. GetNextComponentPosition(&componentPosition);
  256. IncrementComponentsPositioned();
  257. TBOOL(SetRect(&rcComponent, componentPosition.iLeft, componentPosition.iTop, componentPosition.iLeft + componentPosition.dwWidth, componentPosition.iTop + componentPosition.dwHeight));
  258. // Get the primary monitor index in our monitor rectangle array.
  259. SetPt(ptOrigin, 0, 0);
  260. iNewMonitorIndex = IndexOfMonitor(newMonitorArray, MonitorFromPoint(ptOrigin, MONITOR_DEFAULTTOPRIMARY));
  261. ASSERT(iNewMonitorIndex >= 0);
  262. }
  263. }
  264. // At this stage the component position is in GDI co-ordinates.
  265. // Convert from GDI co-ordinates back to trident co-ordinates.
  266. TBOOL(OffsetRect(&rcComponent, -newMonitorArray->miaVirtualScreen.left, -newMonitorArray->miaVirtualScreen.top));
  267. return(bRepositionedComponent);
  268. }
  269. bool RepositionDesktopComponent (COMPPOS& componentPosition, COMPSTATEINFO& componentStateInfo, DWORD dwItemState, int iComponentType)
  270. {
  271. bool bRepositionedComponent;
  272. tMonitorInfoArrayPtr oldMonitorArray, newMonitorArray;
  273. RECT rcComponent;
  274. // Check if the monitor layout has changed. If unchanged then
  275. // there is no need to move the components.
  276. oldMonitorArray = gOldMonitorArray;
  277. newMonitorArray = gNewMonitorArray;
  278. if (oldMonitorArray == NULL)
  279. {
  280. oldMonitorArray = newMonitorArray;
  281. }
  282. TBOOL(SetRect(&rcComponent, componentPosition.iLeft, componentPosition.iTop, componentPosition.iLeft + componentPosition.dwWidth, componentPosition.iTop + componentPosition.dwHeight));
  283. bRepositionedComponent = RepositionDesktopRect(rcComponent, oldMonitorArray, newMonitorArray);
  284. componentPosition.iLeft = rcComponent.left;
  285. componentPosition.iTop = rcComponent.top;
  286. componentPosition.dwWidth = rcComponent.right - rcComponent.left;
  287. componentPosition.dwHeight = rcComponent.bottom - rcComponent.top;
  288. ValidateComponentPosition(&componentPosition, dwItemState, iComponentType, NULL, NULL);
  289. // If the component is zoomed also reposition the restored
  290. // COMPSTATEINFO.
  291. if (IsZoomedState(dwItemState))
  292. {
  293. COMPPOS restoredCompPos;
  294. TBOOL(SetRect(&rcComponent, componentStateInfo.iLeft, componentStateInfo.iTop, componentStateInfo.iLeft + componentStateInfo.dwWidth, componentStateInfo.iTop + componentStateInfo.dwHeight));
  295. bRepositionedComponent = RepositionDesktopRect(rcComponent, oldMonitorArray, newMonitorArray) || bRepositionedComponent;
  296. restoredCompPos.iLeft = componentStateInfo.iLeft = rcComponent.left;
  297. restoredCompPos.iTop = componentStateInfo.iTop = rcComponent.top;
  298. restoredCompPos.dwWidth = componentStateInfo.dwWidth = rcComponent.right - rcComponent.left;
  299. restoredCompPos.dwHeight = componentStateInfo.dwHeight = rcComponent.bottom - rcComponent.top;
  300. ZoomComponent(&componentPosition, dwItemState, FALSE);
  301. restoredCompPos.dwSize = sizeof(restoredCompPos);
  302. ValidateComponentPosition(&restoredCompPos, IS_NORMAL, iComponentType, NULL, NULL);
  303. }
  304. return(bRepositionedComponent);
  305. }
  306. bool ReadAllComponents (HKEY hKeyDesktop, tComponentInfoPtr& pComponentInfo, DWORD& dwComponentCount)
  307. {
  308. tComponentInfoPtr pCI;
  309. if (RegQueryInfoKey(hKeyDesktop, NULL, NULL, NULL, &dwComponentCount, NULL, NULL, NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
  310. dwComponentCount = 0;
  311. if (dwComponentCount > 0)
  312. {
  313. // 99/08/09 #383184: STRESS fix. Allocate the whole block of
  314. // memory required for the components but allocate one extra
  315. // entry. advapi32!RegEnumKeyEx will try to access the memory
  316. // before determining that there is a failure condition. With
  317. // pageheap on (and the block allocated at the end of the page)
  318. // this causes an access violation. The simplest fix is to add
  319. // an extra entry.
  320. pComponentInfo = pCI = reinterpret_cast<tComponentInfoPtr>(LocalAlloc(LPTR, (dwComponentCount + 1) * sizeof(*pCI))); // LMEM_FIXED | LMEM_ZEROINIT
  321. if (pCI != NULL)
  322. {
  323. DWORD dwIndex, dwSize;
  324. // Enumerate all the desktop components.
  325. dwIndex = 0;
  326. dwSize = sizeof(pCI->ciName);
  327. while (RegEnumKeyEx(hKeyDesktop, dwIndex, pCI->ciName, &dwSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
  328. {
  329. CRegKey regKeyComponent;
  330. if (regKeyComponent.Open(hKeyDesktop, pCI->ciName, KEY_READ | KEY_WRITE) == ERROR_SUCCESS)
  331. {
  332. DWORD dwType, cbData;
  333. // Read the Position value.
  334. cbData = sizeof(pCI->ciPosition);
  335. if (SHQueryValueEx(regKeyComponent, REG_VAL_COMP_POSITION, NULL, &dwType, &pCI->ciPosition, &cbData) == ERROR_SUCCESS)
  336. {
  337. DWORD dwFlags;
  338. pCI->ciValidData = true;
  339. if (SHQueryValueEx(regKeyComponent, REG_VAL_COMP_FLAGS, NULL, &dwType, &dwFlags, &cbData) == ERROR_SUCCESS)
  340. {
  341. pCI->ciVisible = ((dwFlags & COMP_SELECTED) != 0);
  342. pCI->ciType = (dwFlags & COMP_TYPE_MASK);
  343. }
  344. else
  345. {
  346. pCI->ciVisible = false;
  347. pCI->ciType = COMP_TYPE_WEBSITE;
  348. }
  349. pCI->ciItemState = IS_NORMAL; // if missing (IE4 machine) or error the assume normal
  350. cbData = sizeof(pCI->ciItemState);
  351. if ((SHQueryValueEx(regKeyComponent, REG_VAL_COMP_CURSTATE, NULL, &dwType, &pCI->ciItemState, &cbData) == ERROR_SUCCESS))
  352. {
  353. // If the component is zoomed also read in the COMPSTATEINFO.
  354. if (IsZoomedState(pCI->ciItemState))
  355. {
  356. cbData = sizeof(pCI->ciStateInfo);
  357. TW32(SHQueryValueEx(regKeyComponent, REG_VAL_COMP_RESTOREDSTATEINFO, NULL, &dwType, &pCI->ciStateInfo, &cbData));
  358. }
  359. }
  360. }
  361. }
  362. ++pCI;
  363. ++dwIndex;
  364. dwSize = sizeof(pCI->ciName);
  365. }
  366. }
  367. }
  368. return((dwComponentCount != 0) && (pComponentInfo != NULL));
  369. }
  370. int IndexOfComponent (tComponentInfoPtr pComponentInfo, DWORD dwComponentCount, LPCTSTR pcszName)
  371. {
  372. int iResult, i;
  373. for (iResult = -1, i = 0; (iResult < 0) && (i < static_cast<int>(dwComponentCount)); ++i)
  374. {
  375. if (lstrcmp(pComponentInfo[i].ciName, pcszName) == 0)
  376. iResult = i;
  377. }
  378. return(iResult);
  379. }
  380. void WriteAllComponents (HKEY hKeyDesktop, tComponentInfoPtr pComponentInfo, DWORD dwComponentCount)
  381. {
  382. TCHAR szSubKeyName[kNameSize];
  383. DWORD dwSubKeyIndex, dwSubKeySize;
  384. // Enumerate all the desktop components.
  385. dwSubKeyIndex = 0;
  386. dwSubKeySize = ARRAYSIZE(szSubKeyName);
  387. while (RegEnumKeyEx(hKeyDesktop, dwSubKeyIndex, szSubKeyName, &dwSubKeySize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
  388. {
  389. CRegKey regKeyComponent;
  390. if (regKeyComponent.Open(hKeyDesktop, szSubKeyName, KEY_READ | KEY_WRITE) == ERROR_SUCCESS)
  391. {
  392. int i;
  393. i = IndexOfComponent(pComponentInfo, dwComponentCount, szSubKeyName);
  394. if ((i >= 0) && pComponentInfo[i].ciRepositioned)
  395. {
  396. TW32(RegSetValueEx(regKeyComponent, REG_VAL_COMP_POSITION, 0, REG_BINARY, reinterpret_cast<const unsigned char*>(&pComponentInfo[i].ciPosition), sizeof(pComponentInfo[i].ciPosition)));
  397. TW32(RegSetValueEx(regKeyComponent, REG_VAL_COMP_CURSTATE, NULL, REG_BINARY, reinterpret_cast<const unsigned char*>(&pComponentInfo[i].ciItemState), sizeof(pComponentInfo[i].ciItemState)));
  398. // If the component is zoomed also write out the COMPSTATEINFO.
  399. if (IsZoomedState(pComponentInfo[i].ciItemState))
  400. {
  401. TW32(RegSetValueEx(regKeyComponent, REG_VAL_COMP_RESTOREDSTATEINFO, 0, REG_BINARY, reinterpret_cast<const unsigned char*>(&pComponentInfo[i].ciStateInfo), sizeof(pComponentInfo[i].ciStateInfo)));
  402. }
  403. }
  404. }
  405. ++dwSubKeyIndex;
  406. dwSubKeySize = ARRAYSIZE(szSubKeyName);
  407. }
  408. }
  409. BOOL AdjustDesktopComponents (LPCRECT arectNew,
  410. int crectNew,
  411. LPCRECT arectOldMonitors,
  412. LPCRECT arectOld,
  413. int crectOld)
  414. {
  415. static const int kMaximumMonitorCount = 16;
  416. HRESULT hr;
  417. bool bRepositionedComponent;
  418. int zoomedComponentIndices[kMaximumMonitorCount]; // 16 monitors limitation here - make dynamic if required
  419. int i;
  420. tMonitorInfoArrayPtr oldMonitorArray;
  421. CRegKey regKeyDesktop;
  422. TCHAR lpszDeskcomp[MAX_PATH];
  423. for (i = 0; i < kMaximumMonitorCount; ++i)
  424. zoomedComponentIndices[i] = -1;
  425. bRepositionedComponent = false;
  426. hr = CalculateCurrentMonitorArray();
  427. if (SUCCEEDED(hr))
  428. {
  429. oldMonitorArray = gOldMonitorArray;
  430. if (oldMonitorArray == NULL)
  431. oldMonitorArray = gNewMonitorArray;
  432. GetRegLocation(lpszDeskcomp, SIZECHARS(lpszDeskcomp), REG_DESKCOMP_COMPONENTS, NULL);
  433. if (regKeyDesktop.Open(HKEY_CURRENT_USER, lpszDeskcomp, KEY_READ) == ERROR_SUCCESS)
  434. {
  435. DWORD dwComponentCount;
  436. tComponentInfoPtr pComponentInfo;
  437. // Enumerate all the desktop components.
  438. if (ReadAllComponents(regKeyDesktop, pComponentInfo, dwComponentCount))
  439. {
  440. tComponentInfoPtr pCI;
  441. for (pCI = pComponentInfo, i = 0; i < static_cast<int>(dwComponentCount); ++pCI, ++i)
  442. {
  443. int iPreviousMonitorIndexOfComponent;
  444. // Calculate the previous monitor position BEFORE the component
  445. // gets repositioned.
  446. iPreviousMonitorIndexOfComponent = IndexOfMonitor(oldMonitorArray, pCI->ciPosition);
  447. if (RepositionDesktopComponent(pCI->ciPosition, pCI->ciStateInfo, pCI->ciItemState, pCI->ciType))
  448. {
  449. int iCurrentMonitorIndexOfComponent;
  450. pCI->ciRepositioned = bRepositionedComponent = true;
  451. iCurrentMonitorIndexOfComponent = IndexOfMonitor(gNewMonitorArray, pCI->ciPosition);
  452. if (iCurrentMonitorIndexOfComponent >= 0)
  453. {
  454. // 99/05/12 #338446 vtan: Only use a zero or positive index into the
  455. // monitor array. -1 is invalid and will cause an AV. This should NEVER
  456. // happen but rather than assert this condition is handled.
  457. if (IsZoomedState(pCI->ciItemState) && (zoomedComponentIndices[iCurrentMonitorIndexOfComponent] >= 0))
  458. {
  459. tComponentInfoPtr pCIToRestore;
  460. // This component is zoomed on a monitor that already has a zoomed
  461. // component. Compare this component and the component already on the
  462. // monitor. The one that was there before is the one that stays. The one
  463. // that shouldn't be there is the one that gets restored.
  464. if ((iPreviousMonitorIndexOfComponent == iCurrentMonitorIndexOfComponent) && pCI->ciVisible)
  465. pCIToRestore = pComponentInfo + zoomedComponentIndices[iCurrentMonitorIndexOfComponent];
  466. else
  467. pCIToRestore = pCI;
  468. pCIToRestore->ciPosition.iLeft = pCIToRestore->ciStateInfo.iLeft;
  469. pCIToRestore->ciPosition.iTop = pCIToRestore->ciStateInfo.iTop;
  470. pCIToRestore->ciPosition.dwWidth = pCIToRestore->ciStateInfo.dwWidth;
  471. pCIToRestore->ciPosition.dwHeight = pCIToRestore->ciStateInfo.dwHeight;
  472. pCIToRestore->ciPosition.izIndex = COMPONENT_TOP;
  473. pCIToRestore->ciItemState = IS_NORMAL;
  474. }
  475. // If the component is zoomed also write out the COMPSTATEINFO.
  476. if (IsZoomedState(pCI->ciItemState))
  477. {
  478. zoomedComponentIndices[iCurrentMonitorIndexOfComponent] = i;
  479. }
  480. }
  481. }
  482. }
  483. WriteAllComponents(regKeyDesktop, pComponentInfo, dwComponentCount);
  484. LocalFree(pComponentInfo);
  485. }
  486. if (bRepositionedComponent)
  487. {
  488. SHELLSTATE ss;
  489. SetDesktopFlags(COMPONENTS_DIRTY, COMPONENTS_DIRTY);
  490. SHGetSetSettings(&ss, SSF_DESKTOPHTML, FALSE);
  491. // Refresh only if AD is turned on.
  492. if(ss.fDesktopHTML)
  493. {
  494. // 98/09/22 #182982 vtan: Use dynamic HTML by default to refresh.
  495. // Only disallow usage when specifically told to by a flag.
  496. PokeWebViewDesktop(AD_APPLY_FORCE | AD_APPLY_HTMLGEN | AD_APPLY_REFRESH);
  497. }
  498. }
  499. }
  500. ApplyCurrentMonitorArray();
  501. }
  502. return bRepositionedComponent;
  503. }