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.

1015 lines
35 KiB

  1. #include "shellprv.h"
  2. #include "duiinfo.h"
  3. #include "ids.h"
  4. #include "datautil.h"
  5. DWORD FormatMessageArg(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageID, DWORD dwLangID,
  6. LPWSTR pwzBuffer, DWORD cchSize, ...)
  7. {
  8. va_list vaParamList;
  9. va_start(vaParamList, cchSize);
  10. DWORD dwResult = FormatMessageW(dwFlags, lpSource, dwMessageID, dwLangID, pwzBuffer,
  11. cchSize, &vaParamList);
  12. va_end(vaParamList);
  13. return dwResult;
  14. }
  15. CNameSpaceItemUIProperty::~CNameSpaceItemUIProperty()
  16. {
  17. }
  18. void CNameSpaceItemUIProperty::_SetParentAndItem(IShellFolder2 *psf, LPCITEMIDLIST pidl)
  19. {
  20. // set aliases to current values these are not refed
  21. // it is assumed that all helpers that use these variables won't be called
  22. // unless these have been set. since this can't fail this all works out fine
  23. m_psf = psf; // alias, not refed
  24. m_pidl = pidl; // alias, not cloned
  25. }
  26. STDMETHODIMP CNameSpaceItemUIProperty::GetPropertyDisplayName(SHCOLUMNID scid, WCHAR* pwszPropDisplayName, int cchPropDisplayName)
  27. {
  28. *pwszPropDisplayName = 0;
  29. CComPtr<IPropertyUI> spPropertyUI;
  30. HRESULT hr = _GetPropertyUI(&spPropertyUI);
  31. if (SUCCEEDED(hr))
  32. {
  33. hr = spPropertyUI->GetDisplayName(
  34. scid.fmtid,
  35. scid.pid,
  36. PUIFNF_DEFAULT,
  37. pwszPropDisplayName,
  38. cchPropDisplayName);
  39. }
  40. return hr;
  41. }
  42. STDMETHODIMP CNameSpaceItemUIProperty::GetPropertyDisplayValue(SHCOLUMNID scid, WCHAR* pszValue, int cch, PROPERTYUI_FORMAT_FLAGS flagsFormat)
  43. {
  44. *pszValue = 0;
  45. HRESULT hr = E_FAIL;
  46. // Use GetDisplayNameOf for the SCID_NAME property
  47. if (IsEqualSCID(scid, SCID_NAME))
  48. {
  49. hr = DisplayNameOf(m_psf, m_pidl, SHGDN_INFOLDER, pszValue, cch);
  50. }
  51. else
  52. { // Use GetDetailsEx to get the value
  53. CComVariant varPropDisplayValue;
  54. if (m_psf->GetDetailsEx(m_pidl, &scid, &varPropDisplayValue) == S_OK) // S_FALSE means property wasn't there.
  55. {
  56. if (IsEqualSCID(scid, SCID_SIZE) &&
  57. ((varPropDisplayValue.vt == VT_UI8) && (varPropDisplayValue.ullVal <= 0)))
  58. {
  59. hr = E_FAIL; // Don't display 0 byte sizes
  60. }
  61. else
  62. {
  63. CComPtr<IPropertyUI> spPropertyUI;
  64. hr = _GetPropertyUI(&spPropertyUI);
  65. if (SUCCEEDED(hr))
  66. {
  67. hr = spPropertyUI->FormatForDisplay(scid.fmtid, scid.pid,
  68. (PROPVARIANT*)&varPropDisplayValue, //cast from VARIANT to PROPVARIANT should be ok
  69. flagsFormat, pszValue, cch);
  70. }
  71. }
  72. }
  73. }
  74. return hr;
  75. }
  76. HRESULT CNameSpaceItemUIProperty::_GetPropertyUI(IPropertyUI **pppui)
  77. {
  78. HRESULT hr = E_FAIL;
  79. if (!m_spPropertyUI)
  80. {
  81. hr = SHCoCreateInstance(NULL, &CLSID_PropertiesUI, NULL, IID_PPV_ARG(IPropertyUI, &m_spPropertyUI));
  82. }
  83. *pppui = m_spPropertyUI;
  84. if (*pppui)
  85. {
  86. (*pppui)->AddRef();
  87. hr = S_OK;
  88. }
  89. return hr;
  90. }
  91. CNameSpaceItemInfoList::~CNameSpaceItemInfoList()
  92. {
  93. if (m_pDUIView)
  94. {
  95. m_pDUIView->SetDetailsInfoMsgWindowPtr(NULL, this);
  96. m_pDUIView->Release();
  97. }
  98. }
  99. STDMETHODIMP CNameSpaceItemInfoList::Create(CDUIView* pDUIView, Value* pvDetailsSheet,
  100. IShellItemArray *psiItemArray, Element** ppElement)
  101. {
  102. HRESULT hr;
  103. *ppElement = NULL;
  104. CNameSpaceItemInfoList* pNSIInfoList = HNewAndZero<CNameSpaceItemInfoList>();
  105. if (!pNSIInfoList)
  106. {
  107. hr = E_OUTOFMEMORY;
  108. }
  109. else
  110. {
  111. hr = pNSIInfoList->Initialize(pDUIView, pvDetailsSheet, psiItemArray);
  112. if (SUCCEEDED(hr))
  113. *ppElement = pNSIInfoList;
  114. else
  115. pNSIInfoList->Destroy();
  116. }
  117. return hr;
  118. }
  119. STDMETHODIMP CNameSpaceItemInfoList::Initialize(CDUIView* pDUIView, Value* pvDetailsSheet,
  120. IShellItemArray *psiItemArray)
  121. {
  122. HRESULT hr = Element::Initialize(0);
  123. if (SUCCEEDED(hr))
  124. {
  125. IDataObject *pdtobj = NULL;
  126. (m_pDUIView = pDUIView)->AddRef();
  127. Value* pvLayout = NULL;
  128. int arVLOptions[] = { FALSE, ALIGN_LEFT, ALIGN_JUSTIFY, ALIGN_TOP };
  129. hr = VerticalFlowLayout::Create(ARRAYSIZE(arVLOptions), arVLOptions, &pvLayout);
  130. if (SUCCEEDED(hr))
  131. {
  132. SetValue(LayoutProp, PI_Local, pvLayout);
  133. pvLayout->Release();
  134. }
  135. if (pvDetailsSheet)
  136. {
  137. SetValue(SheetProp, PI_Local, pvDetailsSheet);
  138. }
  139. // the HIDA format has 2 forms, one is each item in the array is a
  140. // fully qualified pidl. this is what the search folder produces
  141. // the other is the items are relative to a sigle folder pidl
  142. // the code below deals with both cases
  143. // Should just use use the ShellItemArray instead of getting the HIDA
  144. if (psiItemArray)
  145. {
  146. if (FAILED(psiItemArray->BindToHandler(NULL,BHID_DataObject,IID_PPV_ARG(IDataObject,&pdtobj))))
  147. {
  148. pdtobj = NULL;
  149. }
  150. }
  151. hr = S_OK;
  152. BOOL bDetailsAvailable = FALSE;
  153. if (pdtobj)
  154. {
  155. STGMEDIUM medium;
  156. LPIDA pida = DataObj_GetHIDA(pdtobj, &medium);
  157. if (pida)
  158. {
  159. IShellFolder2 *psfRoot;
  160. LPCITEMIDLIST pidlFolder = HIDA_GetPIDLFolder(pida);
  161. hr = SHBindToObjectEx(NULL, pidlFolder, NULL, IID_PPV_ARG(IShellFolder2, &psfRoot));
  162. if (SUCCEEDED(hr))
  163. {
  164. if (pida->cidl == 1)
  165. {
  166. LPCITEMIDLIST pidlItem = IDA_GetIDListPtr(pida, 0);
  167. IShellFolder2 *psf;
  168. LPCITEMIDLIST pidl;
  169. hr = SHBindToFolderIDListParent(psfRoot, pidlItem, IID_PPV_ARG(IShellFolder2, &psf), &pidl);
  170. if (SUCCEEDED(hr))
  171. {
  172. ULONG rgfInOut = SFGAO_FOLDER | SFGAO_ISSLOW;
  173. if (SUCCEEDED(psf->GetAttributesOf(1, &pidl, &rgfInOut)) && !(rgfInOut & SFGAO_ISSLOW))
  174. {
  175. if (!(rgfInOut & SFGAO_FOLDER) && m_pDUIView->ShouldShowMiniPreview())
  176. {
  177. _AddMiniPreviewerToList(psf, pidl);
  178. bDetailsAvailable = TRUE;
  179. }
  180. LPITEMIDLIST pidlFull;
  181. if (SUCCEEDED(SHILCombine(pidlFolder, pidlItem, &pidlFull)))
  182. {
  183. if (SUCCEEDED(m_pDUIView->InitializeDetailsInfo(
  184. CNameSpaceItemInfoList::WindowProc)))
  185. {
  186. m_pDUIView->SetDetailsInfoMsgWindowPtr(this, NULL);
  187. m_pDUIView->StartInfoExtraction(pidlFull);
  188. bDetailsAvailable = TRUE;
  189. }
  190. ILFree(pidlFull);
  191. }
  192. }
  193. psf->Release();
  194. }
  195. }
  196. else
  197. {
  198. hr = _OnMultiSelect(psfRoot, pida);
  199. bDetailsAvailable = SUCCEEDED(hr);
  200. }
  201. psfRoot->Release();
  202. }
  203. HIDA_ReleaseStgMedium(pida, &medium);
  204. }
  205. pdtobj->Release();
  206. }
  207. if (!pdtobj || !bDetailsAvailable)
  208. {
  209. pDUIView->ShowDetails(FALSE);
  210. }
  211. }
  212. return hr;
  213. }
  214. LRESULT CALLBACK CNameSpaceItemInfoList::WindowProc(HWND hwnd, UINT uMsg,
  215. WPARAM wParam, LPARAM lParam)
  216. {
  217. CNameSpaceItemInfoList* pNSIInfoList = (CNameSpaceItemInfoList*)::GetWindowPtr(hwnd, 0);
  218. switch(uMsg)
  219. {
  220. case WM_DESTROY:
  221. // ignore late messages
  222. {
  223. MSG msg;
  224. while (PeekMessage(&msg, hwnd, WM_DETAILS_INFO, WM_DETAILS_INFO, PM_REMOVE))
  225. {
  226. if (msg.lParam)
  227. {
  228. CDetailsInfoList* pDetailsInfoList = (CDetailsInfoList*)msg.lParam;
  229. // The destructor will do the necessary cleanup
  230. delete pDetailsInfoList;
  231. }
  232. }
  233. SetWindowPtr(hwnd, 0, NULL);
  234. }
  235. break;
  236. case WM_DETAILS_INFO:
  237. {
  238. // Check that pDetailsInfo is still alive and that you have a CDetailsInfoList object of the requested pidl
  239. CDetailsInfoList* pDetailsInfoList = (CDetailsInfoList*)lParam;
  240. if (pDetailsInfoList && pNSIInfoList
  241. && (wParam == pNSIInfoList->m_pDUIView->_dwDetailsInfoID))
  242. {
  243. BOOL fShow = FALSE;
  244. StartDefer();
  245. Element * peDetailsInfoArea = pNSIInfoList->GetParent();
  246. if (peDetailsInfoArea)
  247. {
  248. peDetailsInfoArea->RemoveLocalValue(HeightProp);
  249. }
  250. for (int i = 0; i < pDetailsInfoList->_nProperties; i++)
  251. {
  252. if (!pDetailsInfoList->_diProperty[i].bstrValue)
  253. {
  254. continue;
  255. }
  256. // 253647 - surpress the comment field from showing in the
  257. // Details section. Note, I left the support for Comments
  258. // in the code below because this decision might be reversed.
  259. if (IsEqualSCID(pDetailsInfoList->_diProperty[i].scid, SCID_Comment))
  260. {
  261. continue;
  262. }
  263. WCHAR wszInfoString[INTERNET_MAX_URL_LENGTH];
  264. wszInfoString[0] = L'\0';
  265. SHCOLUMNID scid = pDetailsInfoList->_diProperty[i].scid;
  266. // No DisplayName if we don't have one
  267. // or if it is one of the following properties
  268. if ((!pDetailsInfoList->_diProperty[i].bstrDisplayName)
  269. || ( IsEqualSCID(scid, SCID_NAME)
  270. || IsEqualSCID(scid, SCID_TYPE)
  271. || IsEqualSCID(scid, SCID_Comment) ))
  272. {
  273. StringCchCopyW(wszInfoString, ARRAYSIZE(wszInfoString), pDetailsInfoList->_diProperty[i].bstrValue);
  274. }
  275. else
  276. {
  277. // Now, combine the display name and value, seperated by a colon
  278. // ShellConstructMessageString here to form the string. Note: A
  279. // truncated string in wszInfoString is not considered fatal.
  280. WCHAR wszFormatStr[50];
  281. LoadStringW(HINST_THISDLL, IDS_COLONSEPERATED, wszFormatStr, ARRAYSIZE(wszFormatStr));
  282. FormatMessageArg(FORMAT_MESSAGE_FROM_STRING, wszFormatStr, 0, 0,
  283. wszInfoString, ARRAYSIZE(wszInfoString),
  284. pDetailsInfoList->_diProperty[i].bstrDisplayName,
  285. pDetailsInfoList->_diProperty[i].bstrValue);
  286. }
  287. if (wszInfoString[0])
  288. {
  289. Element* pElement;
  290. HRESULT hr = CNameSpaceItemInfo::Create(wszInfoString, &pElement);
  291. if (SUCCEEDED(hr))
  292. {
  293. hr = pNSIInfoList->Add(pElement);
  294. if (IsEqualSCID(scid, SCID_NAME))
  295. {
  296. pElement->SetID(L"InfoName");
  297. }
  298. else if (IsEqualSCID(scid, SCID_TYPE))
  299. {
  300. pElement->SetID(L"InfoType");
  301. }
  302. else if (IsEqualSCID(scid, SCID_Comment))
  303. {
  304. pElement->SetID(L"InfoTip");
  305. }
  306. fShow = TRUE;
  307. }
  308. }
  309. }
  310. pNSIInfoList->m_pDUIView->ShowDetails(fShow);
  311. EndDefer();
  312. }
  313. if (pDetailsInfoList)
  314. {
  315. delete pDetailsInfoList; // The destructor will do the necessary cleanup
  316. }
  317. break;
  318. }
  319. default:
  320. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  321. }
  322. return (LRESULT)0;
  323. }
  324. HRESULT CNameSpaceItemInfoList::_AddMiniPreviewerToList(IShellFolder2 *psf, LPCITEMIDLIST pidl)
  325. {
  326. Element* pElement;
  327. HRESULT hr = CMiniPreviewer::Create(m_pDUIView, psf, pidl, &pElement);
  328. if (SUCCEEDED(hr))
  329. {
  330. hr = Add(pElement);
  331. }
  332. return E_NOTIMPL;
  333. }
  334. #define MAX_FILES_FOR_COMPUTING_SIZE 100
  335. HRESULT CNameSpaceItemInfoList::_OnMultiSelect(IShellFolder2 *psfRoot, LPIDA pida)
  336. {
  337. WCHAR wszText[INTERNET_MAX_URL_LENGTH];
  338. // Get the format string for n selection text
  339. WCHAR wszFormatStr[128];
  340. LoadStringW(HINST_THISDLL, IDS_NSELECTED, wszFormatStr, ARRAYSIZE(wszFormatStr));
  341. // Now, form the n selection text
  342. StringCchPrintfW(wszText, ARRAYSIZE(wszText), wszFormatStr, pida->cidl); // truncation ok (for display only)
  343. CComPtr<IPropertyUI> spPropertyUI;
  344. HRESULT hr = _GetPropertyUI(&spPropertyUI);
  345. if (SUCCEEDED(hr))
  346. {
  347. ULONGLONG ullSizeTotal = 0;
  348. if (pida->cidl <= MAX_FILES_FOR_COMPUTING_SIZE)
  349. {
  350. // Compute the total size and the names of the selected files
  351. for (UINT i = 0; i < pida->cidl; i++)
  352. {
  353. IShellFolder2 *psf;
  354. LPCITEMIDLIST pidl;
  355. hr = SHBindToFolderIDListParent(psfRoot, IDA_GetIDListPtr(pida, i), IID_PPV_ARG(IShellFolder2, &psf), &pidl);
  356. if (SUCCEEDED(hr))
  357. {
  358. ULONGLONG ullSize;
  359. if (SUCCEEDED(GetLongProperty(psf, pidl, &SCID_SIZE, &ullSize)))
  360. {
  361. ullSizeTotal += ullSize;
  362. }
  363. psf->Release();
  364. }
  365. }
  366. }
  367. // Get the display string for Total Size
  368. if (ullSizeTotal > 0)
  369. {
  370. // Convert ullSizeTotal to a string
  371. PROPVARIANT propvar;
  372. propvar.vt = VT_UI8;
  373. propvar.uhVal.QuadPart = ullSizeTotal;
  374. WCHAR wszFormattedTotalSize[128];
  375. if (SUCCEEDED(spPropertyUI->FormatForDisplay(SCID_SIZE.fmtid, SCID_SIZE.pid,
  376. &propvar, PUIFFDF_DEFAULT, wszFormattedTotalSize,
  377. ARRAYSIZE(wszFormattedTotalSize))))
  378. {
  379. // Get the format string for Total File Size text
  380. LoadStringW(HINST_THISDLL, IDS_TOTALFILESIZE, wszFormatStr, ARRAYSIZE(wszFormatStr));
  381. // Now, form the Total File Size text
  382. WCHAR wszTemp[MAX_PATH];
  383. if (SUCCEEDED(StringCchPrintfW(wszTemp, ARRAYSIZE(wszTemp), wszFormatStr, wszFormattedTotalSize)))
  384. {
  385. // Append two line breaks
  386. StringCchCatW(wszText, ARRAYSIZE(wszText), L"\n\n"); // truncation ok (for display only)
  387. // Append the Total Size string
  388. StringCchCatW(wszText, ARRAYSIZE(wszText), wszTemp); // truncation ok (for display only)
  389. }
  390. }
  391. }
  392. }
  393. // Now make a dui gadget for wszText
  394. Element* pElement;
  395. if (SUCCEEDED(CNameSpaceItemInfo::Create(wszText, &pElement)))
  396. {
  397. Add(pElement);
  398. }
  399. return S_OK;
  400. }
  401. IClassInfo* CNameSpaceItemInfoList::Class = NULL;
  402. HRESULT CNameSpaceItemInfoList::Register()
  403. {
  404. return ClassInfo<CNameSpaceItemInfoList,Element>::Register(L"NameSpaceItemInfoList", NULL, 0);
  405. }
  406. STDMETHODIMP CNameSpaceItemInfo::Create(WCHAR* pwszInfoString, Element** ppElement)
  407. {
  408. *ppElement = NULL;
  409. HRESULT hr = E_FAIL;
  410. CNameSpaceItemInfo* pNSIInfo = HNewAndZero<CNameSpaceItemInfo>();
  411. if (!pNSIInfo)
  412. {
  413. hr = E_OUTOFMEMORY;
  414. }
  415. else
  416. {
  417. hr = pNSIInfo->Initialize(pwszInfoString);
  418. if (SUCCEEDED(hr))
  419. *ppElement = pNSIInfo;
  420. else
  421. pNSIInfo->Destroy();
  422. }
  423. return hr;
  424. }
  425. STDMETHODIMP CNameSpaceItemInfo::Initialize(WCHAR* pwszInfoString)
  426. {
  427. HRESULT hr = Element::Initialize(0);
  428. if (SUCCEEDED(hr))
  429. {
  430. hr = SetContentString(pwszInfoString);
  431. }
  432. return hr;
  433. }
  434. IClassInfo* CNameSpaceItemInfo::Class = NULL;
  435. HRESULT CNameSpaceItemInfo::Register()
  436. {
  437. return ClassInfo<CNameSpaceItemInfo,Element>::Register(L"NameSpaceItemInfo", NULL, 0);
  438. }
  439. STDMETHODIMP CBitmapElement::Create(HBITMAP hBitmap, Element** ppElement)
  440. {
  441. *ppElement = NULL;
  442. HRESULT hr;
  443. CBitmapElement* pBitmapElement = HNewAndZero<CBitmapElement>();
  444. if (!pBitmapElement)
  445. {
  446. hr = E_OUTOFMEMORY;
  447. }
  448. else
  449. {
  450. hr = pBitmapElement->Initialize(hBitmap);
  451. if (SUCCEEDED(hr))
  452. *ppElement = pBitmapElement;
  453. else
  454. pBitmapElement->Destroy();
  455. }
  456. return hr;
  457. }
  458. STDMETHODIMP CBitmapElement::Initialize(HBITMAP hBitmap)
  459. {
  460. HRESULT hr = Element::Initialize(0);
  461. if (SUCCEEDED(hr))
  462. {
  463. if (hBitmap)
  464. {
  465. Value* pGraphic = Value::CreateGraphic(hBitmap);
  466. if (pGraphic)
  467. {
  468. SetValue(ContentProp, PI_Local, pGraphic);
  469. pGraphic->Release();
  470. }
  471. }
  472. }
  473. return hr;
  474. }
  475. IClassInfo* CBitmapElement::Class = NULL;
  476. HRESULT CBitmapElement::Register()
  477. {
  478. return ClassInfo<CBitmapElement,Element>::Register(L"BitmapElement", NULL, 0);
  479. }
  480. CMiniPreviewer::~CMiniPreviewer()
  481. {
  482. // We are going away
  483. if (m_pDUIView)
  484. {
  485. m_pDUIView->SetThumbnailMsgWindowPtr(NULL, this);
  486. m_pDUIView->Release();
  487. }
  488. }
  489. STDMETHODIMP CMiniPreviewer::Create(CDUIView* pDUIView, IShellFolder2* psf, LPCITEMIDLIST pidl, Element** ppElement)
  490. {
  491. HRESULT hr;
  492. *ppElement = NULL;
  493. CMiniPreviewer* pMiniPreviewer = HNewAndZero<CMiniPreviewer>();
  494. if (!pMiniPreviewer)
  495. {
  496. hr = E_OUTOFMEMORY;
  497. }
  498. else
  499. {
  500. hr = pMiniPreviewer->Initialize(pDUIView, psf, pidl);
  501. if (SUCCEEDED(hr))
  502. *ppElement = pMiniPreviewer;
  503. else
  504. pMiniPreviewer->Destroy();
  505. }
  506. return hr;
  507. }
  508. STDMETHODIMP CMiniPreviewer::Initialize(CDUIView* pDUIView, IShellFolder2 *psf, LPCITEMIDLIST pidl)
  509. {
  510. HRESULT hr = Element::Initialize(0);
  511. if (SUCCEEDED(hr))
  512. {
  513. (m_pDUIView = pDUIView)->AddRef();
  514. LPITEMIDLIST pidlFull;
  515. if (SUCCEEDED(SHFullIDListFromFolderAndItem(psf, pidl, &pidlFull)))
  516. {
  517. if (SUCCEEDED(m_pDUIView->InitializeThumbnail(CMiniPreviewer::WindowProc)))
  518. {
  519. m_pDUIView->SetThumbnailMsgWindowPtr(this, NULL);
  520. m_pDUIView->StartBitmapExtraction(pidlFull);
  521. }
  522. ILFree(pidlFull);
  523. }
  524. }
  525. return hr;
  526. }
  527. // Window procedure for catching the "image-extraction-done" message
  528. // from m_pDUIView->_spThumbnailExtractor2
  529. LRESULT CALLBACK CMiniPreviewer::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  530. {
  531. CMiniPreviewer* pMiniPreviewer = (CMiniPreviewer*)::GetWindowPtr(hwnd, 0);
  532. switch(uMsg)
  533. {
  534. case WM_DESTROY:
  535. // ignore late messages
  536. {
  537. MSG msg;
  538. while (PeekMessage(&msg, hwnd, WM_HTML_BITMAP, WM_HTML_BITMAP, PM_REMOVE))
  539. {
  540. if (msg.lParam)
  541. {
  542. DeleteObject((HBITMAP)msg.lParam);
  543. }
  544. }
  545. SetWindowPtr(hwnd, 0, NULL);
  546. }
  547. break;
  548. case WM_HTML_BITMAP:
  549. // Check that pMiniPreviewer is still alive and that you have an HBITMAP of the requested pidl
  550. if (pMiniPreviewer && (wParam == pMiniPreviewer->m_pDUIView->_dwThumbnailID))
  551. {
  552. if (lParam) // This is the HBITMAP of the extracted image
  553. {
  554. Element* pElement;
  555. HRESULT hr = CBitmapElement::Create((HBITMAP)lParam, &pElement);
  556. if (SUCCEEDED(hr))
  557. {
  558. // The addition of the thumbnail comes in late. DUI is
  559. // not currently set up to handle a DisableAnimations()/
  560. // EnableAnimations() here, which we were originally
  561. // doing to prevent jumpiness. This was discovered in
  562. // RAID 389343, because our coming off the background
  563. // thread and calling DisableAnimations() was screwing up
  564. // other animations that were already underway. Talking
  565. // with markfi, the problem is understood BUT not one to
  566. // be fixed because of the negative perf impact it would
  567. // have on DUI. So instead we'll StartDefer()/EndDefer()
  568. // to minimize jumpiness from our two layout ops below.
  569. StartDefer();
  570. // Set the VerticalFlowLayout for our element. Otherwise,
  571. // our control will not render.
  572. Value* pvLayout = NULL;
  573. hr = FillLayout::Create(0, NULL, &pvLayout);
  574. if (SUCCEEDED(hr))
  575. {
  576. hr = pMiniPreviewer->SetValue(LayoutProp, PI_Local, pvLayout);
  577. if (SUCCEEDED(hr))
  578. {
  579. hr = pMiniPreviewer->Add(pElement);
  580. }
  581. pvLayout->Release();
  582. }
  583. if (FAILED(hr))
  584. {
  585. pElement->Destroy();
  586. }
  587. EndDefer();
  588. }
  589. else
  590. {
  591. DeleteObject((HBITMAP)lParam);
  592. }
  593. }
  594. }
  595. else if (lParam) // This extraction got done too late.
  596. // So, just delete the wasted HBITMAP.
  597. {
  598. DeleteObject((HBITMAP)lParam);
  599. }
  600. break;
  601. default:
  602. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  603. }
  604. return (LRESULT)0;
  605. }
  606. IClassInfo* CMiniPreviewer::Class = NULL;
  607. HRESULT CMiniPreviewer::Register()
  608. {
  609. return ClassInfo<CMiniPreviewer,Element>::Register(L"MiniPreviewer", NULL, 0);
  610. }
  611. // ***** CDetailsInfoList *******
  612. CDetailsInfoList::CDetailsInfoList() : _nProperties(0)
  613. {
  614. }
  615. CDetailsInfoList::~CDetailsInfoList()
  616. {
  617. for (int i = 0; i < _nProperties; i++)
  618. {
  619. if (_diProperty[i].bstrValue)
  620. {
  621. SysFreeString(_diProperty[i].bstrValue);
  622. }
  623. if (_diProperty[i].bstrDisplayName)
  624. {
  625. SysFreeString(_diProperty[i].bstrDisplayName);
  626. }
  627. }
  628. }
  629. // ***** CDetailsSectionInfoTask *******
  630. CDetailsSectionInfoTask::CDetailsSectionInfoTask(HRESULT *phr,
  631. IShellFolder *psfContaining,
  632. LPCITEMIDLIST pidlAbsolute,
  633. HWND hwndMsg,
  634. UINT uMsg,
  635. DWORD dwDetailsInfoID)
  636. : CRunnableTask(RTF_DEFAULT),
  637. _hwndMsg(hwndMsg),
  638. _uMsg(uMsg),
  639. _dwDetailsInfoID(dwDetailsInfoID)
  640. {
  641. ASSERT(psfContaining && pidlAbsolute && hwndMsg);
  642. _psfContaining = psfContaining;
  643. _psfContaining->AddRef();
  644. *phr = SHILClone(pidlAbsolute, &_pidlAbsolute);
  645. }
  646. CDetailsSectionInfoTask::~CDetailsSectionInfoTask()
  647. {
  648. _psfContaining->Release();
  649. ILFree(_pidlAbsolute);
  650. }
  651. HRESULT CDetailsSectionInfoTask_CreateInstance(IShellFolder *psfContaining,
  652. LPCITEMIDLIST pidlAbsolute,
  653. HWND hwndMsg,
  654. UINT uMsg,
  655. DWORD dwDetailsInfoID,
  656. CDetailsSectionInfoTask **ppTask)
  657. {
  658. *ppTask = NULL;
  659. HRESULT hr;
  660. CDetailsSectionInfoTask* pNewTask = new CDetailsSectionInfoTask(
  661. &hr,
  662. psfContaining,
  663. pidlAbsolute,
  664. hwndMsg,
  665. uMsg,
  666. dwDetailsInfoID);
  667. if (pNewTask)
  668. {
  669. if (SUCCEEDED(hr))
  670. *ppTask = pNewTask;
  671. else
  672. pNewTask->Release();
  673. }
  674. else
  675. {
  676. hr = E_OUTOFMEMORY;
  677. }
  678. return hr;
  679. }
  680. STDMETHODIMP CDetailsSectionInfoTask::RunInitRT()
  681. {
  682. ASSERT(_pidlAbsolute);
  683. BOOL bMsgPosted = FALSE;
  684. HRESULT hr = E_FAIL;
  685. CDetailsInfoList* pCDetailsInfoList = new CDetailsInfoList;
  686. if (!pCDetailsInfoList)
  687. {
  688. hr = E_OUTOFMEMORY;
  689. }
  690. else
  691. {
  692. CComPtr<IShellFolder2> psf2;
  693. LPCITEMIDLIST pidlLast;
  694. hr = SHBindToIDListParent(_pidlAbsolute, IID_PPV_ARG(IShellFolder2, &psf2), &pidlLast);
  695. if (SUCCEEDED(hr))
  696. {
  697. _SetParentAndItem(psf2, pidlLast);
  698. WCHAR wszProperties[MAX_PATH];
  699. hr = _GetDisplayedDetailsProperties(psf2, pidlLast, wszProperties, ARRAYSIZE(wszProperties));
  700. if (SUCCEEDED(hr))
  701. {
  702. // pwszProperties is usually of the form "prop:Name;Type;Author"
  703. CComPtr<IPropertyUI> spPropertyUI;
  704. hr = _GetPropertyUI(&spPropertyUI);
  705. if (SUCCEEDED(hr))
  706. {
  707. SHCOLUMNID scid;
  708. WCHAR wszInfoString[INTERNET_MAX_URL_LENGTH];
  709. ULONG chEaten = 0; // loop var, incremented by ParsePropertyName
  710. for (pCDetailsInfoList->_nProperties = 0;
  711. pCDetailsInfoList->_nProperties < ARRAYSIZE(pCDetailsInfoList->_diProperty)
  712. && SUCCEEDED(spPropertyUI->ParsePropertyName(wszProperties, &scid.fmtid, &scid.pid, &chEaten));
  713. pCDetailsInfoList->_nProperties++)
  714. {
  715. pCDetailsInfoList->_diProperty[pCDetailsInfoList->_nProperties].scid = scid;
  716. PROPERTYUI_FORMAT_FLAGS flagsFormat = IsEqualSCID(scid, SCID_WRITETIME) ? PUIFFDF_FRIENDLYDATE : PUIFFDF_DEFAULT;
  717. // Get the display value
  718. hr = GetPropertyDisplayValue(scid, wszInfoString, ARRAYSIZE(wszInfoString), flagsFormat);
  719. if (SUCCEEDED(hr) && wszInfoString[0])
  720. {
  721. pCDetailsInfoList->_diProperty[pCDetailsInfoList->_nProperties].bstrValue = SysAllocString(wszInfoString);
  722. }
  723. // Get the display name
  724. hr = GetPropertyDisplayName(scid, wszInfoString, ARRAYSIZE(wszInfoString));
  725. if (SUCCEEDED(hr) && wszInfoString[0])
  726. {
  727. pCDetailsInfoList->_diProperty[pCDetailsInfoList->_nProperties].bstrDisplayName = SysAllocString(wszInfoString);
  728. }
  729. }
  730. //The extraction is done. Now post a message.
  731. if (PostMessage(_hwndMsg, WM_DETAILS_INFO,
  732. (WPARAM)_dwDetailsInfoID, (LPARAM)pCDetailsInfoList))
  733. {
  734. bMsgPosted = TRUE;
  735. }
  736. }
  737. }
  738. }
  739. }
  740. if (!bMsgPosted && pCDetailsInfoList)
  741. {
  742. delete pCDetailsInfoList;
  743. }
  744. return S_OK;
  745. }
  746. HRESULT CDetailsSectionInfoTask::_GetDisplayedDetailsProperties(IShellFolder2* psf,
  747. LPCITEMIDLIST pidl,
  748. WCHAR* pwszProperties,
  749. int cchProperties)
  750. {
  751. HRESULT hr = GetStringProperty(psf, pidl, &SCID_DetailsProperties, pwszProperties, cchProperties);
  752. if (FAILED(hr)) // Default properties
  753. {
  754. if (SHGetAttributes(psf, pidl, SFGAO_ISSLOW))
  755. {
  756. // SCID_NAME;SCID_TYPE
  757. StringCchCopyW(pwszProperties, cchProperties, L"prop:Name;Type");
  758. }
  759. else
  760. {
  761. // SCID_NAME;SCID_TYPE;SCID_ATTRIBUTES_DESCRIPTION;SCID_Comment;SCID_WRITETIME;SCID_SIZE;SCID_Author;SCID_CSC_STATUS
  762. StringCchCopyW(pwszProperties, cchProperties, L"prop:Name;Type;AttributesDescription;DocComments;Write;Size;DocAuthor;CSCStatus");
  763. }
  764. }
  765. // Augment properties to include "Location" if in CLSID_DocFindFolder.
  766. IPersist *pPersist;
  767. ASSERT(_psfContaining);
  768. if (SUCCEEDED(_psfContaining->QueryInterface(IID_IPersist, (void**)&pPersist)))
  769. {
  770. CLSID clsid;
  771. if (SUCCEEDED(pPersist->GetClassID(&clsid)) && IsEqualCLSID(clsid, CLSID_DocFindFolder))
  772. _AugmentDisplayedDetailsProperties(pwszProperties, cchProperties);
  773. pPersist->Release();
  774. }
  775. return S_OK;
  776. }
  777. void CDetailsSectionInfoTask::_AugmentDisplayedDetailsProperties(LPWSTR pszDetailsProperties, size_t cchDetailsProperties)
  778. {
  779. static WCHAR szDeclarator[] = L"prop:";
  780. static size_t lenDeclarator = lstrlen(szDeclarator);
  781. static WCHAR szName[64] = { 0 };
  782. static size_t lenName = 0;
  783. static WCHAR szType[64] = { 0 };
  784. static size_t lenType = 0;
  785. static WCHAR szDirectory[64] = { 0 };
  786. static size_t lenDirectory = 0;
  787. // Initialize statics once 'n only once.
  788. if (!szName[0] || !szType[0] || !szDirectory[0])
  789. {
  790. HRESULT hr;
  791. hr = SCIDCannonicalName((SHCOLUMNID *)&SCID_NAME, szName, ARRAYSIZE(szName));
  792. ASSERT(SUCCEEDED(hr));
  793. lenName = lstrlen(szName);
  794. hr = SCIDCannonicalName((SHCOLUMNID *)&SCID_TYPE, szType, ARRAYSIZE(szType));
  795. ASSERT(SUCCEEDED(hr));
  796. lenType = lstrlen(szType);
  797. hr = SCIDCannonicalName((SHCOLUMNID *)&SCID_DIRECTORY, szDirectory, ARRAYSIZE(szDirectory));
  798. ASSERT(SUCCEEDED(hr));
  799. lenDirectory = lstrlen(szDirectory);
  800. }
  801. // Attempt to merge the "Directory" property, in the following ways:
  802. // "prop:Name;Type;Directory;..."
  803. // "prop:Name;Directory;..."
  804. // "prop:Directory;..."
  805. //
  806. size_t lenDetailsProperties = lstrlen(pszDetailsProperties);
  807. size_t lenMerged = lenDetailsProperties + 1 + lenDirectory;
  808. if (lenMerged < cchDetailsProperties && 0 == StrCmpNI(pszDetailsProperties, szDeclarator, lenDeclarator))
  809. {
  810. // Search for "Directory" property (in case it is already specified).
  811. if (!_SearchDisplayedDetailsProperties(pszDetailsProperties, lenDetailsProperties, szDirectory, lenDirectory))
  812. {
  813. // Allocate a temporary buffer to merge into.
  814. size_t cchMerged = cchDetailsProperties;
  815. LPWSTR pszMerged = new WCHAR[cchMerged];
  816. if (pszMerged)
  817. {
  818. // Determine offset in pszDetailsProperties to merge at.
  819. size_t offsetInsert;
  820. if (lenDeclarator < lenDetailsProperties)
  821. {
  822. // Search for "Name" property.
  823. LPWSTR pszName = _SearchDisplayedDetailsProperties(
  824. &pszDetailsProperties[lenDeclarator],
  825. lenDetailsProperties - lenDeclarator,
  826. szName,
  827. lenName);
  828. if (pszName)
  829. {
  830. // Search for "Type" property (immediately following "Name").
  831. size_t offsetName = (pszName - pszDetailsProperties);
  832. size_t offsetType = offsetName + lenName + 1;
  833. size_t offsetRemainder = offsetType + lenType;
  834. if ((offsetRemainder == lenDetailsProperties || (offsetRemainder < lenDetailsProperties && pszDetailsProperties[offsetRemainder] == ';')) &&
  835. !StrCmpNI(&pszDetailsProperties[offsetType], szType, lenType))
  836. {
  837. offsetInsert = offsetRemainder;
  838. }
  839. else
  840. offsetInsert = offsetName + lenName;
  841. }
  842. else
  843. offsetInsert = lenDeclarator;
  844. }
  845. else
  846. offsetInsert = lenDeclarator;
  847. // Merge the "Directory" property.
  848. StringCchCopy(pszMerged, offsetInsert + 1, pszDetailsProperties); // + 1 to account for null terminator.
  849. if (offsetInsert > lenDeclarator)
  850. StringCchCat(pszMerged, cchMerged, L";"); // ';' prepend if necessary
  851. StringCchCat(pszMerged, cchMerged, szDirectory); // "Directory"
  852. if (offsetInsert < lenDetailsProperties)
  853. {
  854. if (pszDetailsProperties[offsetInsert] != ';')
  855. StringCchCat(pszMerged, cchMerged, L";"); // ';' append if necessary
  856. StringCchCat(pszMerged, cchMerged, &pszDetailsProperties[offsetInsert]);
  857. }
  858. // Update in/out pszDetailsProperties.
  859. StringCchCopy(pszDetailsProperties, cchDetailsProperties, pszMerged);
  860. ASSERT(lenMerged == lstrlen(pszMerged));
  861. ASSERT(lenMerged < cchDetailsProperties);
  862. delete[] pszMerged;
  863. }
  864. }
  865. }
  866. else
  867. {
  868. // Invalid format.
  869. ASSERT(FALSE);
  870. }
  871. }
  872. LPWSTR CDetailsSectionInfoTask::_SearchDisplayedDetailsProperties(LPWSTR pszDetailsProperties, size_t lenDetailsProperties, LPWSTR pszProperty, size_t lenProperty)
  873. {
  874. LPWSTR psz = StrStrI(pszDetailsProperties, pszProperty);
  875. while (psz)
  876. {
  877. // Check start...
  878. if (psz == pszDetailsProperties || psz[-1] == ';')
  879. {
  880. // ... and end.
  881. size_t lenToEndOfProperty = (psz - pszDetailsProperties) + lenProperty;
  882. if (lenToEndOfProperty == lenDetailsProperties || pszDetailsProperties[lenToEndOfProperty] == ';')
  883. break;
  884. }
  885. psz = StrStrI(psz + lenProperty, pszProperty);
  886. }
  887. return psz;
  888. }