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

2784 lines
76 KiB

  1. #include "shellprv.h"
  2. #include "duiview.h"
  3. #include "duilist.h"
  4. #include "duisec.h"
  5. #include "duitask.h"
  6. #include "duiinfo.h"
  7. #include "duihost.h"
  8. #include "duidrag.h"
  9. #include "defviewp.h"
  10. #include "ids.h"
  11. #include "dvtasks.h"
  12. #include <shimgvw.h>
  13. #include <uxtheme.h>
  14. #include <shstyle.h>
  15. UsingDUIClass(DUIListView);
  16. UsingDUIClass(DUIAxHost);
  17. UsingDUIClass(Expando);
  18. UsingDUIClass(ActionTask);
  19. UsingDUIClass(DestinationTask);
  20. //
  21. // These are private window messages posted to the host window
  22. // so they will be processed async. There are issues with
  23. // trying to destroy a handler while inside of the handler
  24. //
  25. #define WM_NAVIGATETOPIDL (WM_USER + 42)
  26. #define WM_REFRESHVIEW (WM_USER + 43)
  27. #define DUI_HOST_WINDOW_CLASS_NAME TEXT("DUIViewWndClassName")
  28. //
  29. // Default attributes associated with our DUI sections.
  30. //
  31. struct DUISEC_ATTRIBUTES {
  32. DUISEC _eDUISecID;
  33. BOOL _bExpandedDefault;
  34. LPCWSTR _pszExpandedPropName;
  35. } const c_DUISectionAttributes[] = {
  36. DUISEC_SPECIALTASKS, TRUE, L"ExpandSpecialTasks",
  37. DUISEC_FILETASKS, TRUE, L"ExpandFileTasks",
  38. DUISEC_OTHERPLACESTASKS, TRUE, L"ExpandOtherPlacesTasks",
  39. DUISEC_DETAILSTASKS, FALSE, L"ExpandDetailsTasks"
  40. };
  41. // pDefView - pointer to the defview class
  42. CDUIView* Create_CDUIView(CDefView * pDefView)
  43. {
  44. CDUIView* p = new CDUIView(pDefView);
  45. if (p)
  46. {
  47. if (FAILED(p->Initialize()))
  48. {
  49. delete p;
  50. p = NULL;
  51. }
  52. }
  53. return p;
  54. }
  55. CDUIView::CDUIView(CDefView * pDefView)
  56. {
  57. // We have a zero-init constructor. Be paranoid and check a couple:
  58. ASSERT(NULL ==_hWnd);
  59. ASSERT(NULL == _pshlItems);
  60. ASSERT(NULL == _ppbShellFolders);
  61. _cRef = 1;
  62. _pDefView = pDefView;
  63. _pDefView->AddRef();
  64. }
  65. HRESULT CDUIView::Initialize()
  66. {
  67. // Initialize DirectUI process (InitProcess) and register classes
  68. _hrInit = InitializeDirectUI();
  69. if (FAILED(_hrInit))
  70. goto Failure;
  71. // Initialize DirectUI thread
  72. _hrInit = InitThread();
  73. if (FAILED(_hrInit))
  74. goto Failure;
  75. ManageAnimations(FALSE);
  76. _pDT = new CDUIDropTarget ();
  77. Failure:
  78. return _hrInit;
  79. }
  80. CDUIView::~CDUIView()
  81. {
  82. IUnknown_SetSite(_spThumbnailExtractor2, NULL);
  83. if (_hwndMsgThumbExtract) // May have been (likely) created by CMiniPreviewer
  84. {
  85. DestroyWindow(_hwndMsgThumbExtract);
  86. }
  87. if (_hwndMsgInfoExtract) // May have been (likely) created by CNameSpaceItemInfoList
  88. {
  89. DestroyWindow(_hwndMsgInfoExtract);
  90. }
  91. ATOMICRELEASE(_pshlItems);
  92. if (_bstrIntroText)
  93. {
  94. SysFreeString(_bstrIntroText);
  95. }
  96. if (_hinstTheme)
  97. {
  98. FreeLibrary(_hinstTheme);
  99. _hinstTheme = NULL;
  100. _fLoadedTheme = FALSE;
  101. }
  102. if (_hinstScrollbarTheme)
  103. {
  104. CloseThemeData(_hinstScrollbarTheme);
  105. _hinstScrollbarTheme = NULL;
  106. }
  107. UnInitializeDirectUI();
  108. if (_ppbShellFolders)
  109. _ppbShellFolders->Release();
  110. _pDefView->Release();
  111. }
  112. //
  113. // This DUI uninitialization code was broken out from the destructor
  114. // because we need to call it from defview in response to WM_NCDESTROY
  115. // before the CDUIView object is destroyed. This is required to properly
  116. // initiate the shutdown of DUser on the thread. Since we don't own the
  117. // browser thread message pump we must ensure all DUser processing is
  118. // complete before our defview instance goes away.
  119. // Therefore, since it can be called twice, once from defview and once
  120. // from CDUIView::~CDUIView, all processing must tolerate multiple calls
  121. // for the same instance.
  122. //
  123. void CDUIView::UnInitializeDirectUI(void)
  124. {
  125. ATOMICRELEASE(_pvSpecialTaskSheet);
  126. ATOMICRELEASE(_pvFolderTaskSheet);
  127. ATOMICRELEASE(_pvDetailsSheet);
  128. _ClearNonStdTaskSections();
  129. if (_pDT)
  130. {
  131. _pDT->Release();
  132. _pDT = NULL;
  133. }
  134. ManageAnimations(TRUE);
  135. if (SUCCEEDED(_hrInit))
  136. {
  137. UnInitThread();
  138. _hrInit = E_FAIL; // UnInit thread only once.
  139. }
  140. }
  141. // Right now our themeing information is hard-coded due to limitations of DirectUI (only one resource)
  142. // so we'll ask the namespace for a hardcoded name that we can look up in the below table. Add new
  143. // names/entries to this list as we add theme parts to our shellstyle.dll.
  144. //
  145. // These theme elements come from shellstyle.dll.
  146. const WVTHEME c_wvTheme[] =
  147. {
  148. { L"music", IDB_MUSIC_ICON_BMP, IDB_MUSIC_TASKS_BMP, IDB_MUSIC_LISTVIEW_BMP },
  149. { L"picture", IDB_PICTURES_ICON_BMP, IDB_PICTURES_TASKS_BMP, IDB_PICTURES_LISTVIEW_BMP },
  150. { L"video", IDB_VIDEO_ICON_BMP, IDB_VIDEO_TASKS_BMP, IDB_VIDEO_LISTVIEW_BMP },
  151. { L"search", IDB_SEARCH_ICON_BMP, IDB_SEARCH_TASKS_BMP, IDB_SEARCH_LISTVIEW_BMP },
  152. };
  153. const WVTHEME* CDUIView::GetThemeInfo()
  154. {
  155. for (UINT i = 0 ; i < ARRAYSIZE(c_wvTheme) ; i++)
  156. {
  157. if (0 == lstrcmp(_pDefView->_wvTheme.pszThemeID, c_wvTheme[i].pszThemeName))
  158. return &(c_wvTheme[i]);
  159. }
  160. return NULL;
  161. }
  162. // Main intialization point for DUI view
  163. //
  164. // bDisplayBarrier - Display soft barrier over top of listview
  165. HRESULT CDUIView::Initialize(BOOL bDisplayBarrier, IUnknown * punkPreview)
  166. {
  167. DisableAnimations();
  168. Element::StartDefer();
  169. // Create the host window for the DUI elements
  170. HRESULT hr = _CreateHostWindow();
  171. if (SUCCEEDED(hr))
  172. {
  173. // Dynamically build the .ui file for this view
  174. int iCharCount;
  175. char *pUIFile = NULL;
  176. hr = _BuildUIFile(&pUIFile, &iCharCount);
  177. if (SUCCEEDED(hr))
  178. {
  179. // Parse the .ui file and initialize the elements
  180. hr = _InitializeElements(pUIFile, iCharCount, bDisplayBarrier, punkPreview);
  181. if (SUCCEEDED(hr))
  182. {
  183. BuildDropTarget(_phe->GetDisplayNode(), _phe->GetHWND());
  184. // Set visible for host element
  185. _phe->SetVisible(true);
  186. }
  187. LocalFree(pUIFile);
  188. }
  189. }
  190. // Note:
  191. // EndDefer() here so layout coordinates are calculated before executing
  192. // the next snippit of code which depends on them being set properly.
  193. // The one thing to be aware of in future is that if this isn't the
  194. // outermost BeginDefer()/EndDefer() pair in the codepath, we're in
  195. // trouble because then DUI won't calculate its layout coordinates.
  196. Element::EndDefer();
  197. if (SUCCEEDED(hr))
  198. {
  199. Value* pv;
  200. if (_peTaskPane->GetExtent(&pv))
  201. {
  202. const SIZE * pSize = pv->GetSize();
  203. _iOriginalTaskPaneWidth = pSize->cx;
  204. _iTaskPaneWidth = pSize->cx;
  205. pv->Release();
  206. // REVIEW: Why are we doing this based on a resource string, instead
  207. // of simply having the localizers localize the size in the theme???
  208. // It kind of sucks because we're forcing two layouts all the time.
  209. _iTaskPaneWidth = ScaleSizeBasedUponLocalization(_iOriginalTaskPaneWidth);
  210. if (_iTaskPaneWidth != _iOriginalTaskPaneWidth)
  211. {
  212. Element::StartDefer();
  213. // Increase the width of the scroller if the localizers have
  214. // bumped up the size defined in the resources
  215. _peTaskPane->SetWidth(_iTaskPaneWidth);
  216. Element::EndDefer();
  217. }
  218. }
  219. if (_fHideTasklist || (_phe->GetWidth() / 2) < _iTaskPaneWidth)
  220. {
  221. Element::StartDefer();
  222. _peTaskPane->SetWidth(0);
  223. Element::EndDefer();
  224. }
  225. _bInitialized = true;
  226. }
  227. else
  228. {
  229. if (_hWnd)
  230. {
  231. DestroyWindow (_hWnd);
  232. _hWnd = NULL;
  233. }
  234. }
  235. // Note:
  236. // We don't re-enable animations until after we're completely finished
  237. // with all our crazy resizing and stuff. This prevents some nasty
  238. // issues with DUI panes only partly painting (i.e. RAID 422057).
  239. EnableAnimations();
  240. return hr;
  241. }
  242. void CDUIView::DetachListview()
  243. {
  244. if (_peListView)
  245. _peListView->DetachListview();
  246. if (_hWnd)
  247. {
  248. DestroyWindow(_hWnd);
  249. _hWnd = NULL;
  250. }
  251. }
  252. // Creates the host window for the DUI elements to
  253. // be associated with. This child window
  254. // will also be passed back to defview to be used
  255. // as the result pane host.
  256. HRESULT CDUIView::_CreateHostWindow (void)
  257. {
  258. WNDCLASS wc = {0};
  259. wc.style = CS_HREDRAW | CS_VREDRAW;
  260. wc.lpfnWndProc = _DUIHostWndProc;
  261. wc.hInstance = HINST_THISDLL;
  262. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  263. wc.hbrBackground = (HBRUSH)GetStockObject(HOLLOW_BRUSH);
  264. wc.lpszClassName = DUI_HOST_WINDOW_CLASS_NAME;
  265. RegisterClass(&wc);
  266. // Query for the size of defview's client window so we can size this window
  267. // to match
  268. RECT rc;
  269. GetClientRect(_pDefView->_hwndView, &rc);
  270. _hWnd = CreateWindowEx(0, DUI_HOST_WINDOW_CLASS_NAME, NULL,
  271. WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN,
  272. rc.left, rc.top, rc.right, rc.bottom,
  273. _pDefView->_hwndView, NULL, HINST_THISDLL, (void *)this);
  274. if (!_hWnd)
  275. {
  276. TraceMsg(TF_ERROR, "CDUIView::_CreateHostWindow: CreateWindowEx failed with %d", GetLastError());
  277. return HRESULT_FROM_WIN32(GetLastError());
  278. }
  279. // Temporary work-around for DUI mirroring bug 259158
  280. SHSetWindowBits(_hWnd, GWL_EXSTYLE, WS_EX_LAYOUTRTL, 0);
  281. return S_OK;
  282. }
  283. void CDUIView::ManageAnimations(BOOL bExiting)
  284. {
  285. if (bExiting)
  286. {
  287. if (_bAnimationsDisabled)
  288. {
  289. DirectUI::EnableAnimations();
  290. _bAnimationsDisabled = FALSE;
  291. }
  292. }
  293. else
  294. {
  295. BOOL bAnimate = TRUE;
  296. SystemParametersInfo(SPI_GETMENUANIMATION, 0, &bAnimate, 0);
  297. if (bAnimate)
  298. {
  299. if (_bAnimationsDisabled)
  300. {
  301. DirectUI::EnableAnimations();
  302. _bAnimationsDisabled = FALSE;
  303. }
  304. }
  305. else
  306. {
  307. if (!_bAnimationsDisabled)
  308. {
  309. DirectUI::DisableAnimations();
  310. _bAnimationsDisabled = TRUE;
  311. }
  312. }
  313. }
  314. }
  315. HINSTANCE CDUIView::_GetThemeHinst()
  316. {
  317. if (!_fLoadedTheme)
  318. {
  319. _fLoadedTheme = TRUE;
  320. if (_hinstTheme)
  321. {
  322. FreeLibrary(_hinstTheme);
  323. }
  324. _hinstTheme = SHGetShellStyleHInstance();
  325. if (_hinstScrollbarTheme)
  326. {
  327. CloseThemeData (_hinstScrollbarTheme);
  328. }
  329. _hinstScrollbarTheme = OpenThemeData(_hWnd, L"Scrollbar");
  330. }
  331. return _hinstTheme ? _hinstTheme : HINST_THISDLL;
  332. }
  333. // Loads the requested UI file from shell32's resources
  334. //
  335. // iID - UI file id
  336. // pUIFile - receives a pointer to the UI file
  337. HRESULT CDUIView::_LoadUIFileFromResources(HINSTANCE hinst, int iID, char **pUIFile)
  338. {
  339. HRESULT hr;
  340. HRSRC hFile = FindResource(hinst, MAKEINTRESOURCE(iID), TEXT("UIFILE"));
  341. if (hFile)
  342. {
  343. HGLOBAL hFileHandle = LoadResource(hinst, hFile);
  344. if (hFileHandle)
  345. {
  346. char *pFile = (char *)LockResource(hFileHandle);
  347. if (pFile)
  348. {
  349. DWORD dwSize = SizeofResource(hinst, hFile);
  350. *pUIFile = (char *)LocalAlloc(LPTR, dwSize + 1);
  351. if (*pUIFile)
  352. {
  353. CopyMemory(*pUIFile, pFile, dwSize);
  354. hr = S_OK;
  355. }
  356. else
  357. {
  358. hr = E_OUTOFMEMORY;
  359. }
  360. }
  361. else
  362. {
  363. hr = HRESULT_FROM_WIN32(GetLastError());
  364. }
  365. }
  366. else
  367. {
  368. hr = HRESULT_FROM_WIN32(GetLastError());
  369. }
  370. }
  371. else
  372. {
  373. hr = HRESULT_FROM_WIN32(GetLastError());
  374. }
  375. return hr;
  376. }
  377. // Builds the UI file for this view from the
  378. // appropriate base template + style sheet
  379. //
  380. // pUIFile receives a pointer to the ui file in memory
  381. // piCharCount receives the size of the file
  382. HRESULT CDUIView::_BuildUIFile(char **pUIFile, int *piCharCount)
  383. {
  384. // Load the base UI file
  385. char * pBase;
  386. HRESULT hr = _LoadUIFileFromResources(HINST_THISDLL, IDR_DUI_FOLDER, &pBase);
  387. if (SUCCEEDED(hr))
  388. {
  389. // Load the style sheet. First, check if the current theme has a style sheet,
  390. // if not, use the default style sheet in the resources.
  391. char *pStyle;
  392. hr = _LoadUIFileFromResources(_GetThemeHinst(), IDR_DUI_STYLESHEET, &pStyle);
  393. if (SUCCEEDED(hr))
  394. {
  395. char *pResult = (char *)LocalAlloc(LPTR, lstrlenA(pBase) + lstrlenA(pStyle) + 1);
  396. if (pResult)
  397. {
  398. // Put the files together
  399. lstrcpyA(pResult, pStyle);
  400. lstrcatA(pResult, pBase);
  401. // Store the final results
  402. *pUIFile = pResult;
  403. *piCharCount = lstrlenA(pResult);
  404. }
  405. else
  406. {
  407. hr = E_OUTOFMEMORY;
  408. }
  409. LocalFree(pStyle);
  410. }
  411. LocalFree(pBase);
  412. }
  413. return hr;
  414. }
  415. // Callback function used by the ui file parser
  416. //
  417. // pszError - Error text
  418. // pszToken - Token text
  419. // iLine - Line number
  420. void CALLBACK UIFileParseError(LPCWSTR pszError, LPCWSTR pszToken, int iLine)
  421. {
  422. TraceMsg (TF_ERROR, "UIFileParseError: %s '%s' at line %d", pszError, pszToken, iLine);
  423. }
  424. // Builds a section which holds tasks
  425. //
  426. // peSectionList - parent of the section
  427. // bMain - Main section or normal section
  428. // pTitleUI - interface describing the title, may be NULL if pTitleDesc provided
  429. // pBitmapDesc - Description of the bitmap
  430. // pWatermarkDesc - Description of the watermark
  431. // pvSectionSheet - Style sheet to be used
  432. // pParser - Parser instance pointer
  433. // fExpanded - Expanded or closed
  434. // ppeExpando - [out,optional] Receives the section just created
  435. // pTaskList - [out] Receives the task list area element pointer within the pExpando
  436. HRESULT CDUIView::_BuildSection(Element* peSectionList, BOOL bMain, IUIElement* pTitleUI,
  437. int idBitmapDesc, int idWatermarkDesc, Value* pvSectionSheet,
  438. Parser* pParser, DUISEC eDUISecID, Expando** ppeExpando, Element ** pTaskList)
  439. {
  440. Expando* peSection = NULL;
  441. Value* pv = NULL;
  442. Element* pe = NULL;
  443. HBITMAP hBitmap;
  444. // Create a section using the definition in the ui file
  445. HRESULT hr = pParser->CreateElement (bMain ? L"mainsection" : L"section", NULL, &pe);
  446. if (FAILED(hr))
  447. {
  448. TraceMsg (TF_ERROR, "CDUIView::_BuildSection: CreateElement failed with 0x%x", hr);
  449. return hr;
  450. }
  451. ASSERTMSG(pe->GetClassInfo() == Expando::Class, "CDUIView::_BuildSection: didn't get an Expando::Class object (%s)", pe->GetClassInfo()->GetName());
  452. peSection = (Expando*)pe;
  453. pe->SetWidth(ScaleSizeBasedUponLocalization(pe->GetWidth()));
  454. peSection->Initialize(eDUISecID, pTitleUI, this, _pDefView);
  455. if (ppeExpando)
  456. *ppeExpando = peSection;
  457. // Add the section to the list
  458. peSectionList->Add (peSection);
  459. // Set the title
  460. peSection->UpdateTitleUI(NULL); // nothing is selected when the folder starts up
  461. // Set the bitmap on the left side
  462. if (idBitmapDesc)
  463. {
  464. pe = peSection->FindDescendent (Expando::idIcon);
  465. if (pe)
  466. {
  467. hBitmap = DUILoadBitmap(_GetThemeHinst(), idBitmapDesc, LR_CREATEDIBSECTION);
  468. if (hBitmap)
  469. {
  470. pv = Value::CreateGraphic(hBitmap, GRAPHIC_AlphaConstPerPix);
  471. if (pv)
  472. {
  473. pe->SetValue (Element::ContentProp, PI_Local, pv);
  474. pv->Release ();
  475. }
  476. else
  477. {
  478. DeleteObject(hBitmap);
  479. TraceMsg (TF_ERROR, "CDUIView::_BuildSection: CreateGraphic for the bitmap failed.");
  480. }
  481. }
  482. else
  483. {
  484. TraceMsg (TF_ERROR, "CDUIView::_BuildSection: DUILoadBitmap failed.");
  485. }
  486. }
  487. else
  488. {
  489. TraceMsg (TF_ERROR, "CDUIView::_BuildSection: FindDescendent for the bitmap failed.");
  490. }
  491. }
  492. if (idWatermarkDesc)
  493. {
  494. HINSTANCE hinstTheme = _GetThemeHinst();
  495. pe = peSection->FindDescendent (Expando::idWatermark);
  496. if (pe)
  497. {
  498. // Note: in Classic mode, we don't want the watermarks, so this function
  499. // will return NULL
  500. hBitmap = DUILoadBitmap(hinstTheme, idWatermarkDesc, LR_CREATEDIBSECTION);
  501. if (hBitmap)
  502. {
  503. pv = Value::CreateGraphic(hBitmap, GRAPHIC_NoBlend);
  504. if (pv)
  505. {
  506. pe->SetValue (Element::ContentProp, PI_Local, pv);
  507. pv->Release ();
  508. }
  509. else
  510. {
  511. DeleteObject(hBitmap);
  512. TraceMsg (TF_ERROR, "CDUIView::_BuildSection: CreateGraphic for the watermark failed.");
  513. }
  514. }
  515. }
  516. else
  517. {
  518. TraceMsg (TF_ERROR, "CDUIView::_BuildSection: FindDescendent for the watermark failed.");
  519. }
  520. }
  521. // Set the style sheet if specified
  522. if (pvSectionSheet)
  523. {
  524. peSection->SetValue (Element::SheetProp, PI_Local, pvSectionSheet);
  525. }
  526. // Set the expanded state. By default, it is expanded.
  527. if (!_ShowSectionExpanded(eDUISecID))
  528. {
  529. peSection->SetSelected(FALSE);
  530. }
  531. // Add padding for the icon if appropriate. Note, this has to happen
  532. // after the style sheet is applied
  533. if (idBitmapDesc)
  534. {
  535. Element* pe = peSection->FindDescendent(StrToID(L"header"));
  536. if (pe)
  537. {
  538. Value* pvValue;
  539. const RECT * prect;
  540. prect = pe->GetPadding (&pvValue);
  541. if (prect)
  542. {
  543. pe->SetPadding ((prect->left + 20), prect->top, prect->right, prect->bottom);
  544. pvValue->Release();
  545. }
  546. }
  547. }
  548. // Return the task list element pointer
  549. *pTaskList = peSection->FindDescendent (Expando::idTaskList);
  550. if (*pTaskList)
  551. {
  552. hr = S_OK;
  553. }
  554. else
  555. {
  556. TraceMsg (TF_ERROR, "CDUIView::_BuildSection: Failed to find task list element");
  557. hr = E_FAIL;
  558. }
  559. return hr;
  560. }
  561. // Adds the action tasks to the task list
  562. //
  563. // peTaskList - Parent element
  564. // penum - enumeration interface
  565. // pvTaskSheet - Style sheet
  566. HRESULT CDUIView::_AddActionTasks(Expando* peExpando, Element* peTaskList, IEnumUICommand* penum, Value* pvTaskSheet, BOOL bIntroAdded)
  567. {
  568. IUICommand* puiCommand;
  569. BOOL fShow = bIntroAdded;
  570. while (S_OK==penum->Next(1, &puiCommand, NULL))
  571. {
  572. UISTATE uis;
  573. HRESULT hr = puiCommand->get_State(_pshlItems, FALSE, &uis); // Don't do it if it's going to take long, instead, returns E_PENDING
  574. if (SUCCEEDED(hr) && (uis==UIS_ENABLED))
  575. {
  576. Element *pe;
  577. HRESULT hr = ActionTask::Create(0, puiCommand, _pshlItems, this, _pDefView, &pe);
  578. if (SUCCEEDED(hr))
  579. {
  580. if (pvTaskSheet)
  581. {
  582. pe->SetValue(Element::SheetProp, PI_Local, pvTaskSheet);
  583. }
  584. peTaskList->Add(pe);
  585. fShow = TRUE;
  586. }
  587. }
  588. else if (hr == E_PENDING)
  589. {
  590. IRunnableTask *pTask;
  591. if (SUCCEEDED(CGetCommandStateTask_Create(_pDefView, puiCommand, _pshlItems, &pTask)))
  592. {
  593. _pDefView->_AddTask(pTask, TOID_DVGetCommandState, 0, TASK_PRIORITY_GETSTATE, ADDTASK_ATEND);
  594. pTask->Release();
  595. }
  596. }
  597. puiCommand->Release();
  598. }
  599. penum->Reset();
  600. peExpando->ShowExpando(fShow);
  601. return S_OK;
  602. }
  603. // Adds the destination tasks to the task list
  604. //
  605. // peTaskList - Parent element
  606. // penum - enumerator of pidls to display
  607. // pvTaskSheet - Style sheet
  608. HRESULT CDUIView::_AddDestinationTasks(Element* peTaskList, IEnumIDList* penum, Value* pvTaskSheet)
  609. {
  610. HRESULT hr = S_OK;
  611. LPITEMIDLIST pidl;
  612. while (S_OK==penum->Next(1, &pidl, NULL))
  613. {
  614. Element *pe;
  615. hr = DestinationTask::Create (0, pidl, this, _pDefView, &pe);
  616. if (SUCCEEDED(hr))
  617. {
  618. if (pvTaskSheet)
  619. {
  620. pe->SetValue(Element::SheetProp, PI_Local, pvTaskSheet);
  621. }
  622. peTaskList->Add(pe);
  623. }
  624. ILFree(pidl);
  625. }
  626. penum->Reset();
  627. return hr;
  628. }
  629. //
  630. // Purpose: Adds the DetailsSectionInfo
  631. //
  632. HRESULT CDUIView::_AddDetailsSectionInfo()
  633. {
  634. IShellItemArray *psiShellItems = _pshlItems;
  635. if (!psiShellItems && _pDefView)
  636. {
  637. psiShellItems = _pDefView->_GetFolderAsShellItemArray();
  638. }
  639. //TODO: background thread!
  640. Element* pElement;
  641. HRESULT hr = CNameSpaceItemInfoList::Create(this, _pvDetailsSheet,psiShellItems, &pElement);
  642. if (pElement)
  643. {
  644. hr = _peDetailsInfoArea->Add(pElement);
  645. }
  646. return hr;
  647. }
  648. // Navigates to the destination pidl
  649. //
  650. // pidl - destination
  651. HRESULT CDUIView::NavigateToDestination(LPCITEMIDLIST pidl)
  652. {
  653. LPITEMIDLIST pidlClone = ILClone(pidl);
  654. if (pidlClone)
  655. {
  656. UINT wFlags = (SBSP_DEFBROWSER | SBSP_ABSOLUTE);
  657. // mimic "new window" behavior
  658. if (0 > GetKeyState(VK_SHIFT))
  659. {
  660. wFlags |= SBSP_NEWBROWSER;
  661. }
  662. PostMessage(_hWnd, WM_NAVIGATETOPIDL, (WPARAM)wFlags, (LPARAM)pidlClone);
  663. }
  664. return S_OK;
  665. }
  666. // Sends a delay navigation command to the view window. This delay allows
  667. // double-clicks to be interpretted as a single click. This prevents
  668. // double navigations usually causing the user to end up with two "things"
  669. // instead of just one.
  670. //
  671. // Also by doing this, the issue of the 2nd click causing the old window to
  672. // get activation is handled. The user is expecting the new window to pop
  673. // up in front of the old window. But, because the user double-clicked,
  674. // the old window would get reactivated and the new window would end up
  675. // behind the current window. See WM_USER_DELAY_NAVIGATION in HWNDView (below)
  676. // for more details.
  677. //
  678. // psiItemArray - the shell item to navigate. Can be NULL.
  679. // puiCommand - the command object to send the navigation to.
  680. HRESULT CDUIView::DelayedNavigation(IShellItemArray *psiItemArray, IUICommand *puiCommand)
  681. {
  682. SendMessage(_phe->GetHWND(), WM_USER_DELAY_NAVIGATION, (WPARAM) psiItemArray, (LPARAM) puiCommand);
  683. return S_OK;
  684. }
  685. // Builds the task list area
  686. //
  687. // pParser - Parsing instance
  688. HRESULT CDUIView::_BuildTaskList(Parser* pParser)
  689. {
  690. HRESULT hr = S_OK;
  691. // Locate section list element
  692. Element* peSectionList = _phe->FindDescendent (StrToID(L"sectionlist"));
  693. if (!peSectionList)
  694. {
  695. TraceMsg (TF_ERROR, "CDUIView::_BuildTaskList: Failed to find section list element");
  696. return E_FAIL;
  697. }
  698. if (SFVMWVF_ENUMTASKS & _pDefView->_wvContent.dwFlags)
  699. {
  700. if (_bInitialized)
  701. {
  702. //
  703. // The 'non-standard' task list is the type who's contents
  704. // are dynamically enumerated by the folder view.
  705. // In the case of Control Panel, items in this content appear
  706. // conditionally based upon many factors, one being the categorization
  707. // of applets. In order for the content to be correct, categorization
  708. // must be correct which means that all folder items are known.
  709. // To avoid multiple repaints of the task lists, we defer creation
  710. // of the task lists until AFTER the initial creation of the view.
  711. // Once all folder items have been enumerated, the webview content
  712. // is refreshed in response to a 'contents changed' notification from
  713. // defview. It is during this update that we pass through this code
  714. // section and build the task list.
  715. //
  716. _ClearNonStdTaskSections();
  717. hr = _GetNonStdTaskSectionsFromViewCB();
  718. if (SUCCEEDED(hr) && NULL != _hdsaNonStdTaskSections)
  719. {
  720. hr = _BuildNonStandardTaskList(pParser, peSectionList, _hdsaNonStdTaskSections);
  721. }
  722. }
  723. }
  724. else
  725. {
  726. hr = _BuildStandardTaskList(pParser, peSectionList);
  727. }
  728. return THR(hr);
  729. }
  730. //
  731. // Builds the task list by requesting task section information
  732. // from the view callback using an enumeration mechanism.
  733. //
  734. //
  735. // ISSUE-2001/01/03-BrianAu Review
  736. //
  737. // Review this with MikeSh and EricFlo.
  738. // I think we should build this generic mechanism then implement the
  739. // 'standard' webview code in terms of this generic mechanism.
  740. // Would be best to replace the SFVM_ENUMWEBVIEWTASKS callback message
  741. // with a message that receives a COM enumerator.
  742. //
  743. // I like the idea. We replace SFVMWVF_SPECIALTASK with an LPCSTR to the theme identifier.
  744. // We can put a SFVM_GETWEBVIEWTASKS to SFVM_ENUMWEBVIEWTASKS layer in for us too.
  745. //
  746. HRESULT CDUIView::_BuildNonStandardTaskList(Parser *pParser, Element *peSectionList, HDSA hdsaSections)
  747. {
  748. Value* pvMainSectionSheet = NULL;
  749. Value *pvMainTaskSheet = NULL;
  750. Value* pvStdSectionSheet = NULL;
  751. Value* pvStdTaskSheet = NULL;
  752. HRESULT hr = S_OK;
  753. ASSERT(NULL != hdsaSections);
  754. ASSERT(NULL != pParser);
  755. ASSERT(NULL != peSectionList);
  756. const int cSections = DSA_GetItemCount(hdsaSections);
  757. for (int i = 0; i < cSections; i++)
  758. {
  759. SFVM_WEBVIEW_ENUMTASKSECTION_DATA *pSection = (SFVM_WEBVIEW_ENUMTASKSECTION_DATA *)DSA_GetItemPtr(hdsaSections, i);
  760. ASSERT(NULL != pSection);
  761. const BOOL bMainSection = (0 != (SFVMWVF_SPECIALTASK & pSection->dwFlags));
  762. Value *pvSectionSheet = NULL;
  763. Value *pvTaskSheet = NULL;
  764. DUISEC eDUISecID;
  765. if (bMainSection)
  766. {
  767. if (NULL == pvMainSectionSheet)
  768. {
  769. pvMainSectionSheet = pParser->GetSheet(L"mainsectionss");
  770. }
  771. if (NULL == pvMainTaskSheet)
  772. {
  773. pvMainTaskSheet = pParser->GetSheet(L"mainsectiontaskss");
  774. }
  775. pvSectionSheet = pvMainSectionSheet;
  776. pvTaskSheet = pvMainTaskSheet;
  777. eDUISecID = DUISEC_SPECIALTASKS;
  778. }
  779. else
  780. {
  781. if (NULL == pvStdSectionSheet)
  782. {
  783. pvStdSectionSheet = pParser->GetSheet(L"sectionss");
  784. }
  785. if (NULL == pvStdTaskSheet)
  786. {
  787. pvStdTaskSheet = pParser->GetSheet(L"sectiontaskss");
  788. }
  789. pvSectionSheet = pvStdSectionSheet;
  790. pvTaskSheet = pvStdTaskSheet;
  791. eDUISecID = DUISEC_FILETASKS;
  792. }
  793. ASSERT(NULL != pvSectionSheet);
  794. Expando *peSection;
  795. Element *peTaskList;
  796. hr = _BuildSection(peSectionList,
  797. bMainSection,
  798. pSection->pHeader,
  799. pSection->idBitmap,
  800. pSection->idWatermark,
  801. pvSectionSheet,
  802. pParser,
  803. eDUISecID,
  804. &peSection,
  805. &peTaskList);
  806. if (SUCCEEDED(hr))
  807. {
  808. hr = _AddActionTasks(peSection, peTaskList, pSection->penumTasks, pvTaskSheet, FALSE);
  809. }
  810. }
  811. if (pvMainSectionSheet)
  812. {
  813. pvMainSectionSheet->Release();
  814. }
  815. if (pvMainTaskSheet)
  816. {
  817. pvMainTaskSheet->Release();
  818. }
  819. if (pvStdSectionSheet)
  820. {
  821. pvStdSectionSheet->Release();
  822. }
  823. if (pvStdTaskSheet)
  824. {
  825. pvStdTaskSheet->Release();
  826. }
  827. return THR(hr);
  828. }
  829. HRESULT CDUIView::_GetIntroTextElement(Element** ppeIntroText)
  830. {
  831. if (SHRegGetBoolUSValue(REGSTR_PATH_EXPLORER, TEXT("ShowWebViewIntroText"), FALSE, FALSE))
  832. {
  833. if (!_bstrIntroText)
  834. {
  835. WCHAR wszIntroText[INFOTIPSIZE];
  836. if (_bBarrierShown)
  837. {
  838. LoadString(HINST_THISDLL, IDS_INTRO_BARRICADED, wszIntroText, ARRAYSIZE(wszIntroText));
  839. }
  840. else if (!_pDefView->_pshf2Parent
  841. || FAILED(GetStringProperty(_pDefView->_pshf2Parent, _pDefView->_pidlRelative,
  842. &SCID_FolderIntroText, wszIntroText, ARRAYSIZE(wszIntroText))))
  843. {
  844. wszIntroText[0] = L'\0';
  845. }
  846. _bstrIntroText = SysAllocString(wszIntroText);
  847. }
  848. }
  849. HRESULT hr = E_FAIL;
  850. if (_bstrIntroText && _bstrIntroText[0])
  851. {
  852. hr = CNameSpaceItemInfo::Create(_bstrIntroText, ppeIntroText);
  853. if (SUCCEEDED(hr))
  854. {
  855. if (_pvDetailsSheet)
  856. {
  857. (*ppeIntroText)->SetValue(Element::SheetProp, PI_Local, _pvDetailsSheet);
  858. }
  859. }
  860. }
  861. return hr;
  862. }
  863. HRESULT CDUIView::_BuildStandardTaskList(Parser *pParser, Element *peSectionList)
  864. {
  865. Element* peTaskList;
  866. Value* pvSectionSheet = NULL;
  867. Value* pvTaskSheet = NULL;
  868. Value* pvDetailsSheet = NULL;
  869. HRESULT hr = S_OK;
  870. Element* peIntroText;
  871. if (FAILED(_GetIntroTextElement(&peIntroText)))
  872. {
  873. peIntroText = NULL;
  874. }
  875. //
  876. // Special Tasks section is optional (main section)
  877. //
  878. if (_pDefView->_wvContent.pSpecialTaskHeader)
  879. {
  880. pvSectionSheet = pParser->GetSheet(L"mainsectionss");
  881. int idBitmap = 0;
  882. int idWatermark = 0;
  883. const WVTHEME* pThemeInfo = GetThemeInfo();
  884. if (pThemeInfo)
  885. {
  886. idBitmap = pThemeInfo->idSpecialSectionIcon;
  887. idWatermark = pThemeInfo->idSpecialSectionWatermark;
  888. }
  889. // TODO: get special section open/closed state from the per-user-per-pidl property bag
  890. hr = _BuildSection(
  891. peSectionList,
  892. TRUE,
  893. _pDefView->_wvContent.pSpecialTaskHeader,
  894. idBitmap,
  895. idWatermark,
  896. pvSectionSheet,
  897. pParser,
  898. DUISEC_SPECIALTASKS,
  899. &_peSpecialSection,
  900. &peTaskList);
  901. if (SUCCEEDED(hr))
  902. {
  903. BOOL bIntroTextAdded = FALSE;
  904. _peSpecialTaskList = peTaskList;
  905. // Add the tasks + style sheet
  906. _pvSpecialTaskSheet = pParser->GetSheet(L"mainsectiontaskss");
  907. if (peIntroText)
  908. {
  909. if (SUCCEEDED(_peSpecialTaskList->Add(peIntroText)))
  910. {
  911. bIntroTextAdded = TRUE;
  912. peIntroText = NULL;
  913. }
  914. }
  915. _AddActionTasks(_peSpecialSection, _peSpecialTaskList, _pDefView->_wvTasks.penumSpecialTasks, _pvSpecialTaskSheet, bIntroTextAdded);
  916. }
  917. if (pvSectionSheet)
  918. pvSectionSheet->Release();
  919. }
  920. // Get the style sheets for remaining standard sections
  921. pvSectionSheet = pParser->GetSheet (L"sectionss");
  922. pvTaskSheet = pParser->GetSheet (L"sectiontaskss");
  923. // File tasks section (standard section) Not shown if the barricade is shown.
  924. if (!_bBarrierShown)
  925. {
  926. if (_pDefView->_wvContent.pFolderTaskHeader)
  927. {
  928. // TODO: get folder section open/closed state from the per-user-per-pidl property bag
  929. hr = _BuildSection(
  930. peSectionList,
  931. FALSE,
  932. _pDefView->_wvContent.pFolderTaskHeader,
  933. 0,
  934. 0,
  935. pvSectionSheet,
  936. pParser,
  937. DUISEC_FILETASKS,
  938. &_peFolderSection,
  939. &peTaskList);
  940. if (SUCCEEDED(hr))
  941. {
  942. BOOL bIntroTextAdded = FALSE;
  943. _peFolderTaskList = peTaskList;
  944. _pvFolderTaskSheet = pvTaskSheet;
  945. if (_pvFolderTaskSheet)
  946. _pvFolderTaskSheet->AddRef();
  947. if (peIntroText)
  948. {
  949. if (SUCCEEDED(_peFolderTaskList->Add(peIntroText)))
  950. {
  951. bIntroTextAdded = TRUE;
  952. peIntroText = NULL;
  953. }
  954. }
  955. _AddActionTasks(_peFolderSection, _peFolderTaskList, _pDefView->_wvTasks.penumFolderTasks, _pvFolderTaskSheet, bIntroTextAdded);
  956. }
  957. }
  958. }
  959. // Other places tasks section (standard section)
  960. if (_pDefView->_pOtherPlacesHeader)
  961. {
  962. // TODO: get OtherPlaces section open/closed state from the per-user-per-pidl property bag
  963. hr = _BuildSection(
  964. peSectionList,
  965. FALSE,
  966. _pDefView->_pOtherPlacesHeader,
  967. 0,
  968. 0,
  969. pvSectionSheet,
  970. pParser,
  971. DUISEC_OTHERPLACESTASKS,
  972. NULL,
  973. &peTaskList);
  974. if (SUCCEEDED(hr))
  975. {
  976. _AddDestinationTasks(peTaskList, _pDefView->_wvContent.penumOtherPlaces, pvTaskSheet);
  977. }
  978. }
  979. // Details tasks section (standard section)
  980. if (_pDefView->_pDetailsHeader)
  981. {
  982. // TODO: get Details section open/closed state from the per-user-per-pidl property bag
  983. hr = _BuildSection(
  984. peSectionList,
  985. FALSE,
  986. _pDefView->_pDetailsHeader,
  987. 0,
  988. 0,
  989. pvSectionSheet,
  990. pParser,
  991. DUISEC_DETAILSTASKS,
  992. &_peDetailsSection,
  993. &_peDetailsInfoArea);
  994. if (SUCCEEDED(hr))
  995. {
  996. _AddDetailsSectionInfo();
  997. }
  998. }
  999. if (peIntroText)
  1000. {
  1001. peIntroText->Destroy();
  1002. }
  1003. if (pvTaskSheet)
  1004. {
  1005. pvTaskSheet->Release();
  1006. }
  1007. if (pvSectionSheet)
  1008. {
  1009. pvSectionSheet->Release();
  1010. }
  1011. return hr;
  1012. }
  1013. BOOL CDUIView::_ShowSectionExpanded(DUISEC eDUISecID)
  1014. {
  1015. const struct DUISEC_ATTRIBUTES *pAttrib = _GetSectionAttributes(eDUISecID);
  1016. BOOL bDefault;
  1017. BOOL bShow;
  1018. if (eDUISecID == DUISEC_DETAILSTASKS)
  1019. bDefault = ((_pDefView->_wvLayout.dwLayout & SFVMWVL_ORDINAL_MASK) == SFVMWVL_DETAILS);
  1020. else
  1021. bDefault = pAttrib->_bExpandedDefault;
  1022. if (_ppbShellFolders)
  1023. bShow = SHPropertyBag_ReadBOOLDefRet(_ppbShellFolders, pAttrib->_pszExpandedPropName, bDefault);
  1024. else
  1025. bShow = bDefault;
  1026. return bShow;
  1027. }
  1028. const struct DUISEC_ATTRIBUTES *CDUIView::_GetSectionAttributes(DUISEC eDUISecID)
  1029. {
  1030. static const size_t nSections = ARRAYSIZE(c_DUISectionAttributes);
  1031. size_t iSection;
  1032. // Determine attributes of DUISEC we're interested in.
  1033. for (iSection = 0; iSection < nSections; iSection++)
  1034. if (c_DUISectionAttributes[iSection]._eDUISecID == eDUISecID)
  1035. return &c_DUISectionAttributes[iSection];
  1036. ASSERT(FALSE); // Game over -- insert quarters!
  1037. return NULL; // AV!
  1038. }
  1039. HRESULT SetDescendentString(Element* pe, LPWSTR pszID, UINT idString)
  1040. {
  1041. HRESULT hr;
  1042. Element* peChild = pe->FindDescendent(StrToID(pszID));
  1043. if (peChild)
  1044. {
  1045. TCHAR szString [INFOTIPSIZE];
  1046. LoadString(HINST_THISDLL, idString, szString, ARRAYSIZE(szString));
  1047. hr = peChild->SetContentString(szString);
  1048. }
  1049. else
  1050. {
  1051. hr = E_FAIL;
  1052. }
  1053. return hr;
  1054. }
  1055. // Parses the .ui file and initializes the DUI elements
  1056. //
  1057. // pUIFile - Pointer to the UI file in memory
  1058. // iCharCount - Number of characters in the ui file
  1059. // bDisplayBarrier - Display soft barrier over listview
  1060. // punkPreview - IUnknown interface for the preview control
  1061. HRESULT CDUIView::_InitializeElements (char * pUIFile, int iCharCount,
  1062. BOOL bDisplayBarrier, IUnknown * punkPreview)
  1063. {
  1064. Parser* pParser;
  1065. Element* pe;
  1066. RECT rc;
  1067. HANDLE arH[2];
  1068. // Parse the UI file
  1069. arH[0] = _GetThemeHinst();
  1070. arH[1] = _hinstScrollbarTheme;
  1071. HRESULT hr = Parser::Create(pUIFile, iCharCount, arH, UIFileParseError, &pParser);
  1072. if (FAILED(hr))
  1073. {
  1074. TraceMsg (TF_ERROR, "CDUIView::_InitializeElements: Parser::Create failed with 0x%x", hr);
  1075. return hr;
  1076. }
  1077. if (pParser->WasParseError())
  1078. {
  1079. TraceMsg (TF_ERROR, "CDUIView::_InitializeElements: WasParseError is TRUE");
  1080. pParser->Destroy();
  1081. return E_FAIL;
  1082. }
  1083. // Create the host element
  1084. hr = HWNDView::Create(_hWnd, false, 0, this, _pDefView, (Element**)&_phe); // _phe is owned by _hWnd
  1085. if (FAILED(hr))
  1086. {
  1087. TraceMsg (TF_ERROR, "CDUIView::_InitializeElements: HWNDElement::Create failed with 0x%x", hr);
  1088. pParser->Destroy();
  1089. return hr;
  1090. }
  1091. // We need to ensure that the root item will not paint on WM_ERASEBCKGRND, so here we remove the default brush
  1092. // - Turn off the (default) background fill
  1093. HGADGET hgadRoot = _phe->GetDisplayNode();
  1094. ASSERTMSG(hgadRoot != NULL, "Must have a peer Gadget");
  1095. SetGadgetFillI(hgadRoot, NULL, BLEND_OPAQUE, 0, 0);
  1096. // We need to ensure that the root item will not paint on WM_ERASEBCKGRND, so make it transparent
  1097. _phe->SetBackgroundColor(ARGB(0, 0, 0, 0));
  1098. // Size the host element to match the size of the host window
  1099. GetClientRect (_hWnd, &rc);
  1100. _phe->SetWidth(rc.right - rc.left);
  1101. _phe->SetHeight(rc.bottom - rc.top);
  1102. // Create the main element in the ui file
  1103. hr = pParser->CreateElement(L"main", _phe, &pe);
  1104. if (FAILED(hr))
  1105. {
  1106. TraceMsg (TF_ERROR, "CDUIView::_InitializeElements: pParser->CreateElement failed with 0x%x", hr);
  1107. pParser->Destroy();
  1108. return hr;
  1109. }
  1110. // Cache the element pointers to the 3 main areas: taskpane, clientviewhost, blockade
  1111. _peTaskPane = _phe->FindDescendent(StrToID(L"scroller"));
  1112. _peClientViewHost = _phe->FindDescendent(StrToID(L"clientviewhost"));
  1113. _peBarrier = _phe->FindDescendent(StrToID(L"blockade"));
  1114. // Cache style sheets for the items we create directly (that don't inherit from their immediate parents)
  1115. _pvDetailsSheet = pParser->GetSheet(L"NameSpaceItemInfoList");
  1116. if (_peTaskPane && _peClientViewHost && _peBarrier && _pvDetailsSheet)
  1117. {
  1118. // Double buffered items need to be opaque
  1119. _peTaskPane->SetBackgroundColor(ARGB(255, 0, 0, 0));
  1120. _peTaskPane->DoubleBuffered(true);
  1121. // Create the real listview element
  1122. hr = DUIListView::Create(AE_MouseAndKeyboard, _pDefView->_hwndListview, (Element **)&_peListView);
  1123. if (SUCCEEDED(hr))
  1124. {
  1125. _peListView->SetLayoutPos(BLP_Client);
  1126. _peListView->SetID(L"listview");
  1127. hr = _peClientViewHost->Add(_peListView);
  1128. if (SUCCEEDED(hr))
  1129. {
  1130. _pDefView->_AutoAutoArrange(0);
  1131. }
  1132. else
  1133. {
  1134. TraceMsg(TF_ERROR, "CDUIView::_InitializeElements: DUIListView::Could not add listview with 0x%x", hr);
  1135. _peListView->Destroy();
  1136. _peListView = NULL;
  1137. }
  1138. }
  1139. else
  1140. {
  1141. TraceMsg(TF_ERROR, "CDUIView::_InitializeElements: Could not create listview element");
  1142. }
  1143. }
  1144. else
  1145. {
  1146. TraceMsg(TF_ERROR, "CDUIView::_InitializeElements: Could not find main element");
  1147. hr = E_FAIL;
  1148. }
  1149. if (FAILED(hr))
  1150. {
  1151. // we gotta have the listview or you get no webview...
  1152. pParser->Destroy();
  1153. return hr;
  1154. }
  1155. // Build the preview control if appropriate
  1156. _ManagePreview(punkPreview);
  1157. _BuildSoftBarrier();
  1158. _SwitchToBarrier(bDisplayBarrier);
  1159. // Create an interface to the property bag for this class of IShellFolder.
  1160. _InitializeShellFolderPropertyBag();
  1161. // Build the task list area
  1162. hr = _BuildTaskList (pParser);
  1163. _fHideTasklist = (S_OK == IUnknown_Exec(_pDefView->_psb, &CGID_ShellDocView, SHDVID_ISEXPLORERBARVISIBLE, 0, NULL, NULL));
  1164. pParser->Destroy();
  1165. return hr;
  1166. }
  1167. void CDUIView::_InitializeShellFolderPropertyBag()
  1168. {
  1169. CLSID clsid;
  1170. if (SUCCEEDED(IUnknown_GetClassID(_pDefView->_pshf, &clsid)))
  1171. {
  1172. WCHAR szSubKey[] = L"DUIBags\\ShellFolders\\{00000000-0000-0000-0000-000000000000}";
  1173. if (SHStringFromGUID(clsid, &szSubKey[lstrlen(szSubKey) + 1 - GUIDSTR_MAX], GUIDSTR_MAX) == GUIDSTR_MAX)
  1174. {
  1175. HKEY hk = SHGetShellKey(SKPATH_SHELLNOROAM, szSubKey, TRUE);
  1176. if (hk)
  1177. {
  1178. SHCreatePropertyBagOnRegKey(hk, NULL, STGM_READWRITE | STGM_SHARE_DENY_NONE, IID_PPV_ARG(IPropertyBag, &_ppbShellFolders));
  1179. RegCloseKey(hk);
  1180. }
  1181. }
  1182. }
  1183. }
  1184. HRESULT CDUIView::_BuildSoftBarrier(void)
  1185. {
  1186. HRESULT hr = S_OK;
  1187. // Build the soft barrier if the view wants one
  1188. if (_pDefView->_wvContent.dwFlags & SFVMWVF_BARRICADE)
  1189. {
  1190. // Allow the view to give us a barrier implementation
  1191. Element* peBarricade = NULL;
  1192. _pDefView->CallCB(SFVM_GETWEBVIEWBARRICADE, 0, (LPARAM)&peBarricade);
  1193. if (peBarricade)
  1194. {
  1195. Element *pe = _peBarrier->GetParent();
  1196. hr = pe->Add(peBarricade);
  1197. if (SUCCEEDED(hr))
  1198. {
  1199. _peBarrier->Destroy();
  1200. _peBarrier = peBarricade;
  1201. }
  1202. else
  1203. {
  1204. peBarricade->Destroy();
  1205. }
  1206. }
  1207. else
  1208. {
  1209. // Load the bitmap
  1210. Element *peClient = _peBarrier->FindDescendent(StrToID(L"blockadeclient"));
  1211. if (peClient)
  1212. {
  1213. HBITMAP hBitmap = DUILoadBitmap(_GetThemeHinst(), IDB_BLOCKADE_WATERMARK, LR_CREATEDIBSECTION);
  1214. if (hBitmap)
  1215. {
  1216. BITMAP bmp;
  1217. if (GetObject (hBitmap, sizeof(bmp), &bmp))
  1218. {
  1219. BYTE dBlendMode = GRAPHIC_TransColor;
  1220. if (bmp.bmBitsPixel == 32)
  1221. {
  1222. dBlendMode = GRAPHIC_AlphaConstPerPix;
  1223. }
  1224. Value *pVal = Value::CreateGraphic(hBitmap, dBlendMode, 255);
  1225. if (pVal)
  1226. {
  1227. peClient->SetValue(Element::ContentProp, PI_Local, pVal);
  1228. pVal->Release();
  1229. }
  1230. }
  1231. }
  1232. }
  1233. // Give the view the standard barrier
  1234. hr = SetDescendentString(_peBarrier, L"blockadetitle", IDS_BLOCKADETITLE);
  1235. if (SUCCEEDED(hr))
  1236. {
  1237. hr = SetDescendentString(_peBarrier, L"blockademessage", IDS_BLOCKADEMESSAGE);
  1238. // "clear barrier" button (failure of "clear barrier" button setup is not fatal)
  1239. Element *peButton = _peBarrier->FindDescendent(StrToID(L"blockadeclearbutton"));
  1240. if (peButton)
  1241. {
  1242. Element *peButtonText = peButton->FindDescendent(StrToID(L"blockadecleartext"));
  1243. if (peButtonText)
  1244. {
  1245. WCHAR wsz[INFOTIPSIZE];
  1246. if (LoadString(HINST_THISDLL, IDS_TASK_DEFVIEW_VIEWCONTENTS_FOLDER, wsz, ARRAYSIZE(wsz)))
  1247. {
  1248. Value *pv = Value::CreateString(wsz, NULL);
  1249. if (pv)
  1250. {
  1251. if (SUCCEEDED(peButtonText->SetValue(Element::ContentProp, PI_Local, pv)))
  1252. {
  1253. peButton->SetAccessible(true);
  1254. peButton->SetAccName(wsz);
  1255. peButton->SetAccRole(ROLE_SYSTEM_PUSHBUTTON);
  1256. if (LoadString(HINST_THISDLL, IDS_LINKWINDOW_DEFAULTACTION, wsz, ARRAYSIZE(wsz)))
  1257. {
  1258. peButton->SetAccDefAction(wsz);
  1259. }
  1260. }
  1261. pv->Release();
  1262. }
  1263. }
  1264. }
  1265. }
  1266. }
  1267. }
  1268. // Double buffered items need to be opaque
  1269. _phe->SetBackgroundColor(ARGB(255, 0, 0, 0));
  1270. _phe->DoubleBuffered(true);
  1271. // We couldn't create the barrier? don't use it then...
  1272. if (FAILED(hr))
  1273. {
  1274. _peBarrier->Destroy();
  1275. _peBarrier = NULL;
  1276. }
  1277. }
  1278. return hr;
  1279. }
  1280. // Switches to / from the soft barrier and the listview
  1281. HRESULT CDUIView::_SwitchToBarrier (BOOL bDisplayBarrier)
  1282. {
  1283. if (bDisplayBarrier && !_peBarrier)
  1284. bDisplayBarrier = FALSE;
  1285. Element *peClearButton = _peBarrier ? _peBarrier->FindDescendent(StrToID(L"blockadeclearbutton")) : NULL;
  1286. if (peClearButton)
  1287. {
  1288. // Note:
  1289. // This is required to prevent the "clear barrier" button from being
  1290. // accessed via our accessibility interface when the barrier is hidden.
  1291. peClearButton->SetAccessible(bDisplayBarrier == TRUE);
  1292. }
  1293. if (bDisplayBarrier)
  1294. {
  1295. _peClientViewHost->SetVisible(FALSE);
  1296. _peBarrier->SetVisible(TRUE);
  1297. }
  1298. else
  1299. {
  1300. if (_peBarrier)
  1301. {
  1302. _peBarrier->SetVisible(FALSE);
  1303. }
  1304. _peClientViewHost->SetVisible(TRUE);
  1305. _pDefView->_AutoAutoArrange(0);
  1306. }
  1307. _bBarrierShown = bDisplayBarrier;
  1308. return S_OK;
  1309. }
  1310. // Controls the display of the soft barrier
  1311. HRESULT CDUIView::EnableBarrier (BOOL bDisplayBarrier)
  1312. {
  1313. if (_bBarrierShown != bDisplayBarrier)
  1314. {
  1315. DisableAnimations();
  1316. Element::StartDefer ();
  1317. _SwitchToBarrier (bDisplayBarrier);
  1318. PostMessage (_hWnd, WM_REFRESHVIEW, 0, 0);
  1319. Element::EndDefer ();
  1320. EnableAnimations();
  1321. }
  1322. return S_OK;
  1323. }
  1324. // Creates / destroys the preview control
  1325. HRESULT CDUIView::_ManagePreview (IUnknown * punkPreview)
  1326. {
  1327. HRESULT hr = S_OK;
  1328. if ((_pePreview && punkPreview) ||
  1329. (!_pePreview && !punkPreview))
  1330. {
  1331. return S_OK;
  1332. }
  1333. if (punkPreview)
  1334. {
  1335. // Create the DUI element that can host an active x control
  1336. hr = DUIAxHost::Create (&_pePreview);
  1337. if (SUCCEEDED(hr))
  1338. {
  1339. _pePreview->SetLayoutPos (BLP_Top);
  1340. _pePreview->SetID (L"preview");
  1341. _pePreview->SetHeight(_phe->GetHeight());
  1342. _pePreview->SetAccessible(TRUE);
  1343. // The order of the next 4 calls is very important!
  1344. //
  1345. // Initialize atl so the window class is registered.
  1346. // Then call the Add method. This will cause CreateHWND to be
  1347. // called. Then site it so when we call AttachControl to
  1348. // put the preview control in (this requires the hwnd to exist already)
  1349. // it will be parented properly
  1350. AtlAxWinInit();
  1351. hr = _peClientViewHost->Add (_pePreview);
  1352. if (SUCCEEDED(hr))
  1353. {
  1354. _pePreview->SetSite(SAFECAST(_pDefView, IShellView2*));
  1355. hr = _pePreview->AttachControl(punkPreview);
  1356. if (SUCCEEDED(hr))
  1357. {
  1358. // Double buffered items need to be opaque
  1359. _phe->SetBackgroundColor(ARGB(255, 0, 0, 0));
  1360. _phe->DoubleBuffered(true);
  1361. if (_peListView)
  1362. {
  1363. // Since the preview control is displayed, the listview
  1364. // will be sized to 1 row in height. Determine the height
  1365. // of the listview now so we can size the preview control
  1366. // appropriate plus take care of the sizing in the SetSize
  1367. // method later
  1368. DWORD dwItemSpace = ListView_GetItemSpacing (_peListView->GetHWND(), FALSE);
  1369. _iListViewHeight = (int)HIWORD(dwItemSpace) + GetSystemMetrics (SM_CYHSCROLL) + 4;
  1370. if (_phe->GetHeight() > _iListViewHeight)
  1371. {
  1372. _pePreview->SetHeight(_phe->GetHeight() - _iListViewHeight);
  1373. }
  1374. else
  1375. {
  1376. _pePreview->SetHeight(0);
  1377. }
  1378. }
  1379. }
  1380. }
  1381. if (FAILED(hr))
  1382. {
  1383. _pePreview->Destroy();
  1384. _pePreview = NULL;
  1385. }
  1386. }
  1387. else
  1388. {
  1389. TraceMsg (TF_ERROR, "CDUIView::_ManagePreview: DUIAxHost::Create failed with 0x%x", hr);
  1390. }
  1391. }
  1392. else
  1393. {
  1394. _pePreview->Destroy();
  1395. _pePreview = NULL;
  1396. }
  1397. return S_OK;
  1398. }
  1399. // Controls the display of the preview control
  1400. HRESULT CDUIView::EnablePreview(IUnknown * punkPreview)
  1401. {
  1402. DisableAnimations();
  1403. Element::StartDefer ();
  1404. _ManagePreview (punkPreview);
  1405. Element::EndDefer ();
  1406. EnableAnimations();
  1407. return S_OK;
  1408. }
  1409. // Refreshes the view
  1410. HRESULT CDUIView::Refresh(void)
  1411. {
  1412. Element *pe;
  1413. Parser* pParser = NULL;
  1414. Value* pvSheet = NULL;
  1415. HANDLE arH[2];
  1416. ManageAnimations(FALSE);
  1417. DisableAnimations();
  1418. Element::StartDefer();
  1419. _fLoadedTheme = FALSE; // try to re-load the theme file
  1420. _iTaskPaneWidth = ScaleSizeBasedUponLocalization(_iOriginalTaskPaneWidth);
  1421. // Setting the task pane visibility to the current state will
  1422. // cause it to re-initialize the task pane width appropriately
  1423. SetTaskPaneVisibility(!_bHideTaskPaneAlways);
  1424. // Dynamically build the .ui file for this view
  1425. int iCharCount;
  1426. char *pUIFile = NULL;
  1427. HRESULT hr = _BuildUIFile(&pUIFile, &iCharCount);
  1428. if (FAILED(hr))
  1429. {
  1430. TraceMsg (TF_ERROR, "CDUIView::Refresh: _BuildUIFile failed with 0x%x", hr);
  1431. goto Exit;
  1432. }
  1433. // Parse the UI file
  1434. arH[0] = _GetThemeHinst();
  1435. arH[1] = _hinstScrollbarTheme;
  1436. hr = Parser::Create(pUIFile, iCharCount, arH, UIFileParseError, &pParser);
  1437. if (FAILED(hr))
  1438. {
  1439. TraceMsg (TF_ERROR, "CDUIView::Refresh: Parser::Create failed with 0x%x", hr);
  1440. goto Exit;
  1441. }
  1442. if (pParser->WasParseError())
  1443. {
  1444. TraceMsg (TF_ERROR, "CDUIView::Refresh: WasParseError is TRUE");
  1445. hr = E_FAIL;
  1446. goto Exit;
  1447. }
  1448. // Find the section list element
  1449. pe = _phe->FindDescendent (StrToID(L"sectionlist"));
  1450. if (!pe)
  1451. {
  1452. TraceMsg (TF_ERROR, "CDUIView::Refresh: Failed to find section list element");
  1453. hr = E_FAIL;
  1454. goto Exit;
  1455. }
  1456. // Free all the pointers we have to elements inside of the sectionlist
  1457. ATOMICRELEASE(_pshlItems);
  1458. ATOMICRELEASE(_pvSpecialTaskSheet);
  1459. ATOMICRELEASE(_pvFolderTaskSheet);
  1460. ATOMICRELEASE(_peDetailsInfoArea);
  1461. ATOMICRELEASE(_pvDetailsSheet);
  1462. _peSpecialSection = NULL;
  1463. _peSpecialTaskList = NULL;
  1464. _peFolderSection = NULL;
  1465. _peFolderTaskList = NULL;
  1466. _peDetailsSection = NULL;
  1467. // Destroy the section list
  1468. pe->DestroyAll();
  1469. // Take the style sheets from the new .UI file and put them on the running objects...
  1470. //
  1471. pe = _phe->FindDescendent (StrToID(L"main"));
  1472. if (pe)
  1473. {
  1474. // Query for the main style sheet and set it
  1475. pvSheet = pParser->GetSheet (L"main");
  1476. if (pvSheet)
  1477. {
  1478. pe->SetValue(Element::SheetProp, PI_Local, pvSheet);
  1479. pvSheet->Release();
  1480. pvSheet = NULL;
  1481. }
  1482. }
  1483. pe = _phe->FindDescendent (StrToID(L"scroller"));
  1484. if (pe)
  1485. {
  1486. // Query for the taskpane style sheet and set it
  1487. pvSheet = pParser->GetSheet (L"taskpane");
  1488. if (pvSheet)
  1489. {
  1490. pe->SetValue(Element::SheetProp, PI_Local, pvSheet);
  1491. pvSheet->Release();
  1492. pvSheet = NULL;
  1493. }
  1494. }
  1495. _pvDetailsSheet = pParser->GetSheet(L"NameSpaceItemInfoList");
  1496. // Rebuild the soft barrier if one exists.
  1497. _BuildSoftBarrier();
  1498. // Build the task list area again
  1499. _BuildTaskList (pParser);
  1500. Exit:
  1501. Element::EndDefer();
  1502. EnableAnimations();
  1503. // When turning off the barricade the icons in listview
  1504. // are arranged as if duiview isn't present. Call _AutoAutoArrange
  1505. // to reposition the icons correctly.
  1506. _pDefView->_AutoAutoArrange(0);
  1507. if (pParser)
  1508. {
  1509. pParser->Destroy();
  1510. }
  1511. if (pUIFile)
  1512. {
  1513. LocalFree(pUIFile);
  1514. }
  1515. return hr;
  1516. }
  1517. // Resizes the host element when the frame size changes
  1518. //
  1519. // rc - size of frame
  1520. //
  1521. HRESULT CDUIView::SetSize(RECT * rc)
  1522. {
  1523. _fHideTasklist = (S_OK == IUnknown_Exec(_pDefView->_psb, &CGID_ShellDocView, SHDVID_ISEXPLORERBARVISIBLE, 0, NULL, NULL));
  1524. SetWindowPos(_hWnd, NULL, rc->left, rc->top,
  1525. rc->right - rc->left, rc->bottom - rc->top, SWP_NOZORDER | SWP_NOACTIVATE);
  1526. return S_OK;
  1527. }
  1528. HRESULT CDUIView::_OnResize(long lWidth, long lHeight)
  1529. {
  1530. DisableAnimations();
  1531. Element::StartDefer();
  1532. _phe->SetWidth(lWidth);
  1533. _phe->SetHeight(lHeight);
  1534. if (_pePreview)
  1535. {
  1536. if (_phe->GetHeight() > _iListViewHeight)
  1537. {
  1538. _pePreview->SetHeight(_phe->GetHeight() - _iListViewHeight);
  1539. }
  1540. else
  1541. {
  1542. _pePreview->SetHeight(0);
  1543. }
  1544. }
  1545. // Hide task pane if task area is greater than 50% of the window size
  1546. // The show/hide state of the tasklist pane can change for:
  1547. // 1) we're told to always hide
  1548. // 2) an explorer bar is showing
  1549. // 3) the window is too narrow.
  1550. //
  1551. if (_peTaskPane)
  1552. {
  1553. if (_bHideTaskPaneAlways || _fHideTasklist || ((lWidth / 2) < _iTaskPaneWidth))
  1554. {
  1555. _peTaskPane->SetWidth(0);
  1556. }
  1557. else if (_peTaskPane->GetWidth() == 0)
  1558. {
  1559. _peTaskPane->SetWidth(_iTaskPaneWidth);
  1560. }
  1561. }
  1562. Element::EndDefer();
  1563. EnableAnimations();
  1564. return S_OK;
  1565. }
  1566. HRESULT CDUIView::SetTaskPaneVisibility(BOOL bShow)
  1567. {
  1568. _bHideTaskPaneAlways = !bShow;
  1569. return _OnResize(_phe->GetWidth(), _phe->GetHeight());
  1570. }
  1571. // Description:
  1572. // Calculates the bounding rectangle of the infotip hotspot for
  1573. // the specified element. The bounding rectangle's coordinates
  1574. // are relative to the specified element's root element.
  1575. //
  1576. void CDUIView::CalculateInfotipRect(Element *pe, RECT *pRect)
  1577. {
  1578. ASSERT(pe);
  1579. ASSERT(pRect);
  1580. // Calculate location.
  1581. const POINT ptLocation = { 0, 0 };
  1582. POINT ptLocationRelativeToRoot;
  1583. pe->GetRoot()->MapElementPoint(pe, &ptLocation, &ptLocationRelativeToRoot);
  1584. pRect->left = ptLocationRelativeToRoot.x;
  1585. pRect->top = ptLocationRelativeToRoot.y;
  1586. // Calculate size.
  1587. Value *pvExtent;
  1588. const SIZE *psizeExtent = pe->GetExtent(&pvExtent);
  1589. pRect->right = pRect->left + psizeExtent->cx;
  1590. pRect->bottom = pRect->top + psizeExtent->cy;
  1591. pvExtent->Release();
  1592. // Sanity check.
  1593. ASSERT(pRect->right > pRect->left);
  1594. ASSERT(pRect->bottom > pRect->top);
  1595. }
  1596. HRESULT CDUIView::InitializeThumbnail(WNDPROC pfnWndProc)
  1597. {
  1598. HRESULT hr = E_FAIL;
  1599. if (!_spThumbnailExtractor2)
  1600. {
  1601. if (SUCCEEDED(CoCreateInstance(CLSID_Thumbnail, NULL, CLSCTX_INPROC_SERVER,
  1602. IID_PPV_ARG(IThumbnail2, &_spThumbnailExtractor2))))
  1603. {
  1604. _hwndMsgThumbExtract = SHCreateWorkerWindowW(pfnWndProc, NULL, 0, WS_POPUP, NULL, this);
  1605. if (_hwndMsgThumbExtract)
  1606. {
  1607. // Set defview as the site for the thumbnail extractor so that
  1608. // it can QueryService defview for IShellTaskScheduler
  1609. IUnknown_SetSite(_spThumbnailExtractor2, SAFECAST(_pDefView, IShellView2*));
  1610. // Tell the image extractor to post WM_HTML_BITMAP to _hwndMsgThumbExtract
  1611. // The lParam will be the HBITMAP of the extracted image.
  1612. _spThumbnailExtractor2->Init(_hwndMsgThumbExtract, WM_HTML_BITMAP);
  1613. }
  1614. }
  1615. }
  1616. return (_spThumbnailExtractor2 && _hwndMsgThumbExtract) ? S_OK : E_FAIL;
  1617. }
  1618. // if pCheck != NULL, check if the current window ptr == pCheck before setting it to p
  1619. HRESULT CDUIView::SetThumbnailMsgWindowPtr(void* p, void* pCheck)
  1620. {
  1621. if (_hwndMsgThumbExtract)
  1622. {
  1623. if (pCheck)
  1624. {
  1625. void* pCurrent = GetWindowPtr(_hwndMsgThumbExtract, 0);
  1626. if (pCurrent == pCheck)
  1627. {
  1628. SetWindowPtr(_hwndMsgThumbExtract, 0, p);
  1629. }
  1630. }
  1631. else
  1632. {
  1633. SetWindowPtr(_hwndMsgThumbExtract, 0, p);
  1634. }
  1635. }
  1636. return S_OK;
  1637. }
  1638. HRESULT CDUIView::StartBitmapExtraction(LPCITEMIDLIST pidl)
  1639. {
  1640. _dwThumbnailID++; // We are looking for a new thumbnail
  1641. return _spThumbnailExtractor2 ? _spThumbnailExtractor2->GetBitmapFromIDList(pidl,
  1642. _dwThumbnailID, 150, 100) : E_FAIL;
  1643. }
  1644. HRESULT CDUIView::InitializeDetailsInfo(WNDPROC pfnWndProc)
  1645. {
  1646. if (!_hwndMsgInfoExtract)
  1647. {
  1648. _hwndMsgInfoExtract = SHCreateWorkerWindowW(pfnWndProc, NULL, 0, WS_POPUP, NULL, this);
  1649. }
  1650. return _hwndMsgInfoExtract ? S_OK : E_FAIL;
  1651. }
  1652. // if pCheck != NULL, check if the current window ptr == pCheck before setting it to p
  1653. HRESULT CDUIView::SetDetailsInfoMsgWindowPtr(void* p, void* pCheck)
  1654. {
  1655. if (_hwndMsgInfoExtract)
  1656. {
  1657. if (pCheck)
  1658. {
  1659. void* pCurrent = GetWindowPtr(_hwndMsgInfoExtract, 0);
  1660. if (pCurrent == pCheck)
  1661. {
  1662. SetWindowPtr(_hwndMsgInfoExtract, 0, p);
  1663. }
  1664. }
  1665. else
  1666. {
  1667. SetWindowPtr(_hwndMsgInfoExtract, 0, p);
  1668. }
  1669. }
  1670. return S_OK;
  1671. }
  1672. HRESULT CDUIView::StartInfoExtraction(LPCITEMIDLIST pidl)
  1673. {
  1674. _dwDetailsInfoID++; // We are looking for a new Details section info
  1675. CDetailsSectionInfoTask *pTask;
  1676. HRESULT hr = CDetailsSectionInfoTask_CreateInstance(
  1677. _pDefView->_pshf, pidl, _hwndMsgInfoExtract, WM_DETAILS_INFO, _dwDetailsInfoID, &pTask);
  1678. if (SUCCEEDED(hr))
  1679. {
  1680. if (_pDefView->_pScheduler)
  1681. {
  1682. // Make sure there are no other background DetailsSectionInfo
  1683. // extraction going on...
  1684. _pDefView->_pScheduler->RemoveTasks(TOID_DVBackgroundDetailsSectionInfo,
  1685. ITSAT_DEFAULT_LPARAM, FALSE);
  1686. }
  1687. hr = _pDefView->_AddTask(pTask, TOID_DVBackgroundDetailsSectionInfo,
  1688. 0, TASK_PRIORITY_INFOTIP, ADDTASK_ATEND);
  1689. pTask->Release();
  1690. }
  1691. return hr;
  1692. }
  1693. VOID CDUIView::ShowDetails (BOOL fShow)
  1694. {
  1695. if (_peDetailsSection)
  1696. {
  1697. _peDetailsSection->ShowExpando (fShow);
  1698. }
  1699. }
  1700. BOOL CDUIView::ShouldShowMiniPreview()
  1701. {
  1702. return !_pDefView->_IsImageMode();
  1703. }
  1704. // Window procedure for host window
  1705. LRESULT CALLBACK CDUIView::_DUIHostWndProc(HWND hWnd, UINT uMessage, WPARAM wParam,
  1706. LPARAM lParam)
  1707. {
  1708. CDUIView *pThis = (CDUIView*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
  1709. switch (uMessage)
  1710. {
  1711. case WM_NCCREATE:
  1712. {
  1713. LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam;
  1714. pThis = (CDUIView*)(lpcs->lpCreateParams);
  1715. SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)pThis);
  1716. }
  1717. break;
  1718. case WM_SIZE:
  1719. if (pThis && pThis->_phe)
  1720. {
  1721. pThis->_OnResize(LOWORD(lParam), HIWORD(lParam));
  1722. }
  1723. break;
  1724. case WM_SETFOCUS:
  1725. // Push focus to HWNDElement (won't set gadget focus to the HWNDElement, but
  1726. // will push focus to the previous gadget with focus)
  1727. if (pThis)
  1728. {
  1729. if (pThis->_phe && pThis->_phe->GetHWND())
  1730. SetFocus(pThis->_phe->GetHWND());
  1731. }
  1732. break;
  1733. case WM_PALETTECHANGED:
  1734. case WM_QUERYNEWPALETTE:
  1735. case WM_DISPLAYCHANGE:
  1736. if (pThis && pThis->_phe)
  1737. {
  1738. return SendMessageW(pThis->_phe->GetHWND(), uMessage, wParam, lParam);
  1739. }
  1740. break;
  1741. case WM_DESTROY:
  1742. // clear posted messages
  1743. MSG msg;
  1744. while (PeekMessage(&msg, hWnd, WM_NAVIGATETOPIDL, WM_NAVIGATETOPIDL, PM_REMOVE))
  1745. {
  1746. // PeekMessage(hwnd) can return messages posted to CHILDREN of this hwnd...
  1747. // Verify that the message was really for us.
  1748. if (msg.hwnd == hWnd)
  1749. {
  1750. LPITEMIDLIST pidl = (LPITEMIDLIST)msg.lParam;
  1751. ILFree(pidl);
  1752. }
  1753. }
  1754. break;
  1755. case WM_NAVIGATETOPIDL:
  1756. {
  1757. LPITEMIDLIST pidl = (LPITEMIDLIST)lParam;
  1758. UINT wFlags = (UINT)wParam;
  1759. pThis->_pDefView->_psb->BrowseObject(pidl, wFlags);
  1760. ILFree(pidl);
  1761. }
  1762. break;
  1763. case WM_REFRESHVIEW:
  1764. {
  1765. pThis->Refresh();
  1766. }
  1767. break;
  1768. case WM_MOUSEACTIVATE:
  1769. if (pThis->_bBarrierShown)
  1770. {
  1771. return MA_ACTIVATE;
  1772. }
  1773. break;
  1774. default:
  1775. break;
  1776. }
  1777. return DefWindowProc(hWnd, uMessage, wParam, lParam);
  1778. }
  1779. // Updates all selection-parameterized UI
  1780. //
  1781. // pdo - data object representing the selection
  1782. void CDUIView::_Refresh(IShellItemArray *psiItemArray, DWORD dwRefreshFlags)
  1783. {
  1784. //DirectUI::DisableAnimations();
  1785. Element::StartDefer();
  1786. IUnknown_Set((IUnknown **)&_pshlItems,psiItemArray);
  1787. if (SFVMWVF_ENUMTASKS & _pDefView->_wvContent.dwFlags)
  1788. {
  1789. if (0 == (REFRESH_SELCHG & dwRefreshFlags))
  1790. {
  1791. //
  1792. // Only refresh if it's not a selection change.
  1793. // If we refresh here, Control Panel's left-pane menus
  1794. // are constantly rebuilt as the folder items selection
  1795. // changes. That's really ugly.
  1796. // Will this affect other folders? No, Control Panel
  1797. // is currently the only folder that sets this SFVMWVF_ENUMTASKS
  1798. // flag. Post WinXP if we decide to keep this webview
  1799. // content in the left pane, we need to re-think how better
  1800. // to handle Control Panel's special needs.
  1801. //
  1802. Refresh();
  1803. }
  1804. }
  1805. else
  1806. {
  1807. if (REFRESH_CONTENT & dwRefreshFlags)
  1808. {
  1809. _BuildSoftBarrier();
  1810. }
  1811. if (REFRESH_TASKS & dwRefreshFlags)
  1812. {
  1813. Element* peIntroText;
  1814. if (FAILED(_GetIntroTextElement(&peIntroText)))
  1815. {
  1816. peIntroText = NULL;
  1817. }
  1818. if (_peSpecialSection)
  1819. {
  1820. BOOL bIntroTextAdded = FALSE;
  1821. _peSpecialSection->UpdateTitleUI(_pshlItems);
  1822. _peSpecialTaskList->DestroyAll();
  1823. if (peIntroText)
  1824. {
  1825. if (SUCCEEDED(_peSpecialTaskList->Add(peIntroText)))
  1826. {
  1827. bIntroTextAdded = TRUE;
  1828. peIntroText = NULL;
  1829. }
  1830. }
  1831. _AddActionTasks(_peSpecialSection, _peSpecialTaskList, _pDefView->_wvTasks.penumSpecialTasks, _pvSpecialTaskSheet, bIntroTextAdded);
  1832. }
  1833. if (_peFolderSection)
  1834. {
  1835. BOOL bIntroTextAdded = FALSE;
  1836. _peFolderSection->UpdateTitleUI(_pshlItems);
  1837. _peFolderTaskList->DestroyAll();
  1838. if (peIntroText)
  1839. {
  1840. if (SUCCEEDED(_peFolderTaskList->Add(peIntroText)))
  1841. {
  1842. bIntroTextAdded = TRUE;
  1843. peIntroText = NULL;
  1844. }
  1845. }
  1846. _AddActionTasks(_peFolderSection, _peFolderTaskList, _pDefView->_wvTasks.penumFolderTasks, _pvFolderTaskSheet, bIntroTextAdded);
  1847. }
  1848. if (_peDetailsInfoArea)
  1849. {
  1850. const SIZE *pSize;
  1851. LONG lHeight = 0;
  1852. Value * pv;
  1853. pSize = _peDetailsInfoArea->GetExtent(&pv);
  1854. if (pSize)
  1855. {
  1856. _peDetailsInfoArea->SetHeight(pSize->cy);
  1857. pv->Release();
  1858. }
  1859. _peDetailsInfoArea->DestroyAll();
  1860. _AddDetailsSectionInfo();
  1861. }
  1862. if (peIntroText)
  1863. {
  1864. peIntroText->Destroy();
  1865. }
  1866. }
  1867. }
  1868. Element::EndDefer();
  1869. //DirectUI::EnableAnimations();
  1870. }
  1871. void CDUIView::OnSelectionChange(IShellItemArray *psiItemArray)
  1872. {
  1873. _Refresh(psiItemArray, REFRESH_ALL | REFRESH_SELCHG);
  1874. }
  1875. void CDUIView::OnContentsChange(IShellItemArray *psiItemArray)
  1876. {
  1877. DWORD dwRefreshFlags = 0;
  1878. if (_pDefView->_wvTasks.dwUpdateFlags & SFVMWVTSDF_CONTENTSCHANGE)
  1879. {
  1880. dwRefreshFlags |= REFRESH_TASKS;
  1881. }
  1882. if (_pDefView->_wvContent.dwFlags & SFVMWVF_CONTENTSCHANGE)
  1883. {
  1884. dwRefreshFlags |= REFRESH_CONTENT;
  1885. }
  1886. if (0 != dwRefreshFlags)
  1887. {
  1888. _Refresh(psiItemArray, dwRefreshFlags);
  1889. }
  1890. }
  1891. void CDUIView::OnExpandSection(DUISEC eDUISecID, BOOL bExpanded)
  1892. {
  1893. if (_ppbShellFolders)
  1894. {
  1895. SHPropertyBag_WriteDWORD(_ppbShellFolders, _GetSectionAttributes(eDUISecID)->_pszExpandedPropName, bExpanded);
  1896. }
  1897. }
  1898. //
  1899. // ISSUE-2001/01/02-BrianAu Review
  1900. //
  1901. // This webview task section code may be reworked soon.
  1902. // I created it to address the webview needs of Control Panel.
  1903. // Following this first checkin, the webview guys (EricFlo
  1904. // and MikeSh) and I will look at consolidating the generic
  1905. // needs of Control Panel with the existing webview code.
  1906. //
  1907. //
  1908. // Add a WebView task section to the list of task sections.
  1909. //
  1910. HRESULT CDUIView::_AddNonStdTaskSection(const SFVM_WEBVIEW_ENUMTASKSECTION_DATA *pData)
  1911. {
  1912. ASSERT(NULL != pData);
  1913. ASSERT(!IsBadReadPtr(pData, sizeof(*pData)));
  1914. HRESULT hr = E_OUTOFMEMORY;
  1915. if (NULL == _hdsaNonStdTaskSections)
  1916. {
  1917. _hdsaNonStdTaskSections = DSA_Create(sizeof(*pData), 5);
  1918. }
  1919. if (NULL != _hdsaNonStdTaskSections)
  1920. {
  1921. if (-1 != DSA_AppendItem(_hdsaNonStdTaskSections, (void *)pData))
  1922. {
  1923. ASSERT(NULL != pData->pHeader);
  1924. ASSERT(NULL != pData->penumTasks);
  1925. //
  1926. // The list now owns a ref count on the referenced objects.
  1927. //
  1928. pData->pHeader->AddRef();
  1929. pData->penumTasks->AddRef();
  1930. hr = S_OK;
  1931. }
  1932. }
  1933. return THR(hr);
  1934. }
  1935. void CDUIView::_ClearNonStdTaskSections(void)
  1936. {
  1937. if (NULL != _hdsaNonStdTaskSections)
  1938. {
  1939. HDSA hdsa = _hdsaNonStdTaskSections;
  1940. _hdsaNonStdTaskSections = NULL;
  1941. const int cItems = DSA_GetItemCount(hdsa);
  1942. for (int i = 0; i < cItems; i++)
  1943. {
  1944. SFVM_WEBVIEW_ENUMTASKSECTION_DATA *pData = (SFVM_WEBVIEW_ENUMTASKSECTION_DATA *)DSA_GetItemPtr(hdsa, i);
  1945. if (NULL != pData)
  1946. {
  1947. ATOMICRELEASE(pData->pHeader);
  1948. ATOMICRELEASE(pData->penumTasks);
  1949. }
  1950. }
  1951. DSA_Destroy(hdsa);
  1952. }
  1953. }
  1954. //
  1955. // Enumerate the non-standard webview task sections
  1956. // from the view callback.
  1957. //
  1958. // ISSUE-2001/01/03-BrianAu Review
  1959. //
  1960. // This SFVM_ENUMWEBVIEWTASKS mechanism may be replaced
  1961. // with a COM enumerator. I'll be revisiting this with
  1962. // the webview guys soon.
  1963. //
  1964. HRESULT CDUIView::_GetNonStdTaskSectionsFromViewCB(void)
  1965. {
  1966. SFVM_WEBVIEW_ENUMTASKSECTION_DATA data;
  1967. HRESULT hr = S_OK;
  1968. do
  1969. {
  1970. //
  1971. // Continue requesting task section information from
  1972. // the callback until it sets the SFVMWVF_NOMORETASKS
  1973. // flag in the data. The record with this flag set
  1974. // should not contain any valid data.
  1975. //
  1976. ZeroMemory(&data, sizeof(data));
  1977. hr = _pDefView->CallCB(SFVM_ENUMWEBVIEWTASKS, 0, (LPARAM)&data);
  1978. if (SUCCEEDED(hr))
  1979. {
  1980. if (0 == (SFVMWVF_NOMORETASKS & data.dwFlags))
  1981. {
  1982. hr = _AddNonStdTaskSection(&data);
  1983. ASSERT(S_FALSE != hr);
  1984. data.pHeader->Release();
  1985. data.penumTasks->Release();
  1986. }
  1987. else
  1988. {
  1989. ASSERT(NULL == data.pHeader);
  1990. ASSERT(NULL == data.penumTasks);
  1991. hr = S_FALSE;
  1992. }
  1993. }
  1994. }
  1995. while(S_OK == hr);
  1996. return THR(hr);
  1997. }
  1998. // Loads a bitmap based upon:
  1999. //
  2000. // lpBitmapID - contains the bitmap description
  2001. // hInstTheme - instance handle of theme dll
  2002. HBITMAP DUILoadBitmap(HINSTANCE hInstTheme, int idBitmapID, UINT uiLoadFlags)
  2003. {
  2004. return (HBITMAP)LoadImage(hInstTheme, MAKEINTRESOURCE(idBitmapID), IMAGE_BITMAP, 0, 0, uiLoadFlags);
  2005. }
  2006. // Loads an icon based upon the description.
  2007. // Example: shell32,-42
  2008. //
  2009. // pszIconDesc - contains the icon description
  2010. // bSmall - small icon vs large icon
  2011. HICON DUILoadIcon(LPCWSTR pszIconDesc, BOOL bSmall)
  2012. {
  2013. HICON hIcon = NULL;
  2014. TCHAR szFile[MAX_PATH];
  2015. StrCpyN(szFile, pszIconDesc, ARRAYSIZE(szFile)); // the below writes this buffer
  2016. int iIconID = PathParseIconLocation(szFile);
  2017. if (bSmall)
  2018. {
  2019. PrivateExtractIcons(szFile, iIconID, 16, 16, &hIcon, NULL, 1, 0);
  2020. }
  2021. else
  2022. {
  2023. PrivateExtractIcons(szFile, iIconID, 32, 32, &hIcon, NULL, 1, 0);
  2024. }
  2025. return hIcon;
  2026. }
  2027. BOOL CDUIView::Navigate(BOOL fForward)
  2028. {
  2029. if (!_phe)
  2030. return FALSE;
  2031. return _phe->Navigate(fForward);
  2032. }
  2033. HRESULT CDUIView::InitializeDropTarget (LPITEMIDLIST pidl, HWND hWnd, IDropTarget **pdt)
  2034. {
  2035. HRESULT hr = E_FAIL;
  2036. if (_pDT)
  2037. {
  2038. hr = _pDT->Initialize(pidl, hWnd, pdt);
  2039. }
  2040. return hr;
  2041. }
  2042. ////////////////////////////////////////////////////////
  2043. // HWNDView class
  2044. ////////////////////////////////////////////////////////
  2045. HWNDView::HWNDView(void)
  2046. : _fFocus(TRUE),
  2047. _fDelayedNavigation(false),
  2048. _puiDelayNavCmd(NULL),
  2049. _psiDelayNavArray(NULL),
  2050. _pDefView(NULL),
  2051. _pDUIView(NULL)
  2052. {
  2053. }
  2054. HWNDView::~HWNDView(void)
  2055. {
  2056. ATOMICRELEASE(_puiDelayNavCmd);
  2057. ATOMICRELEASE(_psiDelayNavArray);
  2058. ATOMICRELEASE(_pDefView);
  2059. ATOMICRELEASE(_pDUIView);
  2060. }
  2061. HRESULT HWNDView::Create(OUT Element** ppElement)
  2062. {
  2063. UNREFERENCED_PARAMETER(ppElement);
  2064. DUIAssertForce("Cannot instantiate an HWND host derived Element via parser. Must use substitution.");
  2065. return E_NOTIMPL;
  2066. }
  2067. HRESULT HWNDView::Create(HWND hParent, bool fDblBuffer, UINT nCreate, CDUIView * pDUIView, CDefView *pDefView, OUT Element** ppElement)
  2068. {
  2069. *ppElement = NULL;
  2070. HWNDView* phv = HNewAndZero<HWNDView>();
  2071. if (!phv)
  2072. return E_OUTOFMEMORY;
  2073. HRESULT hr = phv->Initialize(hParent, fDblBuffer, nCreate);
  2074. if (FAILED(hr))
  2075. {
  2076. phv->Destroy();
  2077. return hr;
  2078. }
  2079. phv->SetWrapKeyboardNavigate(false);
  2080. phv->SetAccessible(true);
  2081. phv->SetAccRole(ROLE_SYSTEM_PANE);
  2082. phv->SetAccName(L"WebView Pane");
  2083. phv->SetViewPtrs(pDUIView, pDefView);
  2084. *ppElement = phv;
  2085. return S_OK;
  2086. }
  2087. void HWNDView::SetViewPtrs (CDUIView * pDUIView, CDefView *pDefView)
  2088. {
  2089. pDUIView->AddRef();
  2090. _pDUIView = pDUIView;
  2091. pDefView->AddRef();
  2092. _pDefView = pDefView;
  2093. }
  2094. #define DELAYED_NAVIGATION_TIMER_ID 1236 // random - can be moved
  2095. LRESULT HWNDView::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  2096. {
  2097. switch ( uMsg )
  2098. {
  2099. case WM_TIMER:
  2100. if (wParam == DELAYED_NAVIGATION_TIMER_ID)
  2101. {
  2102. KillTimer(hWnd, DELAYED_NAVIGATION_TIMER_ID);
  2103. //
  2104. // We have encountered some rare scenarios where _puiDelayNavCmd
  2105. // can be NULL.
  2106. //
  2107. if (_puiDelayNavCmd)
  2108. {
  2109. HRESULT hr = _puiDelayNavCmd->Invoke(_psiDelayNavArray, NULL);
  2110. if (FAILED(hr))
  2111. {
  2112. MessageBeep(0);
  2113. }
  2114. }
  2115. ATOMICRELEASE(_puiDelayNavCmd);
  2116. ATOMICRELEASE(_psiDelayNavArray);
  2117. _fDelayedNavigation = false;
  2118. }
  2119. break;
  2120. case WM_USER_DELAY_NAVIGATION:
  2121. ATOMICRELEASE(_puiDelayNavCmd);
  2122. ATOMICRELEASE(_psiDelayNavArray);
  2123. _puiDelayNavCmd = (IUICommand *) lParam;
  2124. _puiDelayNavCmd->AddRef();
  2125. _psiDelayNavArray = (IShellItemArray *) wParam;
  2126. if (NULL != _psiDelayNavArray)
  2127. {
  2128. _psiDelayNavArray->AddRef();
  2129. }
  2130. _fDelayedNavigation = true;
  2131. ::SetTimer(hWnd, DELAYED_NAVIGATION_TIMER_ID, GetDoubleClickTime(), NULL);
  2132. break;
  2133. case WM_MOUSEACTIVATE:
  2134. if ( _fDelayedNavigation )
  2135. {
  2136. //
  2137. // KB: gpease 05-APR-2001 Fix for WinBug #338552
  2138. //
  2139. // This prevents the re-activation of the view window after
  2140. // the user clicks on a link that launches another application,
  2141. // window, or CPL Applet.
  2142. //
  2143. return MA_NOACTIVATE;
  2144. }
  2145. break; // do the default wndproc
  2146. case WM_MOUSEMOVE:
  2147. case WM_LBUTTONDOWN:
  2148. case WM_LBUTTONUP:
  2149. case WM_MBUTTONDOWN:
  2150. case WM_MBUTTONUP:
  2151. case WM_RBUTTONDOWN:
  2152. case WM_RBUTTONUP:
  2153. if (_pDefView)
  2154. {
  2155. // Relay relevant messages to CDefView's infotip control so any
  2156. // infotip tools created in the DUI view will appear/function.
  2157. _pDefView->RelayInfotipMessage(hWnd, uMsg, wParam, lParam);
  2158. }
  2159. break;
  2160. }
  2161. return HWNDElement::WndProc(hWnd, uMsg, wParam, lParam);
  2162. }
  2163. BOOL HWNDView::Navigate(BOOL fForward)
  2164. {
  2165. KeyboardNavigateEvent kne;
  2166. kne.uidType = Element::KeyboardNavigate;
  2167. kne.iNavDir = fForward ? NAV_NEXT : NAV_PREV;
  2168. if (_fFocus) // remove this check after SetGadgetFocus(NULL) is fixed.
  2169. {
  2170. kne.peTarget = GetKeyFocusedElement();
  2171. }
  2172. else
  2173. {
  2174. kne.peTarget = NULL;
  2175. }
  2176. if (kne.peTarget)
  2177. {
  2178. kne.peTarget->FireEvent(&kne);
  2179. _fFocus = !kne.peTarget->GetKeyFocused();
  2180. // If this is the last element in the duiview focus cycle clear focus so if
  2181. // no one else grabs focus and we come back to duiview we'll restart at the
  2182. // first element.
  2183. //
  2184. //
  2185. //if (!fFocus)
  2186. //{
  2187. // SetGadgetFocus(NULL); Doesn't like NULL!!!
  2188. //}
  2189. }
  2190. else
  2191. {
  2192. bool fWrap;
  2193. if(!fForward)
  2194. {
  2195. fWrap = GetWrapKeyboardNavigate();
  2196. SetWrapKeyboardNavigate(true);
  2197. }
  2198. FireEvent(&kne);
  2199. _fFocus = (GetKeyFocusedElement() != NULL);
  2200. if(!fForward)
  2201. {
  2202. SetWrapKeyboardNavigate(fWrap);
  2203. }
  2204. }
  2205. return _fFocus;
  2206. }
  2207. UINT HWNDView::MessageCallback(GMSG* pGMsg)
  2208. {
  2209. EventMsg * pmsg = static_cast<EventMsg *>(pGMsg);
  2210. switch (GET_EVENT_DEST(pmsg))
  2211. {
  2212. case GMF_DIRECT:
  2213. case GMF_BUBBLED:
  2214. if (pGMsg->nMsg == GM_QUERY)
  2215. {
  2216. GMSG_QUERYDROPTARGET * pTemp = (GMSG_QUERYDROPTARGET *)pGMsg;
  2217. if (pTemp->nCode == GQUERY_DROPTARGET)
  2218. {
  2219. if (SUCCEEDED(_pDUIView->InitializeDropTarget(NULL, NULL, &pTemp->pdt)))
  2220. {
  2221. pTemp->hgadDrop = pTemp->hgadMsg;
  2222. return DU_S_COMPLETE;
  2223. }
  2224. }
  2225. }
  2226. break;
  2227. }
  2228. return Element::MessageCallback(pGMsg);
  2229. }
  2230. void HWNDView::OnEvent(Event* pev)
  2231. {
  2232. if (pev->uidType == Button::Click)
  2233. {
  2234. if (pev->peTarget == FindDescendent(StrToID(L"blockadeclearbutton")))
  2235. {
  2236. if (NULL != _pDefView)
  2237. {
  2238. _pDefView->RemoveBarricade();
  2239. }
  2240. pev->fHandled = true;
  2241. }
  2242. }
  2243. HWNDElement::OnEvent(pev);
  2244. }
  2245. ////////////////////////////////////////////////////////
  2246. // ClassInfo (must appear after property definitions)
  2247. // Define class info with type and base type, set static class pointer
  2248. IClassInfo* HWNDView::Class = NULL;
  2249. HRESULT HWNDView::Register()
  2250. {
  2251. return ClassInfo<HWNDView,HWNDElement>::Register(L"HWNDView", NULL, 0);
  2252. }
  2253. HRESULT InitializeDUIViewClasses(void)
  2254. {
  2255. HRESULT hr;
  2256. hr = DUIAxHost::Register();
  2257. if (FAILED(hr))
  2258. goto Failure;
  2259. hr = CNameSpaceItemInfoList::Register();
  2260. if (FAILED(hr))
  2261. goto Failure;
  2262. hr = CNameSpaceItemInfo::Register();
  2263. if (FAILED(hr))
  2264. goto Failure;
  2265. hr = CMiniPreviewer::Register();
  2266. if (FAILED(hr))
  2267. goto Failure;
  2268. hr = CBitmapElement::Register();
  2269. if (FAILED(hr))
  2270. goto Failure;
  2271. hr = DUIListView::Register();
  2272. if (FAILED(hr))
  2273. goto Failure;
  2274. hr = Expando::Register();
  2275. if (FAILED(hr))
  2276. goto Failure;
  2277. hr = Clipper::Register();
  2278. if (FAILED(hr))
  2279. goto Failure;
  2280. hr = TaskList::Register();
  2281. if (FAILED(hr))
  2282. goto Failure;
  2283. hr = ActionTask::Register();
  2284. if (FAILED(hr))
  2285. goto Failure;
  2286. hr = DestinationTask::Register();
  2287. if (FAILED(hr))
  2288. goto Failure;
  2289. hr = HWNDView::Register();
  2290. if (FAILED(hr))
  2291. goto Failure;
  2292. return S_OK;
  2293. Failure:
  2294. return hr;
  2295. }