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.

1596 lines
38 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 2000
  6. //
  7. // File: cpuiele.cpp
  8. //
  9. // This module contains the following classes:
  10. //
  11. // CCplUiElement
  12. // CCplUiCommand
  13. // CCplUiCommandOnPidl
  14. //
  15. // CCplUiElement is an implementation of IUIElement. This provides
  16. // the necessary display information for use in the shell's webview
  17. // implementation. The class also implements ICpUiElementInfo which
  18. // is similar to IUIElement but provides the display information in
  19. // a more 'final' form than a "<module>,<resource>" format.
  20. // The ICpUiElementInfo interface is used internally by the Control Panel
  21. // implementation.
  22. //
  23. // CCplUiCommand is an implementation of IUICommand. As with IUIElement,
  24. // this provides the necessary functions for communicating with webview
  25. // as a 'command' object (i.e. selectable 'link'). Also as with the
  26. // previous class, CCplUiCommand implements an internal version of
  27. // the public interface. ICplUiCommand provides two things:
  28. // 1. A method to invoke a context menu.
  29. // 2. An invocation method that accepts a site pointer. This site
  30. // pointer is passed along to an 'action' object that may need
  31. // access to the shell browser to perform it's function. It
  32. // obtains access to the shell browser through this site ptr.
  33. //
  34. // CCplUiCommandOnPidl is another implementation of IUICommand that
  35. // wraps a shell item ID list. It is used to represent the CPL
  36. // applet items in a category view.
  37. //
  38. //--------------------------------------------------------------------------
  39. #include "shellprv.h"
  40. #include "cpviewp.h"
  41. #include "cpguids.h"
  42. #include "cpuiele.h"
  43. #include "cputil.h"
  44. #include "contextmenu.h"
  45. #include "prop.h"
  46. namespace CPL {
  47. //-----------------------------------------------------------------------------
  48. // CCplUiElement
  49. //-----------------------------------------------------------------------------
  50. class CCplUiElement : public IUIElement,
  51. public ICpUiElementInfo
  52. {
  53. public:
  54. //
  55. // IUnknown
  56. //
  57. STDMETHOD(QueryInterface)(REFIID riid, void **ppv);
  58. STDMETHOD_(ULONG, AddRef)(void);
  59. STDMETHOD_(ULONG, Release)(void);
  60. //
  61. // IUIElement (used by shell webview)
  62. //
  63. STDMETHOD(get_Name)(IShellItemArray *psiItemArray, LPWSTR *ppszName);
  64. STDMETHOD(get_Icon)(IShellItemArray *psiItemArray, LPWSTR *ppszIcon);
  65. STDMETHOD(get_Tooltip)(IShellItemArray *psiItemArray, LPWSTR *ppszInfotip);
  66. //
  67. // ICpUiElementInfo (used internally by Control Panel)
  68. //
  69. STDMETHOD(LoadIcon)(eCPIMGSIZE eSize, HICON *phIcon);
  70. STDMETHOD(LoadName)(LPWSTR *ppszName);
  71. STDMETHOD(LoadTooltip)(LPWSTR *ppszTooltip);
  72. static HRESULT CreateInstance(LPCWSTR pszName, LPCWSTR pszInfotip, LPCWSTR pszIcon, REFIID riid, void **ppvOut);
  73. protected:
  74. CCplUiElement(LPCWSTR pszName, LPCWSTR pszInfotip, LPCWSTR pszIcon);
  75. CCplUiElement(void);
  76. virtual CCplUiElement::~CCplUiElement(void);
  77. private:
  78. LONG m_cRef;
  79. LPCWSTR m_pszName;
  80. LPCWSTR m_pszInfotip;
  81. LPCWSTR m_pszIcon;
  82. HRESULT _GetResourceString(LPCWSTR pszItem, LPWSTR *ppsz);
  83. HRESULT _GetIconResource(LPWSTR *ppsz);
  84. HRESULT _GetNameResource(LPWSTR *ppsz);
  85. HRESULT _GetInfotipResource(LPWSTR *ppsz);
  86. };
  87. CCplUiElement::CCplUiElement(
  88. LPCWSTR pszName,
  89. LPCWSTR pszInfotip, // NULL == No Info Tip
  90. LPCWSTR pszIcon
  91. ) : m_cRef(1),
  92. m_pszName(pszName),
  93. m_pszInfotip(pszInfotip),
  94. m_pszIcon(pszIcon)
  95. {
  96. ASSERT(IS_INTRESOURCE(m_pszName) || !IsBadStringPtr(m_pszName, UINT_PTR(-1)));
  97. ASSERT((NULL == pszInfotip) || IS_INTRESOURCE(m_pszInfotip) || !IsBadStringPtr(m_pszInfotip, UINT_PTR(-1)));
  98. ASSERT(IS_INTRESOURCE(m_pszIcon) || !IsBadStringPtr(m_pszIcon, UINT_PTR(-1)));
  99. }
  100. CCplUiElement::CCplUiElement(
  101. void
  102. ) : m_cRef(1),
  103. m_pszName(NULL),
  104. m_pszInfotip(NULL),
  105. m_pszIcon(NULL)
  106. {
  107. TraceMsg(TF_LIFE, "CCplUiElement::CCplUiElement, this = 0x%x", this);
  108. }
  109. CCplUiElement::~CCplUiElement(
  110. void
  111. )
  112. {
  113. TraceMsg(TF_LIFE, "CCplUiElement::~CCplUiElement, this = 0x%x", this);
  114. //
  115. // Note that the member string pointers contain either a resource ID
  116. // or a pointer to constant memory.
  117. // Therefore, we do not try to free them.
  118. //
  119. }
  120. HRESULT
  121. CCplUiElement::CreateInstance( // [static]
  122. LPCWSTR pszName,
  123. LPCWSTR pszInfotip,
  124. LPCWSTR pszIcon,
  125. REFIID riid,
  126. void **ppvOut
  127. )
  128. {
  129. ASSERT(NULL != ppvOut);
  130. ASSERT(!IsBadWritePtr(ppvOut, sizeof(*ppvOut)));
  131. *ppvOut = NULL;
  132. HRESULT hr = E_OUTOFMEMORY;
  133. CCplUiElement *pe = new CCplUiElement(pszName, pszInfotip, pszIcon);
  134. if (NULL != pe)
  135. {
  136. hr = pe->QueryInterface(riid, ppvOut);
  137. pe->Release();
  138. }
  139. return THR(hr);
  140. }
  141. STDMETHODIMP
  142. CCplUiElement::QueryInterface(
  143. REFIID riid,
  144. void **ppv
  145. )
  146. {
  147. ASSERT(NULL != ppv);
  148. ASSERT(!IsBadWritePtr(ppv, sizeof(*ppv)));
  149. static const QITAB qit[] = {
  150. QITABENT(CCplUiElement, IUIElement),
  151. QITABENT(CCplUiElement, ICpUiElementInfo),
  152. { 0 },
  153. };
  154. HRESULT hr = QISearch(this, qit, riid, ppv);
  155. return E_NOINTERFACE == hr ? hr : THR(hr);
  156. }
  157. STDMETHODIMP_(ULONG)
  158. CCplUiElement::AddRef(
  159. void
  160. )
  161. {
  162. return InterlockedIncrement(&m_cRef);
  163. }
  164. STDMETHODIMP_(ULONG)
  165. CCplUiElement::Release(
  166. void
  167. )
  168. {
  169. if (InterlockedDecrement(&m_cRef))
  170. return m_cRef;
  171. delete this;
  172. return 0;
  173. }
  174. STDMETHODIMP
  175. CCplUiElement::get_Name(
  176. IShellItemArray *psiItemArray,
  177. LPWSTR *ppszName
  178. )
  179. {
  180. UNREFERENCED_PARAMETER(psiItemArray);
  181. HRESULT hr = LoadName(ppszName);
  182. return THR(hr);
  183. }
  184. STDMETHODIMP
  185. CCplUiElement::get_Icon(
  186. IShellItemArray *psiItemArray,
  187. LPWSTR *ppszIcon
  188. )
  189. {
  190. UNREFERENCED_PARAMETER(psiItemArray);
  191. HRESULT hr = _GetIconResource(ppszIcon);
  192. return THR(hr);
  193. }
  194. STDMETHODIMP
  195. CCplUiElement::get_Tooltip(
  196. IShellItemArray *psiItemArray,
  197. LPWSTR *ppszInfotip
  198. )
  199. {
  200. UNREFERENCED_PARAMETER(psiItemArray);
  201. HRESULT hr = THR(LoadTooltip(ppszInfotip));
  202. if (S_FALSE == hr)
  203. {
  204. //
  205. // Tooltips are optional but we need to return a failure
  206. // code to tell webview that we don't have one.
  207. //
  208. hr = E_FAIL;
  209. }
  210. return hr;
  211. }
  212. STDMETHODIMP
  213. CCplUiElement::LoadIcon(
  214. eCPIMGSIZE eSize,
  215. HICON *phIcon
  216. )
  217. {
  218. *phIcon = NULL;
  219. LPWSTR pszResource;
  220. HRESULT hr = _GetIconResource(&pszResource);
  221. if (SUCCEEDED(hr))
  222. {
  223. hr = CPL::LoadIconFromResource(pszResource, eSize, phIcon);
  224. CoTaskMemFree(pszResource);
  225. }
  226. return THR(hr);
  227. }
  228. STDMETHODIMP
  229. CCplUiElement::LoadName(
  230. LPWSTR *ppszName
  231. )
  232. {
  233. LPWSTR pszResource;
  234. HRESULT hr = _GetNameResource(&pszResource);
  235. if (SUCCEEDED(hr))
  236. {
  237. hr = CPL::LoadStringFromResource(pszResource, ppszName);
  238. CoTaskMemFree(pszResource);
  239. }
  240. return THR(hr);
  241. }
  242. STDMETHODIMP
  243. CCplUiElement::LoadTooltip(
  244. LPWSTR *ppszTooltip
  245. )
  246. {
  247. LPWSTR pszResource;
  248. HRESULT hr = _GetInfotipResource(&pszResource);
  249. if (S_OK == hr)
  250. {
  251. hr = CPL::LoadStringFromResource(pszResource, ppszTooltip);
  252. CoTaskMemFree(pszResource);
  253. }
  254. return THR(hr);
  255. }
  256. HRESULT
  257. CCplUiElement::_GetIconResource(
  258. LPWSTR *ppsz
  259. )
  260. {
  261. HRESULT hr = _GetResourceString(m_pszIcon, ppsz);
  262. return THR(hr);
  263. }
  264. HRESULT
  265. CCplUiElement::_GetNameResource(
  266. LPWSTR *ppsz
  267. )
  268. {
  269. HRESULT hr = _GetResourceString(m_pszName, ppsz);
  270. return THR(hr);
  271. }
  272. //
  273. // Returns S_FALSE if tooltip text is not provided.
  274. // Tooltips are optional. For example, the "learn about"
  275. // tasks in Control Panel's web view pane do not have tooltip
  276. // text.
  277. //
  278. HRESULT
  279. CCplUiElement::_GetInfotipResource(
  280. LPWSTR *ppsz
  281. )
  282. {
  283. HRESULT hr = S_FALSE;
  284. if (NULL != m_pszInfotip)
  285. {
  286. hr = _GetResourceString(m_pszInfotip, ppsz);
  287. }
  288. return THR(hr);
  289. }
  290. //
  291. // On successful return, caller must free returned string using
  292. // CoTaskMemFree.
  293. //
  294. HRESULT
  295. CCplUiElement::_GetResourceString(
  296. LPCWSTR pszItem,
  297. LPWSTR *ppsz
  298. )
  299. {
  300. ASSERT(NULL != ppsz);
  301. ASSERT(!IsBadWritePtr(ppsz, sizeof(*ppsz)));
  302. *ppsz = NULL;
  303. HRESULT hr = E_FAIL;
  304. if (IS_INTRESOURCE(pszItem))
  305. {
  306. //
  307. // pszItem is a resource identifier integer. Create a resource
  308. // ID string "<module>,<-i>" for the resource.
  309. //
  310. WCHAR szModule[MAX_PATH];
  311. if (GetModuleFileNameW(HINST_THISDLL, szModule, ARRAYSIZE(szModule)))
  312. {
  313. *ppsz = (LPWSTR)CoTaskMemAlloc((lstrlenW(szModule) + 15) * sizeof(WCHAR));
  314. if (NULL != *ppsz)
  315. {
  316. //
  317. // Precede the resource ID with a minus sign so that it will be
  318. // treated as a resource ID and not an index.
  319. //
  320. wsprintfW(*ppsz, L"%s,-%u", szModule, PtrToUint(pszItem));
  321. hr = S_OK;
  322. }
  323. else
  324. {
  325. hr = E_OUTOFMEMORY;
  326. }
  327. }
  328. else
  329. {
  330. hr = CPL::ResultFromLastError();
  331. }
  332. }
  333. else
  334. {
  335. //
  336. // pszItem is a text string. Assume it's in the form of
  337. // "<module>,<-i>". Simply duplicate it.
  338. //
  339. ASSERT(!IsBadStringPtr(pszItem, UINT_PTR(-1)));
  340. hr = SHStrDup(pszItem, ppsz);
  341. }
  342. return THR(hr);
  343. }
  344. //-----------------------------------------------------------------------------
  345. // CCplUiCommand
  346. //-----------------------------------------------------------------------------
  347. class CCplUiCommand : public CObjectWithSite,
  348. public CCplUiElement,
  349. public IUICommand,
  350. public ICpUiCommand
  351. {
  352. public:
  353. //
  354. // IUnknown
  355. //
  356. STDMETHOD(QueryInterface)(REFIID riid, void **ppv);
  357. STDMETHOD_(ULONG, AddRef)(void)
  358. { return CCplUiElement::AddRef(); }
  359. STDMETHOD_(ULONG, Release)(void)
  360. { return CCplUiElement::Release(); }
  361. //
  362. // IUICommand
  363. //
  364. STDMETHOD(get_Name)(IShellItemArray *psiItemArray, LPWSTR *ppszName)
  365. { return CCplUiElement::get_Name(psiItemArray, ppszName); }
  366. STDMETHOD(get_Icon)(IShellItemArray *psiItemArray, LPWSTR *ppszIcon)
  367. { return CCplUiElement::get_Icon(psiItemArray, ppszIcon); }
  368. STDMETHOD(get_Tooltip)(IShellItemArray *psiItemArray, LPWSTR *ppszInfotip)
  369. { return CCplUiElement::get_Tooltip(psiItemArray, ppszInfotip); }
  370. STDMETHOD(get_CanonicalName)(GUID *pguidCommandName);
  371. STDMETHOD(get_State)(IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE *puisState);
  372. STDMETHOD(Invoke)(IShellItemArray *psiItemArray, IBindCtx *pbc);
  373. //
  374. // ICpUiCommand
  375. //
  376. STDMETHOD(InvokeContextMenu)(HWND hwndParent, const POINT *ppt);
  377. STDMETHOD(Invoke)(HWND hwndParent, IUnknown *punkSite);
  378. STDMETHOD(GetDataObject)(IDataObject **ppdtobj);
  379. //
  380. // ICpUiElementInfo
  381. //
  382. STDMETHOD(LoadIcon)(eCPIMGSIZE eSize, HICON *phIcon)
  383. { return CCplUiElement::LoadIcon(eSize, phIcon); }
  384. STDMETHOD(LoadName)(LPWSTR *ppszName)
  385. { return CCplUiElement::LoadName(ppszName); }
  386. STDMETHOD(LoadTooltip)(LPWSTR *ppszTooltip)
  387. { return CCplUiElement::LoadTooltip(ppszTooltip); }
  388. static HRESULT CreateInstance(LPCWSTR pszName, LPCWSTR pszInfotip, LPCWSTR pszIcon, const IAction *pAction, REFIID riid, void **ppvOut);
  389. protected:
  390. CCplUiCommand(LPCWSTR pszName, LPCWSTR pszInfotip, LPCWSTR pszIcon, const IAction *pAction);
  391. CCplUiCommand(void);
  392. ~CCplUiCommand(void);
  393. private:
  394. const IAction *m_pAction;
  395. HRESULT _IsCommandRestricted(void);
  396. };
  397. CCplUiCommand::CCplUiCommand(
  398. void
  399. ) : m_pAction(NULL)
  400. {
  401. TraceMsg(TF_LIFE, "CCplUiCommand::CCplUiCommand, this = 0x%x", this);
  402. }
  403. CCplUiCommand::CCplUiCommand(
  404. LPCWSTR pszName,
  405. LPCWSTR pszInfotip,
  406. LPCWSTR pszIcon,
  407. const IAction *pAction
  408. ) : CCplUiElement(pszName, pszInfotip, pszIcon),
  409. m_pAction(pAction)
  410. {
  411. TraceMsg(TF_LIFE, "CCplUiCommand::CCplUiCommand, this = 0x%x", this);
  412. }
  413. CCplUiCommand::~CCplUiCommand(
  414. void
  415. )
  416. {
  417. TraceMsg(TF_LIFE, "CCplUiCommand::~CCplUiCommand, this = 0x%x", this);
  418. //
  419. // Note that m_pAction is a pointer to a const object.
  420. // Therefore, we don't try to free it.
  421. //
  422. }
  423. HRESULT
  424. CCplUiCommand::CreateInstance( // [static]
  425. LPCWSTR pszName,
  426. LPCWSTR pszInfotip,
  427. LPCWSTR pszIcon,
  428. const IAction *pAction,
  429. REFIID riid,
  430. void **ppvOut
  431. )
  432. {
  433. ASSERT(NULL != ppvOut);
  434. ASSERT(!IsBadWritePtr(ppvOut, sizeof(*ppvOut)));
  435. *ppvOut = NULL;
  436. HRESULT hr = E_OUTOFMEMORY;
  437. CCplUiCommand *pc = new CCplUiCommand(pszName, pszInfotip, pszIcon, pAction);
  438. if (NULL != pc)
  439. {
  440. hr = pc->QueryInterface(riid, ppvOut);
  441. pc->Release();
  442. }
  443. return THR(hr);
  444. }
  445. STDMETHODIMP
  446. CCplUiCommand::QueryInterface(
  447. REFIID riid,
  448. void **ppv
  449. )
  450. {
  451. ASSERT(NULL != ppv);
  452. ASSERT(!IsBadWritePtr(ppv, sizeof(*ppv)));
  453. static const QITAB qit[] = {
  454. QITABENT(CCplUiCommand, IUICommand),
  455. QITABENT(CCplUiCommand, ICpUiElementInfo),
  456. QITABENT(CCplUiCommand, ICpUiCommand),
  457. QITABENT(CCplUiCommand, IObjectWithSite),
  458. QITABENTMULTI(CCplUiCommand, IUIElement, IUICommand),
  459. { 0 },
  460. };
  461. HRESULT hr = QISearch(this, qit, riid, ppv);
  462. return E_NOINTERFACE == hr ? hr : THR(hr);
  463. }
  464. STDMETHODIMP
  465. CCplUiCommand::get_CanonicalName(
  466. GUID *pguidCommandName
  467. )
  468. {
  469. UNREFERENCED_PARAMETER(pguidCommandName);
  470. //
  471. // This function is unimplemented. It is in IUICommand to
  472. // support generic functionality in the shell. This functionality
  473. // is not applicable to the use of IUICommand in the Control
  474. // Panel.
  475. //
  476. return E_NOTIMPL;
  477. }
  478. STDMETHODIMP
  479. CCplUiCommand::get_State(
  480. IShellItemArray *psiItemArray,
  481. BOOL fOkToBeSlow,
  482. UISTATE *puisState
  483. )
  484. {
  485. ASSERT(NULL != m_pAction);
  486. ASSERT(NULL != puisState);
  487. ASSERT(!IsBadWritePtr(puisState, sizeof(*puisState)));
  488. UNREFERENCED_PARAMETER(psiItemArray);
  489. *puisState = UIS_DISABLED; // default;
  490. //
  491. // If an action is restricted, we hide it's corresponding
  492. // UI element in the user interface.
  493. //
  494. HRESULT hr = _IsCommandRestricted();
  495. if (SUCCEEDED(hr))
  496. {
  497. switch(hr)
  498. {
  499. case S_OK:
  500. *puisState = UIS_HIDDEN;
  501. break;
  502. case S_FALSE:
  503. *puisState = UIS_ENABLED;
  504. default:
  505. break;
  506. }
  507. //
  508. // Don't propagate S_FALSE to caller.
  509. //
  510. hr = S_OK;
  511. }
  512. return THR(hr);
  513. }
  514. //
  515. // IUICommand::Invoke
  516. // This version is called by webview when the user selects an
  517. // item from a webview menu.
  518. //
  519. STDMETHODIMP
  520. CCplUiCommand::Invoke(
  521. IShellItemArray *psiItemArray,
  522. IBindCtx *pbc
  523. )
  524. {
  525. DBG_ENTER(FTF_CPANEL, "CCplUiCommand::Invoke");
  526. ASSERT(NULL != m_pAction);
  527. UNREFERENCED_PARAMETER(psiItemArray);
  528. UNREFERENCED_PARAMETER(pbc);
  529. HRESULT hr = m_pAction->Execute(NULL, _punkSite);
  530. DBG_EXIT_HRES(FTF_CPANEL, "CCplUiCommand::Invoke", hr);
  531. return THR(hr);
  532. }
  533. //
  534. // ICpUiCommand::Invoke
  535. // This version is called by CLinkElement::_OnSelected when
  536. // the user selects either a category task or a category item
  537. // in the category choice view.
  538. //
  539. STDMETHODIMP
  540. CCplUiCommand::Invoke(
  541. HWND hwndParent,
  542. IUnknown *punkSite
  543. )
  544. {
  545. ASSERT(NULL != m_pAction);
  546. HRESULT hr = m_pAction->Execute(hwndParent, punkSite);
  547. return THR(hr);
  548. }
  549. STDMETHODIMP
  550. CCplUiCommand::InvokeContextMenu(
  551. HWND hwndParent,
  552. const POINT *ppt
  553. )
  554. {
  555. //
  556. // Only commands on pidls provide a context menu.
  557. //
  558. UNREFERENCED_PARAMETER(hwndParent);
  559. UNREFERENCED_PARAMETER(ppt);
  560. return E_NOTIMPL;
  561. }
  562. STDMETHODIMP
  563. CCplUiCommand::GetDataObject(
  564. IDataObject **ppdtobj
  565. )
  566. {
  567. //
  568. // Simple UI commands don't provide a data object.
  569. //
  570. return E_NOTIMPL;
  571. }
  572. //
  573. // Returns:
  574. // S_OK = Command is restricted.
  575. // S_FALSE = Command is not restricted.
  576. //
  577. HRESULT
  578. CCplUiCommand::_IsCommandRestricted(
  579. void
  580. )
  581. {
  582. //
  583. // The ICplNamespace ptr is passed to IsRestricted in case the restriction
  584. // code needs to inspect contents of the namespace. The "Other Cpl Options"
  585. // link command uses this to determine if the "OTHER" category contains any
  586. // CPL applets or not. If it contains no applets, the link is hidden (restricted).
  587. //
  588. ICplNamespace *pns;
  589. HRESULT hr = IUnknown_QueryService(_punkSite, SID_SControlPanelView, IID_ICplNamespace, (void **)&pns);
  590. if (SUCCEEDED(hr))
  591. {
  592. hr = m_pAction->IsRestricted(pns);
  593. pns->Release();
  594. }
  595. return THR(hr);
  596. }
  597. //-----------------------------------------------------------------------------
  598. // CCplUiCommandOnPidl
  599. //-----------------------------------------------------------------------------
  600. class CCplUiCommandOnPidl : public CObjectWithSite,
  601. public IUICommand,
  602. public ICpUiCommand,
  603. public ICpUiElementInfo,
  604. public IDataObject
  605. {
  606. public:
  607. ~CCplUiCommandOnPidl(void);
  608. //
  609. // IUnknown
  610. //
  611. STDMETHOD(QueryInterface)(REFIID riid, void **ppv);
  612. STDMETHOD_(ULONG, AddRef)(void);
  613. STDMETHOD_(ULONG, Release)(void);
  614. //
  615. // IUICommand
  616. //
  617. STDMETHOD(get_Name)(IShellItemArray *psiItemArray, LPWSTR *ppszName);
  618. STDMETHOD(get_Icon)(IShellItemArray *psiItemArray, LPWSTR *ppszIcon);
  619. STDMETHOD(get_Tooltip)(IShellItemArray *psiItemArray, LPWSTR *ppszInfotip);
  620. STDMETHOD(get_CanonicalName)(GUID *pguidCommandName);
  621. STDMETHOD(get_State)(IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE *puisState);
  622. STDMETHOD(Invoke)(IShellItemArray *psiItemArray, IBindCtx *pbc);
  623. //
  624. // ICpUiCommand
  625. //
  626. STDMETHOD(InvokeContextMenu)(HWND hwndParent, const POINT *ppt);
  627. STDMETHOD(Invoke)(HWND hwndParent, IUnknown *punkSite);
  628. STDMETHOD(GetDataObject)(IDataObject **ppdtobj);
  629. //
  630. // ICpUiElementInfo
  631. //
  632. STDMETHOD(LoadIcon)(eCPIMGSIZE eSize, HICON *phIcon);
  633. STDMETHOD(LoadName)(LPWSTR *ppszName);
  634. STDMETHOD(LoadTooltip)(LPWSTR *ppszTooltip);
  635. //
  636. // IDataObject
  637. //
  638. STDMETHOD(GetData)(FORMATETC *pFmtEtc, STGMEDIUM *pstm);
  639. STDMETHOD(GetDataHere)(FORMATETC *pFmtEtc, STGMEDIUM *pstm);
  640. STDMETHOD(QueryGetData)(FORMATETC *pFmtEtc);
  641. STDMETHOD(GetCanonicalFormatEtc)(FORMATETC *pFmtEtcIn, FORMATETC *pFmtEtcOut);
  642. STDMETHOD(SetData)(FORMATETC *pFmtEtc, STGMEDIUM *pstm, BOOL fRelease);
  643. STDMETHOD(EnumFormatEtc)(DWORD dwDirection, LPENUMFORMATETC *ppEnum);
  644. STDMETHOD(DAdvise)(FORMATETC *pFmtEtc, DWORD grfAdv, LPADVISESINK pAdvSink, DWORD *pdwConnection);
  645. STDMETHOD(DUnadvise)(DWORD dwConnection);
  646. STDMETHOD(EnumDAdvise)(LPENUMSTATDATA *ppEnum);
  647. static HRESULT CreateInstance(LPCITEMIDLIST pidl, REFIID riid, void **ppvOut);
  648. private:
  649. LONG m_cRef;
  650. IShellFolder *m_psf; // Cached Control Panel IShellFolder ptr.
  651. LPITEMIDLIST m_pidl; // Assumed to be relative to Control Panel.
  652. IDataObject *m_pdtobj;
  653. CCplUiCommandOnPidl(void);
  654. HRESULT _GetControlPanelFolder(IShellFolder **ppsf);
  655. HRESULT _Initialize(LPCITEMIDLIST pidl);
  656. HRESULT _GetName(LPWSTR *ppszName);
  657. HRESULT _GetInfotip(LPWSTR *ppszInfotip);
  658. HRESULT _GetIconResource(LPWSTR *ppszIcon);
  659. HRESULT _Invoke(HWND hwndParent, IUnknown *punkSite);
  660. HRESULT _GetDataObject(IDataObject **ppdtobj);
  661. };
  662. CCplUiCommandOnPidl::CCplUiCommandOnPidl(
  663. void
  664. ) : m_cRef(1),
  665. m_psf(NULL),
  666. m_pidl(NULL),
  667. m_pdtobj(NULL)
  668. {
  669. TraceMsg(TF_LIFE, "CCplUiCommandOnPidl::CCplUiCommandOnPidl, this = 0x%x", this);
  670. }
  671. CCplUiCommandOnPidl::~CCplUiCommandOnPidl(
  672. void
  673. )
  674. {
  675. TraceMsg(TF_LIFE, "CCplUiCommandOnPidl::~CCplUiCommandOnPidl, this = 0x%x", this);
  676. ATOMICRELEASE(m_psf);
  677. ATOMICRELEASE(m_pdtobj);
  678. if (NULL != m_pidl)
  679. {
  680. ILFree(m_pidl);
  681. }
  682. }
  683. HRESULT
  684. CCplUiCommandOnPidl::CreateInstance( // [static]
  685. LPCITEMIDLIST pidl,
  686. REFIID riid,
  687. void **ppvOut
  688. )
  689. {
  690. ASSERT(NULL != ppvOut);
  691. ASSERT(!IsBadWritePtr(ppvOut, sizeof(*ppvOut)));
  692. ASSERT(NULL != pidl);
  693. *ppvOut = NULL;
  694. HRESULT hr = E_OUTOFMEMORY;
  695. CCplUiCommandOnPidl *pc = new CCplUiCommandOnPidl();
  696. if (NULL != pc)
  697. {
  698. hr = pc->_Initialize(pidl);
  699. if (SUCCEEDED(hr))
  700. {
  701. hr = pc->QueryInterface(riid, ppvOut);
  702. }
  703. pc->Release();
  704. }
  705. return THR(hr);
  706. }
  707. STDMETHODIMP
  708. CCplUiCommandOnPidl::QueryInterface(
  709. REFIID riid,
  710. void **ppv
  711. )
  712. {
  713. ASSERT(NULL != ppv);
  714. ASSERT(!IsBadWritePtr(ppv, sizeof(*ppv)));
  715. static const QITAB qit[] = {
  716. QITABENT(CCplUiCommandOnPidl, IUICommand),
  717. QITABENT(CCplUiCommandOnPidl, ICpUiCommand),
  718. QITABENT(CCplUiCommandOnPidl, ICpUiElementInfo),
  719. QITABENT(CCplUiCommandOnPidl, IObjectWithSite),
  720. QITABENT(CCplUiCommandOnPidl, IDataObject),
  721. QITABENTMULTI(CCplUiCommandOnPidl, IUIElement, IUICommand),
  722. { 0 },
  723. };
  724. HRESULT hr = QISearch(this, qit, riid, ppv);
  725. return E_NOINTERFACE == hr ? hr : THR(hr);
  726. }
  727. STDMETHODIMP_(ULONG)
  728. CCplUiCommandOnPidl::AddRef(
  729. void
  730. )
  731. {
  732. return InterlockedIncrement(&m_cRef);
  733. }
  734. STDMETHODIMP_(ULONG)
  735. CCplUiCommandOnPidl::Release(
  736. void
  737. )
  738. {
  739. if (InterlockedDecrement(&m_cRef))
  740. return m_cRef;
  741. delete this;
  742. return 0;
  743. }
  744. STDMETHODIMP
  745. CCplUiCommandOnPidl::get_Name(
  746. IShellItemArray *psiItemArray,
  747. LPWSTR *ppszName
  748. )
  749. {
  750. UNREFERENCED_PARAMETER(psiItemArray);
  751. HRESULT hr = _GetName(ppszName);
  752. return THR(hr);
  753. }
  754. STDMETHODIMP
  755. CCplUiCommandOnPidl::get_Icon(
  756. IShellItemArray *psiItemArray,
  757. LPWSTR *ppszIcon
  758. )
  759. {
  760. UNREFERENCED_PARAMETER(psiItemArray);
  761. HRESULT hr = _GetIconResource(ppszIcon);
  762. return THR(hr);
  763. }
  764. STDMETHODIMP
  765. CCplUiCommandOnPidl::get_Tooltip(
  766. IShellItemArray *psiItemArray,
  767. LPWSTR *ppszInfotip
  768. )
  769. {
  770. UNREFERENCED_PARAMETER(psiItemArray);
  771. HRESULT hr = _GetInfotip(ppszInfotip);
  772. return THR(hr);
  773. }
  774. STDMETHODIMP
  775. CCplUiCommandOnPidl::get_CanonicalName(
  776. GUID *pguidCommandName
  777. )
  778. {
  779. UNREFERENCED_PARAMETER(pguidCommandName);
  780. return E_NOTIMPL;
  781. }
  782. STDMETHODIMP
  783. CCplUiCommandOnPidl::get_State(
  784. IShellItemArray *psiItemArray,
  785. BOOL fOkToBeSlow,
  786. UISTATE *puisState
  787. )
  788. {
  789. ASSERT(NULL != puisState);
  790. ASSERT(!IsBadWritePtr(puisState, sizeof(*puisState)));
  791. UNREFERENCED_PARAMETER(psiItemArray);
  792. UNREFERENCED_PARAMETER(fOkToBeSlow);
  793. HRESULT hr = S_OK;
  794. *puisState = UIS_ENABLED; // default;
  795. //
  796. // We do not handle restrictions on CPL applets in the same
  797. // sense as other 'tasks' in this architecture.
  798. // CPL applets are restricted by the Control Panel folder's
  799. // item enumerator. If the folder enumerates a CPL applet
  800. // then we assume it's valid to present that applet in the
  801. // UI.
  802. //
  803. return THR(hr);
  804. }
  805. STDMETHODIMP
  806. CCplUiCommandOnPidl::Invoke(
  807. IShellItemArray *psiItemArray,
  808. IBindCtx *pbc
  809. )
  810. {
  811. DBG_ENTER(FTF_CPANEL, "CCplUiCommandOnPidl::Invoke");
  812. UNREFERENCED_PARAMETER(psiItemArray);
  813. UNREFERENCED_PARAMETER(pbc);
  814. HRESULT hr = _Invoke(NULL, NULL);
  815. DBG_EXIT_HRES(FTF_CPANEL, "CCplUiCommandOnPidl::Invoke", hr);
  816. return THR(hr);
  817. }
  818. //
  819. // ICpUiCommand::Invoke
  820. //
  821. STDMETHODIMP
  822. CCplUiCommandOnPidl::Invoke(
  823. HWND hwndParent,
  824. IUnknown *punkSite
  825. )
  826. {
  827. DBG_ENTER(FTF_CPANEL, "CCplUiCommandOnPidl::Invoke");
  828. UNREFERENCED_PARAMETER(punkSite);
  829. HRESULT hr = _Invoke(hwndParent, punkSite);
  830. DBG_EXIT_HRES(FTF_CPANEL, "CCplUiCommandOnPidl::Invoke", hr);
  831. return THR(hr);
  832. }
  833. HRESULT
  834. CCplUiCommandOnPidl::_Invoke(
  835. HWND hwndParent,
  836. IUnknown *punkSite
  837. )
  838. {
  839. DBG_ENTER(FTF_CPANEL, "CCplUiCommandOnPidl::_Invoke");
  840. UNREFERENCED_PARAMETER(hwndParent);
  841. LPITEMIDLIST pidlCpanel;
  842. HRESULT hr = SHGetSpecialFolderLocation(NULL, CSIDL_CONTROLS, &pidlCpanel);
  843. if (SUCCEEDED(hr))
  844. {
  845. LPITEMIDLIST pidl = ILCombine(pidlCpanel, m_pidl);
  846. if (FAILED(hr))
  847. {
  848. hr = E_OUTOFMEMORY;
  849. }
  850. else
  851. {
  852. bool bItemIsBrowsable = false;
  853. IUnknown *punkSiteToRelease = NULL;
  854. if (NULL == punkSite)
  855. {
  856. //
  857. // No site provided. Let's use our site.
  858. //
  859. ASSERT(NULL != _punkSite);
  860. (punkSite = punkSiteToRelease = _punkSite)->AddRef();
  861. }
  862. if (NULL != punkSite)
  863. {
  864. //
  865. // If we have a site pointer, try to browse the object in-place
  866. // if it is indeed browsable.
  867. //
  868. WCHAR szName[MAX_PATH];
  869. ULONG rgfAttrs = SFGAO_BROWSABLE | SFGAO_FOLDER;
  870. hr = SHGetNameAndFlags(pidl, SHGDN_FORPARSING, szName, ARRAYSIZE(szName), &rgfAttrs);
  871. if (SUCCEEDED(hr))
  872. {
  873. if ((SFGAO_BROWSABLE | SFGAO_FOLDER) & rgfAttrs)
  874. {
  875. //
  876. // Browse the object in-place. This is the path taken
  877. // by things like the "Printers" folder, "Scheduled Tasks" etc.
  878. //
  879. bItemIsBrowsable = true;
  880. IShellBrowser *psb;
  881. hr = CPL::ShellBrowserFromSite(punkSite, &psb);
  882. if (SUCCEEDED(hr))
  883. {
  884. hr = CPL::BrowseIDListInPlace(pidl, psb);
  885. psb->Release();
  886. }
  887. }
  888. }
  889. }
  890. if (NULL == punkSite || !bItemIsBrowsable)
  891. {
  892. //
  893. // Either we don't have a site ptr (can't get to the browser)
  894. // or the item is not browsable. Simply execute it.
  895. // This is the path taken by conventional CPL applets like
  896. // Mouse, Power Options, Display etc.
  897. //
  898. SHELLEXECUTEINFOW sei = {
  899. sizeof(sei), // cbSize;
  900. SEE_MASK_INVOKEIDLIST, // fMask
  901. NULL, // hwnd
  902. NULL, // lpVerb
  903. NULL, // lpFile
  904. NULL, // lpParameters
  905. NULL, // lpDirectory
  906. SW_SHOWNORMAL, // nShow
  907. 0, // hInstApp
  908. pidl, // lpIDList
  909. NULL, // lpClass
  910. NULL, // hkeyClass
  911. 0, // dwHotKey
  912. NULL, // hIcon
  913. NULL // hProcess
  914. };
  915. if (!ShellExecuteExW(&sei))
  916. {
  917. hr = CPL::ResultFromLastError();
  918. }
  919. }
  920. ATOMICRELEASE(punkSiteToRelease);
  921. ILFree(pidl);
  922. }
  923. ILFree(pidlCpanel);
  924. }
  925. DBG_EXIT_HRES(FTF_CPANEL, "CCplUiCommandOnPidl::_Invoke", hr);
  926. return THR(hr);
  927. }
  928. HRESULT
  929. CCplUiCommandOnPidl::InvokeContextMenu(
  930. HWND hwndParent,
  931. const POINT *ppt
  932. )
  933. {
  934. DBG_ENTER(FTF_CPANEL, "CCplUiCommandOnPidl::InvokeContextMenu");
  935. ASSERT(NULL != ppt);
  936. ASSERT(NULL == hwndParent || IsWindow(hwndParent));
  937. //
  938. // First build a full pidl to the item.
  939. //
  940. LPITEMIDLIST pidlCpanel;
  941. HRESULT hr = SHGetSpecialFolderLocation(hwndParent, CSIDL_CONTROLS, &pidlCpanel);
  942. if (SUCCEEDED(hr))
  943. {
  944. LPITEMIDLIST pidlFull = ILCombine(pidlCpanel, m_pidl);
  945. if (NULL == pidlFull)
  946. {
  947. hr = E_OUTOFMEMORY;
  948. }
  949. else
  950. {
  951. //
  952. // Get the item's context menu interface from the shell.
  953. //
  954. IContextMenu *pcm;
  955. hr = SHGetUIObjectFromFullPIDL(pidlFull, hwndParent, IID_PPV_ARG(IContextMenu, &pcm));
  956. if (SUCCEEDED(hr))
  957. {
  958. ASSERT(NULL != _punkSite);
  959. IContextMenu *pcmNoDelete;
  960. hr = Create_ContextMenuWithoutVerbs(pcm, L"cut;delete", IID_PPV_ARG(IContextMenu, &pcmNoDelete));
  961. if (SUCCEEDED(hr))
  962. {
  963. hr = IUnknown_DoContextMenuPopup(_punkSite, pcmNoDelete, CMF_NORMAL, *ppt);
  964. pcmNoDelete->Release();
  965. }
  966. pcm->Release();
  967. }
  968. else
  969. {
  970. TraceMsg(TF_ERROR, "Shell item does not provide a context menu");
  971. }
  972. ILFree(pidlFull);
  973. }
  974. ILFree(pidlCpanel);
  975. }
  976. DBG_EXIT_HRES(FTF_CPANEL, "CCplUiCommandOnPidl::InvokeContextMenu", hr);
  977. return THR(hr);
  978. }
  979. STDMETHODIMP
  980. CCplUiCommandOnPidl::GetDataObject(
  981. IDataObject **ppdtobj
  982. )
  983. {
  984. return _GetDataObject(ppdtobj);
  985. }
  986. STDMETHODIMP
  987. CCplUiCommandOnPidl::LoadIcon(
  988. eCPIMGSIZE eSize,
  989. HICON *phIcon
  990. )
  991. {
  992. IShellFolder *psf;
  993. HRESULT hr = CPL::GetControlPanelFolder(&psf);
  994. if (SUCCEEDED(hr))
  995. {
  996. hr = CPL::ExtractIconFromPidl(psf, m_pidl, eSize, phIcon);
  997. psf->Release();
  998. }
  999. return THR(hr);
  1000. }
  1001. STDMETHODIMP
  1002. CCplUiCommandOnPidl::LoadName(
  1003. LPWSTR *ppszName
  1004. )
  1005. {
  1006. HRESULT hr = _GetName(ppszName);
  1007. return THR(hr);
  1008. }
  1009. STDMETHODIMP
  1010. CCplUiCommandOnPidl::LoadTooltip(
  1011. LPWSTR *ppszTooltip
  1012. )
  1013. {
  1014. HRESULT hr = _GetInfotip(ppszTooltip);
  1015. return THR(hr);
  1016. }
  1017. HRESULT
  1018. CCplUiCommandOnPidl::_Initialize(
  1019. LPCITEMIDLIST pidl
  1020. )
  1021. {
  1022. ASSERT(NULL == m_pidl);
  1023. ASSERT(NULL != pidl);
  1024. HRESULT hr = E_OUTOFMEMORY;
  1025. m_pidl = ILClone(pidl);
  1026. if (NULL != m_pidl)
  1027. {
  1028. hr = S_OK;
  1029. }
  1030. return THR(hr);
  1031. }
  1032. HRESULT
  1033. CCplUiCommandOnPidl::_GetControlPanelFolder(
  1034. IShellFolder **ppsf
  1035. )
  1036. {
  1037. ASSERT(NULL != ppsf);
  1038. ASSERT(!IsBadWritePtr(ppsf, sizeof(*ppsf)));
  1039. HRESULT hr = S_OK;
  1040. if (NULL == m_psf)
  1041. {
  1042. hr = CPL::GetControlPanelFolder(&m_psf);
  1043. }
  1044. *ppsf = m_psf;
  1045. if (NULL != *ppsf)
  1046. {
  1047. (*ppsf)->AddRef();
  1048. }
  1049. return THR(hr);
  1050. }
  1051. HRESULT
  1052. CCplUiCommandOnPidl::_GetName(
  1053. LPWSTR *ppszName
  1054. )
  1055. {
  1056. ASSERT(NULL != m_pidl);
  1057. ASSERT(NULL != ppszName);
  1058. ASSERT(!IsBadWritePtr(ppszName, sizeof(*ppszName)));
  1059. *ppszName = NULL;
  1060. IShellFolder *psf;
  1061. HRESULT hr = _GetControlPanelFolder(&psf);
  1062. if (SUCCEEDED(hr))
  1063. {
  1064. STRRET strret;
  1065. hr = psf->GetDisplayNameOf(m_pidl, SHGDN_INFOLDER, &strret);
  1066. if (SUCCEEDED(hr))
  1067. {
  1068. hr = StrRetToStrW(&strret, m_pidl, ppszName);
  1069. }
  1070. psf->Release();
  1071. }
  1072. return THR(hr);
  1073. }
  1074. HRESULT
  1075. CCplUiCommandOnPidl::_GetInfotip(
  1076. LPWSTR *ppszInfotip
  1077. )
  1078. {
  1079. ASSERT(NULL != ppszInfotip);
  1080. ASSERT(!IsBadWritePtr(ppszInfotip, sizeof(*ppszInfotip)));
  1081. ASSERT(NULL != m_pidl);
  1082. *ppszInfotip = NULL;
  1083. IShellFolder *psf;
  1084. HRESULT hr = _GetControlPanelFolder(&psf);
  1085. if (SUCCEEDED(hr))
  1086. {
  1087. IShellFolder2 *psf2;
  1088. psf->QueryInterface(IID_PPV_ARG(IShellFolder2, &psf2));
  1089. if (SUCCEEDED(hr))
  1090. {
  1091. TCHAR szBuf[256];
  1092. hr = GetStringProperty(psf2, m_pidl, &SCID_Comment, szBuf, ARRAYSIZE(szBuf));
  1093. if (SUCCEEDED(hr))
  1094. {
  1095. hr = SHStrDup(szBuf, ppszInfotip);
  1096. }
  1097. psf2->Release();
  1098. }
  1099. psf->Release();
  1100. }
  1101. return THR(hr);
  1102. }
  1103. HRESULT
  1104. CCplUiCommandOnPidl::_GetIconResource(
  1105. LPWSTR *ppszIcon
  1106. )
  1107. {
  1108. ASSERT(NULL != ppszIcon);
  1109. ASSERT(!IsBadWritePtr(ppszIcon, sizeof(*ppszIcon)));
  1110. ASSERT(NULL != m_pidl);
  1111. LPWSTR pszIconPath = NULL;
  1112. IShellFolder *psf;
  1113. HRESULT hr = _GetControlPanelFolder(&psf);
  1114. if (SUCCEEDED(hr))
  1115. {
  1116. IExtractIconW* pxi;
  1117. hr = psf->GetUIObjectOf(NULL, 1, (LPCITEMIDLIST *)&m_pidl, IID_PPV_ARG_NULL(IExtractIconW, &pxi));
  1118. if (SUCCEEDED(hr))
  1119. {
  1120. WCHAR szPath[MAX_PATH];
  1121. int iIndex;
  1122. UINT wFlags = 0;
  1123. hr = pxi->GetIconLocation(GIL_FORSHELL, szPath, ARRAYSIZE(szPath), &iIndex, &wFlags);
  1124. if (SUCCEEDED(hr))
  1125. {
  1126. pszIconPath = (LPWSTR)SHAlloc(sizeof(WCHAR)*(lstrlenW(szPath) + 12));
  1127. if (pszIconPath)
  1128. {
  1129. wsprintfW(pszIconPath,L"%s,%d", szPath, iIndex);
  1130. }
  1131. else
  1132. {
  1133. hr = E_OUTOFMEMORY;
  1134. }
  1135. }
  1136. pxi->Release();
  1137. }
  1138. psf->Release();
  1139. }
  1140. *ppszIcon = pszIconPath;
  1141. return THR(hr);
  1142. }
  1143. HRESULT
  1144. CCplUiCommandOnPidl::_GetDataObject(
  1145. IDataObject **ppdtobj
  1146. )
  1147. {
  1148. ASSERT(NULL != ppdtobj);
  1149. ASSERT(!IsBadWritePtr(ppdtobj, sizeof(*ppdtobj)));
  1150. HRESULT hr = S_OK;
  1151. if (NULL == m_pdtobj)
  1152. {
  1153. IShellFolder *psf;
  1154. hr = _GetControlPanelFolder(&psf);
  1155. if (SUCCEEDED(hr))
  1156. {
  1157. hr = THR(psf->GetUIObjectOf(NULL,
  1158. 1,
  1159. (LPCITEMIDLIST *)&m_pidl,
  1160. IID_PPV_ARG_NULL(IDataObject, &m_pdtobj)));
  1161. psf->Release();
  1162. }
  1163. }
  1164. if (SUCCEEDED(hr))
  1165. {
  1166. ASSERT(NULL != m_pdtobj);
  1167. (*ppdtobj = m_pdtobj)->AddRef();
  1168. }
  1169. return THR(hr);
  1170. }
  1171. STDMETHODIMP
  1172. CCplUiCommandOnPidl::GetData(
  1173. FORMATETC *pFmtEtc,
  1174. STGMEDIUM *pstm
  1175. )
  1176. {
  1177. IDataObject *pdtobj;
  1178. HRESULT hr = _GetDataObject(&pdtobj);
  1179. if (SUCCEEDED(hr))
  1180. {
  1181. hr = pdtobj->GetData(pFmtEtc, pstm);
  1182. pdtobj->Release();
  1183. }
  1184. return THR(hr);
  1185. }
  1186. STDMETHODIMP
  1187. CCplUiCommandOnPidl::GetDataHere(
  1188. FORMATETC *pFmtEtc,
  1189. STGMEDIUM *pstm
  1190. )
  1191. {
  1192. IDataObject *pdtobj;
  1193. HRESULT hr = _GetDataObject(&pdtobj);
  1194. if (SUCCEEDED(hr))
  1195. {
  1196. hr = pdtobj->GetDataHere(pFmtEtc, pstm);
  1197. pdtobj->Release();
  1198. }
  1199. return THR(hr);
  1200. }
  1201. STDMETHODIMP
  1202. CCplUiCommandOnPidl::QueryGetData(
  1203. FORMATETC *pFmtEtc
  1204. )
  1205. {
  1206. IDataObject *pdtobj;
  1207. HRESULT hr = _GetDataObject(&pdtobj);
  1208. if (SUCCEEDED(hr))
  1209. {
  1210. hr = pdtobj->QueryGetData(pFmtEtc);
  1211. pdtobj->Release();
  1212. }
  1213. return THR(hr);
  1214. }
  1215. STDMETHODIMP
  1216. CCplUiCommandOnPidl::GetCanonicalFormatEtc(
  1217. FORMATETC *pFmtEtcIn,
  1218. FORMATETC *pFmtEtcOut
  1219. )
  1220. {
  1221. IDataObject *pdtobj;
  1222. HRESULT hr = _GetDataObject(&pdtobj);
  1223. if (SUCCEEDED(hr))
  1224. {
  1225. hr = pdtobj->GetCanonicalFormatEtc(pFmtEtcIn, pFmtEtcOut);
  1226. pdtobj->Release();
  1227. }
  1228. return THR(hr);
  1229. }
  1230. STDMETHODIMP
  1231. CCplUiCommandOnPidl::SetData(
  1232. FORMATETC *pFmtEtc,
  1233. STGMEDIUM *pstm,
  1234. BOOL fRelease
  1235. )
  1236. {
  1237. IDataObject *pdtobj;
  1238. HRESULT hr = _GetDataObject(&pdtobj);
  1239. if (SUCCEEDED(hr))
  1240. {
  1241. hr = pdtobj->SetData(pFmtEtc, pstm, fRelease);
  1242. pdtobj->Release();
  1243. }
  1244. return THR(hr);
  1245. }
  1246. STDMETHODIMP
  1247. CCplUiCommandOnPidl::EnumFormatEtc(
  1248. DWORD dwDirection,
  1249. LPENUMFORMATETC *ppEnum
  1250. )
  1251. {
  1252. IDataObject *pdtobj;
  1253. HRESULT hr = _GetDataObject(&pdtobj);
  1254. if (SUCCEEDED(hr))
  1255. {
  1256. hr = pdtobj->EnumFormatEtc(dwDirection, ppEnum);
  1257. pdtobj->Release();
  1258. }
  1259. return THR(hr);
  1260. }
  1261. STDMETHODIMP
  1262. CCplUiCommandOnPidl::DAdvise(
  1263. FORMATETC *pFmtEtc,
  1264. DWORD grfAdv,
  1265. LPADVISESINK pAdvSink,
  1266. DWORD *pdwConnection
  1267. )
  1268. {
  1269. IDataObject *pdtobj;
  1270. HRESULT hr = _GetDataObject(&pdtobj);
  1271. if (SUCCEEDED(hr))
  1272. {
  1273. hr = pdtobj->DAdvise(pFmtEtc, grfAdv, pAdvSink, pdwConnection);
  1274. pdtobj->Release();
  1275. }
  1276. return THR(hr);
  1277. }
  1278. STDMETHODIMP
  1279. CCplUiCommandOnPidl::DUnadvise(
  1280. DWORD dwConnection
  1281. )
  1282. {
  1283. IDataObject *pdtobj;
  1284. HRESULT hr = _GetDataObject(&pdtobj);
  1285. if (SUCCEEDED(hr))
  1286. {
  1287. hr = pdtobj->DUnadvise(dwConnection);
  1288. pdtobj->Release();
  1289. }
  1290. return THR(hr);
  1291. }
  1292. STDMETHODIMP
  1293. CCplUiCommandOnPidl::EnumDAdvise(
  1294. LPENUMSTATDATA *ppEnum
  1295. )
  1296. {
  1297. IDataObject *pdtobj;
  1298. HRESULT hr = _GetDataObject(&pdtobj);
  1299. if (SUCCEEDED(hr))
  1300. {
  1301. hr = pdtobj->EnumDAdvise(ppEnum);
  1302. pdtobj->Release();
  1303. }
  1304. return THR(hr);
  1305. }
  1306. //-----------------------------------------------------------------------------
  1307. // Public instance generators.
  1308. //-----------------------------------------------------------------------------
  1309. HRESULT
  1310. Create_CplUiElement(
  1311. LPCWSTR pszName,
  1312. LPCWSTR pszInfotip,
  1313. LPCWSTR pszIcon,
  1314. REFIID riid,
  1315. void **ppvOut
  1316. )
  1317. {
  1318. ASSERT(NULL != ppvOut);
  1319. ASSERT(!IsBadWritePtr(ppvOut, sizeof(*ppvOut)));
  1320. return CCplUiElement::CreateInstance(pszName, pszInfotip, pszIcon, riid, ppvOut);
  1321. }
  1322. HRESULT
  1323. Create_CplUiCommand(
  1324. LPCWSTR pszName,
  1325. LPCWSTR pszInfotip,
  1326. LPCWSTR pszIcon,
  1327. const IAction *pAction,
  1328. REFIID riid,
  1329. void **ppvOut
  1330. )
  1331. {
  1332. ASSERT(NULL != ppvOut);
  1333. ASSERT(!IsBadWritePtr(ppvOut, sizeof(*ppvOut)));
  1334. return CCplUiCommand::CreateInstance(pszName, pszInfotip, pszIcon, pAction, riid, ppvOut);
  1335. }
  1336. HRESULT
  1337. Create_CplUiCommandOnPidl(
  1338. LPCITEMIDLIST pidl,
  1339. REFIID riid,
  1340. void **ppvOut
  1341. )
  1342. {
  1343. ASSERT(NULL != ppvOut);
  1344. ASSERT(!IsBadWritePtr(ppvOut, sizeof(*ppvOut)));
  1345. ASSERT(NULL != pidl);
  1346. HRESULT hr = CCplUiCommandOnPidl::CreateInstance(pidl, riid, ppvOut);
  1347. return THR(hr);
  1348. }
  1349. } // namespace CPL