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.

663 lines
18 KiB

  1. #include "shellprv.h"
  2. #include "enumuicommand.h"
  3. #include "datautil.h"
  4. HRESULT CWVTASKITEM::_get_String(const WVTASKITEM* pTask,
  5. DWORD dwIndex,
  6. LPWSTR * ppsz,
  7. DWORD cchMin,
  8. BOOL bIsIcon)
  9. {
  10. HRESULT hr;
  11. DWORD cchIcon = (unsigned)(lstrlen(pTask->pszDllName) + 9); // 9 = comma + minus + 2*65535 + \0
  12. DWORD cch = bIsIcon
  13. ? cchIcon // "DLL,-0" string format required for loading icons from DLL resource
  14. : max(cchIcon + 1, cchMin); // "@DLL,-0" string format required for loading strings from DLL resource
  15. LPWSTR psz = (LPWSTR)CoTaskMemAlloc(cch * sizeof(WCHAR));
  16. if (psz)
  17. {
  18. if (bIsIcon)
  19. {
  20. wnsprintf(psz, cch, L"%s,-%u", pTask->pszDllName, dwIndex);
  21. hr = S_OK;
  22. }
  23. else
  24. {
  25. wnsprintf(psz, cch, L"@%s,-%u", pTask->pszDllName, dwIndex);
  26. hr = SHLoadIndirectString(psz, psz, cch, NULL);
  27. }
  28. }
  29. else
  30. {
  31. hr = E_OUTOFMEMORY;
  32. }
  33. *ppsz = psz;
  34. return hr;
  35. }
  36. #define SS_UNKNOWN 0
  37. #define SS_NOTSUPPORTED 1
  38. #define SS_NONE 2
  39. #define SS_FILE 3
  40. #define SS_FOLDER 4
  41. #define SS_MULTI 5
  42. DWORD CWVTASKITEM::_GetSelectionState(const WVTASKITEM* pTask, IShellItemArray *psiItemArray)
  43. {
  44. DWORD dwSelectionState;
  45. DWORD cItems = 0;
  46. if (psiItemArray)
  47. {
  48. if (FAILED(psiItemArray->GetCount(&cItems)))
  49. {
  50. cItems = 0;
  51. }
  52. }
  53. switch (cItems)
  54. {
  55. case 0:
  56. dwSelectionState = SS_NONE;
  57. break;
  58. case 1:
  59. {
  60. DWORD dwAttribs = 0;
  61. if (psiItemArray)
  62. {
  63. if (FAILED(psiItemArray->GetAttributes(SIATTRIBFLAGS_AND, SFGAO_FOLDER|SFGAO_STREAM,&dwAttribs)))
  64. {
  65. dwAttribs = 0;
  66. }
  67. }
  68. switch (dwAttribs)
  69. {
  70. case SFGAO_FOLDER:
  71. dwSelectionState = SS_FOLDER;
  72. break;
  73. case SFGAO_FOLDER|SFGAO_STREAM:
  74. // zip and cab files are the only things that get here.
  75. // we'll call them files unless somebody has a better idea
  76. // (SS_MULTI has plurality that sounds funny).
  77. // fall through
  78. default:
  79. dwSelectionState = SS_FILE;
  80. break;
  81. }
  82. }
  83. break;
  84. default:
  85. dwSelectionState = SS_MULTI;
  86. break;
  87. }
  88. if ((SS_NONE == dwSelectionState && 0 == pTask->dwTitleIndexNoSelection) ||
  89. (SS_FILE == dwSelectionState && 0 == pTask->dwTitleIndexFileSelected) ||
  90. (SS_FOLDER == dwSelectionState && 0 == pTask->dwTitleIndexFolderSelected) ||
  91. (SS_MULTI == dwSelectionState && 0 == pTask->dwTitleIndexMultiSelected))
  92. {
  93. dwSelectionState = SS_NOTSUPPORTED;
  94. }
  95. return dwSelectionState;
  96. }
  97. HRESULT CWVTASKITEM::get_Name(const WVTASKITEM* pTask, IShellItemArray *psiItemArray, LPWSTR *ppszName)
  98. {
  99. DWORD dwSelState = _GetSelectionState(pTask, psiItemArray);
  100. switch (dwSelState)
  101. {
  102. case SS_NONE: return _get_String(pTask, pTask->dwTitleIndexNoSelection, ppszName, MAX_PATH, FALSE);
  103. case SS_FILE: return _get_String(pTask, pTask->dwTitleIndexFileSelected, ppszName, MAX_PATH, FALSE);
  104. case SS_FOLDER: return _get_String(pTask, pTask->dwTitleIndexFolderSelected, ppszName, MAX_PATH, FALSE);
  105. case SS_MULTI: return _get_String(pTask, pTask->dwTitleIndexMultiSelected, ppszName, MAX_PATH, FALSE);
  106. }
  107. *ppszName = NULL;
  108. return E_NOTIMPL;
  109. }
  110. HRESULT CWVTASKITEM::get_Icon(const WVTASKITEM* pTask, IShellItemArray *psiItemArray, LPWSTR *ppszIcon)
  111. {
  112. return _get_String(pTask, pTask->dwIconIndex, ppszIcon, 0, TRUE);
  113. }
  114. HRESULT CWVTASKITEM::get_Tooltip(const WVTASKITEM* pTask, IShellItemArray *psiItemArray, LPWSTR *ppszInfotip)
  115. {
  116. return _get_String(pTask, pTask->dwTooltipIndex, ppszInfotip, INFOTIPSIZE, FALSE);
  117. }
  118. HRESULT CWVTASKITEM::get_CanonicalName(const WVTASKITEM* pTask, GUID* pguidCommandName)
  119. {
  120. *pguidCommandName = *(pTask->pguidCanonicalName);
  121. return S_OK;
  122. }
  123. HRESULT CWVTASKITEM::get_State(const WVTASKITEM* pTask, IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  124. {
  125. HRESULT hr = S_OK;
  126. *puisState = UIS_DISABLED;
  127. if (_GetSelectionState(pTask, psiItemArray) != SS_NOTSUPPORTED)
  128. {
  129. if (pTask->pfn_get_State)
  130. hr = pTask->pfn_get_State(pv, psiItemArray, fOkToBeSlow, puisState);
  131. else
  132. *puisState = UIS_ENABLED;
  133. }
  134. return hr;
  135. }
  136. HRESULT CWVTASKITEM::Invoke(const WVTASKITEM* pTask, IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  137. {
  138. return pTask->pfn_Invoke(pv, psiItemArray, pbc);
  139. }
  140. class CUIElement : public CWVTASKITEM, public IUIElement
  141. {
  142. public:
  143. STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
  144. STDMETHODIMP_(ULONG) AddRef();
  145. STDMETHODIMP_(ULONG) Release();
  146. // IUIElement
  147. STDMETHODIMP get_Name(IShellItemArray *psiItemArray, LPWSTR *ppszName) {return CWVTASKITEM::get_Name(_pTask, psiItemArray, ppszName);}
  148. STDMETHODIMP get_Icon(IShellItemArray *psiItemArray, LPWSTR *ppszIcon) {return CWVTASKITEM::get_Icon(_pTask, psiItemArray, ppszIcon);}
  149. STDMETHODIMP get_Tooltip(IShellItemArray *psiItemArray, LPWSTR *ppszInfotip) {return CWVTASKITEM::get_Tooltip(_pTask, psiItemArray, ppszInfotip);}
  150. friend HRESULT Create_IUIElement(const WVTASKITEM* pwvti, IUIElement**ppuie);
  151. protected:
  152. CUIElement(const WVTASKITEM* pTask) { _cRef = 1; _pTask=pTask; }
  153. ~CUIElement() {}
  154. LONG _cRef;
  155. const WVTASKITEM* _pTask;
  156. };
  157. HRESULT Create_IUIElement(const WVTASKITEM* pwvti, IUIElement**ppuie)
  158. {
  159. HRESULT hr;
  160. if (NULL!=pwvti)
  161. {
  162. CUIElement* p = new CUIElement(pwvti);
  163. if (p)
  164. {
  165. hr = p->QueryInterface(IID_PPV_ARG(IUIElement, ppuie));
  166. p->Release();
  167. }
  168. else
  169. {
  170. hr = E_OUTOFMEMORY;
  171. *ppuie = NULL;
  172. }
  173. }
  174. else
  175. {
  176. TraceMsg(TF_WARNING, "Create_IUIElement: caller passed in bad pwvti.");
  177. hr = E_INVALIDARG;
  178. *ppuie = NULL;
  179. }
  180. return hr;
  181. }
  182. HRESULT CUIElement::QueryInterface(REFIID riid, void **ppv)
  183. {
  184. static const QITAB qit[] = {
  185. QITABENT(CUIElement, IUIElement),
  186. { 0 },
  187. };
  188. return QISearch(this, qit, riid, ppv);
  189. }
  190. ULONG CUIElement::AddRef()
  191. {
  192. return InterlockedIncrement(&_cRef);
  193. }
  194. ULONG CUIElement::Release()
  195. {
  196. if (InterlockedDecrement(&_cRef))
  197. return _cRef;
  198. delete this;
  199. return 0;
  200. }
  201. class CUICommand : public CUIElement, public IUICommand
  202. {
  203. public:
  204. STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
  205. STDMETHODIMP_(ULONG) AddRef() { return CUIElement::AddRef(); }
  206. STDMETHODIMP_(ULONG) Release() { return CUIElement::Release(); }
  207. // IUICommand
  208. STDMETHODIMP get_Name(IShellItemArray *psiItemArray, LPWSTR *ppszName) { return CUIElement::get_Name(psiItemArray, ppszName); }
  209. STDMETHODIMP get_Icon(IShellItemArray *psiItemArray, LPWSTR *ppszIcon) { return CUIElement::get_Icon(psiItemArray, ppszIcon); }
  210. STDMETHODIMP get_Tooltip(IShellItemArray *psiItemArray, LPWSTR *ppszInfotip) { return CUIElement::get_Tooltip(psiItemArray, ppszInfotip); }
  211. STDMETHODIMP get_CanonicalName(GUID* pguidCommandName) { return CWVTASKITEM::get_CanonicalName(_pTask, pguidCommandName); }
  212. STDMETHODIMP get_State(IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState) { return CWVTASKITEM::get_State(_pTask, _pv, psiItemArray, fOkToBeSlow, puisState); }
  213. STDMETHODIMP Invoke(IShellItemArray *psiItemArray, IBindCtx *pbc) { return CWVTASKITEM::Invoke(_pTask, _pv, psiItemArray, pbc); }
  214. friend HRESULT Create_IUICommand(IUnknown* pv, const WVTASKITEM* pwvti, IUICommand**ppuic);
  215. private:
  216. CUICommand(IUnknown* pv, const WVTASKITEM* pTask);
  217. ~CUICommand();
  218. IUnknown* _pv;
  219. };
  220. HRESULT Create_IUICommand(IUnknown* pv, const WVTASKITEM* pwvti, IUICommand**ppuic)
  221. {
  222. HRESULT hr;
  223. if (NULL!=pwvti)
  224. {
  225. CUICommand* p = new CUICommand(pv, pwvti);
  226. if (p)
  227. {
  228. hr = p->QueryInterface(IID_PPV_ARG(IUICommand, ppuic));
  229. p->Release();
  230. }
  231. else
  232. {
  233. hr = E_OUTOFMEMORY;
  234. *ppuic = NULL;
  235. }
  236. }
  237. else
  238. {
  239. TraceMsg(TF_WARNING, "Create_IUICommand: caller passed in bad pwvti.");
  240. hr = E_INVALIDARG;
  241. *ppuic = NULL;
  242. }
  243. return hr;
  244. }
  245. CUICommand::CUICommand(IUnknown* pv, const WVTASKITEM* pTask)
  246. : CUIElement(pTask)
  247. {
  248. _pv = pv;
  249. if (_pv)
  250. _pv->AddRef();
  251. }
  252. CUICommand::~CUICommand()
  253. {
  254. if (_pv)
  255. _pv->Release();
  256. }
  257. HRESULT CUICommand::QueryInterface(REFIID riid, void **ppv)
  258. {
  259. static const QITAB qit[] = {
  260. QITABENT(CUICommand, IUICommand),
  261. QITABENTMULTI(CUICommand, IUIElement, IUICommand),
  262. { 0 },
  263. };
  264. return QISearch(this, qit, riid, ppv);
  265. }
  266. #if 0 // { CUICommandOnPidl is currently not used, may come back for RC1
  267. // a IUICommand wrapper around an IShellItem interface
  268. //
  269. class CUICommandOnPidl : public IUICommand
  270. {
  271. public:
  272. STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
  273. STDMETHODIMP_(ULONG) AddRef();
  274. STDMETHODIMP_(ULONG) Release();
  275. // IUICommand
  276. STDMETHODIMP get_Name(IShellItemArray *psiItemArray, LPWSTR *ppszName);
  277. STDMETHODIMP get_Icon(IShellItemArray *psiItemArray, LPWSTR *ppszIcon);
  278. STDMETHODIMP get_Tooltip(IShellItemArray *psiItemArray, LPWSTR *ppszInfotip);
  279. STDMETHODIMP get_CanonicalName(GUID* pguidCommandName);
  280. STDMETHODIMP get_State(IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState);
  281. STDMETHODIMP Invoke(IShellItemArray *psiItemArray, IBindCtx *pbc);
  282. friend HRESULT Create_UICommandFromParseName(LPCWSTR pszParseName, REFGUID guidCanonicalName, HINSTANCE hinst, int idsName, int idsTip, IUICommand** ppuiCommand);
  283. private:
  284. CUICommandOnPidl() { _cRef = 1; }
  285. ~CUICommandOnPidl();
  286. HRESULT Initialize(LPCWSTR pszParseName, REFGUID guidCanonicalName, HINSTANCE hinst, int idsName, int idsTip);
  287. LONG _cRef;
  288. const GUID* _pguidCanonicalName;
  289. IShellFolder* _psf;
  290. LPCITEMIDLIST _pidl;
  291. LPITEMIDLIST _pidlAbsolute;
  292. // optional hinst,idsName,idsTip to override display text for the item
  293. HINSTANCE _hinst;
  294. int _idsName;
  295. int _idsTip;
  296. };
  297. HRESULT Create_UICommandFromParseName(LPCWSTR pszParseName, REFGUID guidCanonicalName, HINSTANCE hinst, int idsName, int idsTip, IUICommand** ppuiCommand)
  298. {
  299. HRESULT hr = E_OUTOFMEMORY;
  300. *ppuiCommand = NULL;
  301. CUICommandOnPidl* p = new CUICommandOnPidl();
  302. if (p)
  303. {
  304. if (SUCCEEDED(p->Initialize(pszParseName, guidCanonicalName, hinst, idsName, idsTip)))
  305. {
  306. hr = p->QueryInterface(IID_PPV_ARG(IUICommand, ppuiCommand));
  307. }
  308. p->Release();
  309. }
  310. return hr;
  311. }
  312. HRESULT CUICommandOnPidl::Initialize(LPCWSTR pszParseName, REFGUID guidCanonicalName, HINSTANCE hinst, int idsName, int idsTip)
  313. {
  314. _pguidCanonicalName = &guidCanonicalName;
  315. IShellFolder* psfDesktop;
  316. HRESULT hr = SHGetDesktopFolder(&psfDesktop);
  317. if (SUCCEEDED(hr))
  318. {
  319. hr = psfDesktop->ParseDisplayName(NULL, NULL, (LPOLESTR)pszParseName, NULL, &_pidlAbsolute, NULL);
  320. if (SUCCEEDED(hr))
  321. {
  322. hr = SHBindToIDListParent(_pidlAbsolute, IID_PPV_ARG(IShellFolder, &_psf), &_pidl);
  323. _hinst = hinst;
  324. _idsName = idsName;
  325. _idsTip = idsTip;
  326. }
  327. psfDesktop->Release();
  328. }
  329. return hr;
  330. }
  331. CUICommandOnPidl::~CUICommandOnPidl()
  332. {
  333. if (_psf)
  334. _psf->Release();
  335. ILFree(_pidlAbsolute);
  336. }
  337. HRESULT CUICommandOnPidl::QueryInterface(REFIID riid, void **ppv)
  338. {
  339. static const QITAB qit[] = {
  340. QITABENT(CUICommandOnPidl, IUICommand),
  341. QITABENTMULTI(CUICommandOnPidl, IUIElement, IUICommand),
  342. { 0 },
  343. };
  344. return QISearch(this, qit, riid, ppv);
  345. }
  346. ULONG CUICommandOnPidl::AddRef()
  347. {
  348. return InterlockedIncrement(&_cRef);
  349. }
  350. ULONG CUICommandOnPidl::Release()
  351. {
  352. if (InterlockedDecrement(&_cRef))
  353. return _cRef;
  354. delete this;
  355. return 0;
  356. }
  357. HRESULT CUICommandOnPidl::get_Name(IShellItemArray *psiItemArray, LPWSTR *ppszName)
  358. {
  359. if (_hinst && _idsName)
  360. {
  361. // TODO: load the string... but we have to fix dui to handle direct strings!
  362. return DisplayNameOfAsOLESTR(_psf, _pidl, SHGDN_INFOLDER, ppszName);
  363. }
  364. else
  365. return DisplayNameOfAsOLESTR(_psf, _pidl, SHGDN_INFOLDER, ppszName);
  366. }
  367. HRESULT CUICommandOnPidl::get_Icon(IShellItemArray *psiItemArray, LPWSTR *ppszIcon)
  368. {
  369. LPWSTR pszIconPath = NULL;
  370. // TODO: use SHGetIconFromPIDL so we get system imagelist support
  371. IExtractIcon* pxi;
  372. HRESULT hr = _psf->GetUIObjectOf(NULL, 1, &_pidl, IID_PPV_ARG_NULL(IExtractIcon, &pxi));
  373. if (SUCCEEDED(hr))
  374. {
  375. WCHAR szPath[MAX_PATH];
  376. int iIndex;
  377. UINT wFlags=0;
  378. // BUGBUG: assume the location is a proper dll,-id value...
  379. hr = pxi->GetIconLocation(GIL_FORSHELL, szPath, ARRAYSIZE(szPath), &iIndex, &wFlags);
  380. if (SUCCEEDED(hr))
  381. {
  382. pszIconPath = (LPWSTR)SHAlloc(sizeof(WCHAR)*(lstrlen(szPath)+1+8));
  383. if (pszIconPath)
  384. {
  385. wsprintf(pszIconPath,L"%s,%d", szPath, iIndex);
  386. }
  387. else
  388. {
  389. hr = E_OUTOFMEMORY;
  390. }
  391. }
  392. pxi->Release();
  393. }
  394. *ppszIcon = pszIconPath;
  395. return hr;
  396. }
  397. HRESULT CUICommandOnPidl::get_Tooltip(IShellItemArray *psiItemArray, LPWSTR *ppszInfotip)
  398. {
  399. *ppszInfotip = NULL;
  400. if (_hinst && _idsName)
  401. {
  402. // TODO: load the string... but we have to fix dui to handle direct strings!
  403. return E_NOTIMPL;
  404. }
  405. else
  406. return E_NOTIMPL;
  407. }
  408. HRESULT CUICommandOnPidl::get_CanonicalName(GUID* pguidCommandName)
  409. {
  410. *pguidCommandName = *_pguidCanonicalName;
  411. return S_OK;
  412. }
  413. HRESULT CUICommandOnPidl::get_State(IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  414. {
  415. *puisState = UIS_ENABLED;
  416. return S_OK;
  417. }
  418. HRESULT CUICommandOnPidl::Invoke(IIShellItemArray *psiItemArray, IBindCtx *pbc)
  419. {
  420. SHELLEXECUTEINFO sei = { 0 };
  421. sei.cbSize = sizeof(sei);
  422. sei.lpIDList = _pidlAbsolute;
  423. sei.fMask = SEE_MASK_IDLIST;
  424. sei.nShow = SW_SHOWNORMAL;
  425. return ShellExecuteEx(&sei) ? S_OK : E_FAIL;
  426. }
  427. #endif // } CUICommandOnPidl may come back for RC1
  428. class CEnumUICommand : public IEnumUICommand
  429. {
  430. public:
  431. STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
  432. STDMETHODIMP_(ULONG) AddRef();
  433. STDMETHODIMP_(ULONG) Release();
  434. // IEnumUICommand
  435. STDMETHODIMP Next(ULONG celt, IUICommand** pUICommand, ULONG *pceltFetched);
  436. STDMETHODIMP Skip(ULONG celt);
  437. STDMETHODIMP Reset();
  438. STDMETHODIMP Clone(IEnumUICommand **ppenum);
  439. friend HRESULT Create_IEnumUICommandWithArray(IUnknown *pv, const WVTASKITEM* rgwvti, UINT cwvti, IUICommand** rguiCommand, UINT cuiCommand, IEnumUICommand**ppenum);
  440. private:
  441. CEnumUICommand(IUnknown *pv, const WVTASKITEM* rgwvti, ULONG cwvti, IUICommand** rguiCommand, UINT cuiCommand);
  442. ~CEnumUICommand();
  443. LONG _cRef;
  444. IUnknown* _pv;
  445. const WVTASKITEM* _rgwvti;
  446. ULONG _cItems;
  447. IUICommand** _prguiCommand;
  448. ULONG _cuiCommand;
  449. ULONG _ulIndex;
  450. };
  451. HRESULT Create_IEnumUICommandWithArray(IUnknown *pv, const WVTASKITEM* rgwvti, UINT cwvti, IUICommand** rguiCommand, UINT cuiCommand, IEnumUICommand**ppenum)
  452. {
  453. HRESULT hr;
  454. if (NULL!=rgwvti)
  455. {
  456. CEnumUICommand* p = new CEnumUICommand(pv, rgwvti, cwvti, rguiCommand, cuiCommand);
  457. if (p)
  458. {
  459. hr = p->QueryInterface(IID_PPV_ARG(IEnumUICommand, ppenum));
  460. p->Release();
  461. }
  462. else
  463. {
  464. hr = E_OUTOFMEMORY;
  465. *ppenum = NULL;
  466. }
  467. }
  468. else
  469. {
  470. TraceMsg(TF_WARNING, "Create_IEnumUICommand: caller passed in bad pwvti.");
  471. hr = E_INVALIDARG;
  472. *ppenum = NULL;
  473. }
  474. return hr;
  475. }
  476. HRESULT Create_IEnumUICommand(IUnknown *pv, const WVTASKITEM* rgwvti, UINT cwvti, IEnumUICommand**ppenum)
  477. {
  478. return Create_IEnumUICommandWithArray(pv, rgwvti, cwvti, NULL, 0, ppenum);
  479. }
  480. CEnumUICommand::CEnumUICommand(IUnknown *pv, const WVTASKITEM* rgwvti, ULONG cwvti, IUICommand** rguiCommand, UINT cuiCommand)
  481. {
  482. if (pv)
  483. {
  484. _pv = pv;
  485. _pv->AddRef();
  486. }
  487. _rgwvti = rgwvti;
  488. _cItems = cwvti;
  489. if (cuiCommand)
  490. {
  491. _prguiCommand = (IUICommand**)LocalAlloc(LPTR, cuiCommand*sizeof(IUICommand*));
  492. if (_prguiCommand)
  493. {
  494. for (UINT i = 0 ; i < cuiCommand && rguiCommand[i]; i++)
  495. {
  496. _prguiCommand[i] = rguiCommand[i];
  497. _prguiCommand[i]->AddRef();
  498. }
  499. _cuiCommand = i;
  500. }
  501. }
  502. _cRef = 1;
  503. }
  504. CEnumUICommand::~CEnumUICommand()
  505. {
  506. if (_pv)
  507. _pv->Release();
  508. if (_prguiCommand)
  509. {
  510. for (UINT i = 0 ; i < _cuiCommand ; i++)
  511. _prguiCommand[i]->Release();
  512. LocalFree(_prguiCommand);
  513. }
  514. }
  515. HRESULT CEnumUICommand::QueryInterface(REFIID riid, void **ppv)
  516. {
  517. static const QITAB qit[] = {
  518. QITABENT(CEnumUICommand, IEnumUICommand),
  519. { 0 },
  520. };
  521. return QISearch(this, qit, riid, ppv);
  522. }
  523. ULONG CEnumUICommand::AddRef()
  524. {
  525. return InterlockedIncrement(&_cRef);
  526. }
  527. ULONG CEnumUICommand::Release()
  528. {
  529. if (InterlockedDecrement(&_cRef))
  530. return _cRef;
  531. delete this;
  532. return 0;
  533. }
  534. HRESULT CEnumUICommand::Next(ULONG celt, IUICommand** ppUICommand, ULONG *pceltFetched)
  535. {
  536. HRESULT hr;
  537. if (_ulIndex < _cItems)
  538. {
  539. hr = Create_IUICommand(_pv, &_rgwvti[_ulIndex++], ppUICommand);
  540. }
  541. else if (_ulIndex < _cItems + _cuiCommand)
  542. {
  543. *ppUICommand = _prguiCommand[_ulIndex++ - _cItems];
  544. (*ppUICommand)->AddRef();
  545. hr = S_OK;
  546. }
  547. else
  548. {
  549. *ppUICommand = NULL;
  550. hr = S_FALSE;
  551. }
  552. if (pceltFetched)
  553. *pceltFetched = (hr == S_OK) ? 1 : 0;
  554. return hr;
  555. }
  556. HRESULT CEnumUICommand::Skip(ULONG celt)
  557. {
  558. _ulIndex = min(_cItems, _ulIndex+celt);
  559. return S_OK;
  560. }
  561. HRESULT CEnumUICommand::Reset()
  562. {
  563. _ulIndex = 0;
  564. return S_OK;
  565. }
  566. HRESULT CEnumUICommand::Clone(IEnumUICommand **ppenum)
  567. {
  568. *ppenum = NULL;
  569. return E_NOTIMPL;
  570. }