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.

479 lines
14 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. hr = StringCchPrintf(psz, cch, L"%s,-%u", pTask->pszDllName, dwIndex);
  21. }
  22. else
  23. {
  24. hr = StringCchPrintf(psz, cch, L"@%s,-%u", pTask->pszDllName, dwIndex);
  25. if (SUCCEEDED(hr))
  26. {
  27. hr = SHLoadIndirectString(psz, psz, cch, NULL);
  28. }
  29. }
  30. if (FAILED(hr))
  31. {
  32. CoTaskMemFree(psz);
  33. psz = NULL;
  34. }
  35. }
  36. else
  37. {
  38. hr = E_OUTOFMEMORY;
  39. }
  40. *ppsz = psz;
  41. return hr;
  42. }
  43. #define SS_UNKNOWN 0
  44. #define SS_NOTSUPPORTED 1
  45. #define SS_NONE 2
  46. #define SS_FILE 3
  47. #define SS_FOLDER 4
  48. #define SS_MULTI 5
  49. DWORD CWVTASKITEM::_GetSelectionState(const WVTASKITEM* pTask, IShellItemArray *psiItemArray)
  50. {
  51. DWORD dwSelectionState;
  52. DWORD cItems = 0;
  53. if (psiItemArray)
  54. {
  55. if (FAILED(psiItemArray->GetCount(&cItems)))
  56. {
  57. cItems = 0;
  58. }
  59. }
  60. switch (cItems)
  61. {
  62. case 0:
  63. dwSelectionState = SS_NONE;
  64. break;
  65. case 1:
  66. {
  67. DWORD dwAttribs = 0;
  68. if (psiItemArray)
  69. {
  70. if (FAILED(psiItemArray->GetAttributes(SIATTRIBFLAGS_AND, SFGAO_FOLDER|SFGAO_STREAM,&dwAttribs)))
  71. {
  72. dwAttribs = 0;
  73. }
  74. }
  75. switch (dwAttribs)
  76. {
  77. case SFGAO_FOLDER:
  78. dwSelectionState = SS_FOLDER;
  79. break;
  80. case SFGAO_FOLDER|SFGAO_STREAM:
  81. // zip and cab files are the only things that get here.
  82. // we'll call them files unless somebody has a better idea
  83. // (SS_MULTI has plurality that sounds funny).
  84. // fall through
  85. default:
  86. dwSelectionState = SS_FILE;
  87. break;
  88. }
  89. }
  90. break;
  91. default:
  92. dwSelectionState = SS_MULTI;
  93. break;
  94. }
  95. if ((SS_NONE == dwSelectionState && 0 == pTask->dwTitleIndexNoSelection) ||
  96. (SS_FILE == dwSelectionState && 0 == pTask->dwTitleIndexFileSelected) ||
  97. (SS_FOLDER == dwSelectionState && 0 == pTask->dwTitleIndexFolderSelected) ||
  98. (SS_MULTI == dwSelectionState && 0 == pTask->dwTitleIndexMultiSelected))
  99. {
  100. dwSelectionState = SS_NOTSUPPORTED;
  101. }
  102. return dwSelectionState;
  103. }
  104. HRESULT CWVTASKITEM::get_Name(const WVTASKITEM* pTask, IShellItemArray *psiItemArray, LPWSTR *ppszName)
  105. {
  106. DWORD dwSelState = _GetSelectionState(pTask, psiItemArray);
  107. switch (dwSelState)
  108. {
  109. case SS_NONE: return _get_String(pTask, pTask->dwTitleIndexNoSelection, ppszName, MAX_PATH, FALSE);
  110. case SS_FILE: return _get_String(pTask, pTask->dwTitleIndexFileSelected, ppszName, MAX_PATH, FALSE);
  111. case SS_FOLDER: return _get_String(pTask, pTask->dwTitleIndexFolderSelected, ppszName, MAX_PATH, FALSE);
  112. case SS_MULTI: return _get_String(pTask, pTask->dwTitleIndexMultiSelected, ppszName, MAX_PATH, FALSE);
  113. }
  114. *ppszName = NULL;
  115. return E_NOTIMPL;
  116. }
  117. HRESULT CWVTASKITEM::get_Icon(const WVTASKITEM* pTask, IShellItemArray *psiItemArray, LPWSTR *ppszIcon)
  118. {
  119. return _get_String(pTask, pTask->dwIconIndex, ppszIcon, 0, TRUE);
  120. }
  121. HRESULT CWVTASKITEM::get_Tooltip(const WVTASKITEM* pTask, IShellItemArray *psiItemArray, LPWSTR *ppszInfotip)
  122. {
  123. return _get_String(pTask, pTask->dwTooltipIndex, ppszInfotip, INFOTIPSIZE, FALSE);
  124. }
  125. HRESULT CWVTASKITEM::get_CanonicalName(const WVTASKITEM* pTask, GUID* pguidCommandName)
  126. {
  127. *pguidCommandName = *(pTask->pguidCanonicalName);
  128. return S_OK;
  129. }
  130. HRESULT CWVTASKITEM::get_State(const WVTASKITEM* pTask, IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  131. {
  132. HRESULT hr = S_OK;
  133. *puisState = UIS_DISABLED;
  134. if (_GetSelectionState(pTask, psiItemArray) != SS_NOTSUPPORTED)
  135. {
  136. if (pTask->pfn_get_State)
  137. hr = pTask->pfn_get_State(pv, psiItemArray, fOkToBeSlow, puisState);
  138. else
  139. *puisState = UIS_ENABLED;
  140. }
  141. return hr;
  142. }
  143. HRESULT CWVTASKITEM::Invoke(const WVTASKITEM* pTask, IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  144. {
  145. return pTask->pfn_Invoke(pv, psiItemArray, pbc);
  146. }
  147. class CUIElement : public CWVTASKITEM, public IUIElement
  148. {
  149. public:
  150. STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
  151. STDMETHODIMP_(ULONG) AddRef();
  152. STDMETHODIMP_(ULONG) Release();
  153. // IUIElement
  154. STDMETHODIMP get_Name(IShellItemArray *psiItemArray, LPWSTR *ppszName) {return CWVTASKITEM::get_Name(_pTask, psiItemArray, ppszName);}
  155. STDMETHODIMP get_Icon(IShellItemArray *psiItemArray, LPWSTR *ppszIcon) {return CWVTASKITEM::get_Icon(_pTask, psiItemArray, ppszIcon);}
  156. STDMETHODIMP get_Tooltip(IShellItemArray *psiItemArray, LPWSTR *ppszInfotip) {return CWVTASKITEM::get_Tooltip(_pTask, psiItemArray, ppszInfotip);}
  157. friend HRESULT Create_IUIElement(const WVTASKITEM* pwvti, IUIElement**ppuie);
  158. protected:
  159. CUIElement(const WVTASKITEM* pTask) { _cRef = 1; _pTask=pTask; }
  160. ~CUIElement() {}
  161. LONG _cRef;
  162. const WVTASKITEM* _pTask;
  163. };
  164. HRESULT Create_IUIElement(const WVTASKITEM* pwvti, IUIElement**ppuie)
  165. {
  166. HRESULT hr;
  167. if (NULL!=pwvti)
  168. {
  169. CUIElement* p = new CUIElement(pwvti);
  170. if (p)
  171. {
  172. hr = p->QueryInterface(IID_PPV_ARG(IUIElement, ppuie));
  173. p->Release();
  174. }
  175. else
  176. {
  177. hr = E_OUTOFMEMORY;
  178. *ppuie = NULL;
  179. }
  180. }
  181. else
  182. {
  183. TraceMsg(TF_WARNING, "Create_IUIElement: caller passed in bad pwvti.");
  184. hr = E_INVALIDARG;
  185. *ppuie = NULL;
  186. }
  187. return hr;
  188. }
  189. HRESULT CUIElement::QueryInterface(REFIID riid, void **ppv)
  190. {
  191. static const QITAB qit[] = {
  192. QITABENT(CUIElement, IUIElement),
  193. { 0 },
  194. };
  195. return QISearch(this, qit, riid, ppv);
  196. }
  197. ULONG CUIElement::AddRef()
  198. {
  199. return InterlockedIncrement(&_cRef);
  200. }
  201. ULONG CUIElement::Release()
  202. {
  203. ASSERT( 0 != _cRef );
  204. ULONG cRef = InterlockedDecrement(&_cRef);
  205. if ( 0 == cRef )
  206. {
  207. delete this;
  208. }
  209. return cRef;
  210. }
  211. class CUICommand : public CUIElement, public IUICommand
  212. {
  213. public:
  214. STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
  215. STDMETHODIMP_(ULONG) AddRef() { return CUIElement::AddRef(); }
  216. STDMETHODIMP_(ULONG) Release() { return CUIElement::Release(); }
  217. // IUICommand
  218. STDMETHODIMP get_Name(IShellItemArray *psiItemArray, LPWSTR *ppszName) { return CUIElement::get_Name(psiItemArray, ppszName); }
  219. STDMETHODIMP get_Icon(IShellItemArray *psiItemArray, LPWSTR *ppszIcon) { return CUIElement::get_Icon(psiItemArray, ppszIcon); }
  220. STDMETHODIMP get_Tooltip(IShellItemArray *psiItemArray, LPWSTR *ppszInfotip) { return CUIElement::get_Tooltip(psiItemArray, ppszInfotip); }
  221. STDMETHODIMP get_CanonicalName(GUID* pguidCommandName) { return CWVTASKITEM::get_CanonicalName(_pTask, pguidCommandName); }
  222. STDMETHODIMP get_State(IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState) { return CWVTASKITEM::get_State(_pTask, _pv, psiItemArray, fOkToBeSlow, puisState); }
  223. STDMETHODIMP Invoke(IShellItemArray *psiItemArray, IBindCtx *pbc) { return CWVTASKITEM::Invoke(_pTask, _pv, psiItemArray, pbc); }
  224. friend HRESULT Create_IUICommand(IUnknown* pv, const WVTASKITEM* pwvti, IUICommand**ppuic);
  225. private:
  226. CUICommand(IUnknown* pv, const WVTASKITEM* pTask);
  227. ~CUICommand();
  228. IUnknown* _pv;
  229. };
  230. HRESULT Create_IUICommand(IUnknown* pv, const WVTASKITEM* pwvti, IUICommand**ppuic)
  231. {
  232. HRESULT hr;
  233. if (NULL!=pwvti)
  234. {
  235. CUICommand* p = new CUICommand(pv, pwvti);
  236. if (p)
  237. {
  238. hr = p->QueryInterface(IID_PPV_ARG(IUICommand, ppuic));
  239. p->Release();
  240. }
  241. else
  242. {
  243. hr = E_OUTOFMEMORY;
  244. *ppuic = NULL;
  245. }
  246. }
  247. else
  248. {
  249. TraceMsg(TF_WARNING, "Create_IUICommand: caller passed in bad pwvti.");
  250. hr = E_INVALIDARG;
  251. *ppuic = NULL;
  252. }
  253. return hr;
  254. }
  255. CUICommand::CUICommand(IUnknown* pv, const WVTASKITEM* pTask)
  256. : CUIElement(pTask)
  257. {
  258. _pv = pv;
  259. if (_pv)
  260. _pv->AddRef();
  261. }
  262. CUICommand::~CUICommand()
  263. {
  264. if (_pv)
  265. _pv->Release();
  266. }
  267. HRESULT CUICommand::QueryInterface(REFIID riid, void **ppv)
  268. {
  269. static const QITAB qit[] = {
  270. QITABENT(CUICommand, IUICommand),
  271. QITABENTMULTI(CUICommand, IUIElement, IUICommand),
  272. { 0 },
  273. };
  274. return QISearch(this, qit, riid, ppv);
  275. }
  276. class CEnumUICommand : public IEnumUICommand
  277. {
  278. public:
  279. STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
  280. STDMETHODIMP_(ULONG) AddRef();
  281. STDMETHODIMP_(ULONG) Release();
  282. // IEnumUICommand
  283. STDMETHODIMP Next(ULONG celt, IUICommand** pUICommand, ULONG *pceltFetched);
  284. STDMETHODIMP Skip(ULONG celt);
  285. STDMETHODIMP Reset();
  286. STDMETHODIMP Clone(IEnumUICommand **ppenum);
  287. friend HRESULT Create_IEnumUICommandWithArray(IUnknown *pv, const WVTASKITEM* rgwvti, UINT cwvti, IUICommand** rguiCommand, UINT cuiCommand, IEnumUICommand**ppenum);
  288. private:
  289. CEnumUICommand(IUnknown *pv, const WVTASKITEM* rgwvti, ULONG cwvti, IUICommand** rguiCommand, UINT cuiCommand);
  290. ~CEnumUICommand();
  291. LONG _cRef;
  292. IUnknown* _pv;
  293. const WVTASKITEM* _rgwvti;
  294. ULONG _cItems;
  295. IUICommand** _prguiCommand;
  296. ULONG _cuiCommand;
  297. ULONG _ulIndex;
  298. };
  299. HRESULT Create_IEnumUICommandWithArray(IUnknown *pv, const WVTASKITEM* rgwvti, UINT cwvti, IUICommand** rguiCommand, UINT cuiCommand, IEnumUICommand**ppenum)
  300. {
  301. HRESULT hr;
  302. if (NULL!=rgwvti)
  303. {
  304. CEnumUICommand* p = new CEnumUICommand(pv, rgwvti, cwvti, rguiCommand, cuiCommand);
  305. if (p)
  306. {
  307. hr = p->QueryInterface(IID_PPV_ARG(IEnumUICommand, ppenum));
  308. p->Release();
  309. }
  310. else
  311. {
  312. hr = E_OUTOFMEMORY;
  313. *ppenum = NULL;
  314. }
  315. }
  316. else
  317. {
  318. TraceMsg(TF_WARNING, "Create_IEnumUICommand: caller passed in bad pwvti.");
  319. hr = E_INVALIDARG;
  320. *ppenum = NULL;
  321. }
  322. return hr;
  323. }
  324. HRESULT Create_IEnumUICommand(IUnknown *pv, const WVTASKITEM* rgwvti, UINT cwvti, IEnumUICommand**ppenum)
  325. {
  326. return Create_IEnumUICommandWithArray(pv, rgwvti, cwvti, NULL, 0, ppenum);
  327. }
  328. CEnumUICommand::CEnumUICommand(IUnknown *pv, const WVTASKITEM* rgwvti, ULONG cwvti, IUICommand** rguiCommand, UINT cuiCommand)
  329. {
  330. if (pv)
  331. {
  332. _pv = pv;
  333. _pv->AddRef();
  334. }
  335. _rgwvti = rgwvti;
  336. _cItems = cwvti;
  337. if (cuiCommand)
  338. {
  339. _prguiCommand = (IUICommand**)LocalAlloc(LPTR, cuiCommand*sizeof(IUICommand*));
  340. if (_prguiCommand)
  341. {
  342. for (UINT i = 0 ; i < cuiCommand && rguiCommand[i]; i++)
  343. {
  344. _prguiCommand[i] = rguiCommand[i];
  345. _prguiCommand[i]->AddRef();
  346. }
  347. _cuiCommand = i;
  348. }
  349. }
  350. _cRef = 1;
  351. }
  352. CEnumUICommand::~CEnumUICommand()
  353. {
  354. if (_pv)
  355. _pv->Release();
  356. if (_prguiCommand)
  357. {
  358. for (UINT i = 0 ; i < _cuiCommand ; i++)
  359. _prguiCommand[i]->Release();
  360. LocalFree(_prguiCommand);
  361. }
  362. }
  363. HRESULT CEnumUICommand::QueryInterface(REFIID riid, void **ppv)
  364. {
  365. static const QITAB qit[] = {
  366. QITABENT(CEnumUICommand, IEnumUICommand),
  367. { 0 },
  368. };
  369. return QISearch(this, qit, riid, ppv);
  370. }
  371. ULONG CEnumUICommand::AddRef()
  372. {
  373. return InterlockedIncrement(&_cRef);
  374. }
  375. ULONG CEnumUICommand::Release()
  376. {
  377. ASSERT( 0 != _cRef );
  378. ULONG cRef = InterlockedDecrement(&_cRef);
  379. if ( 0 == cRef )
  380. {
  381. delete this;
  382. }
  383. return cRef;
  384. }
  385. HRESULT CEnumUICommand::Next(ULONG celt, IUICommand** ppUICommand, ULONG *pceltFetched)
  386. {
  387. HRESULT hr;
  388. if (_ulIndex < _cItems)
  389. {
  390. hr = Create_IUICommand(_pv, &_rgwvti[_ulIndex++], ppUICommand);
  391. }
  392. else if (_ulIndex < _cItems + _cuiCommand)
  393. {
  394. *ppUICommand = _prguiCommand[_ulIndex++ - _cItems];
  395. (*ppUICommand)->AddRef();
  396. hr = S_OK;
  397. }
  398. else
  399. {
  400. *ppUICommand = NULL;
  401. hr = S_FALSE;
  402. }
  403. if (pceltFetched)
  404. *pceltFetched = (hr == S_OK) ? 1 : 0;
  405. return hr;
  406. }
  407. HRESULT CEnumUICommand::Skip(ULONG celt)
  408. {
  409. _ulIndex = min(_cItems, _ulIndex+celt);
  410. return S_OK;
  411. }
  412. HRESULT CEnumUICommand::Reset()
  413. {
  414. _ulIndex = 0;
  415. return S_OK;
  416. }
  417. HRESULT CEnumUICommand::Clone(IEnumUICommand **ppenum)
  418. {
  419. *ppenum = NULL;
  420. return E_NOTIMPL;
  421. }