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.

2443 lines
78 KiB

  1. #include "stdafx.h"
  2. #include "icwcfg.h"
  3. #pragma hdrstop
  4. EXTERN_C const TCHAR c_szPatterns[] = TEXT("patterns");
  5. EXTERN_C const TCHAR c_szBackgroundPreview2[] = TEXT("BackgroundPreview2");
  6. EXTERN_C const TCHAR c_szComponentPreview[] = TEXT("ComponentPreview");
  7. EXTERN_C const TCHAR c_szRegDeskHtmlProp[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Controls Folder\\Display\\shellex\\PropertySheetHandlers\\DeskHtmlExt");
  8. EXTERN_C const TCHAR c_szWallPaperDir[] = TEXT("WallPaperDir");
  9. // 98/10/01 vtan: Added local function prototypes.
  10. // Some of these functions are commented out. The linker may not be smart
  11. // enough to strip the dead code so this is done manually. These prototypes
  12. // will allow the code to compile but it won't link. If you get linker
  13. // errors, uncomment the desired function and recompile. It should then link.
  14. // Point arithmetic
  15. void SetPt (POINT& pt, LONG x, LONG y);
  16. void OffsetPt (POINT& pt, LONG dh, LONG dv);
  17. // Virtual screen calculation
  18. BOOL CALLBACK GDIToTridentEnumProc (HMONITOR hMonitor, HDC hDC, RECT* rcMonitor, LPARAM lpUserData);
  19. void CalculateVirtualScreen (RECT& rcVirtualScreen);
  20. // GDI point to Trident point co-ordinate mapping
  21. void GDIToTrident (int& leftCoordinate, int& topCoordinate);
  22. void GDIToTrident (POINT& pt);
  23. void GDIToTrident (RECT& r);
  24. void GDIToTrident (HRGN hRgn);
  25. void TridentToGDI (int& leftCoordinate, int& topCoordinate);
  26. void TridentToGDI (POINT& pt);
  27. void TridentToGDI (RECT& r);
  28. void TridentToGDI (HRGN hRgn);
  29. // Component position validation
  30. BOOL CALLBACK ValidateComponentPositionEnumProc (HMONITOR hMonitor, HDC hdcMonitor, RECT* r, LPARAM lParam);
  31. void GetNextComponentPosition (COMPPOS *pcp)
  32. {
  33. int iScreenWidth, iScreenHeight, iBorderSize;
  34. DWORD dwComponentPosition, dwComponentLayer, dwRegDataScratch;
  35. HKEY hKey;
  36. RECT rcScreen;
  37. TCHAR lpszDeskcomp[MAX_PATH];
  38. TBOOL(SystemParametersInfo(SPI_GETWORKAREA, 0, &rcScreen, false));
  39. // 99/04/13 vtan: A result of zero-width or zero-height occurred on a machine.
  40. // Make a defensive stand against this and assert that this happened but also
  41. // handle this cause so that division by zero doesn't happen.
  42. iScreenWidth = rcScreen.right - rcScreen.left;
  43. iScreenHeight = rcScreen.bottom - rcScreen.top;
  44. iBorderSize = GetSystemMetrics(SM_CYSMCAPTION);
  45. ASSERT(iScreenWidth > 0); // get vtan
  46. ASSERT(iScreenHeight > 0); // if any of
  47. ASSERT(iBorderSize > 0); // these occur
  48. if ((iScreenWidth <= 0) || (iScreenHeight <= 0) || (iBorderSize <= 0))
  49. {
  50. pcp->iLeft = pcp->iTop = 0;
  51. pcp->dwWidth = MYCURHOME_WIDTH;
  52. pcp->dwHeight = MYCURHOME_HEIGHT;
  53. }
  54. else
  55. {
  56. // Get the number of components positioned. If no such registry key exists
  57. // or an error occurs then use 0.
  58. GetRegLocation(lpszDeskcomp, SIZECHARS(lpszDeskcomp), REG_DESKCOMP_GENERAL, NULL);
  59. dwComponentPosition = 0;
  60. if (RegCreateKeyEx(HKEY_CURRENT_USER, lpszDeskcomp, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &hKey, &dwRegDataScratch) == ERROR_SUCCESS)
  61. {
  62. DWORD regDataSize;
  63. regDataSize = sizeof(dwComponentPosition);
  64. TW32(SHQueryValueEx(hKey, REG_VAL_GENERAL_CCOMPPOS, NULL, &dwRegDataScratch, &dwComponentPosition, &regDataSize));
  65. TW32(RegCloseKey(hKey));
  66. }
  67. // Compute the layer we live on (see below).
  68. dwComponentLayer = dwComponentPosition / (COMPONENT_PER_ROW * COMPONENT_PER_COL);
  69. if (((dwComponentLayer * iBorderSize) > (DWORD)(iScreenWidth / (COMPONENT_PER_ROW + 1))) ||
  70. ((dwComponentLayer * iBorderSize) > (DWORD)(iScreenHeight / (COMPONENT_PER_COL + 1))))
  71. {
  72. int iLayerModulo;
  73. // 99/04/29 vtan: It's possible for SystemParametersInfo(SPI_GETWORKAREA) to
  74. // return a work area that's small horizontally. Here's a repro scenario for
  75. // that.
  76. // 1. Set screen resolution 1280 x 1024.
  77. // 2. Move the taskbar to the left of the screen.
  78. // 3. Grow the taskbar to the right until the center of the screen.
  79. // 4. Open display control panel.
  80. // 5. Go to "Settings" tab.
  81. // 6. Change monitor resolution to 640x480.
  82. // 7. Click either "OK" or "Apply".
  83. // 8. BOOM - divide zero.
  84. iLayerModulo = (iScreenWidth / (COMPONENT_PER_ROW + 1) / iBorderSize);
  85. if (iLayerModulo != 0)
  86. dwComponentLayer %= iLayerModulo;
  87. }
  88. // Compute the position. Assuming 3 components per row,
  89. // and 2 per column, we position components thusly:
  90. //
  91. // +-------+
  92. // |x 4 2 0|
  93. // |x 5 3 1| <-- screen, divided into 4x3 block coordinates
  94. // |x x x x|
  95. // +-------+
  96. //
  97. // The 6th component sits in a new layer, offset down
  98. // and to the left of component 0 by the amount iBorder.
  99. //
  100. // The first calculation for iLeft and iTop determines the
  101. // block coordinate value (for instance, component 0 would
  102. // be at block coordinate value [3,0] and component 1 at [3,1]).
  103. //
  104. // The second calculation turns the block coordinate into
  105. // a screen coordinate.
  106. //
  107. // The third calculation adjusts for the border (always down and
  108. // to the right) and the layers (always down and to the left).
  109. pcp->iLeft = COMPONENT_PER_ROW - ((dwComponentPosition / COMPONENT_PER_COL) % COMPONENT_PER_ROW); // 3 3 2 2 1 1 3 3 2 2 1 1 ...
  110. pcp->iLeft *= (iScreenWidth / (COMPONENT_PER_ROW + 1));
  111. pcp->iLeft += iBorderSize - (dwComponentLayer * iBorderSize);
  112. pcp->iTop = dwComponentPosition % COMPONENT_PER_COL; // 0 1 0 1 0 1 ...
  113. pcp->iTop *= (iScreenHeight / (COMPONENT_PER_COL + 1));
  114. pcp->iTop += iBorderSize + (dwComponentLayer * iBorderSize);
  115. pcp->iTop += GET_CYCAPTION; //vtan: Added this to allow for the title area of the component window
  116. pcp->dwWidth = (iScreenWidth / (COMPONENT_PER_ROW + 1)) - 2 * iBorderSize;
  117. pcp->dwHeight = (iScreenHeight / (COMPONENT_PER_COL + 1)) - 2 * iBorderSize;
  118. }
  119. if (IS_BIDI_LOCALIZED_SYSTEM())
  120. {
  121. pcp->iLeft = iScreenWidth - (pcp->iLeft + pcp->dwWidth);
  122. }
  123. }
  124. void IncrementComponentsPositioned (void)
  125. {
  126. DWORD dwRegDataScratch;
  127. HKEY hKey;
  128. TCHAR lpszDeskcomp[MAX_PATH];
  129. // Increment the registry count. If no such count exists create it.
  130. GetRegLocation(lpszDeskcomp, SIZECHARS(lpszDeskcomp), REG_DESKCOMP_GENERAL, NULL);
  131. if (RegCreateKeyEx(HKEY_CURRENT_USER, lpszDeskcomp, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &hKey, &dwRegDataScratch) == ERROR_SUCCESS)
  132. {
  133. DWORD dwComponentPosition, regDataSize;
  134. regDataSize = sizeof(dwComponentPosition);
  135. dwComponentPosition = 0;
  136. TW32(SHQueryValueEx(hKey, REG_VAL_GENERAL_CCOMPPOS, NULL, &dwRegDataScratch, &dwComponentPosition, &regDataSize));
  137. ++dwComponentPosition;
  138. TW32(RegSetValueEx(hKey, REG_VAL_GENERAL_CCOMPPOS, 0, REG_DWORD, reinterpret_cast<unsigned char*>(&dwComponentPosition), sizeof(dwComponentPosition)));
  139. TW32(RegCloseKey(hKey));
  140. }
  141. }
  142. // vtan: Point arithmetic functions. Simple. It may be worth
  143. // converting these to inline C++ functions or macros if they
  144. // get used a lot.
  145. void SetPt (POINT& pt, LONG x, LONG y)
  146. {
  147. pt.x = x;
  148. pt.y = y;
  149. }
  150. void OffsetPt (POINT& pt, LONG dh, LONG dv)
  151. {
  152. pt.x += dh;
  153. pt.y += dv;
  154. }
  155. BOOL CALLBACK GDIToTridentEnumProc (HMONITOR hMonitor, HDC hDC, RECT* rcMonitor, LPARAM lpUserData)
  156. {
  157. RECT* prcNew, rcOld;
  158. prcNew = reinterpret_cast<RECT*>(lpUserData);
  159. // Documentation for UnionRect does not specify whether the
  160. // RECT structures passed must be distinct. To be safe they
  161. // are passed as distinct structures.
  162. TBOOL(CopyRect(&rcOld, prcNew));
  163. TBOOL(UnionRect(prcNew, &rcOld, rcMonitor));
  164. return(TRUE);
  165. }
  166. void CalculateVirtualScreen (RECT& rcVirtualScreen)
  167. // vtan: Calculates the virtual screen in GDI co-ordinates for
  168. // use in converting co-ordinates from trident scheme to GDI
  169. // scheme.
  170. {
  171. TBOOL(SetRectEmpty(&rcVirtualScreen));
  172. TBOOL(EnumDisplayMonitors(NULL, NULL, GDIToTridentEnumProc, reinterpret_cast<LPARAM>(&rcVirtualScreen)));
  173. }
  174. void GDIToTrident (int& leftCoordinate, int& topCoordinate)
  175. {
  176. RECT rcVirtualScreen;
  177. CalculateVirtualScreen(rcVirtualScreen);
  178. leftCoordinate -= rcVirtualScreen.left;
  179. topCoordinate -= rcVirtualScreen.top;
  180. }
  181. /*
  182. void GDIToTrident (POINT& pt)
  183. {
  184. RECT rcVirtualScreen;
  185. CalculateVirtualScreen(rcVirtualScreen);
  186. OffsetPt(pt, -rcVirtualScreen.left, -rcVirtualScreen.top);
  187. }
  188. */
  189. void GDIToTrident (RECT& rc)
  190. {
  191. RECT rcVirtualScreen;
  192. CalculateVirtualScreen(rcVirtualScreen);
  193. TBOOL(OffsetRect(&rc, -rcVirtualScreen.left, -rcVirtualScreen.top));
  194. }
  195. void GDIToTrident (HRGN hRgn)
  196. {
  197. RECT rcVirtualScreen;
  198. CalculateVirtualScreen(rcVirtualScreen);
  199. TBOOL(OffsetRgn(hRgn, -rcVirtualScreen.left, -rcVirtualScreen.top));
  200. }
  201. /*
  202. void TridentToGDI (int& leftCoordinate, int& topCoordinate)
  203. {
  204. RECT rcVirtualScreen;
  205. CalculateVirtualScreen(rcVirtualScreen);
  206. leftCoordinate += rcVirtualScreen.left;
  207. topCoordinate += rcVirtualScreen.top;
  208. }
  209. */
  210. /*
  211. void TridentToGDI (POINT& pt)
  212. {
  213. RECT rcVirtualScreen;
  214. CalculateVirtualScreen(rcVirtualScreen);
  215. OffsetPt(pt, +rcVirtualScreen.left, +rcVirtualScreen.top);
  216. }
  217. */
  218. void TridentToGDI (RECT& rc)
  219. {
  220. RECT rcVirtualScreen;
  221. CalculateVirtualScreen(rcVirtualScreen);
  222. TBOOL(OffsetRect(&rc, +rcVirtualScreen.left, +rcVirtualScreen.top));
  223. }
  224. /*
  225. void TridentToGDI (HRGN hRgn)
  226. {
  227. RECT rcVirtualScreen;
  228. CalculateVirtualScreen(rcVirtualScreen);
  229. (BOOL)OffsetRgn(hRgn, +rcVirtualScreen.left, +rcVirtualScreen.top);
  230. }
  231. */
  232. // 98/08/14 vtan #196180, #196185: The following code validates
  233. // a new component's position within the current desktop area. This
  234. // allows a component to have co-ordinates that seem to be unusual
  235. // on a single monitor system (such as negative co-ordinates).
  236. class CRGN
  237. {
  238. public:
  239. CRGN (void) { mRgn = CreateRectRgn(0, 0, 0, 0); }
  240. CRGN (const RECT& rc) { mRgn = CreateRectRgnIndirect(&rc); }
  241. ~CRGN (void) { TBOOL(DeleteObject(mRgn)); }
  242. operator HRGN (void) const { return(mRgn); }
  243. void SetRegion (const RECT& rc) { TBOOL(SetRectRgn(mRgn, rc.left, rc.top, rc.right, rc.bottom)); }
  244. private:
  245. HRGN mRgn;
  246. };
  247. typedef struct
  248. {
  249. bool bAllowEntireDesktopRegion;
  250. int iMonitorCount;
  251. CRGN hRgn;
  252. int iWorkAreaCount;
  253. RECT *prcWorkAreaRects;
  254. } tDesktopRegion;
  255. void ListView_GetWorkAreasAsGDI (HWND hWndListView, int iWorkAreaCount, RECT *prcWorkAreas)
  256. {
  257. int i;
  258. ListView_GetWorkAreas(hWndListView, iWorkAreaCount, prcWorkAreas);
  259. for (i = 0; i < iWorkAreaCount; ++i)
  260. {
  261. TridentToGDI(prcWorkAreas[i]);
  262. }
  263. }
  264. int CopyMostSuitableListViewWorkAreaRect (const RECT *pcrcMonitor, int iListViewWorkAreaCount, const RECT *pcrcListViewWorkAreaRects, RECT *prcWorkArea)
  265. {
  266. int i, iResult;
  267. const RECT *pcrcRects;
  268. // This function given a rectangle for a GDI monitor (typically the monitor's
  269. // work area) as well as given the desktop's list view work area rectangle
  270. // array (obtained by ListView_GetWorkArea()) will search the list view
  271. // work area array to find a match for the GDI monitor and use the list view
  272. // work area rectangle instead as this has docked toolbar information which
  273. // GDI does not have access to.
  274. // This function works on the principle that the list view rectangle is
  275. // always a complete subset of the GDI monitor rectangle which is true.
  276. // The list view rectangle may be smaller but it should never be bigger.
  277. // It's ok to pass a NULL pcrcListViewWorkAreaRects as long as
  278. // iListViewWorkAreaCount is 0.
  279. pcrcRects = pcrcListViewWorkAreaRects;
  280. iResult = -1;
  281. i = 0;
  282. while ((iResult == -1) && (i < iListViewWorkAreaCount))
  283. {
  284. RECT rcIntersection;
  285. (BOOL)IntersectRect(&rcIntersection, pcrcMonitor, pcrcRects);
  286. if (EqualRect(&rcIntersection, pcrcRects) != 0)
  287. {
  288. iResult = i;
  289. }
  290. else
  291. {
  292. ++pcrcRects;
  293. ++i;
  294. }
  295. }
  296. if (iResult < 0)
  297. {
  298. TraceMsg(TF_WARNING, "CopyMostSuitableListViewWorkAreaRect() unable to find matching list view rectangle for GDI monitor rectangle");
  299. TBOOL(CopyRect(prcWorkArea, pcrcMonitor));
  300. }
  301. else
  302. {
  303. TBOOL(CopyRect(prcWorkArea, &pcrcListViewWorkAreaRects[iResult]));
  304. }
  305. return(iResult);
  306. }
  307. BOOL GetMonitorInfoWithCompensation (int iMonitorCount, HMONITOR hMonitor, MONITORINFO *pMonitorInfo)
  308. {
  309. BOOL fResult;
  310. // 99/05/20 #338585 vtan: Transplanted the logic explained in the
  311. // comment below for #211510 from GetZoomRect to here so that other
  312. // functions can share the behavior. Remember that this ONLY applies
  313. // a single monitor system where there is part of the monitor's
  314. // rectangle excluded by a docked toolbar on the left or top of the
  315. // monitor. A very specific case.
  316. // 98/10/30 #211510 vtan: Oops. If the task bar is at the top of the
  317. // screen and there is only one monitor then the shell returns a work
  318. // area starting at (0, 0) instead of (0, 28); the same applies when
  319. // the task bar is at the left of the screen; this does NOT occur in
  320. // a multiple monitor setting. In the single monitor case GDI returns
  321. // a work area starting at (0, 28) so this code checks for the case
  322. // where there is a single monitor and offsets the GDI information to
  323. // (0, 0) so that it matches the shell work area which is compared
  324. // against in the while loop.
  325. fResult = GetMonitorInfo(hMonitor, pMonitorInfo);
  326. if ((fResult != 0) && (iMonitorCount == 1))
  327. {
  328. TBOOL(OffsetRect(&pMonitorInfo->rcWork, -pMonitorInfo->rcWork.left, -pMonitorInfo->rcWork.top));
  329. }
  330. return(fResult);
  331. }
  332. // MonitorCountEnumProc()'s body is located in adjust.cpp
  333. BOOL CALLBACK MonitorCountEnumProc (HMONITOR hMonitor, HDC dc, RECT *rc, LPARAM data);
  334. BOOL CALLBACK ValidateComponentPositionEnumProc (HMONITOR hMonitor, HDC hdcMonitor, RECT* prc, LPARAM lpUserData)
  335. {
  336. HRGN hRgnDesktop;
  337. HMONITOR hMonitorTopLeft, hMonitorTopRight;
  338. POINT ptAbove;
  339. RECT rcMonitor;
  340. MONITORINFO monitorInfo;
  341. tDesktopRegion *pDesktopRegion;
  342. pDesktopRegion = reinterpret_cast<tDesktopRegion*>(lpUserData);
  343. monitorInfo.cbSize = sizeof(monitorInfo);
  344. if (GetMonitorInfoWithCompensation(pDesktopRegion->iMonitorCount, hMonitor, &monitorInfo) != 0)
  345. {
  346. TINT(CopyMostSuitableListViewWorkAreaRect(&monitorInfo.rcWork, pDesktopRegion->iWorkAreaCount, pDesktopRegion->prcWorkAreaRects, &rcMonitor));
  347. }
  348. else
  349. {
  350. TBOOL(CopyRect(&rcMonitor, prc));
  351. }
  352. // If this monitor does not have a monitor above it then
  353. // make the monitor rectangle one pixel lower from the
  354. // top.
  355. CRGN hRgnMonitor(rcMonitor);
  356. if (!pDesktopRegion->bAllowEntireDesktopRegion)
  357. {
  358. // This bizarre little algorithm calculates the margins of the current
  359. // monitor that do not have a monitor above them. The rcExclude is the
  360. // the final rectangle that contains this information and is one pixel
  361. // high. This calculation is only valid if the entire desktop region
  362. // has been DISALLOWED (not zooming a component).
  363. // Note that the algorithm fails if there is a monitor that is above
  364. // this one but is contained within the confines of it. For example,
  365. // this monitor is at 1024x768 and the one above is at 640x480 and
  366. // centered. In this case it should be possible to drop the component
  367. // on the exact zero pixel point but this case is disallowed due to
  368. // this fault. No big deal.
  369. SetPt(ptAbove, rcMonitor.left, rcMonitor.top - 1);
  370. hMonitorTopLeft = MonitorFromPoint(ptAbove, MONITOR_DEFAULTTONULL);
  371. SetPt(ptAbove, rcMonitor.right, rcMonitor.top - 1);
  372. hMonitorTopRight = MonitorFromPoint(ptAbove, MONITOR_DEFAULTTONULL);
  373. if ((hMonitorTopLeft == NULL) && (hMonitorTopRight == NULL))
  374. {
  375. // No monitor above this one
  376. ++rcMonitor.top;
  377. hRgnMonitor.SetRegion(rcMonitor);
  378. }
  379. else if (hMonitorTopLeft != hMonitorTopRight)
  380. {
  381. RECT rcExclude;
  382. // Either one or two different monitors above this one
  383. // == case is the same monitor completely covers this
  384. // monitor.
  385. TBOOL(SetRect(&rcExclude, rcMonitor.left, rcMonitor.top, rcMonitor.right, rcMonitor.top + 1));
  386. if (hMonitorTopLeft != NULL)
  387. {
  388. TBOOL(GetMonitorInfoWithCompensation(pDesktopRegion->iMonitorCount, hMonitorTopLeft, &monitorInfo));
  389. rcExclude.left = monitorInfo.rcWork.right + 1;
  390. }
  391. if (hMonitorTopRight != NULL)
  392. {
  393. TBOOL(GetMonitorInfoWithCompensation(pDesktopRegion->iMonitorCount, hMonitorTopRight, &monitorInfo));
  394. rcExclude.right = monitorInfo.rcWork.left;
  395. }
  396. CRGN hRgnExclude(rcExclude);
  397. TINT(CombineRgn(hRgnMonitor, hRgnMonitor, hRgnExclude, RGN_DIFF));
  398. }
  399. }
  400. hRgnDesktop = pDesktopRegion->hRgn;
  401. TINT(CombineRgn(hRgnDesktop, hRgnDesktop, hRgnMonitor, RGN_OR));
  402. return(true);
  403. }
  404. void ValidateComponentPosition (COMPPOS *pcp, DWORD dwComponentState, int iComponentType, bool *pbChangedPosition, bool *pbChangedSize)
  405. {
  406. bool bChangedPosition, bChangedSize;
  407. HRGN hRgnDesktop;
  408. HWND hWndDesktopListView, hWndShell, hWndShellChild;
  409. RECT rcComponent, rcComponentTop;
  410. tDesktopRegion desktopRegion;
  411. COMPPOS defaultComponentPosition;
  412. bChangedPosition = bChangedSize = false;
  413. GetNextComponentPosition(&defaultComponentPosition);
  414. GDIToTrident(defaultComponentPosition.iLeft, defaultComponentPosition.iTop);
  415. // If the component has default left or top then give it the next
  416. // default component position.
  417. if ((pcp->iLeft == COMPONENT_DEFAULT_LEFT) && (pcp->iTop == COMPONENT_DEFAULT_TOP))
  418. {
  419. pcp->iLeft = defaultComponentPosition.iLeft;
  420. pcp->iTop = defaultComponentPosition.iTop;
  421. IncrementComponentsPositioned();
  422. bChangedPosition = true;
  423. }
  424. // If the component has default width or height then give it the
  425. // next default component size unless it is type COMP_TYPE_PICTURE
  426. // 98/10/02 #222449 vtan: Only change the size of an unpositioned
  427. // component if it's not a picture.
  428. if ((pcp->dwWidth == COMPONENT_DEFAULT_WIDTH) && (pcp->dwHeight == COMPONENT_DEFAULT_HEIGHT) && (iComponentType != COMP_TYPE_PICTURE))
  429. {
  430. pcp->dwWidth = defaultComponentPosition.dwWidth;
  431. pcp->dwHeight = defaultComponentPosition.dwHeight;
  432. bChangedSize = false;
  433. }
  434. // Make sure that the top line of the component is visible or at
  435. // least one pixel below the top most part of a virtual screen.
  436. // Check to see if the component has a negative width and height or
  437. // a width and height that is too small. The only exception to this
  438. // is if the component is a picture.
  439. desktopRegion.bAllowEntireDesktopRegion = IsZoomedState(dwComponentState);
  440. if (iComponentType != COMP_TYPE_PICTURE)
  441. {
  442. if (static_cast<int>(pcp->dwWidth) < 10)
  443. {
  444. pcp->dwWidth = defaultComponentPosition.dwWidth;
  445. bChangedSize = false;
  446. }
  447. if (static_cast<int>(pcp->dwHeight) < 10)
  448. {
  449. pcp->dwHeight= defaultComponentPosition.dwHeight;
  450. bChangedSize = false;
  451. }
  452. }
  453. TBOOL(SetRect(&rcComponent, pcp->iLeft, pcp->iTop, pcp->iLeft + pcp->dwWidth, pcp->iTop + pcp->dwHeight));
  454. TBOOL(CopyRect(&rcComponentTop, &rcComponent));
  455. rcComponentTop.bottom = rcComponentTop.top + 1;
  456. // Before calculating the desktopRegion as a region by using GDI calls
  457. // get the List View work area which will have information about docked
  458. // toolbars in addition to the taskbar which is the only thing that GDI
  459. // has. This will allow this function to invalidate regions occupied by
  460. // toolbars also.
  461. desktopRegion.iWorkAreaCount = 0;
  462. desktopRegion.prcWorkAreaRects = NULL;
  463. hWndDesktopListView = NULL;
  464. hWndShell = GetShellWindow();
  465. if (hWndShell != NULL)
  466. {
  467. hWndShellChild = GetWindow(hWndShell, GW_CHILD);
  468. if (hWndShellChild != NULL)
  469. {
  470. hWndDesktopListView = FindWindowEx(hWndShellChild, NULL, WC_LISTVIEW, NULL);
  471. }
  472. }
  473. if (hWndDesktopListView != NULL)
  474. {
  475. DWORD dwProcessID;
  476. GetWindowThreadProcessId(hWndDesktopListView, &dwProcessID);
  477. if (GetCurrentProcessId() == dwProcessID)
  478. {
  479. ListView_GetNumberOfWorkAreas(hWndDesktopListView, &desktopRegion.iWorkAreaCount);
  480. desktopRegion.prcWorkAreaRects = reinterpret_cast<RECT*>(LocalAlloc(GPTR, desktopRegion.iWorkAreaCount * sizeof(desktopRegion.prcWorkAreaRects[0])));
  481. ListView_GetWorkAreasAsGDI(hWndDesktopListView, desktopRegion.iWorkAreaCount, desktopRegion.prcWorkAreaRects);
  482. }
  483. }
  484. CRGN hRgnComponentTop(rcComponentTop), hRgnResult;
  485. desktopRegion.iMonitorCount = 0;
  486. TBOOL(EnumDisplayMonitors(NULL, NULL, MonitorCountEnumProc, reinterpret_cast<LPARAM>(&desktopRegion.iMonitorCount)));
  487. TBOOL(EnumDisplayMonitors(NULL, NULL, ValidateComponentPositionEnumProc, reinterpret_cast<LPARAM>(&desktopRegion)));
  488. hRgnDesktop = desktopRegion.hRgn;
  489. GDIToTrident(hRgnDesktop);
  490. // 99/03/23 #266412 vtan: Make sure that the top pixel of the component is within
  491. // the visible desktop. This allows the deskmovr to be positioned over the
  492. // component and therefore allows it to be moved. If the deskmovr cannot be
  493. // positioned over it then "snap" the component back into the visible region
  494. // to a maximum best fit algorithm.
  495. if (CombineRgn(hRgnResult, hRgnDesktop, hRgnComponentTop, RGN_AND) == NULLREGION)
  496. {
  497. LONG lDeltaX, lDeltaY;
  498. HMONITOR hMonitorNearest;
  499. RECT rcComponentGDI, rcMonitorWork, rcIntersection;
  500. MONITORINFO monitorInfo;
  501. TBOOL(CopyRect(&rcComponentGDI, &rcComponent));
  502. TridentToGDI(rcComponentGDI);
  503. hMonitorNearest = MonitorFromRect(&rcComponentGDI, MONITOR_DEFAULTTONEAREST);
  504. ASSERT(hMonitorNearest != NULL);
  505. monitorInfo.cbSize = sizeof(monitorInfo);
  506. TBOOL(GetMonitorInfoWithCompensation(desktopRegion.iMonitorCount, hMonitorNearest, &monitorInfo));
  507. TINT(CopyMostSuitableListViewWorkAreaRect(&monitorInfo.rcWork, desktopRegion.iWorkAreaCount, desktopRegion.prcWorkAreaRects, &rcMonitorWork));
  508. ++rcMonitorWork.top;
  509. lDeltaX = lDeltaY = 0;
  510. if (rcComponentGDI.left < rcMonitorWork.left)
  511. lDeltaX = rcMonitorWork.left - rcComponentGDI.left;
  512. if (rcComponentGDI.top < rcMonitorWork.top)
  513. lDeltaY = rcMonitorWork.top - rcComponentGDI.top;
  514. if (rcComponentGDI.right > rcMonitorWork.right)
  515. lDeltaX = rcMonitorWork.right - rcComponentGDI.right;
  516. if (rcComponentGDI.bottom > rcMonitorWork.bottom)
  517. lDeltaY = rcMonitorWork.bottom - rcComponentGDI.bottom;
  518. TBOOL(OffsetRect(&rcComponentGDI, lDeltaX, lDeltaY));
  519. TBOOL(IntersectRect(&rcIntersection, &rcComponentGDI, &rcMonitorWork));
  520. GDIToTrident(rcIntersection);
  521. pcp->iLeft = rcIntersection.left;
  522. pcp->iTop = rcIntersection.top;
  523. pcp->dwWidth = rcIntersection.right - rcIntersection.left;
  524. pcp->dwHeight = rcIntersection.bottom - rcIntersection.top;
  525. bChangedPosition = bChangedSize = true;
  526. }
  527. if (desktopRegion.prcWorkAreaRects != NULL)
  528. LocalFree(desktopRegion.prcWorkAreaRects);
  529. if (pbChangedPosition != NULL)
  530. *pbChangedPosition = bChangedPosition;
  531. if (pbChangedSize != NULL)
  532. *pbChangedSize = bChangedSize;
  533. }
  534. // 98/12/11 #250938 vtan: these two functions are lifted from
  535. // SHBrows2.cpp which is part of browseui.dll.
  536. EXTERN_C DWORD WINAPI IsSmartStart (void);
  537. #ifdef NEVER
  538. // For WinMillennium, we do not want to launch the ICW when active desktop is turned on because
  539. // we do not have a "My Current Homepage" desktop component. So, I am disabling the following code
  540. // This is the temporary fix for Mill bug # 98107 also.
  541. BOOL IsICWCompleted (void)
  542. {
  543. DWORD dwICWCompleted, dwICWSize;
  544. dwICWCompleted = 0;
  545. dwICWSize = sizeof(dwICWCompleted);
  546. TW32(SHGetValue(HKEY_CURRENT_USER, TEXT(ICW_REGPATHSETTINGS), TEXT(ICW_REGKEYCOMPLETED), NULL, &dwICWCompleted, &dwICWSize));
  547. // 99/01/15 #272829 vtan: This is a horrible hack!!! If ICW has
  548. // not been run but settings have been made manually then values
  549. // in HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Connections
  550. // exists with the values given. Look for the presence of a key
  551. // to resolve that settings are present but that ICW hasn't been
  552. // launched.
  553. // The ideal solution is to get ICW to make this determination
  554. // for us BUT TO NOT LAUNCH ICWCONN1.EXE IN THE PROCESS.
  555. // Currently it will only launch. There is no way to get the
  556. // desired result without a launch.
  557. // 99/02/01 #280138 vtan: Well the solution put in for #272829
  558. // doesn't work. So peeking at the CheckConnectionWizard()
  559. // source in inetcfg\export.cpp shows that it uses a
  560. // wininet.dll function to determine whether manually configured
  561. // internet settings exist. It also exports this function so
  562. // look for it and bind to it dynamically. This uses the
  563. // DELAY_LOAD macros in dllload.c
  564. if (dwICWCompleted == 0)
  565. {
  566. #define SMART_RUNICW TRUE
  567. #define SMART_QUITICW FALSE
  568. dwICWCompleted = BOOLIFY(IsSmartStart() == SMART_QUITICW);
  569. }
  570. return(dwICWCompleted != 0);
  571. }
  572. #else //NEVER
  573. BOOL IsICWCompleted (void)
  574. {
  575. return TRUE; //For Millennium we want to always return TRUE for this function.
  576. }
  577. #endif //NEVER
  578. void LaunchICW (void)
  579. {
  580. static bool sbCheckedICW = false;
  581. if (!sbCheckedICW && !IsICWCompleted())
  582. {
  583. HINSTANCE hICWInst;
  584. // Prevent an error in finding the ICW from causing this to
  585. // execute again and again and again.
  586. sbCheckedICW = true;
  587. hICWInst = LoadLibrary(TEXT("inetcfg.dll"));
  588. if (hICWInst != NULL)
  589. {
  590. PFNCHECKCONNECTIONWIZARD pfnCheckConnectionWizard;
  591. pfnCheckConnectionWizard = reinterpret_cast<PFNCHECKCONNECTIONWIZARD>(GetProcAddress(hICWInst, "CheckConnectionWizard"));
  592. if (pfnCheckConnectionWizard != NULL)
  593. {
  594. DWORD dwICWResult;
  595. // If the user cancels ICW then it needs to be launched
  596. // again. Allow this case.
  597. sbCheckedICW = false;
  598. pfnCheckConnectionWizard(ICW_LAUNCHFULL | ICW_LAUNCHMANUAL, &dwICWResult);
  599. }
  600. TBOOL(FreeLibrary(hICWInst));
  601. }
  602. }
  603. }
  604. BOOL IsLocalPicture (LPCTSTR pszURL)
  605. {
  606. return(!PathIsURL(pszURL) && IsUrlPicture(pszURL));
  607. }
  608. BOOL DisableUndisplayableComponents (IActiveDesktop *pIAD)
  609. {
  610. bool bHasVisibleNonLocalPicture;
  611. int iItemCount;
  612. // 98/12/16 vtan #250938: If ICW has not been run to completion then only
  613. // allow the user to show components that are local pictures of some sort.
  614. // If any components are not local pictures then hide these components,
  615. // tell the user why it happened and launch ICW.
  616. bHasVisibleNonLocalPicture = false;
  617. if (SUCCEEDED(pIAD->GetDesktopItemCount(&iItemCount, 0)))
  618. {
  619. int i;
  620. for (i = 0; i < iItemCount; ++i)
  621. {
  622. COMPONENT component;
  623. component.dwSize = sizeof(component);
  624. if (SUCCEEDED(pIAD->GetDesktopItem(i, &component, 0)) && (component.fChecked != 0))
  625. {
  626. bool bIsVisibleNonLocalPicture;
  627. TCHAR szComponentSource[INTERNET_MAX_URL_LENGTH];
  628. SHUnicodeToTChar(component.wszSource, szComponentSource, ARRAYSIZE(szComponentSource));
  629. bIsVisibleNonLocalPicture = !IsLocalPicture(szComponentSource);
  630. bHasVisibleNonLocalPicture = bHasVisibleNonLocalPicture || bIsVisibleNonLocalPicture;
  631. if (bIsVisibleNonLocalPicture)
  632. {
  633. component.fChecked = FALSE;
  634. THR(pIAD->ModifyDesktopItem(&component, COMP_ELEM_CHECKED));
  635. }
  636. }
  637. }
  638. }
  639. if (bHasVisibleNonLocalPicture)
  640. {
  641. // Apply the changes. This should recurse to CActiveDesktop::_SaveSettings()
  642. // but this code path is NOT taken because AD_APPLY_REFRESH is not passed in.
  643. // CActiveDesktop::_SaveSettings() calls this function!
  644. bHasVisibleNonLocalPicture = FAILED(pIAD->ApplyChanges(AD_APPLY_SAVE | AD_APPLY_HTMLGEN));
  645. // Notify the user what happened and launch ICW.
  646. ShellMessageBox(HINST_THISDLL, NULL, MAKEINTRESOURCE(IDS_COMP_ICW_DISABLE), MAKEINTRESOURCE(IDS_COMP_ICW_TITLE), MB_OK);
  647. LaunchICW();
  648. }
  649. return(bHasVisibleNonLocalPicture);
  650. }
  651. int GetIconCountForWorkArea(HWND hwndLV, LPCRECT prect, int crect, int iWorkAreaIndex)
  652. {
  653. int iCount;
  654. iCount = ListView_GetItemCount(hwndLV);
  655. if (crect > 1)
  656. {
  657. int i, iCountWorkArea = 0;
  658. for (i = 0; i < iCount; i++)
  659. {
  660. POINT pt;
  661. ListView_GetItemPosition(hwndLV, i, &pt);
  662. if (iWorkAreaIndex == GetWorkAreaIndexFromPoint(pt, prect, crect))
  663. iCountWorkArea++;
  664. }
  665. iCount = iCountWorkArea;
  666. }
  667. return iCount;
  668. }
  669. BOOL GetZoomRect(BOOL fFullScreen, BOOL fAdjustListview, int iTridentLeft, int iTridentTop, DWORD dwComponentWidth, DWORD dwComponentHeight, LPRECT prcZoom, LPRECT prcWork)
  670. {
  671. HWND hwndShell, hwndLV;
  672. int icWorkAreas = 0, iWAC;
  673. RECT rcWork[LV_MAX_WORKAREAS];
  674. hwndLV = NULL;
  675. hwndShell = GetShellWindow();
  676. if (hwndShell != NULL)
  677. {
  678. HWND hwndShellChild;
  679. hwndShellChild= GetWindow(hwndShell, GW_CHILD);
  680. if (hwndShellChild != NULL)
  681. {
  682. hwndLV = FindWindowEx(hwndShellChild, NULL, WC_LISTVIEW, NULL);
  683. }
  684. }
  685. //
  686. // First calculate the Work Areas and Work Area index for the component, then perform the
  687. // particular operation based on lCommand.
  688. //
  689. if (hwndLV) {
  690. DWORD dwpid;
  691. GetWindowThreadProcessId(hwndLV, &dwpid);
  692. // The listview doesn't thunk these messages so we can't do
  693. // this inter-process!
  694. if (dwpid == GetCurrentProcessId())
  695. {
  696. ListView_GetNumberOfWorkAreas(hwndLV, &icWorkAreas);
  697. if (icWorkAreas <= LV_MAX_WORKAREAS)
  698. ListView_GetWorkAreas(hwndLV, icWorkAreas, &rcWork);
  699. else
  700. hwndLV = NULL;
  701. } else {
  702. return FALSE;
  703. }
  704. }
  705. // 98/10/07 vtan: This used to use a variable icWorkAreasAdd.
  706. // Removed this variable and directly increment icWorkAreas.
  707. // This doesn't affect the call to ListView_SetWorkAreas()
  708. // below because in this case hwndLV is NULL.
  709. if (icWorkAreas == 0)
  710. {
  711. RECT rc;
  712. ++icWorkAreas;
  713. SystemParametersInfo(SPI_GETWORKAREA, 0, (PVOID)&rc, 0);
  714. rcWork[0] = rc;
  715. hwndLV = NULL;
  716. }
  717. // 98/10/02 #212654 vtan: Changed the calculation code to find a
  718. // rectangle to zoom the component to based on GDI co-ordinates.
  719. // The component is passed in trident co-ordinates which are
  720. // stored in a RECT and converted to GDI co-ordinates. The system
  721. // then locates the monitor which the component is on and if it
  722. // cannot find the monitor then defaults to the primary. The
  723. // dimensions of the monitor are used before converting back to
  724. // trident co-ordinates.
  725. int i, iMonitorCount;
  726. HMONITOR hMonitor;
  727. RECT rcComponentRect;
  728. MONITORINFO monitorInfo;
  729. iMonitorCount = 0;
  730. TBOOL(EnumDisplayMonitors(NULL, NULL, MonitorCountEnumProc, reinterpret_cast<LPARAM>(&iMonitorCount)));
  731. TBOOL(SetRect(&rcComponentRect, iTridentLeft, iTridentTop, iTridentLeft + dwComponentWidth, iTridentTop + dwComponentHeight));
  732. TridentToGDI(rcComponentRect);
  733. hMonitor = MonitorFromRect(&rcComponentRect, MONITOR_DEFAULTTOPRIMARY);
  734. ASSERT(hMonitor != NULL);
  735. monitorInfo.cbSize = sizeof(monitorInfo);
  736. TBOOL(GetMonitorInfoWithCompensation(iMonitorCount, hMonitor, &monitorInfo));
  737. GDIToTrident(monitorInfo.rcWork);
  738. // 99/05/19 #340772 vtan: Always try to key off work areas returned
  739. // by ListView_GetWorkAreas because these take into account docked
  740. // toolbars which GDI does not. In this case the listview work areas
  741. // will always be the same rectangle when intersected with the GDI
  742. // work area. Use this rule to determine which listview work area
  743. // to use as the basis for the zoom rectangle.
  744. i = CopyMostSuitableListViewWorkAreaRect(&monitorInfo.rcWork, icWorkAreas, rcWork, prcZoom);
  745. if (i < 0)
  746. {
  747. i = 0;
  748. }
  749. if (prcWork != NULL)
  750. {
  751. TBOOL(CopyRect(prcWork, prcZoom));
  752. }
  753. iWAC = i;
  754. if (!fFullScreen)
  755. {
  756. // For the split case we shrink the work area down temporarily to the smallest rectangle
  757. // that can bound the current number of icons. This will force the icons into that rectangle,
  758. // then restore it back to the way it was before. Finally, we set the size of the split
  759. // component to fill the rest of the space.
  760. if (hwndLV) {
  761. int iCount, iItemsPerColumn, icxWidth, iRightOld;
  762. DWORD dwSpacing;
  763. iCount = GetIconCountForWorkArea(hwndLV, rcWork, icWorkAreas, iWAC);
  764. // Decrement the count so that rounding works right
  765. if (iCount)
  766. iCount--;
  767. // Calculate the new width for the view rectangle
  768. dwSpacing = ListView_GetItemSpacing(hwndLV, FALSE);
  769. iItemsPerColumn = (rcWork[iWAC].bottom - rcWork[iWAC].top) / (HIWORD(dwSpacing));
  770. if (iItemsPerColumn)
  771. icxWidth = ((iCount / iItemsPerColumn) + 1) * (LOWORD(dwSpacing));
  772. else
  773. icxWidth = LOWORD(dwSpacing);
  774. // Don't let it get smaller than half the screen
  775. if (icxWidth > ((rcWork[iWAC].right - rcWork[iWAC].left) / 2))
  776. icxWidth = (rcWork[iWAC].right - rcWork[iWAC].left) / 2;
  777. if (fAdjustListview)
  778. {
  779. // Now take the old work area rectangle and shrink it to our new width
  780. iRightOld = rcWork[iWAC].right;
  781. rcWork[iWAC].right = rcWork[iWAC].left + icxWidth;
  782. ListView_SetWorkAreas(hwndLV, icWorkAreas, &rcWork);
  783. // Finally restore the old work area
  784. rcWork[iWAC].right = iRightOld;
  785. ListView_SetWorkAreas(hwndLV, icWorkAreas, &rcWork);
  786. }
  787. // Adjust the left coordinate of the zoom rect to reflect our calculated split amount
  788. // the rest of the screen.
  789. if (IS_BIDI_LOCALIZED_SYSTEM())
  790. {
  791. prcZoom->right -= icxWidth;
  792. }
  793. else
  794. {
  795. prcZoom->left += icxWidth;
  796. }
  797. } else {
  798. // Fallback case, if there is no listview use 20% of the screen for the icons.
  799. if (IS_BIDI_LOCALIZED_SYSTEM())
  800. {
  801. prcZoom->right -= ((prcZoom->right - prcZoom->left) * 2 / 10);
  802. }
  803. else
  804. {
  805. prcZoom->left += ((prcZoom->right - prcZoom->left) * 2 / 10);
  806. }
  807. }
  808. }
  809. return TRUE;
  810. }
  811. void ZoomComponent(COMPPOS * pcp, DWORD dwCurItemState, BOOL fAdjustListview)
  812. {
  813. RECT rcZoom;
  814. if (GetZoomRect((dwCurItemState & IS_FULLSCREEN), fAdjustListview, pcp->iLeft, pcp->iTop, pcp->dwWidth, pcp->dwHeight, &rcZoom, NULL))
  815. {
  816. // Copy the new Zoom rectangle over and put it on the bottom
  817. pcp->iLeft = rcZoom.left;
  818. pcp->iTop = rcZoom.top;
  819. pcp->dwWidth = rcZoom.right - rcZoom.left;
  820. pcp->dwHeight = rcZoom.bottom - rcZoom.top;
  821. pcp->izIndex = 0;
  822. }
  823. else
  824. {
  825. // Failure implies we couldn't get the zoom rectangle through inter-process calls. Set the
  826. // COMPONENTS_ZOOMDIRTY bit here so that when the desktop is refreshed we will recalculate
  827. // the zoom rectangles in-process inside of EnsureUpdateHTML.
  828. SetDesktopFlags(COMPONENTS_ZOOMDIRTY, COMPONENTS_ZOOMDIRTY);
  829. }
  830. }
  831. //
  832. // PositionComponent will assign a screen position and
  833. // make sure it fits on the screen.
  834. //
  835. void PositionComponent(COMPONENTA *pcomp, COMPPOS *pcp, int iCompType, BOOL fCheckItemState)
  836. {
  837. // vtan: Vastly simplified routine. The work is now done in
  838. // ValidateComponentPosition.
  839. if (ISZOOMED(pcomp))
  840. {
  841. if (fCheckItemState)
  842. {
  843. SetStateInfo(&pcomp->csiRestored, pcp, IS_NORMAL);
  844. SetStateInfo(&pcomp->csiOriginal, pcp, pcomp->dwCurItemState);
  845. }
  846. ZoomComponent(pcp, pcomp->dwCurItemState, FALSE);
  847. }
  848. else
  849. {
  850. ValidateComponentPosition(pcp, pcomp->dwCurItemState, iCompType, NULL, NULL);
  851. if (fCheckItemState)
  852. SetStateInfo(&pcomp->csiOriginal, pcp, pcomp->dwCurItemState);
  853. }
  854. }
  855. typedef struct _tagFILETYPEENTRY {
  856. DWORD dwFlag;
  857. int iFilterId;
  858. } FILETYPEENTRY;
  859. FILETYPEENTRY afte[] = {
  860. { GFN_URL, IDS_URL_FILTER, },
  861. { GFN_CDF, IDS_CDF_FILTER, },
  862. { GFN_LOCALHTM, IDS_HTMLDOC_FILTER, },
  863. { GFN_PICTURE, IDS_IMAGES_FILTER, },
  864. { GFN_LOCALMHTML, IDS_MHTML_FILTER, },
  865. };
  866. //
  867. // Opens either an HTML page or a picture.
  868. //
  869. BOOL GetFileName(HWND hdlg, LPTSTR pszFileName, int iSize, int iTypeId[], DWORD dwFlags[])
  870. {
  871. BOOL fRet = FALSE;
  872. if (dwFlags)
  873. {
  874. int i, iIndex, cchRead;
  875. TCHAR szFilter[MAX_PATH*4];
  876. //
  877. // Set the friendly name.
  878. //
  879. LPTSTR pchFilter = szFilter;
  880. int cchFilter = ARRAYSIZE(szFilter) - 2; // room for term chars
  881. for(iIndex = 0; dwFlags[iIndex]; iIndex++)
  882. {
  883. cchRead = LoadString(HINST_THISDLL, iTypeId[iIndex], pchFilter, cchFilter);
  884. pchFilter += cchRead + 1;
  885. cchFilter -= cchRead + 1;
  886. //
  887. // Append the file filters.
  888. //
  889. BOOL fAddedToString = FALSE;
  890. for (i=0; (cchFilter>0) && (i<ARRAYSIZE(afte)); i++)
  891. {
  892. if (dwFlags[iIndex] & afte[i].dwFlag)
  893. {
  894. if (fAddedToString)
  895. {
  896. *pchFilter++ = TEXT(';');
  897. cchFilter--;
  898. }
  899. cchRead = LoadString(HINST_THISDLL, afte[i].iFilterId,
  900. pchFilter, cchFilter);
  901. pchFilter += cchRead;
  902. cchFilter -= cchRead;
  903. fAddedToString = TRUE;
  904. }
  905. }
  906. *pchFilter++ = TEXT('\0');
  907. }
  908. //
  909. // Double-NULL terminate the string.
  910. //
  911. *pchFilter = TEXT('\0');
  912. TCHAR szBrowserDir[MAX_PATH];
  913. lstrcpy(szBrowserDir, pszFileName);
  914. PathRemoveFileSpec(szBrowserDir);
  915. TCHAR szBuf[MAX_PATH];
  916. LoadString(HINST_THISDLL, IDS_BROWSE, szBuf, ARRAYSIZE(szBuf));
  917. *pszFileName = TEXT('\0');
  918. OPENFILENAME ofn = {0};
  919. ofn.lStructSize = SIZEOF(ofn);
  920. ofn.hwndOwner = hdlg;
  921. ofn.hInstance = NULL;
  922. ofn.lpstrFilter = szFilter;
  923. ofn.lpstrCustomFilter = NULL;
  924. ofn.nFilterIndex = 1;
  925. ofn.nMaxCustFilter = 0;
  926. ofn.lpstrFile = pszFileName;
  927. ofn.nMaxFile = iSize;
  928. ofn.lpstrInitialDir = szBrowserDir;
  929. ofn.lpstrTitle = szBuf;
  930. ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST;
  931. ofn.lpfnHook = NULL;
  932. ofn.lpstrDefExt = NULL;
  933. ofn.lpstrFileTitle = NULL;
  934. fRet = GetOpenFileName(&ofn);
  935. }
  936. return fRet;
  937. }
  938. //
  939. // Convert a pattern string to a bottom-up array of DWORDs,
  940. // useful for BMP format files.
  941. //
  942. void PatternToDwords(LPTSTR psz, DWORD *pdwBits)
  943. {
  944. DWORD i, dwVal;
  945. //
  946. // Get eight groups of numbers separated by non-numeric characters.
  947. //
  948. for (i=0; i<8; i++)
  949. {
  950. dwVal = 0;
  951. if (*psz != TEXT('\0'))
  952. {
  953. //
  954. // Skip over any non-numeric characters.
  955. //
  956. while (*psz && (!(*psz >= TEXT('0') && *psz <= TEXT('9'))))
  957. {
  958. psz++;
  959. }
  960. //
  961. // Get the next series of digits.
  962. //
  963. while (*psz && (*psz >= TEXT('0') && *psz <= TEXT('9')))
  964. {
  965. dwVal = dwVal*10 + *psz++ - TEXT('0');
  966. }
  967. }
  968. pdwBits[7-i] = dwVal;
  969. }
  970. }
  971. //
  972. // Convert a pattern string to a top-down array of WORDs,
  973. // useful for CreateBitmap().
  974. //
  975. void PatternToWords(LPTSTR psz, WORD *pwBits)
  976. {
  977. WORD i, wVal;
  978. //
  979. // Get eight groups of numbers separated by non-numeric characters.
  980. //
  981. for (i=0; i<8; i++)
  982. {
  983. wVal = 0;
  984. if (*psz != TEXT('\0'))
  985. {
  986. //
  987. // Skip over any non-numeric characters.
  988. //
  989. while (*psz && (!(*psz >= TEXT('0') && *psz <= TEXT('9'))))
  990. {
  991. psz++;
  992. }
  993. //
  994. // Get the next series of digits.
  995. //
  996. while (*psz && ((*psz >= TEXT('0') && *psz <= TEXT('9'))))
  997. {
  998. wVal = wVal*10 + *psz++ - TEXT('0');
  999. }
  1000. }
  1001. pwBits[i] = wVal;
  1002. }
  1003. }
  1004. BOOL IsValidPattern(LPCTSTR pszPat)
  1005. {
  1006. BOOL fSawANumber = FALSE;
  1007. //
  1008. // We're mainly trying to filter multilingual upgrade cases
  1009. // where the text for "(None)" is unpredictable.
  1010. //
  1011. //
  1012. //
  1013. while (*pszPat)
  1014. {
  1015. if ((*pszPat < TEXT('0')) || (*pszPat > TEXT('9')))
  1016. {
  1017. //
  1018. // It's not a number, it better be a space.
  1019. //
  1020. if (*pszPat != TEXT(' '))
  1021. {
  1022. return FALSE;
  1023. }
  1024. }
  1025. else
  1026. {
  1027. fSawANumber = TRUE;
  1028. }
  1029. //
  1030. // We avoid the need for AnsiNext by only advancing on US TCHARs.
  1031. //
  1032. pszPat++;
  1033. }
  1034. //
  1035. // TRUE if we saw at least one digit and there were only digits and spaces.
  1036. //
  1037. return fSawANumber;
  1038. }
  1039. //
  1040. // Determines if the wallpaper can be supported in non-active desktop mode.
  1041. //
  1042. BOOL IsNormalWallpaper(LPCTSTR pszFileName)
  1043. {
  1044. BOOL fRet = TRUE;
  1045. if (pszFileName[0] == TEXT('\0'))
  1046. {
  1047. fRet = TRUE;
  1048. }
  1049. else
  1050. {
  1051. LPTSTR pszExt = PathFindExtension(pszFileName);
  1052. //Check for specific files that can be shown only in ActiveDesktop mode!
  1053. if((StrCmpIC(pszExt, TEXT(".GIF")) == 0) || // 368690: Strange, but we must compare 'i' in both caps and lower case.
  1054. (lstrcmpi(pszExt, TEXT(".JPG")) == 0) ||
  1055. (lstrcmpi(pszExt, TEXT(".JPE")) == 0) ||
  1056. (lstrcmpi(pszExt, TEXT(".JPEG")) == 0) ||
  1057. (lstrcmpi(pszExt, TEXT(".PNG")) == 0) ||
  1058. (lstrcmpi(pszExt, TEXT(".HTM")) == 0) ||
  1059. (lstrcmpi(pszExt, TEXT(".HTML")) == 0) ||
  1060. (lstrcmpi(pszExt, TEXT(".HTT")) == 0))
  1061. return FALSE;
  1062. //Everything else (including *.BMP files) are "normal" wallpapers
  1063. }
  1064. return fRet;
  1065. }
  1066. //
  1067. // Determines if the wallpaper is a picture (vs. HTML).
  1068. //
  1069. BOOL IsWallpaperPicture(LPCTSTR pszWallpaper)
  1070. {
  1071. BOOL fRet = TRUE;
  1072. if (pszWallpaper[0] == TEXT('\0'))
  1073. {
  1074. //
  1075. // Empty wallpapers count as empty pictures.
  1076. //
  1077. fRet = TRUE;
  1078. }
  1079. else
  1080. {
  1081. LPTSTR pszExt = PathFindExtension(pszWallpaper);
  1082. if ((lstrcmpi(pszExt, TEXT(".HTM")) == 0) ||
  1083. (lstrcmpi(pszExt, TEXT(".HTML")) == 0) ||
  1084. (lstrcmpi(pszExt, TEXT(".HTT")) == 0))
  1085. {
  1086. fRet = FALSE;
  1087. }
  1088. }
  1089. return fRet;
  1090. }
  1091. void OnDesktopSysColorChange(void)
  1092. {
  1093. static COLORREF clrBackground = 0xffffffff;
  1094. static COLORREF clrWindowText = 0xffffffff;
  1095. //Get the new colors!
  1096. COLORREF clrNewBackground = GetSysColor(COLOR_BACKGROUND);
  1097. COLORREF clrNewWindowText = GetSysColor(COLOR_WINDOWTEXT);
  1098. //Have we initialized these before?
  1099. if(clrBackground != 0xffffffff) //Have we initialized the statics yet?
  1100. {
  1101. // Our HTML file depends only on these two system colors.
  1102. // Check if either of them has changed!
  1103. // If not, no need to regenerate HTML file.
  1104. // This avoids infinite loop. And this is a nice optimization.
  1105. if((clrBackground == clrNewBackground) &&
  1106. (clrWindowText == clrNewWindowText))
  1107. return; //No need to do anything. Just return.
  1108. }
  1109. // Remember the new colors in the statics.
  1110. clrBackground = clrNewBackground;
  1111. clrWindowText = clrNewWindowText;
  1112. //
  1113. // The desktop got a WM_SYSCOLORCHANGE. We need to
  1114. // regenerate the HTML if there are any system colors
  1115. // showing on the desktop. Patterns and the desktop
  1116. // color are both based on system colors.
  1117. //
  1118. IActiveDesktop *pad;
  1119. if (SUCCEEDED(CActiveDesktop_InternalCreateInstance((LPUNKNOWN *)&pad, IID_IActiveDesktop)))
  1120. {
  1121. BOOL fRegenerateHtml = FALSE;
  1122. WCHAR szWallpaperW[INTERNET_MAX_URL_LENGTH];
  1123. if (SUCCEEDED(pad->GetWallpaper(szWallpaperW, ARRAYSIZE(szWallpaperW), 0)))
  1124. {
  1125. if (!*szWallpaperW)
  1126. {
  1127. //
  1128. // No wallpaper means the desktop color
  1129. // or a pattern is showing - we need to
  1130. // regenerate the desktop HTML.
  1131. //
  1132. fRegenerateHtml = TRUE;
  1133. }
  1134. else
  1135. {
  1136. TCHAR *pszWallpaper;
  1137. #ifdef UNICODE
  1138. pszWallpaper = szWallpaperW;
  1139. #else
  1140. CHAR szWallpaperA[INTERNET_MAX_URL_LENGTH];
  1141. SHUnicodeToAnsi(szWallpaperW, szWallpaperA, ARRAYSIZE(szWallpaperA));
  1142. pszWallpaper = szWallpaperA;
  1143. #endif
  1144. if (IsWallpaperPicture(pszWallpaper))
  1145. {
  1146. WALLPAPEROPT wpo = { SIZEOF(wpo) };
  1147. if (SUCCEEDED(pad->GetWallpaperOptions(&wpo, 0)))
  1148. {
  1149. if (wpo.dwStyle == WPSTYLE_CENTER)
  1150. {
  1151. //
  1152. // We have a centered picture,
  1153. // the pattern or desktop color
  1154. // could be leaking around the edges.
  1155. // We need to regenerate the desktop
  1156. // HTML.
  1157. //
  1158. fRegenerateHtml = TRUE;
  1159. }
  1160. }
  1161. else
  1162. {
  1163. TraceMsg(TF_WARNING, "SYSCLRCHG: Could not get wallpaper options!");
  1164. }
  1165. }
  1166. }
  1167. }
  1168. else
  1169. {
  1170. TraceMsg(TF_WARNING, "SYSCLRCHG: Could not get selected wallpaper!");
  1171. }
  1172. if (fRegenerateHtml)
  1173. {
  1174. DWORD dwFlags = AD_APPLY_FORCE | AD_APPLY_HTMLGEN | AD_APPLY_REFRESH | AD_APPLY_DYNAMICREFRESH;
  1175. WCHAR wszPattern[MAX_PATH];
  1176. //If we have a pattern, then we need to force a AD_APPLY_COMPLETEREFRESH
  1177. // because we need to re-generate the pattern.bmp file which can not be
  1178. // done through dynamic HTML.
  1179. if(SUCCEEDED(pad->GetPattern(wszPattern, ARRAYSIZE(wszPattern), 0)))
  1180. {
  1181. #ifdef UNICODE
  1182. LPTSTR szPattern = (LPTSTR)wszPattern;
  1183. #else
  1184. CHAR szPattern[MAX_PATH];
  1185. SHUnicodeToAnsi(wszPattern, szPattern, sizeof(szPattern));
  1186. #endif //UNICODE
  1187. if(IsValidPattern(szPattern)) //Does this have a pattern?
  1188. dwFlags &= ~(AD_APPLY_DYNAMICREFRESH); //Then force a complete refresh!
  1189. }
  1190. pad->ApplyChanges(dwFlags);
  1191. }
  1192. pad->Release();
  1193. }
  1194. else
  1195. {
  1196. TraceMsg(TF_WARNING, "SYSCLRCHG: Could not create CActiveDesktop!");
  1197. }
  1198. }
  1199. //
  1200. // Convert a .URL file into its target.
  1201. //
  1202. void CheckAndResolveLocalUrlFile(LPTSTR pszFileName, int cchFileName)
  1203. {
  1204. //
  1205. // This function only works on *.URL files.
  1206. //
  1207. if (!PathIsURL(pszFileName))
  1208. {
  1209. LPTSTR pszExt;
  1210. //
  1211. // Check if the extension of this file is *.URL
  1212. //
  1213. pszExt = PathFindExtension(pszFileName);
  1214. if (pszExt && *pszExt)
  1215. {
  1216. TCHAR szUrl[15];
  1217. LoadString(HINST_THISDLL, IDS_URL_EXTENSION, szUrl, ARRAYSIZE(szUrl));
  1218. if (lstrcmpi(pszExt, szUrl) == 0)
  1219. {
  1220. HRESULT hr;
  1221. IUniformResourceLocator *purl;
  1222. hr = CoCreateInstance(CLSID_InternetShortcut, NULL, CLSCTX_INPROC_SERVER,
  1223. IID_IUniformResourceLocator,
  1224. (LPVOID *)&purl);
  1225. if (EVAL(SUCCEEDED(hr))) // This works for both Ansi and Unicode
  1226. {
  1227. ASSERT(purl);
  1228. IPersistFile *ppf;
  1229. hr = purl->QueryInterface(IID_IPersistFile, (LPVOID *)&ppf);
  1230. if (SUCCEEDED(hr))
  1231. {
  1232. WCHAR szFileW[MAX_PATH];
  1233. LPTSTR pszTemp;
  1234. SHTCharToUnicode(pszFileName, szFileW, ARRAYSIZE(szFileW));
  1235. ppf->Load(szFileW, STGM_READ);
  1236. hr = purl->GetURL(&pszTemp); // Wow, an ANSI/UNICODE COM interface!
  1237. if (EVAL(SUCCEEDED(hr)))
  1238. {
  1239. StrCpyN(pszFileName, pszTemp, cchFileName);
  1240. CoTaskMemFree(pszTemp);
  1241. }
  1242. ppf->Release();
  1243. }
  1244. purl->Release();
  1245. }
  1246. }
  1247. }
  1248. }
  1249. }
  1250. void GetMyCurHomePageStartPos(int *piLeft, int *piTop, DWORD *pdwWidth, DWORD *pdwHeight)
  1251. {
  1252. #define INVALID_POS 0x80000000
  1253. HKEY hkey;
  1254. //
  1255. // Assume nothing.
  1256. //
  1257. *piLeft = INVALID_POS;
  1258. *piTop = INVALID_POS;
  1259. *pdwWidth = INVALID_POS;
  1260. *pdwHeight = INVALID_POS;
  1261. //
  1262. // Read from registry first.
  1263. //
  1264. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Internet Explorer\\Main"), 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS)
  1265. {
  1266. DWORD dwType, cbData;
  1267. cbData = SIZEOF(*piLeft);
  1268. SHQueryValueEx(hkey, TEXT("MyCurHome_Left"), NULL, &dwType, (LPBYTE)piLeft, &cbData);
  1269. cbData = SIZEOF(*piTop);
  1270. SHQueryValueEx(hkey, TEXT("MyCurHome_Top"), NULL, &dwType, (LPBYTE)piTop, &cbData);
  1271. cbData = SIZEOF(*pdwWidth);
  1272. SHQueryValueEx(hkey, TEXT("MyCurHome_Width"), NULL, &dwType, (LPBYTE)pdwWidth, &cbData);
  1273. cbData = SIZEOF(*pdwHeight);
  1274. SHQueryValueEx(hkey, TEXT("MyCurHome_Height"), NULL, &dwType, (LPBYTE)pdwHeight, &cbData);
  1275. RegCloseKey(hkey);
  1276. }
  1277. //
  1278. // Fill in defaults when registry provides no info.
  1279. //
  1280. if (*piLeft == INVALID_POS)
  1281. {
  1282. *piLeft = -MYCURHOME_WIDTH;
  1283. }
  1284. if (*piTop == INVALID_POS)
  1285. {
  1286. *piTop = MYCURHOME_TOP;
  1287. }
  1288. if (*pdwWidth == INVALID_POS)
  1289. {
  1290. *pdwWidth = MYCURHOME_WIDTH;
  1291. }
  1292. if (*pdwHeight == INVALID_POS)
  1293. {
  1294. *pdwHeight = MYCURHOME_HEIGHT;
  1295. }
  1296. //
  1297. // Convert negative values into positive ones.
  1298. //
  1299. RECT rect;
  1300. SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, FALSE);
  1301. if (*piLeft < 0)
  1302. {
  1303. *piLeft += (rect.right - rect.left) - *pdwWidth;
  1304. }
  1305. if (*piTop < 0)
  1306. {
  1307. *piTop += (rect.bottom - rect.top) - *pdwHeight;
  1308. }
  1309. // Find the virtual dimensions.
  1310. EnumMonitorsArea ema;
  1311. GetMonitorSettings(&ema);
  1312. // Position it in the primary monitor.
  1313. *piLeft -= ema.rcVirtualMonitor.left;
  1314. *piTop -= ema.rcVirtualMonitor.top;
  1315. #undef INVALID_POS
  1316. }
  1317. //
  1318. // Silently adds/removes a specified component to the desktop and use the given
  1319. // apply flags using which you can avoid nested unnecessary HTML generation,
  1320. // or refreshing which may lead to racing conditions.
  1321. //
  1322. //
  1323. BOOL AddRemoveDesktopComponentNoUI(BOOL fAdd, DWORD dwApplyFlags, LPCTSTR pszUrl, LPCTSTR pszFriendlyName, int iCompType, int iLeft, int iTop, int iWidth, int iHeight, BOOL fChecked, DWORD dwCurItemState, BOOL fNoScroll, BOOL fCanResize)
  1324. {
  1325. COMPONENTA Comp;
  1326. BOOL fRet = FALSE;
  1327. HRESULT hres;
  1328. //
  1329. // Build the pcomp structure.
  1330. //
  1331. Comp.dwSize = sizeof(COMPONENTA);
  1332. Comp.dwID = -1;
  1333. Comp.iComponentType = iCompType;
  1334. Comp.fChecked = fChecked;
  1335. Comp.fDirty = FALSE;
  1336. Comp.fNoScroll = fNoScroll;
  1337. Comp.cpPos.dwSize = SIZEOF(COMPPOS);
  1338. Comp.cpPos.iLeft = iLeft;
  1339. Comp.cpPos.iTop = iTop;
  1340. Comp.cpPos.dwWidth = iWidth;
  1341. Comp.cpPos.dwHeight = iHeight;
  1342. Comp.cpPos.izIndex = (dwCurItemState & IS_NORMAL) ? COMPONENT_TOP : 0;
  1343. Comp.cpPos.fCanResize = fCanResize;
  1344. Comp.cpPos.fCanResizeX = fCanResize;
  1345. Comp.cpPos.fCanResizeY = fCanResize;
  1346. Comp.cpPos.iPreferredLeftPercent = 0;
  1347. Comp.cpPos.iPreferredTopPercent = 0;
  1348. Comp.dwCurItemState = dwCurItemState;
  1349. lstrcpyn(Comp.szSource, pszUrl, ARRAYSIZE(Comp.szSource));
  1350. lstrcpyn(Comp.szSubscribedURL, pszUrl, ARRAYSIZE(Comp.szSource));
  1351. if (pszFriendlyName)
  1352. {
  1353. lstrcpyn(Comp.szFriendlyName, pszFriendlyName, ARRAYSIZE(Comp.szFriendlyName));
  1354. }
  1355. else
  1356. {
  1357. Comp.szFriendlyName[0] = TEXT('\0');
  1358. }
  1359. IActiveDesktop *pActiveDesk;
  1360. //
  1361. // Add it to the system.
  1362. //
  1363. hres = CActiveDesktop_InternalCreateInstance((LPUNKNOWN *)&pActiveDesk, IID_IActiveDesktop);
  1364. if (SUCCEEDED(hres))
  1365. {
  1366. COMPONENT CompW;
  1367. CompW.dwSize = sizeof(CompW); //Required for the MultiCompToWideComp to work properly.
  1368. MultiCompToWideComp(&Comp, &CompW);
  1369. if(fAdd)
  1370. pActiveDesk->AddDesktopItem(&CompW, 0);
  1371. else
  1372. pActiveDesk->RemoveDesktopItem(&CompW, 0);
  1373. pActiveDesk->ApplyChanges(dwApplyFlags);
  1374. pActiveDesk->Release();
  1375. fRet = TRUE;
  1376. }
  1377. return fRet;
  1378. }
  1379. //
  1380. // Summary:
  1381. // On upgrade from W2K, it is possible (under certain conditions) that the Active Desktop
  1382. // gets turned ON automatically. This is bug #154993. The following function fixes this bug.
  1383. //
  1384. // Details of why this happens:
  1385. //
  1386. // In W2K, it is possible to enable active desktop components, hide icons, lock the components
  1387. // and then turn off active desktop. But, all the details (like what AD components were ON etc.,)
  1388. // was persisted in the registry. When such a machine is upgraded to Whister, bug #154993 surfaces
  1389. // because of the following reason:
  1390. // In Whislter, ActiveDesktop is turned on/off silently based on whether any desktop component is
  1391. // on etc., As a result when a W2K machine (with AD off) is upgraded to Whistler, the AD will be
  1392. // turned on automatically, if one of the following is true:
  1393. // 1. If the desktop icons were off.
  1394. // 2. If the active desktop components were locked.
  1395. // 3. If any active desktop component is ON; but, not displayed because AD was OFF..
  1396. // Therefore on upgrade from a Win2K or older machine, we check if the AD is OFF. If so, then we
  1397. // need to check for conditions 1, 2 and 3 and change those settings such that AD continues to be
  1398. // OFF even after the upgrade. The following function OnUpgradeDisableActiveDesktopFeatures ()
  1399. // does precisely this.
  1400. //
  1401. // Returns: TRUE, if any setting was modified to keep the active desktop in the turned off state!
  1402. //
  1403. BOOL OnUpgradeDisableActiveDesktopFeatures()
  1404. {
  1405. IActiveDesktop *pActiveDesk;
  1406. BOOL fModified = FALSE;
  1407. // Get the ActiveDesktop and HideIcons flags.
  1408. SHELLSTATE ss = {0};
  1409. SHGetSetSettings(&ss, SSF_DESKTOPHTML | SSF_HIDEICONS, FALSE);
  1410. //Check if ActiveDesktop is already ON.
  1411. if(ss.fDesktopHTML)
  1412. return FALSE; //ActiveDesktop is already ON. No need to change any settings.
  1413. //Active Desktop is OFF. We may need to change the other settings to be consistent with this!
  1414. // 1. Check if Desktop icons are hidden when ActiveDesktop is on.
  1415. if(ss.fHideIcons)
  1416. {
  1417. //Yes! Turn off this. Otherwise, AD will be turned on to support this!
  1418. ss.fHideIcons = FALSE;
  1419. SHGetSetSettings(&ss, SSF_HIDEICONS, TRUE);
  1420. fModified = TRUE;
  1421. }
  1422. // 2. If the ActiveDesktop components are locked, un-lock them.
  1423. DWORD dwDesktopFlags = GetDesktopFlags();
  1424. if(dwDesktopFlags & COMPONENTS_LOCKED)
  1425. {
  1426. if(SetDesktopFlags(COMPONENTS_LOCKED, 0)) //Remove the "locked" flag!
  1427. fModified = TRUE;
  1428. }
  1429. // 3. Let's enumerate all active desktop components and make sure they are all off.
  1430. BOOL fModifiedComp = FALSE;
  1431. HRESULT hres = CActiveDesktop_InternalCreateInstance((LPUNKNOWN *)&pActiveDesk, IID_IActiveDesktop);
  1432. if (SUCCEEDED(hres))
  1433. {
  1434. int iCount = 0;
  1435. pActiveDesk->GetDesktopItemCount(&iCount, 0);
  1436. for(int i = 0; i < iCount; i++)
  1437. {
  1438. COMPONENT Comp;
  1439. Comp.dwSize = sizeof(Comp);
  1440. if(SUCCEEDED(pActiveDesk->GetDesktopItem(i, &Comp, 0)))
  1441. {
  1442. if(Comp.fChecked) //If this component is enabled.....
  1443. {
  1444. Comp.fChecked = FALSE; //...., then disable it!
  1445. if(SUCCEEDED(pActiveDesk->ModifyDesktopItem(&Comp, COMP_ELEM_CHECKED)))
  1446. fModifiedComp = TRUE;
  1447. }
  1448. }
  1449. }
  1450. if(fModifiedComp)
  1451. pActiveDesk->ApplyChanges(AD_APPLY_SAVE); //We just need to save the above changes.
  1452. pActiveDesk ->Release();
  1453. }
  1454. //return whether we modified any setting.
  1455. return (fModified || fModifiedComp);
  1456. }
  1457. // Little helper function used to change the safemode state
  1458. void SetSafeMode(DWORD dwFlags)
  1459. {
  1460. IActiveDesktopP * piadp;
  1461. if (SUCCEEDED(CActiveDesktop_InternalCreateInstance((LPUNKNOWN *)&piadp, IID_IActiveDesktopP)))
  1462. {
  1463. piadp->SetSafeMode(dwFlags);
  1464. piadp->Release();
  1465. }
  1466. }
  1467. /****************************************************************************
  1468. *
  1469. * RefreshWebViewDesktop - regenerates desktop HTML from registry and updates
  1470. * the screen
  1471. *
  1472. * ENTRY:
  1473. * none
  1474. *
  1475. * RETURNS:
  1476. * TRUE on success
  1477. *
  1478. ****************************************************************************/
  1479. BOOL PokeWebViewDesktop(DWORD dwFlags)
  1480. {
  1481. IActiveDesktop *pad;
  1482. HRESULT hres;
  1483. BOOL fRet = FALSE;
  1484. hres = CActiveDesktop_InternalCreateInstance((LPUNKNOWN *)&pad, IID_IActiveDesktop);
  1485. if (SUCCEEDED(hres))
  1486. {
  1487. pad->ApplyChanges(dwFlags);
  1488. pad->Release();
  1489. fRet = TRUE;
  1490. }
  1491. return (fRet);
  1492. }
  1493. #define CCH_NONE 20 //big enough for "(None)" in german
  1494. TCHAR g_szNone[CCH_NONE] = {0};
  1495. void InitDeskHtmlGlobals(void)
  1496. {
  1497. static fGlobalsInited = FALSE;
  1498. if (fGlobalsInited == FALSE)
  1499. {
  1500. LoadString(HINST_THISDLL, IDS_WPNONE, g_szNone, ARRAYSIZE(g_szNone));
  1501. fGlobalsInited = TRUE;
  1502. }
  1503. }
  1504. //
  1505. // Loads the preview bitmap for property sheet pages.
  1506. //
  1507. HBITMAP LoadMonitorBitmap(void)
  1508. {
  1509. HBITMAP hbm,hbmT;
  1510. BITMAP bm;
  1511. HBRUSH hbrT;
  1512. HDC hdc;
  1513. COLORREF c3df = GetSysColor(COLOR_3DFACE);
  1514. hbm = LoadBitmap(HINST_THISDLL, MAKEINTRESOURCE(IDB_MONITOR));
  1515. if (hbm == NULL)
  1516. {
  1517. return NULL;
  1518. }
  1519. //
  1520. // Convert the "base" of the monitor to the right color.
  1521. //
  1522. // The lower left of the bitmap has a transparent color
  1523. // we fixup using FloodFill
  1524. //
  1525. hdc = CreateCompatibleDC(NULL);
  1526. hbmT = (HBITMAP)SelectObject(hdc, hbm);
  1527. hbrT = (HBRUSH)SelectObject(hdc, GetSysColorBrush(COLOR_3DFACE));
  1528. GetObject(hbm, sizeof(bm), &bm);
  1529. ExtFloodFill(hdc, 0, bm.bmHeight-1, GetPixel(hdc, 0, bm.bmHeight-1), FLOODFILLSURFACE);
  1530. //
  1531. // Round off the corners.
  1532. // The bottom two were done by the floodfill above.
  1533. // The top left is important since SS_CENTERIMAGE uses it to fill gaps.
  1534. // The top right should be rounded because the other three are.
  1535. //
  1536. SetPixel( hdc, 0, 0, c3df );
  1537. SetPixel( hdc, bm.bmWidth-1, 0, c3df );
  1538. //
  1539. // Fill in the desktop here.
  1540. //
  1541. HBRUSH hbrOld = (HBRUSH)SelectObject(hdc, GetSysColorBrush(COLOR_DESKTOP));
  1542. PatBlt(hdc, MON_X, MON_Y, MON_DX, MON_DY, PATCOPY);
  1543. SelectObject(hdc, hbrOld);
  1544. //
  1545. // Clean up after ourselves.
  1546. //
  1547. SelectObject(hdc, hbrT);
  1548. SelectObject(hdc, hbmT);
  1549. DeleteDC(hdc);
  1550. return hbm;
  1551. }
  1552. STDAPI_(VOID) ActiveDesktop_ApplyChanges()
  1553. {
  1554. IActiveDesktop* piad;
  1555. if (SUCCEEDED(CoCreateInstance(CLSID_ActiveDesktop, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IActiveDesktop, &piad))))
  1556. {
  1557. piad->ApplyChanges(AD_APPLY_ALL | AD_APPLY_DYNAMICREFRESH);
  1558. piad->Release();
  1559. }
  1560. }
  1561. STDAPI_(DWORD) GetDesktopFlags(void)
  1562. {
  1563. DWORD dwFlags = 0, dwType, cbSize = SIZEOF(dwFlags);
  1564. TCHAR lpszDeskcomp[MAX_PATH];
  1565. GetRegLocation(lpszDeskcomp, SIZECHARS(lpszDeskcomp), REG_DESKCOMP_COMPONENTS, NULL);
  1566. SHGetValue(HKEY_CURRENT_USER, lpszDeskcomp, REG_VAL_COMP_GENFLAGS, &dwType, &dwFlags, &cbSize);
  1567. return dwFlags;
  1568. }
  1569. STDAPI_(BOOL) SetDesktopFlags(DWORD dwMask, DWORD dwNewFlags)
  1570. {
  1571. BOOL fRet = FALSE;
  1572. HKEY hkey;
  1573. DWORD dwDisposition;
  1574. TCHAR lpszDeskcomp[MAX_PATH];
  1575. GetRegLocation(lpszDeskcomp, SIZECHARS(lpszDeskcomp), REG_DESKCOMP_COMPONENTS, NULL);
  1576. if (RegCreateKeyEx(HKEY_CURRENT_USER, (LPCTSTR)lpszDeskcomp,
  1577. 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &hkey,
  1578. &dwDisposition) == ERROR_SUCCESS)
  1579. {
  1580. DWORD dwFlags;
  1581. DWORD cbSize = SIZEOF(dwFlags);
  1582. DWORD dwType;
  1583. if (SHQueryValueEx(hkey, REG_VAL_COMP_GENFLAGS, NULL, &dwType,
  1584. (LPBYTE)&dwFlags, &cbSize) != ERROR_SUCCESS)
  1585. {
  1586. dwFlags = 0;
  1587. }
  1588. dwFlags = (dwFlags & ~dwMask) | (dwNewFlags & dwMask);
  1589. if (RegSetValueEx(hkey, REG_VAL_COMP_GENFLAGS, 0, REG_DWORD,
  1590. (LPBYTE)&dwFlags, sizeof(dwFlags)) == ERROR_SUCCESS)
  1591. {
  1592. fRet = TRUE;
  1593. }
  1594. RegCloseKey(hkey);
  1595. }
  1596. return fRet;
  1597. }
  1598. BOOL UpdateComponentFlags(LPCTSTR pszCompId, DWORD dwMask, DWORD dwNewFlags)
  1599. {
  1600. BOOL fRet = FALSE;
  1601. TCHAR szRegPath[MAX_PATH];
  1602. HKEY hkey;
  1603. GetRegLocation(szRegPath, SIZECHARS(szRegPath), REG_DESKCOMP_COMPONENTS, NULL);
  1604. lstrcat(szRegPath, TEXT("\\"));
  1605. lstrcat(szRegPath, pszCompId);
  1606. //Don't use RegCreateKeyEx here. It will result in Null components to be added.
  1607. if (RegOpenKeyEx(HKEY_CURRENT_USER, szRegPath, 0,
  1608. KEY_READ | KEY_WRITE, &hkey) == ERROR_SUCCESS)
  1609. {
  1610. DWORD dwType, dwFlags, dwDataLength;
  1611. dwDataLength = sizeof(DWORD);
  1612. if(SHQueryValueEx(hkey, REG_VAL_COMP_FLAGS, NULL, &dwType, (LPBYTE)&dwFlags, &dwDataLength) != ERROR_SUCCESS)
  1613. {
  1614. dwFlags = 0;
  1615. }
  1616. dwNewFlags = (dwFlags & ~dwMask) | (dwNewFlags & dwMask);
  1617. if (RegSetValueEx(hkey, REG_VAL_COMP_FLAGS, 0, REG_DWORD, (LPBYTE)&dwNewFlags,
  1618. SIZEOF(DWORD)) == ERROR_SUCCESS)
  1619. {
  1620. fRet = TRUE;
  1621. }
  1622. SetDesktopFlags(COMPONENTS_DIRTY, COMPONENTS_DIRTY);
  1623. RegCloseKey(hkey);
  1624. }
  1625. else
  1626. {
  1627. TraceMsg(TF_WARNING, "DS: Unable to UpdateComponentFlags");
  1628. }
  1629. return fRet;
  1630. }
  1631. DWORD GetCurrentState(LPTSTR pszCompId)
  1632. {
  1633. TCHAR szRegPath[MAX_PATH];
  1634. DWORD cbSize, dwType, dwCurState;
  1635. GetRegLocation(szRegPath, SIZECHARS(szRegPath), REG_DESKCOMP_COMPONENTS, NULL);
  1636. lstrcat(szRegPath, TEXT("\\"));
  1637. lstrcat(szRegPath, pszCompId);
  1638. cbSize = sizeof(dwCurState);
  1639. if (SHGetValue(HKEY_CURRENT_USER, szRegPath, REG_VAL_COMP_CURSTATE, &dwType, &dwCurState, &cbSize) != ERROR_SUCCESS)
  1640. dwCurState = IS_NORMAL;
  1641. return dwCurState;
  1642. }
  1643. BOOL GetSavedStateInfo(LPTSTR pszCompId, LPCOMPSTATEINFO pCompState, BOOL fRestoredState)
  1644. {
  1645. BOOL fRet = FALSE;
  1646. TCHAR szRegPath[MAX_PATH];
  1647. HKEY hkey;
  1648. LPTSTR lpValName = (fRestoredState ? REG_VAL_COMP_RESTOREDSTATEINFO : REG_VAL_COMP_ORIGINALSTATEINFO);
  1649. GetRegLocation(szRegPath, SIZECHARS(szRegPath), REG_DESKCOMP_COMPONENTS, NULL);
  1650. lstrcat(szRegPath, TEXT("\\"));
  1651. lstrcat(szRegPath, pszCompId);
  1652. //No need to use RegCreateKeyEx here. Use RegOpenKeyEx instead.
  1653. if (RegOpenKeyEx(HKEY_CURRENT_USER, szRegPath, 0,
  1654. KEY_READ, &hkey) == ERROR_SUCCESS)
  1655. {
  1656. DWORD cbSize, dwType;
  1657. cbSize = SIZEOF(*pCompState);
  1658. dwType = REG_BINARY;
  1659. if (SHQueryValueEx(hkey, lpValName, NULL, &dwType, (LPBYTE)pCompState, &cbSize) != ERROR_SUCCESS)
  1660. {
  1661. //If the item state is missing, read the item current position and
  1662. // and return that as the saved state.
  1663. COMPPOS cpPos;
  1664. cbSize = SIZEOF(cpPos);
  1665. dwType = REG_BINARY;
  1666. if (SHQueryValueEx(hkey, REG_VAL_COMP_POSITION, NULL, &dwType, (LPBYTE)&cpPos, &cbSize) != ERROR_SUCCESS)
  1667. {
  1668. ZeroMemory(&cpPos, SIZEOF(cpPos));
  1669. }
  1670. SetStateInfo(pCompState, &cpPos, IS_NORMAL);
  1671. }
  1672. RegCloseKey(hkey);
  1673. }
  1674. else
  1675. TraceMsg(TF_WARNING, "DS: Unable to get SavedStateInfo()");
  1676. return fRet;
  1677. }
  1678. BOOL UpdateDesktopPosition(LPTSTR pszCompId, int iLeft, int iTop, DWORD dwWidth, DWORD dwHeight, int izIndex,
  1679. BOOL fSaveRestorePos, BOOL fSaveOriginal, DWORD dwCurState)
  1680. {
  1681. BOOL fRet = FALSE;
  1682. TCHAR szRegPath[MAX_PATH];
  1683. HKEY hkey;
  1684. GetRegLocation(szRegPath, SIZECHARS(szRegPath), REG_DESKCOMP_COMPONENTS, NULL);
  1685. lstrcat(szRegPath, TEXT("\\"));
  1686. lstrcat(szRegPath, pszCompId);
  1687. //Don't use RegCreateKeyEx here; It will result in a NULL component being added.
  1688. if (RegOpenKeyEx(HKEY_CURRENT_USER, szRegPath, 0,
  1689. KEY_READ | KEY_WRITE, &hkey) == ERROR_SUCCESS)
  1690. {
  1691. COMPPOS cp;
  1692. DWORD dwType;
  1693. DWORD dwDataLength;
  1694. COMPSTATEINFO csi;
  1695. dwType = REG_BINARY;
  1696. dwDataLength = sizeof(COMPPOS);
  1697. if(SHQueryValueEx(hkey, REG_VAL_COMP_POSITION, NULL, &dwType, (LPBYTE)&cp, &dwDataLength) != ERROR_SUCCESS)
  1698. {
  1699. cp.fCanResize = cp.fCanResizeX = cp.fCanResizeY = TRUE;
  1700. cp.iPreferredLeftPercent = cp.iPreferredTopPercent = 0;
  1701. }
  1702. //Read the current State
  1703. dwType = REG_DWORD;
  1704. dwDataLength = SIZEOF(csi.dwItemState);
  1705. if (SHQueryValueEx(hkey, REG_VAL_COMP_CURSTATE, NULL, &dwType, (LPBYTE)&csi.dwItemState, &dwDataLength) != ERROR_SUCCESS)
  1706. {
  1707. csi.dwItemState = IS_NORMAL;
  1708. }
  1709. if(fSaveRestorePos)
  1710. {
  1711. //We have just read the current position; Let's save it as the restore position.
  1712. SetStateInfo(&csi, &cp, csi.dwItemState);
  1713. //Now that we know the complete current state, save it as the restore state!
  1714. RegSetValueEx(hkey, REG_VAL_COMP_RESTOREDSTATEINFO, 0, REG_BINARY, (LPBYTE)&csi, SIZEOF(csi));
  1715. }
  1716. //Save the current state too!
  1717. if(dwCurState)
  1718. RegSetValueEx(hkey, REG_VAL_COMP_CURSTATE, 0, REG_DWORD, (LPBYTE)&dwCurState, SIZEOF(dwCurState));
  1719. cp.dwSize = sizeof(COMPPOS);
  1720. cp.iLeft = iLeft;
  1721. cp.iTop = iTop;
  1722. cp.dwWidth = dwWidth;
  1723. cp.dwHeight = dwHeight;
  1724. cp.izIndex = izIndex;
  1725. if (fSaveOriginal) {
  1726. SetStateInfo(&csi, &cp, csi.dwItemState);
  1727. RegSetValueEx(hkey, REG_VAL_COMP_ORIGINALSTATEINFO, 0, REG_BINARY, (LPBYTE)&csi, SIZEOF(csi));
  1728. }
  1729. if (RegSetValueEx(hkey, REG_VAL_COMP_POSITION, 0, REG_BINARY, (LPBYTE)&cp,
  1730. SIZEOF(cp)) == ERROR_SUCCESS)
  1731. {
  1732. fRet = TRUE;
  1733. }
  1734. // Don't need to mark as dirty if we're just saving the original pos
  1735. if (!fSaveOriginal)
  1736. SetDesktopFlags(COMPONENTS_DIRTY, COMPONENTS_DIRTY);
  1737. RegCloseKey(hkey);
  1738. }
  1739. else
  1740. {
  1741. TraceMsg(TF_WARNING, "DS: Unable to UpdateDesktopPosition");
  1742. }
  1743. return fRet;
  1744. }
  1745. HRESULT EnsureFilePathIsPresent(LPCTSTR pszFilePath)
  1746. // Recursively process (in reverse) a path and create the first
  1747. // directory that does not exist and when unwinding the calling
  1748. // chain create each subsequent directory in the path until the
  1749. // whole original path is created.
  1750. {
  1751. HRESULT hr = E_INVALIDARG;
  1752. if (pszFilePath && pszFilePath[0])
  1753. {
  1754. TCHAR szDesktopFileDirectory[MAX_PATH];
  1755. hr = S_OK;
  1756. lstrcpy(szDesktopFileDirectory, pszFilePath);
  1757. ASSERT(lstrlen(szDesktopFileDirectory) > lstrlen(TEXT("C:\\"))); // something wrong if the root directory is hit
  1758. if ((PathRemoveFileSpec(szDesktopFileDirectory) != 0) && (GetFileAttributes(szDesktopFileDirectory) == 0xFFFFFFFF) && (CreateDirectory(szDesktopFileDirectory, NULL) == 0))
  1759. {
  1760. hr = EnsureFilePathIsPresent(szDesktopFileDirectory);
  1761. TBOOL(CreateDirectory(szDesktopFileDirectory, NULL));
  1762. }
  1763. }
  1764. return hr;
  1765. }
  1766. HRESULT GetPerUserFileName(LPTSTR pszOutputFileName, DWORD dwSize, LPTSTR pszPartialFileName)
  1767. {
  1768. LPITEMIDLIST pidlAppData;
  1769. *pszOutputFileName = TEXT('\0');
  1770. if(dwSize < MAX_PATH)
  1771. {
  1772. ASSERT(FALSE);
  1773. return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  1774. }
  1775. HRESULT hr = SHGetSpecialFolderLocation(NULL, CSIDL_APPDATA, &pidlAppData);
  1776. if (SUCCEEDED(hr))
  1777. {
  1778. SHGetPathFromIDList(pidlAppData, pszOutputFileName);
  1779. PathAppend(pszOutputFileName, pszPartialFileName);
  1780. ILFree(pidlAppData);
  1781. hr = EnsureFilePathIsPresent(pszOutputFileName);
  1782. }
  1783. return hr;
  1784. }
  1785. void GetRegLocation(LPTSTR lpszResult, DWORD cchResult, LPCTSTR lpszKey, LPCTSTR lpszScheme)
  1786. {
  1787. TCHAR szSubkey[MAX_PATH];
  1788. DWORD dwDataLength = sizeof(szSubkey) - 2 * sizeof(TCHAR);
  1789. DWORD dwType;
  1790. lstrcpy(szSubkey, TEXT("\\"));
  1791. // use what was given or get it from the registry
  1792. if (lpszScheme)
  1793. StrCatBuff(szSubkey, lpszScheme, SIZECHARS(szSubkey));
  1794. else
  1795. SHGetValue(HKEY_CURRENT_USER, REG_DESKCOMP_SCHEME, REG_VAL_SCHEME_DISPLAY, &dwType,
  1796. (LPBYTE)(szSubkey) + sizeof(TCHAR), &dwDataLength);
  1797. if (szSubkey[1])
  1798. StrCatBuff(szSubkey, TEXT("\\"), SIZECHARS(szSubkey));
  1799. wnsprintf(lpszResult, cchResult, lpszKey, szSubkey);
  1800. }
  1801. BOOL ValidateFileName(HWND hwnd, LPCTSTR pszFilename, int iTypeString)
  1802. {
  1803. BOOL fRet = TRUE;
  1804. DWORD dwAttributes = GetFileAttributes(pszFilename);
  1805. if ((dwAttributes != 0xFFFFFFFF) &&
  1806. (dwAttributes & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN)))
  1807. {
  1808. TCHAR szType1[64];
  1809. TCHAR szType2[64];
  1810. LoadString(HINST_THISDLL, iTypeString, szType1, ARRAYSIZE(szType1));
  1811. LoadString(HINST_THISDLL, iTypeString+1, szType2, ARRAYSIZE(szType2));
  1812. if (ShellMessageBox(HINST_THISDLL, hwnd,
  1813. MAKEINTRESOURCE(IDS_VALIDFN_FMT),
  1814. MAKEINTRESOURCE(IDS_VALIDFN_TITLE),
  1815. MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2,
  1816. szType1, szType2) == IDNO)
  1817. {
  1818. fRet = FALSE;
  1819. }
  1820. }
  1821. return fRet;
  1822. }
  1823. void GetWallpaperDirName(LPTSTR lpszWallPaperDir, int iBuffSize)
  1824. {
  1825. TCHAR szExp[MAX_PATH];
  1826. //Compute the default wallpaper name.
  1827. if (GetWindowsDirectory(lpszWallPaperDir, iBuffSize) != 0)
  1828. {
  1829. lstrcat(lpszWallPaperDir, DESKTOPHTML_WEB_DIR);
  1830. //Read it from the registry key, if it is set!
  1831. DWORD dwType;
  1832. DWORD cbData = (DWORD)iBuffSize;
  1833. SHGetValue(HKEY_LOCAL_MACHINE, REGSTR_PATH_SETUP, c_szWallPaperDir, &dwType, (LPVOID)lpszWallPaperDir, &cbData);
  1834. // Maybe we should check if it is REG_EXPAND_SZ, to save a few CPU cycle?
  1835. SHExpandEnvironmentStrings(lpszWallPaperDir, szExp, ARRAYSIZE(szExp));
  1836. lstrcpyn(lpszWallPaperDir, szExp, iBuffSize);
  1837. }
  1838. }
  1839. BOOL CALLBACK MultiMonEnumAreaCallBack(HMONITOR hMonitor, HDC hdc, LPRECT lprc, LPARAM lData)
  1840. {
  1841. EnumMonitorsArea* pEMA = (EnumMonitorsArea*)lData;
  1842. if (pEMA->iMonitors > LV_MAX_WORKAREAS - 1)
  1843. {
  1844. //ignore the other monitors because we can only handle up to LV_MAX_WORKAREAS
  1845. //REARCHITECT: should we dynamically allocate this?
  1846. return FALSE;
  1847. }
  1848. GetMonitorRect(hMonitor, &pEMA->rcMonitor[pEMA->iMonitors]);
  1849. GetMonitorWorkArea(hMonitor, &pEMA->rcWorkArea[pEMA->iMonitors]);
  1850. if(pEMA->iMonitors == 0)
  1851. {
  1852. pEMA->rcVirtualMonitor.left = pEMA->rcMonitor[0].left;
  1853. pEMA->rcVirtualMonitor.top = pEMA->rcMonitor[0].top;
  1854. pEMA->rcVirtualMonitor.right = pEMA->rcMonitor[0].right;
  1855. pEMA->rcVirtualMonitor.bottom = pEMA->rcMonitor[0].bottom;
  1856. pEMA->rcVirtualWorkArea.left = pEMA->rcWorkArea[0].left;
  1857. pEMA->rcVirtualWorkArea.top = pEMA->rcWorkArea[0].top;
  1858. pEMA->rcVirtualWorkArea.right = pEMA->rcWorkArea[0].right;
  1859. pEMA->rcVirtualWorkArea.bottom = pEMA->rcWorkArea[0].bottom;
  1860. }
  1861. else
  1862. {
  1863. if(pEMA->rcMonitor[pEMA->iMonitors].left < pEMA->rcVirtualMonitor.left)
  1864. {
  1865. pEMA->rcVirtualMonitor.left = pEMA->rcMonitor[pEMA->iMonitors].left;
  1866. }
  1867. if(pEMA->rcMonitor[pEMA->iMonitors].top < pEMA->rcVirtualMonitor.top)
  1868. {
  1869. pEMA->rcVirtualMonitor.top = pEMA->rcMonitor[pEMA->iMonitors].top;
  1870. }
  1871. if(pEMA->rcMonitor[pEMA->iMonitors].right > pEMA->rcVirtualMonitor.right)
  1872. {
  1873. pEMA->rcVirtualMonitor.right = pEMA->rcMonitor[pEMA->iMonitors].right;
  1874. }
  1875. if(pEMA->rcMonitor[pEMA->iMonitors].bottom > pEMA->rcVirtualMonitor.bottom)
  1876. {
  1877. pEMA->rcVirtualMonitor.bottom = pEMA->rcMonitor[pEMA->iMonitors].bottom;
  1878. }
  1879. if(pEMA->rcWorkArea[pEMA->iMonitors].left < pEMA->rcVirtualWorkArea.left)
  1880. {
  1881. pEMA->rcVirtualWorkArea.left = pEMA->rcWorkArea[pEMA->iMonitors].left;
  1882. }
  1883. if(pEMA->rcWorkArea[pEMA->iMonitors].top < pEMA->rcVirtualWorkArea.top)
  1884. {
  1885. pEMA->rcVirtualWorkArea.top = pEMA->rcWorkArea[pEMA->iMonitors].top;
  1886. }
  1887. if(pEMA->rcWorkArea[pEMA->iMonitors].right > pEMA->rcVirtualWorkArea.right)
  1888. {
  1889. pEMA->rcVirtualWorkArea.right = pEMA->rcWorkArea[pEMA->iMonitors].right;
  1890. }
  1891. if(pEMA->rcWorkArea[pEMA->iMonitors].bottom > pEMA->rcVirtualWorkArea.bottom)
  1892. {
  1893. pEMA->rcVirtualWorkArea.bottom = pEMA->rcWorkArea[pEMA->iMonitors].bottom;
  1894. }
  1895. }
  1896. pEMA->iMonitors++;
  1897. return TRUE;
  1898. }
  1899. void GetMonitorSettings(EnumMonitorsArea* ema)
  1900. {
  1901. ema->iMonitors = 0;
  1902. ema->rcVirtualMonitor.left = 0;
  1903. ema->rcVirtualMonitor.top = 0;
  1904. ema->rcVirtualMonitor.right = 0;
  1905. ema->rcVirtualMonitor.bottom = 0;
  1906. ema->rcVirtualWorkArea.left = 0;
  1907. ema->rcVirtualWorkArea.top = 0;
  1908. ema->rcVirtualWorkArea.right = 0;
  1909. ema->rcVirtualWorkArea.bottom = 0;
  1910. EnumDisplayMonitors(NULL, NULL, MultiMonEnumAreaCallBack, (LPARAM)ema);
  1911. }
  1912. int _GetWorkAreaIndexWorker(POINT pt, LPCRECT prect, int crect)
  1913. {
  1914. int iIndex;
  1915. for (iIndex = 0; iIndex < crect; iIndex++)
  1916. {
  1917. if (PtInRect(&prect[iIndex], pt))
  1918. {
  1919. return iIndex;
  1920. }
  1921. }
  1922. return -1;
  1923. }
  1924. int GetWorkAreaIndexFromPoint(POINT pt, LPCRECT prect, int crect)
  1925. {
  1926. ASSERT(crect);
  1927. // Map to correct coords...
  1928. pt.x += prect[0].left;
  1929. pt.y += prect[0].top;
  1930. return _GetWorkAreaIndexWorker(pt, prect, crect);
  1931. }
  1932. int GetWorkAreaIndex(COMPPOS *pcp, LPCRECT prect, int crect, LPPOINT lpptVirtualTopLeft)
  1933. {
  1934. POINT ptComp;
  1935. ptComp.x = pcp->iLeft + lpptVirtualTopLeft->x;
  1936. ptComp.y = pcp->iTop + lpptVirtualTopLeft->y;
  1937. return _GetWorkAreaIndexWorker(ptComp, prect, crect);
  1938. }
  1939. // Prepends the Web wallpaper directory or the system directory to szWallpaper, if necessary
  1940. // (i.e., if the path is not specified). The return value is in szWallpaperWithPath, which is iBufSize
  1941. // bytes long
  1942. void GetWallpaperWithPath(LPCTSTR szWallpaper, LPTSTR szWallpaperWithPath, int iBufSize)
  1943. {
  1944. if (szWallpaper[0] && lstrcmpi(szWallpaper, g_szNone) != 0 && !StrChr(szWallpaper, TEXT('\\'))
  1945. && !StrChr(szWallpaper, TEXT(':'))) // The file could be d:foo.bmp
  1946. {
  1947. // If the file is a normal wallpaper, we prepend the windows directory to the filename
  1948. if (IsNormalWallpaper(szWallpaper))
  1949. {
  1950. GetWindowsDirectory(szWallpaperWithPath, iBufSize);
  1951. }
  1952. // else we prepend the wallpaper directory to the filename
  1953. else
  1954. {
  1955. GetWallpaperDirName(szWallpaperWithPath, iBufSize);
  1956. }
  1957. PathAppend(szWallpaperWithPath, szWallpaper);
  1958. }
  1959. else
  1960. {
  1961. lstrcpyn(szWallpaperWithPath, szWallpaper, iBufSize);
  1962. }
  1963. }
  1964. BOOL GetViewAreas(LPRECT lprcViewAreas, int* pnViewAreas)
  1965. {
  1966. BOOL bRet = FALSE;
  1967. HWND hwndDesktop = GetShellWindow(); // This is the "normal" desktop
  1968. if (hwndDesktop && IsWindow(hwndDesktop))
  1969. {
  1970. DWORD dwProcID, dwCurrentProcID;
  1971. GetWindowThreadProcessId(hwndDesktop, &dwProcID);
  1972. dwCurrentProcID = GetCurrentProcessId();
  1973. if (dwCurrentProcID == dwProcID) {
  1974. SendMessage(hwndDesktop, DTM_GETVIEWAREAS, (WPARAM)pnViewAreas, (LPARAM)lprcViewAreas);
  1975. if (*pnViewAreas <= 0)
  1976. {
  1977. bRet = FALSE;
  1978. }
  1979. else
  1980. {
  1981. bRet = TRUE;
  1982. }
  1983. }
  1984. else
  1985. {
  1986. bRet = FALSE;
  1987. }
  1988. }
  1989. return bRet;
  1990. }
  1991. // We need to enforce a minimum size for the deskmovr caption since it doesn't look
  1992. // right drawn any smaller
  1993. int GetcyCaption()
  1994. {
  1995. int cyCaption = GetSystemMetrics(SM_CYSMCAPTION);
  1996. if (cyCaption < 15)
  1997. cyCaption = 15;
  1998. cyCaption -= GetSystemMetrics(SM_CYBORDER);
  1999. return cyCaption;
  2000. }
  2001. void PathUnExpandEnvStringsWrap(LPTSTR pszString, DWORD cchSize)
  2002. {
  2003. TCHAR szTemp[MAX_PATH];
  2004. StrCpyN(szTemp, pszString, ARRAYSIZE(szTemp));
  2005. if (!PathUnExpandEnvStrings(szTemp, pszString, cchSize))
  2006. {
  2007. StrCpyN(pszString, szTemp, cchSize);
  2008. }
  2009. }
  2010. void PathExpandEnvStringsWrap(LPTSTR pszString, DWORD cchSize)
  2011. {
  2012. TCHAR szTemp[MAX_PATH];
  2013. StrCpyN(szTemp, pszString, ARRAYSIZE(szTemp));
  2014. if (0 == SHExpandEnvironmentStrings(szTemp, pszString, cchSize))
  2015. {
  2016. StrCpyN(pszString, szTemp, cchSize);
  2017. }
  2018. }