Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2376 lines
79 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 szDeskcomp[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. dwComponentPosition = 0;
  59. GetRegLocation(szDeskcomp, ARRAYSIZE(szDeskcomp), REG_DESKCOMP_GENERAL, NULL);
  60. if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_CURRENT_USER, szDeskcomp, 0, NULL, 0, KEY_QUERY_VALUE, NULL, &hKey, &dwRegDataScratch))
  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 szDeskcomp[MAX_PATH];
  129. // Increment the registry count. If no such count exists create it.
  130. GetRegLocation(szDeskcomp, ARRAYSIZE(szDeskcomp), REG_DESKCOMP_GENERAL, NULL);
  131. if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_CURRENT_USER, szDeskcomp, 0, NULL, 0, KEY_QUERY_VALUE | KEY_SET_VALUE, NULL, &hKey, &dwRegDataScratch))
  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. if (SUCCEEDED(StringCchCopy(szBrowserDir, ARRAYSIZE(szBrowserDir), pszFileName)))
  914. {
  915. PathRemoveFileSpec(szBrowserDir);
  916. TCHAR szBuf[MAX_PATH];
  917. LoadString(HINST_THISDLL, IDS_BROWSE, szBuf, ARRAYSIZE(szBuf));
  918. *pszFileName = TEXT('\0');
  919. OPENFILENAME ofn = {0};
  920. ofn.lStructSize = sizeof(ofn);
  921. ofn.hwndOwner = hdlg;
  922. ofn.hInstance = NULL;
  923. ofn.lpstrFilter = szFilter;
  924. ofn.lpstrCustomFilter = NULL;
  925. ofn.nFilterIndex = 1;
  926. ofn.nMaxCustFilter = 0;
  927. ofn.lpstrFile = pszFileName;
  928. ofn.nMaxFile = iSize;
  929. ofn.lpstrInitialDir = szBrowserDir;
  930. ofn.lpstrTitle = szBuf;
  931. ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST;
  932. ofn.lpfnHook = NULL;
  933. ofn.lpstrDefExt = NULL;
  934. ofn.lpstrFileTitle = NULL;
  935. fRet = GetOpenFileName(&ofn);
  936. }
  937. }
  938. return fRet;
  939. }
  940. //
  941. // Convert a pattern string to a bottom-up array of DWORDs,
  942. // useful for BMP format files.
  943. //
  944. void PatternToDwords(LPTSTR psz, DWORD *pdwBits)
  945. {
  946. DWORD i, dwVal;
  947. //
  948. // Get eight groups of numbers separated by non-numeric characters.
  949. //
  950. for (i=0; i<8; i++)
  951. {
  952. dwVal = 0;
  953. if (*psz != TEXT('\0'))
  954. {
  955. //
  956. // Skip over any non-numeric characters.
  957. //
  958. while (*psz && (!(*psz >= TEXT('0') && *psz <= TEXT('9'))))
  959. {
  960. psz++;
  961. }
  962. //
  963. // Get the next series of digits.
  964. //
  965. while (*psz && (*psz >= TEXT('0') && *psz <= TEXT('9')))
  966. {
  967. dwVal = dwVal*10 + *psz++ - TEXT('0');
  968. }
  969. }
  970. pdwBits[7-i] = dwVal;
  971. }
  972. }
  973. //
  974. // Convert a pattern string to a top-down array of WORDs,
  975. // useful for CreateBitmap().
  976. //
  977. void PatternToWords(LPTSTR psz, WORD *pwBits)
  978. {
  979. WORD i, wVal;
  980. //
  981. // Get eight groups of numbers separated by non-numeric characters.
  982. //
  983. for (i=0; i<8; i++)
  984. {
  985. wVal = 0;
  986. if (*psz != TEXT('\0'))
  987. {
  988. //
  989. // Skip over any non-numeric characters.
  990. //
  991. while (*psz && (!(*psz >= TEXT('0') && *psz <= TEXT('9'))))
  992. {
  993. psz++;
  994. }
  995. //
  996. // Get the next series of digits.
  997. //
  998. while (*psz && ((*psz >= TEXT('0') && *psz <= TEXT('9'))))
  999. {
  1000. wVal = wVal*10 + *psz++ - TEXT('0');
  1001. }
  1002. }
  1003. pwBits[i] = wVal;
  1004. }
  1005. }
  1006. BOOL IsValidPattern(LPCTSTR pszPat)
  1007. {
  1008. BOOL fSawANumber = FALSE;
  1009. //
  1010. // We're mainly trying to filter multilingual upgrade cases
  1011. // where the text for "(None)" is unpredictable.
  1012. //
  1013. //
  1014. //
  1015. while (*pszPat)
  1016. {
  1017. if ((*pszPat < TEXT('0')) || (*pszPat > TEXT('9')))
  1018. {
  1019. //
  1020. // It's not a number, it better be a space.
  1021. //
  1022. if (*pszPat != TEXT(' '))
  1023. {
  1024. return FALSE;
  1025. }
  1026. }
  1027. else
  1028. {
  1029. fSawANumber = TRUE;
  1030. }
  1031. //
  1032. // We avoid the need for AnsiNext by only advancing on US TCHARs.
  1033. //
  1034. pszPat++;
  1035. }
  1036. //
  1037. // TRUE if we saw at least one digit and there were only digits and spaces.
  1038. //
  1039. return fSawANumber;
  1040. }
  1041. //
  1042. // Determines if the wallpaper can be supported in non-active desktop mode.
  1043. //
  1044. BOOL IsNormalWallpaper(LPCTSTR pszFileName)
  1045. {
  1046. BOOL fRet = TRUE;
  1047. if (pszFileName[0] == TEXT('\0'))
  1048. {
  1049. fRet = TRUE;
  1050. }
  1051. else
  1052. {
  1053. LPTSTR pszExt = PathFindExtension(pszFileName);
  1054. //Check for specific files that can be shown only in ActiveDesktop mode!
  1055. if((StrCmpIC(pszExt, TEXT(".GIF")) == 0) || // 368690: Strange, but we must compare 'i' in both caps and lower case.
  1056. (lstrcmpi(pszExt, TEXT(".JPG")) == 0) ||
  1057. (lstrcmpi(pszExt, TEXT(".JPE")) == 0) ||
  1058. (lstrcmpi(pszExt, TEXT(".JPEG")) == 0) ||
  1059. (lstrcmpi(pszExt, TEXT(".PNG")) == 0) ||
  1060. (lstrcmpi(pszExt, TEXT(".HTM")) == 0) ||
  1061. (lstrcmpi(pszExt, TEXT(".HTML")) == 0) ||
  1062. (lstrcmpi(pszExt, TEXT(".HTT")) == 0))
  1063. return FALSE;
  1064. //Everything else (including *.BMP files) are "normal" wallpapers
  1065. }
  1066. return fRet;
  1067. }
  1068. //
  1069. // Determines if the wallpaper is a picture (vs. HTML).
  1070. //
  1071. BOOL IsWallpaperPicture(LPCTSTR pszWallpaper)
  1072. {
  1073. BOOL fRet = TRUE;
  1074. if (pszWallpaper[0] == TEXT('\0'))
  1075. {
  1076. //
  1077. // Empty wallpapers count as empty pictures.
  1078. //
  1079. fRet = TRUE;
  1080. }
  1081. else
  1082. {
  1083. LPTSTR pszExt = PathFindExtension(pszWallpaper);
  1084. if ((lstrcmpi(pszExt, TEXT(".HTM")) == 0) ||
  1085. (lstrcmpi(pszExt, TEXT(".HTML")) == 0) ||
  1086. (lstrcmpi(pszExt, TEXT(".HTT")) == 0))
  1087. {
  1088. fRet = FALSE;
  1089. }
  1090. }
  1091. return fRet;
  1092. }
  1093. void OnDesktopSysColorChange(void)
  1094. {
  1095. static COLORREF clrBackground = 0xffffffff;
  1096. static COLORREF clrWindowText = 0xffffffff;
  1097. //Get the new colors!
  1098. COLORREF clrNewBackground = GetSysColor(COLOR_BACKGROUND);
  1099. COLORREF clrNewWindowText = GetSysColor(COLOR_WINDOWTEXT);
  1100. //Have we initialized these before?
  1101. if(clrBackground != 0xffffffff) //Have we initialized the statics yet?
  1102. {
  1103. // Our HTML file depends only on these two system colors.
  1104. // Check if either of them has changed!
  1105. // If not, no need to regenerate HTML file.
  1106. // This avoids infinite loop. And this is a nice optimization.
  1107. if((clrBackground == clrNewBackground) &&
  1108. (clrWindowText == clrNewWindowText))
  1109. return; //No need to do anything. Just return.
  1110. }
  1111. // Remember the new colors in the statics.
  1112. clrBackground = clrNewBackground;
  1113. clrWindowText = clrNewWindowText;
  1114. //
  1115. // The desktop got a WM_SYSCOLORCHANGE. We need to
  1116. // regenerate the HTML if there are any system colors
  1117. // showing on the desktop. Patterns and the desktop
  1118. // color are both based on system colors.
  1119. //
  1120. IActiveDesktop *pad;
  1121. if (SUCCEEDED(CActiveDesktop_InternalCreateInstance((LPUNKNOWN *)&pad, IID_IActiveDesktop)))
  1122. {
  1123. BOOL fRegenerateHtml = FALSE;
  1124. WCHAR szWallpaperW[INTERNET_MAX_URL_LENGTH];
  1125. if (SUCCEEDED(pad->GetWallpaper(szWallpaperW, ARRAYSIZE(szWallpaperW), 0)))
  1126. {
  1127. if (!*szWallpaperW)
  1128. {
  1129. //
  1130. // No wallpaper means the desktop color
  1131. // or a pattern is showing - we need to
  1132. // regenerate the desktop HTML.
  1133. //
  1134. fRegenerateHtml = TRUE;
  1135. }
  1136. else
  1137. {
  1138. TCHAR *pszWallpaper;
  1139. #ifdef UNICODE
  1140. pszWallpaper = szWallpaperW;
  1141. #else
  1142. CHAR szWallpaperA[INTERNET_MAX_URL_LENGTH];
  1143. SHUnicodeToAnsi(szWallpaperW, szWallpaperA, ARRAYSIZE(szWallpaperA));
  1144. pszWallpaper = szWallpaperA;
  1145. #endif
  1146. if (IsWallpaperPicture(pszWallpaper))
  1147. {
  1148. WALLPAPEROPT wpo = { sizeof(wpo) };
  1149. if (SUCCEEDED(pad->GetWallpaperOptions(&wpo, 0)))
  1150. {
  1151. if (wpo.dwStyle == WPSTYLE_CENTER)
  1152. {
  1153. //
  1154. // We have a centered picture,
  1155. // the pattern or desktop color
  1156. // could be leaking around the edges.
  1157. // We need to regenerate the desktop
  1158. // HTML.
  1159. //
  1160. fRegenerateHtml = TRUE;
  1161. }
  1162. }
  1163. else
  1164. {
  1165. TraceMsg(TF_WARNING, "SYSCLRCHG: Could not get wallpaper options!");
  1166. }
  1167. }
  1168. }
  1169. }
  1170. else
  1171. {
  1172. TraceMsg(TF_WARNING, "SYSCLRCHG: Could not get selected wallpaper!");
  1173. }
  1174. if (fRegenerateHtml)
  1175. {
  1176. DWORD dwFlags = AD_APPLY_FORCE | AD_APPLY_HTMLGEN | AD_APPLY_REFRESH | AD_APPLY_DYNAMICREFRESH;
  1177. WCHAR wszPattern[MAX_PATH];
  1178. //If we have a pattern, then we need to force a AD_APPLY_COMPLETEREFRESH
  1179. // because we need to re-generate the pattern.bmp file which can not be
  1180. // done through dynamic HTML.
  1181. if(SUCCEEDED(pad->GetPattern(wszPattern, ARRAYSIZE(wszPattern), 0)))
  1182. {
  1183. #ifdef UNICODE
  1184. LPTSTR szPattern = (LPTSTR)wszPattern;
  1185. #else
  1186. CHAR szPattern[MAX_PATH];
  1187. SHUnicodeToAnsi(wszPattern, szPattern, sizeof(szPattern));
  1188. #endif //UNICODE
  1189. if(IsValidPattern(szPattern)) //Does this have a pattern?
  1190. dwFlags &= ~(AD_APPLY_DYNAMICREFRESH); //Then force a complete refresh!
  1191. }
  1192. pad->ApplyChanges(dwFlags);
  1193. }
  1194. pad->Release();
  1195. }
  1196. else
  1197. {
  1198. TraceMsg(TF_WARNING, "SYSCLRCHG: Could not create CActiveDesktop!");
  1199. }
  1200. }
  1201. //
  1202. // Convert a .URL file into its target.
  1203. //
  1204. BOOL CheckAndResolveLocalUrlFile(LPTSTR pszFileName, int cchFileName)
  1205. {
  1206. BOOL fRet;
  1207. //
  1208. // Check if the extension of this file is *.URL
  1209. //
  1210. LPTSTR pszExt = PathFindExtension(pszFileName);
  1211. if (pszExt && *pszExt)
  1212. {
  1213. TCHAR szUrl[15];
  1214. LoadString(HINST_THISDLL, IDS_URL_EXTENSION, szUrl, ARRAYSIZE(szUrl));
  1215. if (lstrcmpi(pszExt, szUrl) != 0)
  1216. {
  1217. fRet = TRUE;
  1218. }
  1219. else
  1220. {
  1221. fRet = FALSE;
  1222. IUniformResourceLocator *purl;
  1223. HRESULT hr = CoCreateInstance(CLSID_InternetShortcut, NULL, CLSCTX_INPROC_SERVER,
  1224. IID_IUniformResourceLocator,
  1225. (LPVOID *)&purl);
  1226. if (SUCCEEDED(hr))
  1227. {
  1228. ASSERT(purl);
  1229. IPersistFile *ppf;
  1230. hr = purl->QueryInterface(IID_IPersistFile, (LPVOID *)&ppf);
  1231. if (SUCCEEDED(hr))
  1232. {
  1233. hr = ppf->Load(pszFileName, STGM_READ);
  1234. if (SUCCEEDED(hr))
  1235. {
  1236. LPTSTR pszTemp;
  1237. hr = purl->GetURL(&pszTemp);
  1238. if (SUCCEEDED(hr))
  1239. {
  1240. hr = StringCchCopy(pszFileName, cchFileName, pszTemp);
  1241. if (SUCCEEDED(hr))
  1242. {
  1243. fRet = TRUE;
  1244. }
  1245. CoTaskMemFree(pszTemp);
  1246. }
  1247. }
  1248. ppf->Release();
  1249. }
  1250. purl->Release();
  1251. }
  1252. }
  1253. }
  1254. else
  1255. {
  1256. fRet = TRUE;
  1257. }
  1258. return fRet;
  1259. }
  1260. //
  1261. // Silently adds/removes a specified component to the desktop and use the given
  1262. // apply flags using which you can avoid nested unnecessary HTML generation,
  1263. // or refreshing which may lead to racing conditions.
  1264. //
  1265. //
  1266. 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)
  1267. {
  1268. COMPONENTA Comp;
  1269. HRESULT hres;
  1270. //
  1271. // Build the pcomp structure.
  1272. //
  1273. Comp.dwSize = sizeof(COMPONENTA);
  1274. Comp.dwID = -1;
  1275. Comp.iComponentType = iCompType;
  1276. Comp.fChecked = fChecked;
  1277. Comp.fDirty = FALSE;
  1278. Comp.fNoScroll = fNoScroll;
  1279. Comp.cpPos.dwSize = sizeof(COMPPOS);
  1280. Comp.cpPos.iLeft = iLeft;
  1281. Comp.cpPos.iTop = iTop;
  1282. Comp.cpPos.dwWidth = iWidth;
  1283. Comp.cpPos.dwHeight = iHeight;
  1284. Comp.cpPos.izIndex = (dwCurItemState & IS_NORMAL) ? COMPONENT_TOP : 0;
  1285. Comp.cpPos.fCanResize = fCanResize;
  1286. Comp.cpPos.fCanResizeX = fCanResize;
  1287. Comp.cpPos.fCanResizeY = fCanResize;
  1288. Comp.cpPos.iPreferredLeftPercent = 0;
  1289. Comp.cpPos.iPreferredTopPercent = 0;
  1290. Comp.dwCurItemState = dwCurItemState;
  1291. hres = StringCchCopy(Comp.szSource, ARRAYSIZE(Comp.szSource), pszUrl);
  1292. if (SUCCEEDED(hres))
  1293. {
  1294. hres = StringCchCopy(Comp.szSubscribedURL, ARRAYSIZE(Comp.szSubscribedURL), pszUrl);
  1295. if (SUCCEEDED(hres))
  1296. {
  1297. if (pszFriendlyName)
  1298. {
  1299. hres = StringCchCopy(Comp.szFriendlyName, ARRAYSIZE(Comp.szFriendlyName), pszFriendlyName);
  1300. }
  1301. else
  1302. {
  1303. Comp.szFriendlyName[0] = TEXT('\0');
  1304. }
  1305. if (SUCCEEDED(hres))
  1306. {
  1307. IActiveDesktop *pActiveDesk;
  1308. //
  1309. // Add it to the system.
  1310. //
  1311. hres = CActiveDesktop_InternalCreateInstance((LPUNKNOWN *)&pActiveDesk, IID_IActiveDesktop);
  1312. if (SUCCEEDED(hres))
  1313. {
  1314. COMPONENT CompW;
  1315. CompW.dwSize = sizeof(CompW); //Required for the MultiCompToWideComp to work properly.
  1316. MultiCompToWideComp(&Comp, &CompW);
  1317. if(fAdd)
  1318. pActiveDesk->AddDesktopItem(&CompW, 0);
  1319. else
  1320. pActiveDesk->RemoveDesktopItem(&CompW, 0);
  1321. pActiveDesk->ApplyChanges(dwApplyFlags);
  1322. pActiveDesk->Release();
  1323. }
  1324. }
  1325. }
  1326. }
  1327. return SUCCEEDED(hres);
  1328. }
  1329. //
  1330. // Summary:
  1331. // On upgrade from W2K, it is possible (under certain conditions) that the Active Desktop
  1332. // gets turned ON automatically. This is bug #154993. The following function fixes this bug.
  1333. //
  1334. // Details of why this happens:
  1335. //
  1336. // In W2K, it is possible to enable active desktop components, hide icons, lock the components
  1337. // and then turn off active desktop. But, all the details (like what AD components were ON etc.,)
  1338. // was persisted in the registry. When such a machine is upgraded to Whister, bug #154993 surfaces
  1339. // because of the following reason:
  1340. // In Whislter, ActiveDesktop is turned on/off silently based on whether any desktop component is
  1341. // on etc., As a result when a W2K machine (with AD off) is upgraded to Whistler, the AD will be
  1342. // turned on automatically, if one of the following is true:
  1343. // 1. If the desktop icons were off.
  1344. // 2. If the active desktop components were locked.
  1345. // 3. If any active desktop component is ON; but, not displayed because AD was OFF..
  1346. // Therefore on upgrade from a Win2K or older machine, we check if the AD is OFF. If so, then we
  1347. // need to check for conditions 1, 2 and 3 and change those settings such that AD continues to be
  1348. // OFF even after the upgrade. The following function OnUpgradeDisableActiveDesktopFeatures ()
  1349. // does precisely this.
  1350. //
  1351. // Returns: TRUE, if any setting was modified to keep the active desktop in the turned off state!
  1352. //
  1353. BOOL OnUpgradeDisableActiveDesktopFeatures()
  1354. {
  1355. IActiveDesktop *pActiveDesk;
  1356. BOOL fModified = FALSE;
  1357. // Get the ActiveDesktop and HideIcons flags.
  1358. SHELLSTATE ss = {0};
  1359. SHGetSetSettings(&ss, SSF_DESKTOPHTML | SSF_HIDEICONS, FALSE);
  1360. //Check if ActiveDesktop is already ON.
  1361. if(ss.fDesktopHTML)
  1362. return FALSE; //ActiveDesktop is already ON. No need to change any settings.
  1363. //Active Desktop is OFF. We may need to change the other settings to be consistent with this!
  1364. // 1. Check if Desktop icons are hidden when ActiveDesktop is on.
  1365. if(ss.fHideIcons)
  1366. {
  1367. //Yes! Turn off this. Otherwise, AD will be turned on to support this!
  1368. ss.fHideIcons = FALSE;
  1369. SHGetSetSettings(&ss, SSF_HIDEICONS, TRUE);
  1370. fModified = TRUE;
  1371. }
  1372. // 2. If the ActiveDesktop components are locked, un-lock them.
  1373. DWORD dwDesktopFlags = GetDesktopFlags();
  1374. if(dwDesktopFlags & COMPONENTS_LOCKED)
  1375. {
  1376. if(SetDesktopFlags(COMPONENTS_LOCKED, 0)) //Remove the "locked" flag!
  1377. fModified = TRUE;
  1378. }
  1379. // 3. Let's enumerate all active desktop components and make sure they are all off.
  1380. BOOL fModifiedComp = FALSE;
  1381. HRESULT hres = CActiveDesktop_InternalCreateInstance((LPUNKNOWN *)&pActiveDesk, IID_IActiveDesktop);
  1382. if (SUCCEEDED(hres))
  1383. {
  1384. int iCount = 0;
  1385. pActiveDesk->GetDesktopItemCount(&iCount, 0);
  1386. for(int i = 0; i < iCount; i++)
  1387. {
  1388. COMPONENT Comp;
  1389. Comp.dwSize = sizeof(Comp);
  1390. if(SUCCEEDED(pActiveDesk->GetDesktopItem(i, &Comp, 0)))
  1391. {
  1392. if(Comp.fChecked) //If this component is enabled.....
  1393. {
  1394. Comp.fChecked = FALSE; //...., then disable it!
  1395. if(SUCCEEDED(pActiveDesk->ModifyDesktopItem(&Comp, COMP_ELEM_CHECKED)))
  1396. fModifiedComp = TRUE;
  1397. }
  1398. }
  1399. }
  1400. if(fModifiedComp)
  1401. pActiveDesk->ApplyChanges(AD_APPLY_SAVE); //We just need to save the above changes.
  1402. pActiveDesk ->Release();
  1403. }
  1404. //return whether we modified any setting.
  1405. return (fModified || fModifiedComp);
  1406. }
  1407. // Little helper function used to change the safemode state
  1408. void SetSafeMode(DWORD dwFlags)
  1409. {
  1410. IActiveDesktopP * piadp;
  1411. if (SUCCEEDED(CActiveDesktop_InternalCreateInstance((LPUNKNOWN *)&piadp, IID_IActiveDesktopP)))
  1412. {
  1413. piadp->SetSafeMode(dwFlags);
  1414. piadp->Release();
  1415. }
  1416. }
  1417. /****************************************************************************
  1418. *
  1419. * RefreshWebViewDesktop - regenerates desktop HTML from registry and updates
  1420. * the screen
  1421. *
  1422. * ENTRY:
  1423. * none
  1424. *
  1425. * RETURNS:
  1426. * TRUE on success
  1427. *
  1428. ****************************************************************************/
  1429. BOOL PokeWebViewDesktop(DWORD dwFlags)
  1430. {
  1431. IActiveDesktop *pad;
  1432. HRESULT hres;
  1433. BOOL fRet = FALSE;
  1434. hres = CActiveDesktop_InternalCreateInstance((LPUNKNOWN *)&pad, IID_IActiveDesktop);
  1435. if (SUCCEEDED(hres))
  1436. {
  1437. pad->ApplyChanges(dwFlags);
  1438. pad->Release();
  1439. fRet = TRUE;
  1440. }
  1441. return (fRet);
  1442. }
  1443. #define CCH_NONE 20 //big enough for "(None)" in german
  1444. TCHAR g_szNone[CCH_NONE] = {0};
  1445. void InitDeskHtmlGlobals(void)
  1446. {
  1447. static fGlobalsInited = FALSE;
  1448. if (fGlobalsInited == FALSE)
  1449. {
  1450. LoadString(HINST_THISDLL, IDS_WPNONE, g_szNone, ARRAYSIZE(g_szNone));
  1451. fGlobalsInited = TRUE;
  1452. }
  1453. }
  1454. //
  1455. // Loads the preview bitmap for property sheet pages.
  1456. //
  1457. HBITMAP LoadMonitorBitmap(void)
  1458. {
  1459. HBITMAP hbm,hbmT;
  1460. BITMAP bm;
  1461. HBRUSH hbrT;
  1462. HDC hdc;
  1463. COLORREF c3df = GetSysColor(COLOR_3DFACE);
  1464. hbm = LoadBitmap(HINST_THISDLL, MAKEINTRESOURCE(IDB_MONITOR));
  1465. if (hbm == NULL)
  1466. {
  1467. return NULL;
  1468. }
  1469. //
  1470. // Convert the "base" of the monitor to the right color.
  1471. //
  1472. // The lower left of the bitmap has a transparent color
  1473. // we fixup using FloodFill
  1474. //
  1475. hdc = CreateCompatibleDC(NULL);
  1476. hbmT = (HBITMAP)SelectObject(hdc, hbm);
  1477. hbrT = (HBRUSH)SelectObject(hdc, GetSysColorBrush(COLOR_3DFACE));
  1478. GetObject(hbm, sizeof(bm), &bm);
  1479. ExtFloodFill(hdc, 0, bm.bmHeight-1, GetPixel(hdc, 0, bm.bmHeight-1), FLOODFILLSURFACE);
  1480. //
  1481. // Round off the corners.
  1482. // The bottom two were done by the floodfill above.
  1483. // The top left is important since SS_CENTERIMAGE uses it to fill gaps.
  1484. // The top right should be rounded because the other three are.
  1485. //
  1486. SetPixel( hdc, 0, 0, c3df );
  1487. SetPixel( hdc, bm.bmWidth-1, 0, c3df );
  1488. //
  1489. // Fill in the desktop here.
  1490. //
  1491. HBRUSH hbrOld = (HBRUSH)SelectObject(hdc, GetSysColorBrush(COLOR_DESKTOP));
  1492. PatBlt(hdc, MON_X, MON_Y, MON_DX, MON_DY, PATCOPY);
  1493. SelectObject(hdc, hbrOld);
  1494. //
  1495. // Clean up after ourselves.
  1496. //
  1497. SelectObject(hdc, hbrT);
  1498. SelectObject(hdc, hbmT);
  1499. DeleteDC(hdc);
  1500. return hbm;
  1501. }
  1502. STDAPI_(VOID) ActiveDesktop_ApplyChanges()
  1503. {
  1504. IActiveDesktop* piad;
  1505. if (SUCCEEDED(CoCreateInstance(CLSID_ActiveDesktop, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IActiveDesktop, &piad))))
  1506. {
  1507. piad->ApplyChanges(AD_APPLY_ALL | AD_APPLY_DYNAMICREFRESH);
  1508. piad->Release();
  1509. }
  1510. }
  1511. STDAPI_(DWORD) GetDesktopFlags(void)
  1512. {
  1513. DWORD dwFlags = 0, dwType, cbSize = sizeof(dwFlags);
  1514. TCHAR szDeskcomp[MAX_PATH];
  1515. GetRegLocation(szDeskcomp, ARRAYSIZE(szDeskcomp), REG_DESKCOMP_COMPONENTS, NULL);
  1516. SHGetValue(HKEY_CURRENT_USER, szDeskcomp, REG_VAL_COMP_GENFLAGS, &dwType, &dwFlags, &cbSize);
  1517. return dwFlags;
  1518. }
  1519. STDAPI_(BOOL) SetDesktopFlags(DWORD dwMask, DWORD dwNewFlags)
  1520. {
  1521. BOOL fRet = FALSE;
  1522. HKEY hkey;
  1523. DWORD dwDisposition;
  1524. TCHAR szDeskcomp[MAX_PATH];
  1525. GetRegLocation(szDeskcomp, ARRAYSIZE(szDeskcomp), REG_DESKCOMP_COMPONENTS, NULL);
  1526. if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_CURRENT_USER, szDeskcomp,
  1527. 0, NULL, 0, KEY_QUERY_VALUE | KEY_SET_VALUE, NULL, &hkey,
  1528. &dwDisposition))
  1529. {
  1530. DWORD dwFlags;
  1531. DWORD cbSize = sizeof(dwFlags);
  1532. DWORD dwType;
  1533. if (SHQueryValueEx(hkey, REG_VAL_COMP_GENFLAGS, NULL, &dwType,
  1534. (LPBYTE)&dwFlags, &cbSize) != ERROR_SUCCESS)
  1535. {
  1536. dwFlags = 0;
  1537. }
  1538. dwFlags = (dwFlags & ~dwMask) | (dwNewFlags & dwMask);
  1539. if (RegSetValueEx(hkey, REG_VAL_COMP_GENFLAGS, 0, REG_DWORD,
  1540. (LPBYTE)&dwFlags, sizeof(dwFlags)) == ERROR_SUCCESS)
  1541. {
  1542. fRet = TRUE;
  1543. }
  1544. RegCloseKey(hkey);
  1545. }
  1546. return fRet;
  1547. }
  1548. BOOL UpdateComponentFlags(LPCTSTR pszCompId, DWORD dwMask, DWORD dwNewFlags)
  1549. {
  1550. BOOL fRet = FALSE;
  1551. TCHAR szRegPath[MAX_PATH];
  1552. HKEY hkey;
  1553. GetRegLocation(szRegPath, ARRAYSIZE(szRegPath), REG_DESKCOMP_COMPONENTS, NULL);
  1554. if (PathAppend(szRegPath, pszCompId))
  1555. {
  1556. //Don't use RegCreateKeyEx here. It will result in Null components to be added.
  1557. if (RegOpenKeyEx(HKEY_CURRENT_USER, szRegPath, 0,
  1558. KEY_READ | KEY_WRITE, &hkey) == ERROR_SUCCESS)
  1559. {
  1560. DWORD dwType, dwFlags, dwDataLength;
  1561. dwDataLength = sizeof(DWORD);
  1562. if(SHQueryValueEx(hkey, REG_VAL_COMP_FLAGS, NULL, &dwType, (LPBYTE)&dwFlags, &dwDataLength) != ERROR_SUCCESS)
  1563. {
  1564. dwFlags = 0;
  1565. }
  1566. dwNewFlags = (dwFlags & ~dwMask) | (dwNewFlags & dwMask);
  1567. if (RegSetValueEx(hkey, REG_VAL_COMP_FLAGS, 0, REG_DWORD, (LPBYTE)&dwNewFlags,
  1568. sizeof(DWORD)) == ERROR_SUCCESS)
  1569. {
  1570. fRet = TRUE;
  1571. }
  1572. SetDesktopFlags(COMPONENTS_DIRTY, COMPONENTS_DIRTY);
  1573. RegCloseKey(hkey);
  1574. }
  1575. }
  1576. if (!fRet)
  1577. {
  1578. TraceMsg(TF_WARNING, "DS: Unable to UpdateComponentFlags");
  1579. }
  1580. return fRet;
  1581. }
  1582. DWORD GetCurrentState(LPTSTR pszCompId)
  1583. {
  1584. TCHAR szRegPath[MAX_PATH];
  1585. DWORD cbSize, dwType, dwCurState = IS_NORMAL;
  1586. GetRegLocation(szRegPath, ARRAYSIZE(szRegPath), REG_DESKCOMP_COMPONENTS, NULL);
  1587. if (PathAppend(szRegPath, pszCompId))
  1588. {
  1589. cbSize = sizeof(dwCurState);
  1590. SHGetValue(HKEY_CURRENT_USER, szRegPath, REG_VAL_COMP_CURSTATE, &dwType, &dwCurState, &cbSize);
  1591. }
  1592. return dwCurState;
  1593. }
  1594. BOOL GetSavedStateInfo(LPTSTR pszCompId, LPCOMPSTATEINFO pCompState, BOOL fRestoredState)
  1595. {
  1596. BOOL fRet = FALSE;
  1597. TCHAR szRegPath[MAX_PATH];
  1598. HKEY hkey;
  1599. LPTSTR lpValName = (fRestoredState ? REG_VAL_COMP_RESTOREDSTATEINFO : REG_VAL_COMP_ORIGINALSTATEINFO);
  1600. GetRegLocation(szRegPath, ARRAYSIZE(szRegPath), REG_DESKCOMP_COMPONENTS, NULL);
  1601. if (PathAppend(szRegPath, pszCompId) &&
  1602. ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, szRegPath, 0, KEY_READ, &hkey))
  1603. {
  1604. DWORD cbSize, dwType;
  1605. cbSize = sizeof(*pCompState);
  1606. dwType = REG_BINARY;
  1607. if (SHQueryValueEx(hkey, lpValName, NULL, &dwType, (LPBYTE)pCompState, &cbSize) != ERROR_SUCCESS)
  1608. {
  1609. //If the item state is missing, read the item current position and
  1610. // and return that as the saved state.
  1611. COMPPOS cpPos;
  1612. cbSize = sizeof(cpPos);
  1613. dwType = REG_BINARY;
  1614. if (SHQueryValueEx(hkey, REG_VAL_COMP_POSITION, NULL, &dwType, (LPBYTE)&cpPos, &cbSize) != ERROR_SUCCESS)
  1615. {
  1616. ZeroMemory(&cpPos, sizeof(cpPos));
  1617. }
  1618. SetStateInfo(pCompState, &cpPos, IS_NORMAL);
  1619. }
  1620. RegCloseKey(hkey);
  1621. fRet = TRUE;
  1622. }
  1623. if (!fRet)
  1624. {
  1625. TraceMsg(TF_WARNING, "DS: Unable to get SavedStateInfo()");
  1626. }
  1627. return fRet;
  1628. }
  1629. BOOL UpdateDesktopPosition(LPTSTR pszCompId, int iLeft, int iTop, DWORD dwWidth, DWORD dwHeight, int izIndex,
  1630. BOOL fSaveRestorePos, BOOL fSaveOriginal, DWORD dwCurState)
  1631. {
  1632. BOOL fRet = FALSE;
  1633. TCHAR szRegPath[MAX_PATH];
  1634. HKEY hkey;
  1635. GetRegLocation(szRegPath, ARRAYSIZE(szRegPath), REG_DESKCOMP_COMPONENTS, NULL);
  1636. if (PathAppend(szRegPath, pszCompId) &&
  1637. ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, szRegPath, 0, KEY_QUERY_VALUE | KEY_SET_VALUE, &hkey)) //Don't use RegCreateKeyEx here; It will result in a NULL component being added.
  1638. {
  1639. COMPPOS cp;
  1640. DWORD dwType;
  1641. DWORD dwDataLength;
  1642. COMPSTATEINFO csi;
  1643. dwType = REG_BINARY;
  1644. dwDataLength = sizeof(COMPPOS);
  1645. if(SHQueryValueEx(hkey, REG_VAL_COMP_POSITION, NULL, &dwType, (LPBYTE)&cp, &dwDataLength) != ERROR_SUCCESS)
  1646. {
  1647. cp.fCanResize = cp.fCanResizeX = cp.fCanResizeY = TRUE;
  1648. cp.iPreferredLeftPercent = cp.iPreferredTopPercent = 0;
  1649. }
  1650. //Read the current State
  1651. dwType = REG_DWORD;
  1652. dwDataLength = sizeof(csi.dwItemState);
  1653. if (SHQueryValueEx(hkey, REG_VAL_COMP_CURSTATE, NULL, &dwType, (LPBYTE)&csi.dwItemState, &dwDataLength) != ERROR_SUCCESS)
  1654. {
  1655. csi.dwItemState = IS_NORMAL;
  1656. }
  1657. if(fSaveRestorePos)
  1658. {
  1659. //We have just read the current position; Let's save it as the restore position.
  1660. SetStateInfo(&csi, &cp, csi.dwItemState);
  1661. //Now that we know the complete current state, save it as the restore state!
  1662. RegSetValueEx(hkey, REG_VAL_COMP_RESTOREDSTATEINFO, 0, REG_BINARY, (LPBYTE)&csi, sizeof(csi));
  1663. }
  1664. //Save the current state too!
  1665. if(dwCurState)
  1666. RegSetValueEx(hkey, REG_VAL_COMP_CURSTATE, 0, REG_DWORD, (LPBYTE)&dwCurState, sizeof(dwCurState));
  1667. cp.dwSize = sizeof(COMPPOS);
  1668. cp.iLeft = iLeft;
  1669. cp.iTop = iTop;
  1670. cp.dwWidth = dwWidth;
  1671. cp.dwHeight = dwHeight;
  1672. cp.izIndex = izIndex;
  1673. if (fSaveOriginal) {
  1674. SetStateInfo(&csi, &cp, csi.dwItemState);
  1675. RegSetValueEx(hkey, REG_VAL_COMP_ORIGINALSTATEINFO, 0, REG_BINARY, (LPBYTE)&csi, sizeof(csi));
  1676. }
  1677. if (RegSetValueEx(hkey, REG_VAL_COMP_POSITION, 0, REG_BINARY, (LPBYTE)&cp,
  1678. sizeof(cp)) == ERROR_SUCCESS)
  1679. {
  1680. fRet = TRUE;
  1681. }
  1682. // Don't need to mark as dirty if we're just saving the original pos
  1683. if (!fSaveOriginal)
  1684. SetDesktopFlags(COMPONENTS_DIRTY, COMPONENTS_DIRTY);
  1685. RegCloseKey(hkey);
  1686. }
  1687. if (!fRet)
  1688. {
  1689. TraceMsg(TF_WARNING, "DS: Unable to UpdateDesktopPosition");
  1690. }
  1691. return fRet;
  1692. }
  1693. HRESULT GetPerUserFileName(LPTSTR pszOutputFileName, DWORD dwSize, LPTSTR pszPartialFileName)
  1694. {
  1695. LPITEMIDLIST pidlAppData;
  1696. *pszOutputFileName = TEXT('\0');
  1697. if(dwSize < MAX_PATH)
  1698. {
  1699. ASSERT(FALSE);
  1700. return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  1701. }
  1702. HRESULT hr = SHGetSpecialFolderLocation(NULL, CSIDL_APPDATA, &pidlAppData);
  1703. if (SUCCEEDED(hr))
  1704. {
  1705. SHGetPathFromIDList(pidlAppData, pszOutputFileName);
  1706. DWORD err = SHCreateDirectoryEx(NULL, pszOutputFileName, NULL);
  1707. if (ERROR_FILE_EXISTS != err &&
  1708. ERROR_ALREADY_EXISTS != err &&
  1709. ERROR_SUCCESS != err)
  1710. {
  1711. hr = ResultFromLastError();
  1712. }
  1713. else
  1714. {
  1715. if (!PathAppend(pszOutputFileName, pszPartialFileName))
  1716. {
  1717. hr = E_FAIL;
  1718. }
  1719. else
  1720. {
  1721. hr = S_OK;
  1722. }
  1723. }
  1724. ILFree(pidlAppData);
  1725. }
  1726. return hr;
  1727. }
  1728. void GetRegLocation(LPTSTR lpszResult, DWORD cchResult, LPCTSTR lpszKey, LPCTSTR lpszScheme)
  1729. {
  1730. TCHAR szSubkey[MAX_PATH] = TEXT("\\");
  1731. DWORD dwDataLength = sizeof(szSubkey) - 2 * sizeof(TCHAR);
  1732. DWORD dwType;
  1733. // use what was given or get it from the registry
  1734. if (lpszScheme)
  1735. {
  1736. StringCchCat(szSubkey, ARRAYSIZE(szSubkey), lpszScheme);
  1737. }
  1738. else
  1739. {
  1740. SHGetValue(HKEY_CURRENT_USER, REG_DESKCOMP_SCHEME, REG_VAL_SCHEME_DISPLAY, &dwType,
  1741. (LPBYTE)(szSubkey) + sizeof(TCHAR), &dwDataLength);
  1742. }
  1743. if (szSubkey[1])
  1744. {
  1745. StringCchCat(szSubkey, ARRAYSIZE(szSubkey), TEXT("\\"));
  1746. }
  1747. StringCchPrintf(lpszResult, cchResult, lpszKey, szSubkey);
  1748. }
  1749. BOOL ValidateFileName(HWND hwnd, LPCTSTR pszFilename, int iTypeString)
  1750. {
  1751. BOOL fRet = TRUE;
  1752. DWORD dwAttributes = GetFileAttributes(pszFilename);
  1753. if ((dwAttributes != 0xFFFFFFFF) &&
  1754. (dwAttributes & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN)))
  1755. {
  1756. TCHAR szType1[64];
  1757. TCHAR szType2[64];
  1758. LoadString(HINST_THISDLL, iTypeString, szType1, ARRAYSIZE(szType1));
  1759. LoadString(HINST_THISDLL, iTypeString+1, szType2, ARRAYSIZE(szType2));
  1760. if (ShellMessageBox(HINST_THISDLL, hwnd,
  1761. MAKEINTRESOURCE(IDS_VALIDFN_FMT),
  1762. MAKEINTRESOURCE(IDS_VALIDFN_TITLE),
  1763. MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2,
  1764. szType1, szType2) == IDNO)
  1765. {
  1766. fRet = FALSE;
  1767. }
  1768. }
  1769. return fRet;
  1770. }
  1771. BOOL GetWallpaperDirName(LPTSTR lpszWallPaperDir, int iBuffSize)
  1772. {
  1773. BOOL fRet = FALSE;
  1774. TCHAR szExp[MAX_PATH];
  1775. //Compute the default wallpaper name.
  1776. if (GetWindowsDirectory(lpszWallPaperDir, iBuffSize) &&
  1777. SUCCEEDED(StringCchCat(lpszWallPaperDir, iBuffSize, DESKTOPHTML_WEB_DIR)))
  1778. {
  1779. //Read it from the registry key, if it is set!
  1780. DWORD dwType;
  1781. DWORD cbData = (DWORD)iBuffSize;
  1782. SHGetValue(HKEY_LOCAL_MACHINE, REGSTR_PATH_SETUP, c_szWallPaperDir, &dwType, (LPVOID)lpszWallPaperDir, &cbData);
  1783. SHExpandEnvironmentStrings(lpszWallPaperDir, szExp, ARRAYSIZE(szExp));
  1784. if (SUCCEEDED(StringCchCopy(lpszWallPaperDir, iBuffSize, szExp)))
  1785. {
  1786. fRet = TRUE;
  1787. }
  1788. }
  1789. return fRet;
  1790. }
  1791. BOOL CALLBACK MultiMonEnumAreaCallBack(HMONITOR hMonitor, HDC hdc, LPRECT lprc, LPARAM lData)
  1792. {
  1793. EnumMonitorsArea* pEMA = (EnumMonitorsArea*)lData;
  1794. if (pEMA->iMonitors > LV_MAX_WORKAREAS - 1)
  1795. {
  1796. //ignore the other monitors because we can only handle up to LV_MAX_WORKAREAS
  1797. //REARCHITECT: should we dynamically allocate this?
  1798. return FALSE;
  1799. }
  1800. GetMonitorRect(hMonitor, &pEMA->rcMonitor[pEMA->iMonitors]);
  1801. GetMonitorWorkArea(hMonitor, &pEMA->rcWorkArea[pEMA->iMonitors]);
  1802. if(pEMA->iMonitors == 0)
  1803. {
  1804. pEMA->rcVirtualMonitor.left = pEMA->rcMonitor[0].left;
  1805. pEMA->rcVirtualMonitor.top = pEMA->rcMonitor[0].top;
  1806. pEMA->rcVirtualMonitor.right = pEMA->rcMonitor[0].right;
  1807. pEMA->rcVirtualMonitor.bottom = pEMA->rcMonitor[0].bottom;
  1808. pEMA->rcVirtualWorkArea.left = pEMA->rcWorkArea[0].left;
  1809. pEMA->rcVirtualWorkArea.top = pEMA->rcWorkArea[0].top;
  1810. pEMA->rcVirtualWorkArea.right = pEMA->rcWorkArea[0].right;
  1811. pEMA->rcVirtualWorkArea.bottom = pEMA->rcWorkArea[0].bottom;
  1812. }
  1813. else
  1814. {
  1815. if(pEMA->rcMonitor[pEMA->iMonitors].left < pEMA->rcVirtualMonitor.left)
  1816. {
  1817. pEMA->rcVirtualMonitor.left = pEMA->rcMonitor[pEMA->iMonitors].left;
  1818. }
  1819. if(pEMA->rcMonitor[pEMA->iMonitors].top < pEMA->rcVirtualMonitor.top)
  1820. {
  1821. pEMA->rcVirtualMonitor.top = pEMA->rcMonitor[pEMA->iMonitors].top;
  1822. }
  1823. if(pEMA->rcMonitor[pEMA->iMonitors].right > pEMA->rcVirtualMonitor.right)
  1824. {
  1825. pEMA->rcVirtualMonitor.right = pEMA->rcMonitor[pEMA->iMonitors].right;
  1826. }
  1827. if(pEMA->rcMonitor[pEMA->iMonitors].bottom > pEMA->rcVirtualMonitor.bottom)
  1828. {
  1829. pEMA->rcVirtualMonitor.bottom = pEMA->rcMonitor[pEMA->iMonitors].bottom;
  1830. }
  1831. if(pEMA->rcWorkArea[pEMA->iMonitors].left < pEMA->rcVirtualWorkArea.left)
  1832. {
  1833. pEMA->rcVirtualWorkArea.left = pEMA->rcWorkArea[pEMA->iMonitors].left;
  1834. }
  1835. if(pEMA->rcWorkArea[pEMA->iMonitors].top < pEMA->rcVirtualWorkArea.top)
  1836. {
  1837. pEMA->rcVirtualWorkArea.top = pEMA->rcWorkArea[pEMA->iMonitors].top;
  1838. }
  1839. if(pEMA->rcWorkArea[pEMA->iMonitors].right > pEMA->rcVirtualWorkArea.right)
  1840. {
  1841. pEMA->rcVirtualWorkArea.right = pEMA->rcWorkArea[pEMA->iMonitors].right;
  1842. }
  1843. if(pEMA->rcWorkArea[pEMA->iMonitors].bottom > pEMA->rcVirtualWorkArea.bottom)
  1844. {
  1845. pEMA->rcVirtualWorkArea.bottom = pEMA->rcWorkArea[pEMA->iMonitors].bottom;
  1846. }
  1847. }
  1848. pEMA->iMonitors++;
  1849. return TRUE;
  1850. }
  1851. void GetMonitorSettings(EnumMonitorsArea* ema)
  1852. {
  1853. ema->iMonitors = 0;
  1854. ema->rcVirtualMonitor.left = 0;
  1855. ema->rcVirtualMonitor.top = 0;
  1856. ema->rcVirtualMonitor.right = 0;
  1857. ema->rcVirtualMonitor.bottom = 0;
  1858. ema->rcVirtualWorkArea.left = 0;
  1859. ema->rcVirtualWorkArea.top = 0;
  1860. ema->rcVirtualWorkArea.right = 0;
  1861. ema->rcVirtualWorkArea.bottom = 0;
  1862. EnumDisplayMonitors(NULL, NULL, MultiMonEnumAreaCallBack, (LPARAM)ema);
  1863. }
  1864. int _GetWorkAreaIndexWorker(POINT pt, LPCRECT prect, int crect)
  1865. {
  1866. int iIndex;
  1867. for (iIndex = 0; iIndex < crect; iIndex++)
  1868. {
  1869. if (PtInRect(&prect[iIndex], pt))
  1870. {
  1871. return iIndex;
  1872. }
  1873. }
  1874. return -1;
  1875. }
  1876. int GetWorkAreaIndexFromPoint(POINT pt, LPCRECT prect, int crect)
  1877. {
  1878. ASSERT(crect);
  1879. // Map to correct coords...
  1880. pt.x += prect[0].left;
  1881. pt.y += prect[0].top;
  1882. return _GetWorkAreaIndexWorker(pt, prect, crect);
  1883. }
  1884. // Prepends the Web wallpaper directory or the system directory to szWallpaper, if necessary
  1885. // (i.e., if the path is not specified). The return value is in szWallpaperWithPath, which is iBufSize
  1886. // bytes long
  1887. BOOL GetWallpaperWithPath(LPCTSTR szWallpaper, LPTSTR szWallpaperWithPath, int iBufSize)
  1888. {
  1889. BOOL fRet = FALSE;
  1890. if (szWallpaper[0] && lstrcmpi(szWallpaper, g_szNone) != 0 && !StrChr(szWallpaper, TEXT('\\'))
  1891. && !StrChr(szWallpaper, TEXT(':'))) // The file could be d:foo.bmp
  1892. {
  1893. // If the file is a normal wallpaper, we prepend the windows directory to the filename
  1894. if (IsNormalWallpaper(szWallpaper))
  1895. {
  1896. if (ERROR_SUCCESS == GetWindowsDirectory(szWallpaperWithPath, iBufSize))
  1897. {
  1898. fRet = TRUE;
  1899. }
  1900. }
  1901. // else we prepend the wallpaper directory to the filename
  1902. else
  1903. {
  1904. fRet = GetWallpaperDirName(szWallpaperWithPath, iBufSize);
  1905. }
  1906. if (fRet)
  1907. {
  1908. fRet = PathAppend(szWallpaperWithPath, szWallpaper);
  1909. }
  1910. }
  1911. else
  1912. {
  1913. if (SUCCEEDED(StringCchCopy(szWallpaperWithPath, iBufSize, szWallpaper)))
  1914. {
  1915. fRet = TRUE;
  1916. }
  1917. }
  1918. return fRet;
  1919. }
  1920. BOOL GetViewAreas(LPRECT lprcViewAreas, int* pnViewAreas)
  1921. {
  1922. BOOL bRet = FALSE;
  1923. HWND hwndDesktop = GetShellWindow(); // This is the "normal" desktop
  1924. if (hwndDesktop && IsWindow(hwndDesktop))
  1925. {
  1926. DWORD dwProcID, dwCurrentProcID;
  1927. GetWindowThreadProcessId(hwndDesktop, &dwProcID);
  1928. dwCurrentProcID = GetCurrentProcessId();
  1929. if (dwCurrentProcID == dwProcID) {
  1930. SendMessage(hwndDesktop, DTM_GETVIEWAREAS, (WPARAM)pnViewAreas, (LPARAM)lprcViewAreas);
  1931. if (*pnViewAreas <= 0)
  1932. {
  1933. bRet = FALSE;
  1934. }
  1935. else
  1936. {
  1937. bRet = TRUE;
  1938. }
  1939. }
  1940. else
  1941. {
  1942. bRet = FALSE;
  1943. }
  1944. }
  1945. return bRet;
  1946. }
  1947. // We need to enforce a minimum size for the deskmovr caption since it doesn't look
  1948. // right drawn any smaller
  1949. int GetcyCaption()
  1950. {
  1951. int cyCaption = GetSystemMetrics(SM_CYSMCAPTION);
  1952. if (cyCaption < 15)
  1953. cyCaption = 15;
  1954. cyCaption -= GetSystemMetrics(SM_CYBORDER);
  1955. return cyCaption;
  1956. }
  1957. HRESULT PathExpandEnvStringsWrap(LPTSTR pszString, DWORD cchSize)
  1958. {
  1959. HRESULT hr;
  1960. if (!pszString)
  1961. {
  1962. hr = S_OK; // nothing to do!
  1963. }
  1964. else
  1965. {
  1966. TCHAR szTemp[MAX_PATH];
  1967. hr = StringCchCopy(szTemp, ARRAYSIZE(szTemp), pszString);
  1968. if (SUCCEEDED(hr))
  1969. {
  1970. if (0 == SHExpandEnvironmentStrings(szTemp, pszString, cchSize))
  1971. {
  1972. hr = StringCchCopy(pszString, cchSize, szTemp);
  1973. }
  1974. }
  1975. }
  1976. return hr;
  1977. }