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.

983 lines
25 KiB

  1. #include "shellprv.h"
  2. #include "defviewp.h"
  3. #include "duiview.h"
  4. #include "duitask.h"
  5. #include "dvtasks.h"
  6. #include "contextmenu.h"
  7. #include "ids.h"
  8. // Returns a given task element's root HWND element.
  9. //
  10. //
  11. HRESULT GetElementRootHWNDElement(Element *pe, HWNDElement **pphwndeRoot)
  12. {
  13. HRESULT hr;
  14. if (pe)
  15. {
  16. Element *peRoot = pe->GetRoot();
  17. if (peRoot && peRoot->GetClassInfo()->IsSubclassOf(HWNDElement::Class))
  18. {
  19. *pphwndeRoot = reinterpret_cast<HWNDElement *>(peRoot);
  20. hr = S_OK;
  21. }
  22. else
  23. {
  24. *pphwndeRoot = NULL;
  25. hr = E_FAIL;
  26. }
  27. }
  28. else
  29. {
  30. hr = E_INVALIDARG;
  31. ASSERT(FALSE);
  32. }
  33. return hr;
  34. }
  35. // Returns a given task element's root HWND element's HWND.
  36. //
  37. //
  38. HRESULT GetElementRootHWND(Element *pe, HWND *phwnd)
  39. {
  40. HWNDElement *phwndeRoot;
  41. HRESULT hr = GetElementRootHWNDElement(pe, &phwndeRoot);
  42. if (SUCCEEDED(hr))
  43. {
  44. *phwnd = phwndeRoot->GetHWND();
  45. hr = *phwnd ? S_OK : S_FALSE;
  46. }
  47. return hr;
  48. }
  49. // Creates an instance of the ActionTask and
  50. // initializes it
  51. //
  52. // nActive - Activation type
  53. // puiCommand - the Task itself
  54. // ppElement - Receives element pointer
  55. HRESULT ActionTask::Create(UINT nActive, IUICommand* puiCommand, IShellItemArray* psiItemArray, CDUIView* pDUIView, CDefView* pDefView, OUT Element** ppElement)
  56. {
  57. *ppElement = NULL;
  58. if (!puiCommand || !pDUIView || !pDefView)
  59. {
  60. return E_INVALIDARG;
  61. }
  62. ActionTask* pAT = HNewAndZero<ActionTask>();
  63. if (!pAT)
  64. {
  65. return E_OUTOFMEMORY;
  66. }
  67. HRESULT hr = pAT->Initialize(puiCommand, psiItemArray, pDUIView, pDefView);
  68. if (FAILED(hr))
  69. {
  70. pAT->Destroy();
  71. return hr;
  72. }
  73. *ppElement = pAT;
  74. return S_OK;
  75. }
  76. // Initializes this task
  77. //
  78. // puiCommand - the Task itself
  79. HRESULT ActionTask::Initialize(IUICommand *puiCommand, IShellItemArray *psiItemArray, CDUIView *pDUIView, CDefView *pDefView)
  80. {
  81. HRESULT hr;
  82. // Initialize this DUI Element.
  83. hr = InitializeElement();
  84. if (SUCCEEDED(hr))
  85. {
  86. // Initialize the contained DUI Button.
  87. hr = InitializeButton();
  88. if (SUCCEEDED(hr))
  89. {
  90. // Save the pointer to the IUICommand class
  91. puiCommand->AddRef();
  92. _puiCommand = puiCommand;
  93. // Save the pointer to the CDUIView class
  94. pDUIView->AddRef();
  95. _pDUIView = pDUIView;
  96. // Save the pointer to the CDefView class
  97. pDefView->AddRef();
  98. _pDefView = pDefView;
  99. // Save the pointer to the IShellItemArray class (if available)
  100. if (psiItemArray)
  101. {
  102. psiItemArray->AddRef();
  103. _psiItemArray = psiItemArray;
  104. }
  105. UpdateTaskUI();
  106. }
  107. }
  108. return hr;
  109. }
  110. HRESULT ActionTask::InitializeElement()
  111. {
  112. HRESULT hr;
  113. // Initialize base class (normal display node creation).
  114. hr = Element::Initialize(0);
  115. if (SUCCEEDED(hr))
  116. {
  117. // Create a layout for this element.
  118. Value *pv;
  119. hr = BorderLayout::Create(0, NULL, &pv);
  120. if (SUCCEEDED(hr))
  121. {
  122. // Set the layout for this element.
  123. hr = SetValue(LayoutProp, PI_Local, pv);
  124. pv->Release();
  125. }
  126. }
  127. else
  128. {
  129. TraceMsg(TF_ERROR, "ActionTask::Initialize: base class failed to initialize with 0x%x", hr);
  130. }
  131. return hr;
  132. }
  133. HRESULT ActionTask::InitializeButton()
  134. {
  135. HRESULT hr;
  136. // Create the button.
  137. hr = Button::Create((Element**)&_peButton);
  138. if (SUCCEEDED(hr))
  139. {
  140. // Set some button attributes.
  141. _peButton->SetLayoutPos(BLP_Left);
  142. _peButton->SetAccessible(true);
  143. _peButton->SetAccRole(ROLE_SYSTEM_PUSHBUTTON);
  144. TCHAR szDefaultAction[50] = {0};
  145. LoadString(HINST_THISDLL, IDS_LINKWINDOW_DEFAULTACTION, szDefaultAction, ARRAYSIZE(szDefaultAction));
  146. _peButton->SetAccDefAction(szDefaultAction);
  147. // Create a border layout for the icon and title in the button.
  148. Value *pv;
  149. hr = BorderLayout::Create(0, NULL, &pv);
  150. if (SUCCEEDED(hr))
  151. {
  152. // Set the button layout.
  153. hr = _peButton->SetValue(LayoutProp, PI_Local, pv);
  154. if (SUCCEEDED(hr))
  155. {
  156. // Add the button to this element.
  157. hr = Add(_peButton);
  158. }
  159. pv->Release();
  160. }
  161. // Cleanup (if necessary).
  162. if (FAILED(hr))
  163. {
  164. _peButton->Destroy();
  165. _peButton = NULL;
  166. }
  167. }
  168. return hr;
  169. }
  170. ActionTask::ActionTask()
  171. {
  172. // Catch unexpected STACK allocations which would break us.
  173. ASSERT(_peButton == NULL);
  174. ASSERT(_puiCommand == NULL);
  175. ASSERT(_psiItemArray == NULL);
  176. ASSERT(_pDefView == NULL);
  177. ASSERT(_pDefView == NULL);
  178. ASSERT(_hwndRoot == NULL);
  179. ASSERT(_pDUIView == NULL);
  180. _bInfotip = FALSE;
  181. }
  182. ActionTask::~ActionTask()
  183. {
  184. if (_bInfotip)
  185. {
  186. // Destroy the infotip.
  187. _pDefView->DestroyInfotip(_hwndRoot, (UINT_PTR)this);
  188. }
  189. if (_puiCommand)
  190. _puiCommand->Release();
  191. if (_psiItemArray)
  192. _psiItemArray->Release();
  193. if (_pDUIView)
  194. _pDUIView->Release();
  195. if (_pDefView)
  196. _pDefView->Release();
  197. }
  198. void ActionTask::UpdateTaskUI()
  199. {
  200. // Set the icon
  201. LPWSTR pIconDesc;
  202. if (SUCCEEDED(_puiCommand->get_Icon(_psiItemArray, &pIconDesc)))
  203. {
  204. Element* pe;
  205. if (SUCCEEDED(Element::Create(0, &pe)))
  206. {
  207. pe->SetLayoutPos(BLP_Left);
  208. pe->SetID(L"icon");
  209. _peButton->Add(pe);
  210. HICON hIcon = DUILoadIcon(pIconDesc, TRUE);
  211. if (hIcon)
  212. {
  213. Value* pv = Value::CreateGraphic (hIcon);
  214. if (pv)
  215. {
  216. pe->SetValue(Element::ContentProp, PI_Local, pv);
  217. pv->Release();
  218. }
  219. else
  220. {
  221. DestroyIcon(hIcon);
  222. TraceMsg(TF_ERROR, "ActionTask::Initialize: CreateGraphic for the icon failed.");
  223. }
  224. }
  225. else
  226. {
  227. TraceMsg(TF_ERROR, "ActionTask::Initialize: DUILoadIcon failed.");
  228. }
  229. }
  230. else
  231. {
  232. TraceMsg(TF_ERROR, "ActionTask::Initialize: Failed to create icon element");
  233. }
  234. CoTaskMemFree(pIconDesc);
  235. }
  236. // Set the title
  237. LPWSTR pszTitleDesc;
  238. if (SUCCEEDED(_puiCommand->get_Name(_psiItemArray, &pszTitleDesc)))
  239. {
  240. Element* pe;
  241. if (SUCCEEDED(Element::Create(0, &pe)))
  242. {
  243. pe->SetLayoutPos(BLP_Left);
  244. pe->SetID(L"title");
  245. _peButton->Add(pe);
  246. Value* pv = Value::CreateString(pszTitleDesc);
  247. if (pv)
  248. {
  249. _peButton->SetValue(Element::AccNameProp, PI_Local, pv);
  250. pe->SetValue(Element::ContentProp, PI_Local, pv);
  251. pv->Release();
  252. }
  253. else
  254. {
  255. TraceMsg(TF_ERROR, "ActionTask::Initialize: CreateString for the title failed.");
  256. }
  257. }
  258. else
  259. {
  260. TraceMsg(TF_ERROR, "ActionTask::Initialize: Failed to create title element");
  261. }
  262. CoTaskMemFree(pszTitleDesc);
  263. }
  264. }
  265. // Shows/hides an Infotip window
  266. //
  267. // bShow - TRUE or FALSE to show or hide the Infotip window
  268. HRESULT ActionTask::ShowInfotipWindow(BOOL bShow)
  269. {
  270. RECT rect = { 0 };
  271. HRESULT hr;
  272. if (bShow)
  273. {
  274. _pDUIView->CalculateInfotipRect(this, &rect);
  275. if (_bInfotip)
  276. {
  277. // Reposition infotip at position.
  278. hr = _pDefView->RepositionInfotip(_hwndRoot, (UINT_PTR)this, &rect);
  279. }
  280. else
  281. {
  282. // Create infotip at position (on the ui thread).
  283. LPWSTR pwszInfotip;
  284. hr = _puiCommand->get_Tooltip(_psiItemArray, &pwszInfotip);
  285. if (SUCCEEDED(hr))
  286. {
  287. hr = GetElementRootHWND(this, &_hwndRoot);
  288. if (SUCCEEDED(hr))
  289. {
  290. hr = _pDefView->CreateInfotip(_hwndRoot, (UINT_PTR)this, &rect, pwszInfotip, 0);
  291. if (SUCCEEDED(hr))
  292. {
  293. _bInfotip = TRUE;
  294. }
  295. }
  296. CoTaskMemFree(pwszInfotip);
  297. }
  298. }
  299. }
  300. else
  301. {
  302. if (_bInfotip)
  303. {
  304. // Reposition infotip at nowhere.
  305. hr = _pDefView->RepositionInfotip(_hwndRoot, (UINT_PTR)this, &rect);
  306. }
  307. else
  308. {
  309. // No infotip == no show!
  310. hr = S_OK;
  311. }
  312. }
  313. return hr;
  314. }
  315. // System event handler
  316. //
  317. //
  318. void ActionTask::OnPropertyChanged(PropertyInfo* ppi, int iIndex, Value* pvOld, Value* pvNew)
  319. {
  320. // Default processing...
  321. Element::OnPropertyChanged(ppi, iIndex, pvOld, pvNew);
  322. // Extended processing for infotip...
  323. if (IsProp(MouseWithin))
  324. ShowInfotipWindow(pvNew->GetBool() && SHShowInfotips());
  325. }
  326. // Event handler
  327. //
  328. // pev - event information
  329. void ActionTask::OnEvent(Event* pev)
  330. {
  331. if (pev->peTarget == _peButton)
  332. {
  333. if (pev->uidType == Button::Click)
  334. {
  335. if ( NULL != _pDUIView ) // This should have been past in during initialization.
  336. {
  337. _pDUIView->DelayedNavigation(_psiItemArray, _puiCommand);
  338. }
  339. pev->fHandled = true;
  340. }
  341. }
  342. Element::OnEvent(pev);
  343. }
  344. // Class information
  345. IClassInfo* ActionTask::Class = NULL;
  346. HRESULT ActionTask::Register()
  347. {
  348. return ClassInfo<ActionTask,Element>::Register(L"ActionTask", NULL, 0);
  349. }
  350. // Creates an instance of the DestinationTask and
  351. // initializes it
  352. //
  353. // nActive - Activation type
  354. // pidl - pidl of destination
  355. // ppElement - Receives element pointer
  356. //
  357. HRESULT DestinationTask::Create(UINT nActive, LPITEMIDLIST pidl,
  358. CDUIView * pDUIView, CDefView *pDefView, OUT Element** ppElement)
  359. {
  360. *ppElement = NULL;
  361. if (!pidl || !pDUIView || !pDefView)
  362. {
  363. return E_FAIL;
  364. }
  365. DestinationTask* pDT = HNewAndZero<DestinationTask>();
  366. if (!pDT)
  367. {
  368. return E_OUTOFMEMORY;
  369. }
  370. HRESULT hr = pDT->Initialize(pidl, pDUIView, pDefView);
  371. if (FAILED(hr))
  372. {
  373. pDT->Destroy();
  374. return hr;
  375. }
  376. *ppElement = pDT;
  377. return S_OK;
  378. }
  379. // Initializes this task
  380. //
  381. // pidl - Destination pidl
  382. HRESULT DestinationTask::Initialize(LPITEMIDLIST pidl, CDUIView *pDUIView, CDefView *pDefView)
  383. {
  384. HRESULT hr;
  385. // Initialize this DUI Element.
  386. hr = InitializeElement();
  387. if (SUCCEEDED(hr))
  388. {
  389. HICON hIcon = NULL;
  390. WCHAR szTitle[MAX_PATH];
  391. // Retrieve the info needed to initialize the contained DUI Button.
  392. HIMAGELIST himl;
  393. if (Shell_GetImageLists(NULL, &himl))
  394. {
  395. IShellFolder *psf;
  396. LPCITEMIDLIST pidlItem;
  397. hr = SHBindToFolderIDListParent(NULL, pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlItem);
  398. if (SUCCEEDED(hr))
  399. {
  400. // Retrieve icon.
  401. int iSysIndex = SHMapPIDLToSystemImageListIndex(psf, pidlItem, NULL);
  402. if (iSysIndex != -1)
  403. {
  404. hIcon = ImageList_GetIcon(himl, iSysIndex, 0);
  405. }
  406. // Retrieve text.
  407. hr = DisplayNameOf(psf, pidlItem, SHGDN_INFOLDER, szTitle, ARRAYSIZE(szTitle));
  408. psf->Release();
  409. }
  410. }
  411. else
  412. {
  413. hr = E_FAIL;
  414. }
  415. if (SUCCEEDED(hr))
  416. {
  417. // Initialize the contained DUI Button.
  418. hr = InitializeButton(hIcon, szTitle);
  419. if (SUCCEEDED(hr))
  420. {
  421. // Save the destination pidl
  422. hr = SHILClone(pidl, &_pidlDestination);
  423. if (SUCCEEDED(hr))
  424. {
  425. // Save the pointer to the CDUIView class
  426. pDUIView->AddRef();
  427. _pDUIView = pDUIView;
  428. // Save the pointer to the CDefView class
  429. pDefView->AddRef();
  430. _pDefView = pDefView;
  431. }
  432. }
  433. }
  434. }
  435. return hr;
  436. }
  437. HRESULT DestinationTask::InitializeElement()
  438. {
  439. HRESULT hr;
  440. // Initialize base class (normal display node creation).
  441. hr = Element::Initialize(0);
  442. if (SUCCEEDED(hr))
  443. {
  444. // Create a layout for this element.
  445. Value *pv;
  446. hr = BorderLayout::Create(0, NULL, &pv);
  447. if (SUCCEEDED(hr))
  448. {
  449. // Set the layout for this element.
  450. hr = SetValue(LayoutProp, PI_Local, pv);
  451. pv->Release();
  452. }
  453. }
  454. else
  455. {
  456. TraceMsg(TF_ERROR, "DestinationTask::Initialize: base class failed to initialize with 0x%x", hr);
  457. }
  458. return hr;
  459. }
  460. HRESULT DestinationTask::InitializeButton(HICON hIcon, LPCWSTR pwszTitle)
  461. {
  462. ASSERT(pwszTitle);
  463. HRESULT hr;
  464. // Create the button.
  465. hr = Button::Create((Element**)&_peButton);
  466. if (SUCCEEDED(hr))
  467. {
  468. // Set some button attributes.
  469. _peButton->SetLayoutPos(BLP_Left);
  470. _peButton->SetAccessible(true);
  471. _peButton->SetAccRole(ROLE_SYSTEM_LINK);
  472. TCHAR szDefaultAction[50] = {0};
  473. LoadString(HINST_THISDLL, IDS_LINKWINDOW_DEFAULTACTION, szDefaultAction, ARRAYSIZE(szDefaultAction));
  474. _peButton->SetAccDefAction(szDefaultAction);
  475. // Create a border layout for the icon and title in the button.
  476. Value *pv;
  477. hr = BorderLayout::Create(0, NULL, &pv);
  478. if (SUCCEEDED(hr))
  479. {
  480. // Set the layout for the button.
  481. hr = _peButton->SetValue(LayoutProp, PI_Local, pv);
  482. pv->Release();
  483. if (SUCCEEDED(hr))
  484. {
  485. HRESULT hr2 = E_FAIL;
  486. HRESULT hr3 = E_FAIL;
  487. // Init the button icon.
  488. if (hIcon)
  489. {
  490. Element *peIcon;
  491. // Create an icon element.
  492. hr2 = Element::Create(0, &peIcon);
  493. if (SUCCEEDED(hr2))
  494. {
  495. // Set some icon element attributes.
  496. peIcon->SetLayoutPos(BLP_Left);
  497. peIcon->SetID(L"icon");
  498. // Add the icon to the icon element.
  499. pv = Value::CreateGraphic(hIcon);
  500. if (pv)
  501. {
  502. hr2 = peIcon->SetValue(Element::ContentProp, PI_Local, pv);
  503. pv->Release();
  504. if (SUCCEEDED(hr2))
  505. {
  506. // Add the icon element to the button.
  507. hr2 = _peButton->Add(peIcon);
  508. }
  509. }
  510. // Cleanup (if necessary).
  511. if (FAILED(hr2))
  512. {
  513. peIcon->Destroy();
  514. }
  515. }
  516. }
  517. // Init the button title.
  518. if (pwszTitle[0])
  519. {
  520. Element *peTitle;
  521. // Create a title element.
  522. hr3 = Element::Create(0, &peTitle);
  523. if (SUCCEEDED(hr3))
  524. {
  525. // Set some title element attributes.
  526. peTitle->SetLayoutPos(BLP_Left);
  527. peTitle->SetID(L"title");
  528. // Add the title to the title element.
  529. pv = Value::CreateString(pwszTitle);
  530. if (pv)
  531. {
  532. hr3 = peTitle->SetValue(Element::ContentProp, PI_Local, pv);
  533. if (SUCCEEDED(hr3))
  534. {
  535. _peButton->SetValue(Element::AccNameProp, PI_Local, pv);
  536. // Add the title element to the button.
  537. hr3 = _peButton->Add(peTitle);
  538. }
  539. pv->Release();
  540. }
  541. // Cleanup (if necessary).
  542. if (FAILED(hr3))
  543. {
  544. peTitle->Destroy();
  545. }
  546. }
  547. }
  548. if (SUCCEEDED(hr2) || SUCCEEDED(hr3))
  549. {
  550. // Add the button to this element.
  551. hr = Add(_peButton);
  552. }
  553. else
  554. {
  555. // Failed init icon AND init title for button.
  556. hr = E_FAIL;
  557. }
  558. }
  559. }
  560. if (FAILED(hr))
  561. {
  562. _peButton->Destroy();
  563. _peButton = NULL;
  564. }
  565. }
  566. return hr;
  567. }
  568. DestinationTask::DestinationTask()
  569. {
  570. // Catch unexpected STACK allocations which would break us.
  571. ASSERT(_peButton == NULL);
  572. ASSERT(_pidlDestination == NULL);
  573. ASSERT(_pDUIView == NULL);
  574. ASSERT(_pDefView == NULL);
  575. ASSERT(_hwndRoot == NULL);
  576. _bInfotip = FALSE;
  577. }
  578. DestinationTask::~DestinationTask()
  579. {
  580. if (_bInfotip)
  581. {
  582. // Kill the background infotip task (if any).
  583. if (_pDefView->_pScheduler)
  584. _pDefView->_pScheduler->RemoveTasks(TOID_DVBackgroundInfoTip, (DWORD_PTR)this, FALSE);
  585. // Destroy the infotip.
  586. _pDefView->DestroyInfotip(_hwndRoot, (UINT_PTR)this);
  587. }
  588. ILFree(_pidlDestination); /* NULL ok */
  589. if (_pDUIView)
  590. _pDUIView->Release();
  591. if (_pDefView)
  592. _pDefView->Release();
  593. }
  594. // To use _pDUIView->DelayedNavigation(_psiItemArray, _puiCommand)
  595. // we create this bogus IUICommand impl to get Invoke through
  596. class CInvokePidl : public IUICommand
  597. {
  598. STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
  599. STDMETHODIMP_(ULONG) AddRef();
  600. STDMETHODIMP_(ULONG) Release();
  601. // IUICommand
  602. STDMETHODIMP get_Name(IShellItemArray *psiItemArray, LPWSTR *ppszName) { return E_NOTIMPL; }
  603. STDMETHODIMP get_Icon(IShellItemArray *psiItemArray, LPWSTR *ppszIcon) { return E_NOTIMPL; }
  604. STDMETHODIMP get_Tooltip(IShellItemArray *psiItemArray, LPWSTR *ppszInfotip) { return E_NOTIMPL; }
  605. STDMETHODIMP get_CanonicalName(GUID* pguidCommandName) { return E_NOTIMPL; }
  606. STDMETHODIMP get_State(IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState) { return E_NOTIMPL; }
  607. // Our one real method:
  608. STDMETHODIMP Invoke(IShellItemArray *psiItemArray, IBindCtx *pbc)
  609. {
  610. return _pDUIView->NavigateToDestination(_pidlDestination);
  611. }
  612. friend HRESULT Create_InvokePidl(CDUIView* pDUIView, LPCITEMIDLIST pidl, REFIID riid, void** ppv);
  613. private:
  614. CInvokePidl(CDUIView* pDUIView, LPCITEMIDLIST pidl, HRESULT* phr);
  615. ~CInvokePidl();
  616. LONG _cRef;
  617. CDUIView* _pDUIView;
  618. LPITEMIDLIST _pidlDestination;
  619. };
  620. CInvokePidl::CInvokePidl(CDUIView* pDUIView, LPCITEMIDLIST pidl, HRESULT* phr)
  621. {
  622. _cRef = 1;
  623. (_pDUIView = pDUIView)->AddRef();
  624. _pidlDestination = ILClone(pidl);
  625. if (_pidlDestination)
  626. *phr = S_OK;
  627. else
  628. *phr = E_OUTOFMEMORY;
  629. }
  630. CInvokePidl::~CInvokePidl()
  631. {
  632. ILFree(_pidlDestination);
  633. if (_pDUIView)
  634. _pDUIView->Release();
  635. }
  636. HRESULT Create_InvokePidl(CDUIView* pDUIView, LPCITEMIDLIST pidl, REFIID riid, void** ppv)
  637. {
  638. HRESULT hr;
  639. *ppv = NULL;
  640. CInvokePidl* p = new CInvokePidl(pDUIView, pidl, &hr);
  641. if (p)
  642. {
  643. hr = p->QueryInterface(riid, ppv);
  644. p->Release();
  645. }
  646. return hr;
  647. }
  648. STDMETHODIMP CInvokePidl::QueryInterface(REFIID riid, void **ppvObj)
  649. {
  650. static const QITAB qit[] = {
  651. QITABENT(CInvokePidl, IUICommand),
  652. };
  653. return QISearch(this, qit, riid, ppvObj);
  654. }
  655. STDMETHODIMP_(ULONG) CInvokePidl::AddRef()
  656. {
  657. return InterlockedIncrement(&_cRef);
  658. }
  659. STDMETHODIMP_(ULONG) CInvokePidl::Release()
  660. {
  661. if (InterlockedDecrement(&_cRef))
  662. return _cRef;
  663. delete this;
  664. return 0;
  665. }
  666. // Navigates to the destination pidl
  667. //
  668. // none
  669. HRESULT DestinationTask::InvokePidl()
  670. {
  671. IUICommand* puiInvokePidl;
  672. HRESULT hr = Create_InvokePidl(_pDUIView, _pidlDestination, IID_PPV_ARG(IUICommand, &puiInvokePidl));
  673. if (SUCCEEDED(hr))
  674. {
  675. hr = _pDUIView->DelayedNavigation(NULL, puiInvokePidl);
  676. puiInvokePidl->Release();
  677. }
  678. return hr;
  679. }
  680. // Displays the context menu
  681. //
  682. // ppt - point to display menu
  683. HRESULT DestinationTask::OnContextMenu(POINT *ppt)
  684. {
  685. HRESULT hr = E_FAIL;
  686. if (!GetHWND())
  687. return hr;
  688. if (ppt->x == -1) // Keyboard context menu
  689. {
  690. Value *pv;
  691. const SIZE *psize = GetExtent(&pv);
  692. ppt->x = psize->cx/2;
  693. ppt->y = psize->cy/2;
  694. pv->Release();
  695. }
  696. POINT pt;
  697. GetRoot()->MapElementPoint(this, ppt, &pt);
  698. ClientToScreen(GetHWND(), &pt);
  699. IContextMenu *pcm;
  700. if (SUCCEEDED(SHGetUIObjectFromFullPIDL(_pidlDestination, GetHWND(), IID_PPV_ARG(IContextMenu, &pcm))))
  701. {
  702. IContextMenu *pcmWrap;
  703. if (SUCCEEDED(Create_ContextMenuWithoutVerbs(pcm, L"link;cut;delete", IID_PPV_ARG(IContextMenu, &pcmWrap))))
  704. {
  705. hr = IUnknown_DoContextMenuPopup(SAFECAST(_pDefView, IShellView2*), pcmWrap, CMF_NORMAL, pt);
  706. pcmWrap->Release();
  707. }
  708. pcm->Release();
  709. }
  710. return hr;
  711. }
  712. // Shows/hides an Infotip window
  713. //
  714. // bShow - TRUE or FALSE to show or hide the Infotip window
  715. HRESULT DestinationTask::ShowInfotipWindow(BOOL bShow)
  716. {
  717. RECT rect = { 0 };
  718. HRESULT hr;
  719. if (bShow)
  720. {
  721. _pDUIView->CalculateInfotipRect(this, &rect);
  722. if (_bInfotip)
  723. {
  724. // Reposition infotip at position.
  725. hr = _pDefView->RepositionInfotip(_hwndRoot, (UINT_PTR)this, &rect);
  726. }
  727. else
  728. {
  729. // Create infotip at position.
  730. hr = GetElementRootHWND(this, &_hwndRoot);
  731. if (SUCCEEDED(hr))
  732. {
  733. // PreCreateInfotip() on the ui thread.
  734. hr = _pDefView->PreCreateInfotip(_hwndRoot, (UINT_PTR)this, &rect);
  735. if (SUCCEEDED(hr))
  736. {
  737. // PostCreateInfotip() on a background thread.
  738. CDUIInfotipTask *pTask;
  739. hr = CDUIInfotipTask_CreateInstance(_pDefView, _hwndRoot, (UINT_PTR)this, _pidlDestination, &pTask);
  740. if (SUCCEEDED(hr))
  741. {
  742. hr = _pDefView->_AddTask(pTask, TOID_DVBackgroundInfoTip, (DWORD_PTR)this, TASK_PRIORITY_INFOTIP, ADDTASK_ATEND);
  743. pTask->Release();
  744. }
  745. // Persist success or cleanup failure.
  746. if (SUCCEEDED(hr))
  747. _bInfotip = TRUE;
  748. else
  749. _pDefView->DestroyInfotip(_hwndRoot, (UINT_PTR)this);
  750. }
  751. }
  752. }
  753. }
  754. else
  755. {
  756. if (_bInfotip)
  757. {
  758. // Reposition infotip at nowhere.
  759. hr = _pDefView->RepositionInfotip(_hwndRoot, (UINT_PTR)this, &rect);
  760. }
  761. else
  762. {
  763. // No infotip == no show!
  764. hr = S_OK;
  765. }
  766. }
  767. return hr;
  768. }
  769. // System event handler
  770. //
  771. //
  772. void DestinationTask::OnPropertyChanged(PropertyInfo* ppi, int iIndex, Value* pvOld, Value* pvNew)
  773. {
  774. // Default processing...
  775. Element::OnPropertyChanged(ppi, iIndex, pvOld, pvNew);
  776. // Extended processing for infotip...
  777. if (IsProp(MouseWithin))
  778. ShowInfotipWindow(pvNew->GetBool() && SHShowInfotips());
  779. }
  780. // Event handler
  781. //
  782. // pev - event information
  783. void DestinationTask::OnEvent(Event* pev)
  784. {
  785. if (pev->peTarget == _peButton)
  786. {
  787. if (pev->uidType == Button::Click)
  788. {
  789. InvokePidl();
  790. pev->fHandled = true;
  791. }
  792. else if (pev->uidType == Button::Context)
  793. {
  794. ButtonContextEvent *peButton = reinterpret_cast<ButtonContextEvent *>(pev);
  795. OnContextMenu(&peButton->pt);
  796. pev->fHandled = true;
  797. }
  798. }
  799. Element::OnEvent(pev);
  800. }
  801. // Gadget message callback handler used to return
  802. // the IDropTarget interface
  803. //
  804. // pGMsg - Gadget message
  805. //
  806. // DU_S_COMPLETE if handled
  807. // Host element's return value if not
  808. UINT DestinationTask::MessageCallback(GMSG* pGMsg)
  809. {
  810. EventMsg * pmsg = static_cast<EventMsg *>(pGMsg);
  811. switch (GET_EVENT_DEST(pmsg))
  812. {
  813. case GMF_DIRECT:
  814. case GMF_BUBBLED:
  815. if (pGMsg->nMsg == GM_QUERY)
  816. {
  817. GMSG_QUERYDROPTARGET * pTemp = (GMSG_QUERYDROPTARGET *)pGMsg;
  818. if (pTemp->nCode == GQUERY_DROPTARGET)
  819. {
  820. if (SUCCEEDED(_pDUIView->InitializeDropTarget(_pidlDestination, GetHWND(), &pTemp->pdt)))
  821. {
  822. pTemp->hgadDrop = pTemp->hgadMsg;
  823. return DU_S_COMPLETE;
  824. }
  825. }
  826. }
  827. break;
  828. }
  829. return Element::MessageCallback(pGMsg);
  830. }
  831. // Class information
  832. IClassInfo* DestinationTask::Class = NULL;
  833. HRESULT DestinationTask::Register()
  834. {
  835. return ClassInfo<DestinationTask,Element>::Register(L"DestinationTask", NULL, 0);
  836. }