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.

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