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.

839 lines
27 KiB

  1. // ThumbCtl.cpp : Implementation of CThumbCtl
  2. #include "priv.h"
  3. #include "shdguid.h"
  4. #include "strsafe.h"
  5. const CLSID CLSID_ThumbCtlOld = {0x1d2b4f40,0x1f10,0x11d1,{0x9e,0x88,0x00,0xc0,0x4f,0xdc,0xab,0x92}}; // retired from service, so made private
  6. // global
  7. // for LoadLibrary/GetProcAddress on SHGetDiskFreeSpaceA
  8. typedef BOOL (__stdcall * PFNSHGETDISKFREESPACE)(LPCTSTR pszVolume, ULARGE_INTEGER *pqwFreeCaller, ULARGE_INTEGER *pqwTot, ULARGE_INTEGER *pqwFree);
  9. const TCHAR * const g_szWindowClassName = TEXT("MSIE4.0 Webvw.DLL ThumbCtl");
  10. STDAPI IsSafePage(IUnknown *punkSite)
  11. {
  12. // Return S_FALSE if we don't have a host site since we have no way of doing a
  13. // security check. This is as far as VB 5.0 apps get.
  14. if (!punkSite)
  15. return S_FALSE;
  16. HRESULT hr = E_ACCESSDENIED;
  17. CComPtr<IDefViewSafety> spDefViewSafety;
  18. if (SUCCEEDED(IUnknown_QueryService(punkSite, SID_SFolderView,
  19. IID_PPV_ARG(IDefViewSafety, &spDefViewSafety))))
  20. {
  21. hr = spDefViewSafety->IsSafePage();
  22. }
  23. return hr;
  24. }
  25. // === INTERFACE ===
  26. // *** IThumbCtl ***
  27. STDMETHODIMP CThumbCtl::displayFile(BSTR bsFileName, VARIANT_BOOL *pfSuccess)
  28. {
  29. HRESULT hr = E_FAIL;
  30. *pfSuccess = VARIANT_FALSE;
  31. if (S_OK != _IsSafe())
  32. {
  33. // We don't trust this host, so we are going to not carry
  34. // out the action. We are going to return E_ACCESSDENIED so they can't
  35. // determine if the path exists or not.
  36. // return S_FALSE --
  37. // this is because webvw has a customization feature letting people choose
  38. // a intranet htt file as their folder.htt, but for security we generally need
  39. // to block random intranet web pages from calling this method. This will break
  40. // a case where the customization is done on a NT machine, but the user tries to
  41. // view it using Millennium, it will not show any image and pop up error messages
  42. // if we return E_ACCESSDENIED.
  43. hr = S_FALSE;
  44. }
  45. else
  46. {
  47. // Cancel pending bitmap request if in thumbnail mode && have a functioning IThumbnail
  48. // && haven't yet received our bitmap
  49. if(!m_fRootDrive && m_fHaveIThumbnail && m_hbm == NULL)
  50. {
  51. m_pthumb->GetBitmap(NULL, 0, 0, 0);
  52. }
  53. // change ID to catch late bitmap computed
  54. ++m_dwThumbnailID;
  55. // if already displaying something, refresh
  56. if(m_fRootDrive || m_hbm)
  57. {
  58. if(m_hbm)
  59. {
  60. DeleteObject(m_hbm);
  61. m_hbm = NULL;
  62. }
  63. FireViewChange();
  64. }
  65. // Now work on new thumbnail
  66. m_fRootDrive = FALSE;
  67. // check for non-empty file name
  68. if(bsFileName && bsFileName[0])
  69. {
  70. TCHAR szFileName[INTERNET_MAX_URL_LENGTH];
  71. SHUnicodeToTChar(bsFileName, szFileName, ARRAYSIZE(szFileName));
  72. DWORD dwAttrs = GetFileAttributes(szFileName);
  73. // Pie Chart
  74. if(PathIsRoot(szFileName))
  75. {
  76. if(SUCCEEDED(ComputeFreeSpace(szFileName)))
  77. {
  78. m_fRootDrive = TRUE;
  79. *pfSuccess = VARIANT_TRUE;
  80. }
  81. }
  82. // Thumbnail
  83. else if(!(dwAttrs & FILE_ATTRIBUTE_DIRECTORY) && !PathIsSlow(szFileName, dwAttrs)) // should really be calling this from Shell32 private functions
  84. {
  85. if(!m_fInitThumb)
  86. {
  87. m_fHaveIThumbnail = SUCCEEDED(SetupIThumbnail());
  88. m_fInitThumb = TRUE;
  89. }
  90. if(m_fHaveIThumbnail)
  91. {
  92. SIZE size;
  93. AtlHiMetricToPixel(&m_sizeExtent, &size);
  94. if(EVAL(size.cx > 0 && size.cy > 0))
  95. {
  96. if(SUCCEEDED(m_pthumb->GetBitmap(bsFileName, m_dwThumbnailID, size.cx, size.cy)))
  97. {
  98. *pfSuccess = VARIANT_TRUE;
  99. }
  100. }
  101. }
  102. }
  103. }
  104. hr = S_OK;
  105. }
  106. return hr;
  107. } // displayFile
  108. STDMETHODIMP CThumbCtl::haveThumbnail(VARIANT_BOOL *pfRes)
  109. {
  110. HRESULT hr;
  111. *pfRes = VARIANT_FALSE;
  112. if (S_OK != _IsSafe())
  113. {
  114. // We don't trust this host, so we are going to not carry
  115. // out the action. We are going to return E_ACCESSDENIED so they can't
  116. // determine if the path exists or not.
  117. // return S_FALSE --
  118. // this is because webvw has a customization feature letting people choose
  119. // a intranet htt file as their folder.htt, but for security we generally need
  120. // to block random intranet web pages from calling this method. This will break
  121. // a case where the customization is done on a NT machine, but the user tries to
  122. // view it using Millennium, it will not show any image and pop up error messages
  123. // if we return E_ACCESSDENIED.
  124. hr = S_FALSE;
  125. }
  126. else
  127. {
  128. *pfRes = (m_fRootDrive || m_hbm) ? VARIANT_TRUE : VARIANT_FALSE;
  129. hr = S_OK;
  130. }
  131. return hr;
  132. }
  133. STDMETHODIMP CThumbCtl::get_freeSpace(BSTR *pbs)
  134. {
  135. HRESULT hr;
  136. if (S_OK != _IsSafe())
  137. {
  138. // We don't trust this host, so we are going to not carry
  139. // out the action. We are going to return E_ACCESSDENIED so they can't
  140. // determine if the path exists or not.
  141. *pbs = SysAllocString(L"");
  142. hr = (*pbs) ? S_FALSE : E_OUTOFMEMORY;
  143. }
  144. else
  145. {
  146. get_GeneralSpace(m_dwlFreeSpace, pbs);
  147. hr = S_OK;
  148. }
  149. return hr;
  150. } // get_freeSpace
  151. STDMETHODIMP CThumbCtl::get_usedSpace(BSTR *pbs)
  152. {
  153. HRESULT hr;
  154. if (S_OK != _IsSafe())
  155. {
  156. // We don't trust this host, so we are going to not carry
  157. // out the action. We are going to return E_ACCESSDENIED so they can't
  158. // determine if the path exists or not.
  159. *pbs = SysAllocString(L"");
  160. hr = (*pbs) ? S_FALSE : E_OUTOFMEMORY;
  161. }
  162. else
  163. {
  164. get_GeneralSpace(m_dwlUsedSpace, pbs);
  165. hr = S_OK;
  166. }
  167. return hr;
  168. } // get_usedSpace
  169. STDMETHODIMP CThumbCtl::get_totalSpace(BSTR *pbs)
  170. {
  171. HRESULT hr;
  172. if (S_OK != _IsSafe())
  173. {
  174. // We don't trust this host, so we are going to not carry
  175. // out the action. We are going to return E_ACCESSDENIED so they can't
  176. // determine if the path exists or not.
  177. *pbs = SysAllocString(L"");
  178. hr = (*pbs) ? S_FALSE : E_OUTOFMEMORY;
  179. }
  180. else
  181. {
  182. get_GeneralSpace(m_dwlTotalSpace, pbs);
  183. hr = S_OK;
  184. }
  185. return hr;
  186. } // get_totalSpace
  187. // *** IObjectSafety ***
  188. STDMETHODIMP CThumbCtl::GetInterfaceSafetyOptions(REFIID riid, DWORD *pdwSupportedOptions,
  189. DWORD *pdwEnabledOptions)
  190. {
  191. ATLTRACE(_T("IObjectSafetyImpl::GetInterfaceSafetyOptions\n"));
  192. if (pdwSupportedOptions == NULL || pdwEnabledOptions == NULL)
  193. return E_POINTER;
  194. HRESULT hr = S_OK;
  195. if (riid == IID_IDispatch)
  196. {
  197. *pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA;
  198. *pdwEnabledOptions = m_dwCurrentSafety & (INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA);
  199. }
  200. else
  201. {
  202. *pdwSupportedOptions = 0;
  203. *pdwEnabledOptions = 0;
  204. hr = E_NOINTERFACE;
  205. }
  206. return hr;
  207. }
  208. // *** ISupportsErrorInfo ***
  209. STDMETHODIMP CThumbCtl::InterfaceSupportsErrorInfo(REFIID riid)
  210. {
  211. static const IID* arr[] =
  212. {
  213. &IID_IThumbCtl,
  214. };
  215. for (int i=0;i<sizeof(arr)/sizeof(arr[0]);i++)
  216. {
  217. if (InlineIsEqualGUID(*arr[i],riid))
  218. return S_OK;
  219. }
  220. return S_FALSE;
  221. }
  222. // *** IViewObjectEx ***
  223. STDMETHODIMP CThumbCtl::GetViewStatus(DWORD* pdwStatus)
  224. {
  225. ATLTRACE(_T("IViewObjectExImpl::GetViewStatus\n"));
  226. *pdwStatus = VIEWSTATUS_SOLIDBKGND | VIEWSTATUS_OPAQUE;
  227. return S_OK;
  228. }
  229. // *** IOleInPlaceActiveObject ***
  230. HRESULT CThumbCtl::TranslateAccelerator(LPMSG pMsg)
  231. {
  232. HRESULT hres = S_OK;
  233. if (!m_fTabRecieved)
  234. {
  235. hres = IOleInPlaceActiveObjectImpl<CThumbCtl>::TranslateAccelerator(pMsg);
  236. // If we did not handle this and if it is a tab (and we are not getting it in a cycle), forward it to trident, if present.
  237. if (hres != S_OK && pMsg && (pMsg->wParam == VK_TAB || pMsg->wParam == VK_F6) && m_spClientSite)
  238. {
  239. if (GetFocus() != m_hwnd)
  240. {
  241. ::SetFocus(m_hwnd);
  242. hres = S_OK;
  243. }
  244. else
  245. {
  246. IOleControlSite* pocs = NULL;
  247. if (SUCCEEDED(m_spClientSite->QueryInterface(IID_IOleControlSite, (void **)&pocs)))
  248. {
  249. DWORD grfModifiers = 0;
  250. if (GetKeyState(VK_SHIFT) & 0x8000)
  251. {
  252. grfModifiers |= 0x1; //KEYMOD_SHIFT
  253. }
  254. if (GetKeyState(VK_CONTROL) & 0x8000)
  255. {
  256. grfModifiers |= 0x2; //KEYMOD_CONTROL;
  257. }
  258. if (GetKeyState(VK_MENU) & 0x8000)
  259. {
  260. grfModifiers |= 0x4; //KEYMOD_ALT;
  261. }
  262. m_fTabRecieved = TRUE;
  263. hres = pocs->TranslateAccelerator(pMsg, grfModifiers);
  264. m_fTabRecieved = FALSE;
  265. }
  266. }
  267. }
  268. }
  269. return hres;
  270. }
  271. // === PUBLIC FUNCTIONS ===
  272. // CONSTRUCTOR/DESTRUCTOR
  273. CThumbCtl::CThumbCtl(void):
  274. m_fRootDrive(FALSE),
  275. m_fInitThumb(FALSE),
  276. m_fHaveIThumbnail(FALSE),
  277. m_pthumb(NULL),
  278. m_hwnd(NULL),
  279. m_hbm(NULL),
  280. m_dwThumbnailID(0),
  281. m_dwlFreeSpace(0),
  282. m_dwlUsedSpace(0),
  283. m_dwlTotalSpace(0),
  284. m_dwUsedSpacePer1000(0),
  285. m_fUseSystemColors(TRUE)
  286. {
  287. m_fTabRecieved = FALSE;
  288. }
  289. CThumbCtl::~CThumbCtl(void)
  290. {
  291. if(m_hbm)
  292. {
  293. DeleteObject(m_hbm);
  294. m_hbm = NULL;
  295. }
  296. if(m_pthumb)
  297. {
  298. m_pthumb->Release(); // will cancel pending bitmap requests
  299. m_pthumb = NULL;
  300. }
  301. if(m_hwnd)
  302. {
  303. EVAL(::DestroyWindow(m_hwnd));
  304. m_hwnd = NULL;
  305. }
  306. }
  307. // === PRIVATE FUNCTIONS ===
  308. // Thumbnail drawing functions
  309. HRESULT CThumbCtl::SetupIThumbnail(void)
  310. {
  311. HRESULT hr = E_FAIL;
  312. // Create Window Class
  313. WNDCLASS wc;
  314. if (!::GetClassInfoWrap(_Module.GetModuleInstance(), g_szWindowClassName, &wc))
  315. {
  316. wc.style = 0;
  317. wc.lpfnWndProc = CThumbCtl::WndProc;
  318. wc.cbClsExtra = 0;
  319. wc.cbWndExtra = 0;
  320. wc.hInstance = _Module.GetModuleInstance();
  321. wc.hIcon = NULL;
  322. wc.hCursor = NULL;
  323. wc.hbrBackground = NULL;
  324. wc.lpszMenuName = NULL;
  325. wc.lpszClassName = g_szWindowClassName;
  326. RegisterClass(&wc);
  327. }
  328. m_hwnd = CreateWindow(g_szWindowClassName, NULL, WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT,
  329. CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, _Module.GetModuleInstance(), this);
  330. if(m_hwnd)
  331. {
  332. if(SUCCEEDED(CoCreateInstance(CLSID_Thumbnail, NULL, CLSCTX_INPROC_SERVER, IID_IThumbnail, (void **)&m_pthumb)))
  333. {
  334. if(SUCCEEDED(m_pthumb->Init(m_hwnd, WM_HTML_BITMAP)))
  335. {
  336. hr = S_OK;
  337. }
  338. }
  339. if(FAILED(hr))
  340. {
  341. EVAL(::DestroyWindow(m_hwnd));
  342. m_hwnd = NULL;
  343. }
  344. }
  345. return hr;
  346. }
  347. LRESULT CALLBACK CThumbCtl::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  348. {
  349. CThumbCtl *ptc = (CThumbCtl *)::GetWindowLongPtr(hWnd, GWLP_USERDATA);
  350. switch(uMsg)
  351. {
  352. case WM_CREATE:
  353. {
  354. ptc = (CThumbCtl *)((CREATESTRUCT *)lParam)->lpCreateParams;
  355. ::SetWindowLongPtr(hWnd, GWLP_USERDATA, (LPARAM)ptc);
  356. }
  357. break;
  358. case WM_HTML_BITMAP:
  359. // check that ptc is still alive, bitmap is current using ID
  360. if(ptc && ptc->m_dwThumbnailID == wParam)
  361. {
  362. // ptc->displayFile() should've destroyed old bitmap already, but doesn't hurt to check.
  363. if(!EVAL(ptc->m_hbm == NULL))
  364. {
  365. DeleteObject(ptc->m_hbm);
  366. }
  367. ptc->m_hbm = (HBITMAP)lParam;
  368. ptc->InvokeOnThumbnailReady();
  369. }
  370. else if(lParam)
  371. {
  372. DeleteObject((HBITMAP)lParam);
  373. }
  374. break;
  375. case WM_DESTROY:
  376. // ignore late messages
  377. if(ptc)
  378. {
  379. MSG msg;
  380. while(PeekMessage(&msg, hWnd, WM_HTML_BITMAP, WM_HTML_BITMAP, PM_REMOVE))
  381. {
  382. if(msg.lParam)
  383. {
  384. DeleteObject((HBITMAP)msg.lParam);
  385. }
  386. }
  387. ::SetWindowLongPtr(hWnd, GWLP_USERDATA, NULL);
  388. }
  389. break;
  390. default:
  391. return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
  392. }
  393. return 0;
  394. }
  395. // Pie Chart functions
  396. HRESULT CThumbCtl::ComputeFreeSpace(LPTSTR pszFileName)
  397. {
  398. ULARGE_INTEGER qwFreeCaller; // use this for free space -- this will take into account disk quotas and such on NT
  399. ULARGE_INTEGER qwTotal;
  400. ULARGE_INTEGER qwFree; // unused
  401. static PFNSHGETDISKFREESPACE pfnSHGetDiskFreeSpace = NULL;
  402. if (NULL == pfnSHGetDiskFreeSpace)
  403. {
  404. HINSTANCE hinstShell32 = LoadLibrary(TEXT("SHELL32.DLL"));
  405. if (hinstShell32)
  406. {
  407. #ifdef UNICODE
  408. pfnSHGetDiskFreeSpace = (PFNSHGETDISKFREESPACE)GetProcAddress(hinstShell32, "SHGetDiskFreeSpaceExW");
  409. #else
  410. pfnSHGetDiskFreeSpace = (PFNSHGETDISKFREESPACE)GetProcAddress(hinstShell32, "SHGetDiskFreeSpaceExA");
  411. #endif
  412. }
  413. }
  414. // Compute free & total space and check for valid results
  415. // if have a fn pointer call SHGetDiskFreeSpaceA
  416. if( pfnSHGetDiskFreeSpace
  417. && pfnSHGetDiskFreeSpace(pszFileName, &qwFreeCaller, &qwTotal, &qwFree) )
  418. {
  419. m_dwlFreeSpace = qwFreeCaller.QuadPart;
  420. m_dwlTotalSpace = qwTotal.QuadPart;
  421. m_dwlUsedSpace = m_dwlTotalSpace - m_dwlFreeSpace;
  422. if ((m_dwlTotalSpace > 0) && (m_dwlFreeSpace <= m_dwlTotalSpace))
  423. {
  424. // some special cases require interesting treatment
  425. if(m_dwlTotalSpace == 0 || m_dwlFreeSpace == m_dwlTotalSpace)
  426. {
  427. m_dwUsedSpacePer1000 = 0;
  428. }
  429. else if(m_dwlFreeSpace == 0)
  430. {
  431. m_dwUsedSpacePer1000 = 1000;
  432. }
  433. else
  434. {
  435. // not completely full or empty
  436. m_dwUsedSpacePer1000 = (DWORD)(m_dwlUsedSpace * 1000 / m_dwlTotalSpace);
  437. // Trick: if user has extremely little free space, the user expects to still see
  438. // a tiny free slice -- not a full drive. Similarly for almost free drive.
  439. if(m_dwUsedSpacePer1000 == 0)
  440. {
  441. m_dwUsedSpacePer1000 = 1;
  442. }
  443. else if(m_dwUsedSpacePer1000 == 1000)
  444. {
  445. m_dwUsedSpacePer1000 = 999;
  446. }
  447. }
  448. return S_OK;
  449. }
  450. }
  451. return E_FAIL;
  452. }
  453. // 32 should be plenty
  454. #define STRLENGTH_SPACE 32
  455. HRESULT CThumbCtl::get_GeneralSpace(DWORDLONG dwlSpace, BSTR *pbs)
  456. {
  457. ASSERT(pbs != NULL);
  458. WCHAR wszText[STRLENGTH_SPACE];
  459. if(m_fRootDrive)
  460. {
  461. StrFormatByteSizeW(dwlSpace, wszText, ARRAYSIZE(wszText));
  462. *pbs = SysAllocString(wszText);
  463. }
  464. else
  465. {
  466. *pbs = SysAllocString(L"");
  467. }
  468. return *pbs? S_OK: E_OUTOFMEMORY;
  469. }
  470. HRESULT CThumbCtl::Draw3dPie(HDC hdc, LPRECT lprc, DWORD dwPer1000, const COLORREF *lpColors)
  471. {
  472. ASSERT(lprc != NULL && lpColors != NULL);
  473. enum
  474. {
  475. COLOR_UP = 0,
  476. COLOR_DN,
  477. COLOR_UPSHADOW,
  478. COLOR_DNSHADOW,
  479. COLOR_NUM // #of entries
  480. };
  481. // The majority of this code came from "drawpie.c"
  482. const LONG c_lShadowScale = 6; // ratio of shadow depth to height
  483. const LONG c_lAspectRatio = 2; // ratio of width : height of ellipse
  484. // We make sure that the aspect ratio of the pie-chart is always preserved
  485. // regardless of the shape of the given rectangle
  486. // Stabilize the aspect ratio now...
  487. LONG lHeight = lprc->bottom - lprc->top;
  488. LONG lWidth = lprc->right - lprc->left;
  489. LONG lTargetHeight = (lHeight * c_lAspectRatio <= lWidth? lHeight: lWidth / c_lAspectRatio);
  490. LONG lTargetWidth = lTargetHeight * c_lAspectRatio; // need to adjust because w/c * c isn't always == w
  491. // Shrink the rectangle on both sides to the correct size
  492. lprc->top += (lHeight - lTargetHeight) / 2;
  493. lprc->bottom = lprc->top + lTargetHeight;
  494. lprc->left += (lWidth - lTargetWidth) / 2;
  495. lprc->right = lprc->left + lTargetWidth;
  496. // Compute a shadow depth based on height of the image
  497. LONG lShadowDepth = lTargetHeight / c_lShadowScale;
  498. // check dwPer1000 to ensure within bounds
  499. if(dwPer1000 > 1000)
  500. dwPer1000 = 1000;
  501. // Now the drawing function
  502. int cx, cy, rx, ry, x, y;
  503. int uQPctX10;
  504. RECT rcItem;
  505. HRGN hEllRect, hEllipticRgn, hRectRgn;
  506. HBRUSH hBrush, hOldBrush;
  507. HPEN hPen, hOldPen;
  508. rcItem = *lprc;
  509. rcItem.left = lprc->left;
  510. rcItem.top = lprc->top;
  511. rcItem.right = lprc->right - rcItem.left;
  512. rcItem.bottom = lprc->bottom - rcItem.top - lShadowDepth;
  513. rx = rcItem.right / 2;
  514. cx = rcItem.left + rx - 1;
  515. ry = rcItem.bottom / 2;
  516. cy = rcItem.top + ry - 1;
  517. if (rx<=10 || ry<=10)
  518. {
  519. return S_FALSE;
  520. }
  521. rcItem.right = rcItem.left+2*rx;
  522. rcItem.bottom = rcItem.top+2*ry;
  523. /* Translate to first quadrant of a Cartesian system
  524. */
  525. uQPctX10 = (dwPer1000 % 500) - 250;
  526. if (uQPctX10 < 0)
  527. {
  528. uQPctX10 = -uQPctX10;
  529. }
  530. /* Calc x and y. I am trying to make the area be the right percentage.
  531. ** I don't know how to calculate the area of a pie slice exactly, so I
  532. ** approximate it by using the triangle area instead.
  533. */
  534. // NOTE-- *** in response to the above comment ***
  535. // Calculating the area of a pie slice exactly is actually very
  536. // easy by conceptually rescaling into a circle but the complications
  537. // introduced by having to work in fixed-point arithmetic makes it
  538. // unworthwhile to code this-- CemP
  539. if (uQPctX10 < 120)
  540. {
  541. x = IntSqrt(((DWORD)rx*(DWORD)rx*(DWORD)uQPctX10*(DWORD)uQPctX10)
  542. /((DWORD)uQPctX10*(DWORD)uQPctX10+(250L-(DWORD)uQPctX10)*(250L-(DWORD)uQPctX10)));
  543. y = IntSqrt(((DWORD)rx*(DWORD)rx-(DWORD)x*(DWORD)x)*(DWORD)ry*(DWORD)ry/((DWORD)rx*(DWORD)rx));
  544. }
  545. else
  546. {
  547. y = IntSqrt((DWORD)ry*(DWORD)ry*(250L-(DWORD)uQPctX10)*(250L-(DWORD)uQPctX10)
  548. /((DWORD)uQPctX10*(DWORD)uQPctX10+(250L-(DWORD)uQPctX10)*(250L-(DWORD)uQPctX10)));
  549. x = IntSqrt(((DWORD)ry*(DWORD)ry-(DWORD)y*(DWORD)y)*(DWORD)rx*(DWORD)rx/((DWORD)ry*(DWORD)ry));
  550. }
  551. /* Switch on the actual quadrant
  552. */
  553. switch (dwPer1000 / 250)
  554. {
  555. case 1:
  556. y = -y;
  557. break;
  558. case 2:
  559. break;
  560. case 3:
  561. x = -x;
  562. break;
  563. default: // case 0 and case 4
  564. x = -x;
  565. y = -y;
  566. break;
  567. }
  568. /* Now adjust for the center.
  569. */
  570. x += cx;
  571. y += cy;
  572. // Hack to get around bug in NTGDI
  573. x = x < 0 ? 0 : x;
  574. /* Draw the shadows using regions (to reduce flicker).
  575. */
  576. hEllipticRgn = CreateEllipticRgnIndirect(&rcItem);
  577. OffsetRgn(hEllipticRgn, 0, lShadowDepth);
  578. hEllRect = CreateRectRgn(rcItem.left, cy, rcItem.right, cy+lShadowDepth);
  579. hRectRgn = CreateRectRgn(0, 0, 0, 0);
  580. CombineRgn(hRectRgn, hEllipticRgn, hEllRect, RGN_OR);
  581. OffsetRgn(hEllipticRgn, 0, -(int)lShadowDepth);
  582. CombineRgn(hEllRect, hRectRgn, hEllipticRgn, RGN_DIFF);
  583. /* Always draw the whole area in the free shadow/
  584. */
  585. hBrush = CreateSolidBrush(lpColors[COLOR_DNSHADOW]);
  586. if (hBrush)
  587. {
  588. FillRgn(hdc, hEllRect, hBrush);
  589. DeleteObject(hBrush);
  590. }
  591. /* Draw the used shadow only if the disk is at least half used.
  592. */
  593. if (dwPer1000>500 && (hBrush = CreateSolidBrush(lpColors[COLOR_UPSHADOW]))!=NULL)
  594. {
  595. DeleteObject(hRectRgn);
  596. hRectRgn = CreateRectRgn(x, cy, rcItem.right, lprc->bottom);
  597. CombineRgn(hEllipticRgn, hEllRect, hRectRgn, RGN_AND);
  598. FillRgn(hdc, hEllipticRgn, hBrush);
  599. DeleteObject(hBrush);
  600. }
  601. DeleteObject(hRectRgn);
  602. DeleteObject(hEllipticRgn);
  603. DeleteObject(hEllRect);
  604. hPen = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_WINDOWFRAME));
  605. hOldPen = (HPEN__*) SelectObject(hdc, hPen);
  606. // if per1000 is 0 or 1000, draw full elipse, otherwise, also draw a pie section.
  607. // we might have a situation where per1000 isn't 0 or 1000 but y == cy due to approx error,
  608. // so make sure to draw the ellipse the correct color, and draw a line (with Pie()) to
  609. // indicate not completely full or empty pie.
  610. hBrush = CreateSolidBrush(lpColors[dwPer1000 < 500 && y == cy && x < cx? COLOR_DN: COLOR_UP]);
  611. hOldBrush = (HBRUSH__*) SelectObject(hdc, hBrush);
  612. Ellipse(hdc, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom);
  613. SelectObject(hdc, hOldBrush);
  614. DeleteObject(hBrush);
  615. if(dwPer1000 != 0 && dwPer1000 != 1000)
  616. {
  617. // display small sub-section of ellipse for smaller part
  618. hBrush = CreateSolidBrush(lpColors[COLOR_DN]);
  619. hOldBrush = (HBRUSH__*) SelectObject(hdc, hBrush);
  620. // NTRAID#087993-2000/02/16-aidanl: Pie may malfunction when y approaches cy
  621. // If y == cy (when the disk is almost full)and if x approaches
  622. // rcItem.left, on win9x, Pie malfunctions. It draws the larger portion
  623. // of the pie, instead of the smaller portion. We work around it by
  624. // adding 1 to y.
  625. Pie(hdc, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom,
  626. rcItem.left, cy, x, (y == cy) ? (y + 1) : y);
  627. SelectObject(hdc, hOldBrush);
  628. DeleteObject(hBrush);
  629. }
  630. Arc(hdc, rcItem.left, rcItem.top+lShadowDepth, rcItem.right - 1, rcItem.bottom+lShadowDepth - 1,
  631. rcItem.left, cy+lShadowDepth, rcItem.right, cy+lShadowDepth-1);
  632. MoveToEx(hdc, rcItem.left, cy, NULL);
  633. LineTo(hdc, rcItem.left, cy+lShadowDepth);
  634. MoveToEx(hdc, rcItem.right-1, cy, NULL);
  635. LineTo(hdc, rcItem.right-1, cy+lShadowDepth);
  636. if(dwPer1000 > 500 && dwPer1000 < 1000)
  637. {
  638. MoveToEx(hdc, x, y, NULL);
  639. LineTo(hdc, x, y+lShadowDepth);
  640. }
  641. SelectObject(hdc, hOldPen);
  642. DeleteObject(hPen);
  643. return S_OK; // Everything worked fine
  644. } // Draw3dPie
  645. // General functions
  646. void CThumbCtl::InvokeOnThumbnailReady(void)
  647. {
  648. // Fire off "OnThumbnailReady" event to our connection points to indicate that
  649. // either a thumbnail has been computed or we have no thumbnail for this file.
  650. DISPPARAMS dp = {0, NULL, 0, NULL}; // no parameters
  651. IUnknown **pp = NULL; // traverses connection points, where it is interpreted as IDispatch*
  652. Lock();
  653. for(pp = m_vec.begin(); pp < m_vec.end(); ++pp)
  654. {
  655. if(pp)
  656. {
  657. ((IDispatch *)*pp)->Invoke(DISPID_ONTHUMBNAILREADY, IID_NULL, LOCALE_USER_DEFAULT,
  658. DISPATCH_METHOD, &dp, NULL, NULL, NULL);
  659. }
  660. }
  661. Unlock();
  662. FireViewChange();
  663. }
  664. HRESULT CThumbCtl::OnDraw(ATL_DRAWINFO& di)
  665. {
  666. HDC hdc = di.hdcDraw;
  667. RECT rc = *(LPRECT)di.prcBounds;
  668. HRESULT hr = S_OK;
  669. if(m_fRootDrive || m_hbm)
  670. {
  671. HPALETTE hpal = NULL;
  672. // Create pallete appropriate for this HDC
  673. if(GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE)
  674. {
  675. hpal = SHCreateShellPalette(hdc);
  676. HPALETTE hpalOld = SelectPalette(hdc, hpal, TRUE);
  677. RealizePalette(hdc);
  678. // Old one needs to be selected back in
  679. SelectPalette(hdc, hpalOld, TRUE);
  680. }
  681. if(m_fRootDrive)
  682. {
  683. // Draw a pie chart
  684. if(m_fUseSystemColors)
  685. {
  686. // system colors can change!
  687. m_acrChartColors[PIE_USEDCOLOR] = GetSysColor(COLOR_3DFACE);
  688. m_acrChartColors[PIE_FREECOLOR] = GetSysColor(COLOR_3DHILIGHT);
  689. m_acrChartColors[PIE_USEDSHADOW] = GetSysColor(COLOR_3DSHADOW);
  690. m_acrChartColors[PIE_FREESHADOW] = GetSysColor(COLOR_3DFACE);
  691. }
  692. else if(GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE)
  693. {
  694. // Call GetNearestColor on the colors to make sure they're on the palette
  695. // Of course, system colors ARE on the palette (I think)
  696. DWORD dw = 0; // index
  697. for(dw = 0; dw < PIE_NUM; dw++)
  698. {
  699. m_acrChartColors[dw] = GetNearestColor(hdc, m_acrChartColors[dw]);
  700. }
  701. }
  702. hr = Draw3dPie(hdc, &rc, m_dwUsedSpacePer1000, m_acrChartColors);
  703. }
  704. else
  705. {
  706. // Draw the Thumbnail bitmap
  707. HDC hdcBitmap = CreateCompatibleDC(hdc);
  708. if (hdcBitmap)
  709. {
  710. BITMAP bm;
  711. SelectObject(hdcBitmap, m_hbm);
  712. GetObject(m_hbm, SIZEOF(bm), &bm);
  713. if(bm.bmWidth == rc.right - rc.left && bm.bmHeight == rc.bottom - rc.top)
  714. {
  715. BitBlt(hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
  716. hdcBitmap, 0, 0, SRCCOPY);
  717. }
  718. else
  719. {
  720. SetStretchBltMode(hdc, COLORONCOLOR);
  721. StretchBlt(hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
  722. hdcBitmap, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
  723. }
  724. DeleteDC(hdcBitmap);
  725. }
  726. }
  727. // clean up DC, palette
  728. if(hpal)
  729. {
  730. DeleteObject(hpal);
  731. }
  732. }
  733. else
  734. {
  735. SelectObject(hdc, GetStockObject(WHITE_PEN));
  736. SelectObject(hdc, GetStockObject(WHITE_BRUSH));
  737. // Just draw a blank rectangle
  738. Rectangle(hdc, rc.left, rc.top, rc.right, rc.bottom);
  739. }
  740. return hr;
  741. }