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.

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