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.

516 lines
10 KiB

  1. /*++
  2. Implements IEnumIDList.
  3. --*/
  4. #include <windows.h>
  5. #include <shlobj.h>
  6. #include "pstore.h"
  7. #include "utility.h"
  8. #include "enumid.h"
  9. #include "shfolder.h"
  10. extern LONG g_DllRefCount;
  11. CEnumIDList::CEnumIDList(
  12. LPITEMIDLIST pidl,
  13. BOOL bEnumItems
  14. )
  15. {
  16. m_pIEnumProviders = NULL;
  17. m_pIPStoreProvider = NULL;
  18. m_pIEnumTypes = NULL;
  19. m_pIEnumTypesGlobal = NULL;
  20. m_pIEnumSubtypes = NULL;
  21. m_pIEnumItems = NULL;
  22. m_bEnumItems = bEnumItems;
  23. //
  24. // get the shell's IMalloc pointer
  25. // we'll keep this until we get destroyed
  26. //
  27. if(FAILED(SHGetMalloc(&m_pMalloc)))
  28. delete this;
  29. m_KeyType = PST_KEY_CURRENT_USER;
  30. if(pidl == NULL) {
  31. if( PStoreEnumProviders(0, &m_pIEnumProviders) != S_OK )
  32. m_pIEnumProviders = NULL;
  33. m_dwType = PIDL_TYPE_PROVIDER; // top-level
  34. } else {
  35. m_dwType = GetLastPidlType(pidl) + 1; // parent + 1
  36. }
  37. //
  38. // get provider interface
  39. //
  40. if(m_dwType > PIDL_TYPE_PROVIDER) {
  41. PST_PROVIDERID *ProviderId = GetPidlGuid(pidl);
  42. if(PStoreCreateInstance(&m_pIPStoreProvider, ProviderId, NULL, 0) != S_OK)
  43. m_pIPStoreProvider = NULL;
  44. }
  45. //
  46. // prepare two type enumerators, if appropriate:
  47. // PST_KEY_CURRENT_USER and PST_KEY_LOCAL_MACHINE
  48. //
  49. if(m_dwType == PIDL_TYPE_TYPE && m_pIPStoreProvider) {
  50. m_pIPStoreProvider->EnumTypes(PST_KEY_CURRENT_USER, 0, &m_pIEnumTypes);
  51. m_pIPStoreProvider->EnumTypes(PST_KEY_LOCAL_MACHINE, 0, &m_pIEnumTypesGlobal);
  52. }
  53. //
  54. // prepare subtype enumerator
  55. //
  56. if(m_dwType == PIDL_TYPE_SUBTYPE && m_pIPStoreProvider) {
  57. GUID *pguidType;
  58. m_KeyType = GetLastPidlKeyType(pidl);
  59. pguidType = GetLastPidlGuid(pidl);
  60. CopyMemory(&m_guidType, pguidType, sizeof(GUID));
  61. m_pIPStoreProvider->EnumSubtypes(
  62. m_KeyType,
  63. pguidType,
  64. 0,
  65. &m_pIEnumSubtypes
  66. );
  67. }
  68. //
  69. // prepare item enumerator if appropriate.
  70. //
  71. if(m_dwType == PIDL_TYPE_ITEM && m_bEnumItems && m_pIPStoreProvider) {
  72. GUID *pguidType;
  73. GUID *pguidSubtype;
  74. m_KeyType = GetLastPidlKeyType(pidl);
  75. pguidSubtype = GetLastPidlGuid(pidl);
  76. CopyMemory(&m_guidSubtype, pguidSubtype, sizeof(GUID));
  77. pguidType = GetPidlGuid(SearchPidlByType(pidl, PIDL_TYPE_TYPE));
  78. CopyMemory(&m_guidType, pguidType, sizeof(GUID));
  79. m_pIPStoreProvider->EnumItems(
  80. m_KeyType,
  81. pguidType,
  82. pguidSubtype,
  83. 0,
  84. &m_pIEnumItems
  85. );
  86. }
  87. m_ulCurrent = 0;
  88. m_ObjRefCount = 1;
  89. InterlockedIncrement(&g_DllRefCount);
  90. }
  91. CEnumIDList::~CEnumIDList()
  92. {
  93. //
  94. // free any interfaces we established.
  95. //
  96. if(m_pIEnumProviders) {
  97. m_pIEnumProviders->Release();
  98. m_pIEnumProviders = NULL;
  99. }
  100. if(m_pIPStoreProvider) {
  101. m_pIPStoreProvider->Release();
  102. m_pIPStoreProvider = NULL;
  103. }
  104. if(m_pIEnumTypes) {
  105. m_pIEnumTypes->Release();
  106. m_pIEnumTypes = NULL;
  107. }
  108. if(m_pIEnumTypesGlobal) {
  109. m_pIEnumTypesGlobal->Release();
  110. m_pIEnumTypesGlobal = NULL;
  111. }
  112. if(m_pIEnumSubtypes) {
  113. m_pIEnumSubtypes->Release();
  114. m_pIEnumSubtypes = NULL;
  115. }
  116. if(m_pIEnumItems) {
  117. m_pIEnumItems->Release();
  118. m_pIEnumItems = NULL;
  119. }
  120. if(m_pMalloc) {
  121. m_pMalloc->Release();
  122. m_pMalloc = NULL;
  123. }
  124. InterlockedDecrement(&g_DllRefCount);
  125. }
  126. STDMETHODIMP
  127. CEnumIDList::QueryInterface(
  128. REFIID riid,
  129. LPVOID *ppReturn
  130. )
  131. {
  132. *ppReturn = NULL;
  133. if(IsEqualIID(riid, IID_IUnknown))
  134. *ppReturn = (IUnknown*)(CEnumIDList*)this;
  135. else if(IsEqualIID(riid, IID_IEnumIDList))
  136. *ppReturn = (CEnumIDList*)this;
  137. if(*ppReturn == NULL)
  138. return E_NOINTERFACE;
  139. (*(LPUNKNOWN*)ppReturn)->AddRef();
  140. return S_OK;
  141. }
  142. STDMETHODIMP_(DWORD)
  143. CEnumIDList::AddRef()
  144. {
  145. return InterlockedIncrement(&m_ObjRefCount);
  146. }
  147. STDMETHODIMP_(DWORD)
  148. CEnumIDList::Release()
  149. {
  150. LONG lDecremented = InterlockedDecrement(&m_ObjRefCount);
  151. if(lDecremented == 0)
  152. delete this;
  153. return lDecremented;
  154. }
  155. STDMETHODIMP
  156. CEnumIDList::Next(
  157. ULONG ulElements,
  158. LPITEMIDLIST *pPidl,
  159. ULONG *pulFetched
  160. )
  161. /*++
  162. Retrieves the specified number of item identifiers in the enumeration
  163. sequence and advances the current position.
  164. Returns the NOERROR value if successful,
  165. Returns S_FALSE value if there are no more items in the enumeration
  166. or an OLE-defined error value if an error occurs.
  167. --*/
  168. {
  169. HRESULT hr;
  170. *pPidl = NULL;
  171. *pulFetched = 0;
  172. if(m_bEnumItems) {
  173. if(m_dwType > PIDL_TYPE_ITEM)
  174. return S_FALSE;
  175. } else {
  176. if(m_dwType > PIDL_TYPE_SUBTYPE)
  177. return S_FALSE; // nothing left to enumerate
  178. }
  179. if(m_dwType == PIDL_TYPE_PROVIDER && m_pIEnumProviders)
  180. {
  181. PPST_PROVIDERINFO pProvInfo;
  182. if( m_pIEnumProviders->Next(1, &pProvInfo, &m_ulCurrent) != S_OK ) {
  183. //
  184. // enumeration of providers complete
  185. //
  186. return S_FALSE;
  187. }
  188. hr = CreateIDList(m_dwType, m_KeyType, &(pProvInfo->ID), pProvInfo->szProviderName, pPidl);
  189. CoTaskMemFree(pProvInfo);
  190. if(hr != S_OK)
  191. return S_FALSE;
  192. *pulFetched = 1;
  193. return NOERROR;
  194. }
  195. //
  196. // must have a valid provider interface at this point
  197. //
  198. if(m_pIPStoreProvider == NULL)
  199. return S_FALSE;
  200. if(m_dwType == PIDL_TYPE_TYPE) {
  201. IEnumPStoreTypes *pIEnumTypes;
  202. PST_KEY KeyType = PST_KEY_CURRENT_USER;
  203. GUID guidType;
  204. type_enum:
  205. if(KeyType == PST_KEY_LOCAL_MACHINE)
  206. pIEnumTypes = m_pIEnumTypesGlobal;
  207. else
  208. pIEnumTypes = m_pIEnumTypes;
  209. if(pIEnumTypes == NULL)
  210. return S_FALSE;
  211. if(pIEnumTypes->Next(1, &guidType, &m_ulCurrent) != S_OK) {
  212. //
  213. // if enumeration at PST_KEY_CURRENT_USER level complete,
  214. // continue at the PST_KEY_LOCAL_MACHINE level.
  215. //
  216. if(KeyType == PST_KEY_CURRENT_USER) {
  217. KeyType = PST_KEY_LOCAL_MACHINE;
  218. goto type_enum;
  219. }
  220. //
  221. // enumeration of types complete
  222. //
  223. return S_FALSE;
  224. }
  225. PST_TYPEINFO *pTypeInfo = NULL;
  226. if(S_OK != m_pIPStoreProvider->GetTypeInfo(
  227. KeyType,
  228. &guidType,
  229. &pTypeInfo,
  230. 0
  231. )) return S_FALSE;
  232. hr = CreateIDList(m_dwType, KeyType, &guidType, pTypeInfo->szDisplayName, pPidl);
  233. //
  234. // free pTypeInfo data
  235. //
  236. CoTaskMemFree(pTypeInfo);
  237. if(hr != S_OK)
  238. return S_FALSE;
  239. *pulFetched = 1;
  240. return NOERROR;
  241. }
  242. if (m_dwType == PIDL_TYPE_SUBTYPE && m_pIEnumSubtypes) {
  243. GUID guidSubtype;
  244. GUID *pguidType = &m_guidType;
  245. if(m_pIEnumSubtypes->Next(1, &guidSubtype, &m_ulCurrent) != S_OK) {
  246. //
  247. // enumeration of types complete
  248. //
  249. return S_FALSE;
  250. }
  251. PST_TYPEINFO *pTypeInfo = NULL;
  252. if(m_pIPStoreProvider->GetSubtypeInfo(m_KeyType, pguidType, &guidSubtype, &pTypeInfo, 0) != S_OK)
  253. return S_FALSE;
  254. hr = CreateIDList(m_dwType, m_KeyType, &guidSubtype, pTypeInfo->szDisplayName, pPidl);
  255. //
  256. // free pTypeInfo data
  257. //
  258. CoTaskMemFree(pTypeInfo);
  259. if(hr != S_OK)
  260. return S_FALSE;
  261. *pulFetched = 1;
  262. return NOERROR;
  263. }
  264. if(m_dwType == PIDL_TYPE_ITEM && m_pIEnumItems) {
  265. LPWSTR pszItem;
  266. //
  267. // enumerate and add items associated with specified subtype
  268. //
  269. if(m_pIEnumItems->Next(1, &pszItem, &m_ulCurrent) != S_OK) {
  270. //
  271. // enumeration of items complete
  272. //
  273. return S_FALSE;
  274. }
  275. hr = CreateIDList(
  276. m_dwType,
  277. m_KeyType,
  278. NULL, // no item guid
  279. pszItem,
  280. pPidl
  281. );
  282. //
  283. // free pszItem data
  284. //
  285. CoTaskMemFree(pszItem);
  286. if(hr != S_OK)
  287. return S_FALSE;
  288. *pulFetched = 1;
  289. return NOERROR;
  290. }
  291. return S_FALSE;
  292. }
  293. STDMETHODIMP
  294. CEnumIDList::CreateIDList(
  295. DWORD dwType,
  296. PST_KEY KeyType,
  297. GUID *guid,
  298. LPCWSTR szString,
  299. LPITEMIDLIST *pPidlOut
  300. )
  301. {
  302. DWORD cbString = 0;
  303. DWORD cbPidlContent;
  304. if(szString) {
  305. cbString = lstrlenW(szString);
  306. }
  307. cbString = (cbString + 1) * sizeof(WCHAR);
  308. cbPidlContent = sizeof(PIDL_CONTENT) + cbString;
  309. //
  310. // allocate the memory
  311. //
  312. *pPidlOut = (LPITEMIDLIST)m_pMalloc->Alloc(
  313. sizeof(ITEMIDLIST) + // this item's ITEMIDLIST
  314. cbPidlContent + // this item's data
  315. sizeof(ITEMIDLIST) // terminal ITEMIDLIST
  316. );
  317. if(*pPidlOut == NULL)
  318. return E_OUTOFMEMORY;
  319. LPITEMIDLIST pidlTemp = *pPidlOut;
  320. LPPIDL_CONTENT pidlContent = (LPPIDL_CONTENT)&(pidlTemp->mkid.abID);
  321. //
  322. // set the size of this item
  323. //
  324. pidlTemp->mkid.cb = (unsigned short)(sizeof(ITEMIDLIST) + cbPidlContent);
  325. //
  326. // set the data for this item
  327. //
  328. pidlContent->dwType = dwType;
  329. pidlContent->KeyType = KeyType;
  330. if( guid ) {
  331. CopyMemory(&(pidlContent->guid), guid, sizeof(GUID));
  332. } else {
  333. ZeroMemory(&(pidlContent->guid), sizeof(GUID));
  334. }
  335. if(szString) {
  336. CopyMemory((LPBYTE)(pidlContent+1), szString, cbString);
  337. } else {
  338. ((LPWSTR)(pidlContent+1))[0] = L'\0';
  339. }
  340. //
  341. // advance and terminate item ID list
  342. //
  343. pidlTemp = (LPITEMIDLIST)GetPidlNextItem(*pPidlOut);
  344. pidlTemp->mkid.cb = 0;
  345. pidlTemp->mkid.abID[0] = 0;
  346. return NOERROR;
  347. }
  348. STDMETHODIMP
  349. CEnumIDList::Skip(
  350. ULONG ulSkip
  351. )
  352. {
  353. m_ulCurrent += ulSkip;
  354. return NOERROR;
  355. }
  356. STDMETHODIMP
  357. CEnumIDList::Reset(
  358. void
  359. )
  360. {
  361. m_ulCurrent = 0;
  362. return NOERROR;
  363. }
  364. STDMETHODIMP
  365. CEnumIDList::Clone(
  366. LPENUMIDLIST *ppEnum
  367. )
  368. {
  369. return E_NOTIMPL;
  370. }