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.

495 lines
13 KiB

  1. #include "shellprv.h"
  2. #include "ftascstr.h" //for now, until CoCreateInstance
  3. #include "ftassoc.h" //for now, until CoCreate IAssocInfo
  4. #include "ftenum.h"
  5. #define EHKCR_NONE 0
  6. #define EHKCR_EXT 1
  7. #define EHKCR_PROGID 2
  8. ///////////////////////////////////////////////////////////////////////////////
  9. ///////////////////////////////////////////////////////////////////////////////
  10. // CFTEnumAssocInfo
  11. ///////////////////////////////////////////////////////////////////////////////
  12. // Contructor / Destructor
  13. CFTEnumAssocInfo::CFTEnumAssocInfo() : _cRef(1)
  14. {
  15. //DLLAddRef();
  16. }
  17. CFTEnumAssocInfo::~CFTEnumAssocInfo()
  18. {
  19. //DLLRelease();
  20. }
  21. ///////////////////////////////////////////////////////////////////////////////
  22. // IUnknown methods
  23. HRESULT CFTEnumAssocInfo::QueryInterface(REFIID riid, PVOID* ppv)
  24. {
  25. //nothing for now
  26. return E_NOTIMPL;
  27. }
  28. ULONG CFTEnumAssocInfo::AddRef()
  29. {
  30. return InterlockedIncrement(&_cRef);
  31. }
  32. ULONG CFTEnumAssocInfo::Release()
  33. {
  34. if (InterlockedDecrement(&_cRef) > 0)
  35. return _cRef;
  36. delete this;
  37. return 0;
  38. }
  39. ///////////////////////////////////////////////////////////////////////////////
  40. // IEnum methods
  41. HRESULT CFTEnumAssocInfo::Init(ASENUM asenumFlags, LPTSTR pszStr,
  42. AIINIT aiinitFlags)
  43. {
  44. HRESULT hres = E_INVALIDARG;
  45. if (((ASENUM_PROGID & asenumFlags) && !(ASENUM_EXT & asenumFlags)) ||
  46. (!(ASENUM_PROGID & asenumFlags) && (ASENUM_EXT & asenumFlags)) ||
  47. (ASENUM_ACTION & asenumFlags) )
  48. {
  49. hres = S_OK;
  50. _asenumFlags = asenumFlags;
  51. _aiinitFlags = aiinitFlags;
  52. if (pszStr)
  53. StrCpyN(_szInitStr, pszStr, ARRAYSIZE(_szInitStr));
  54. else
  55. _szInitStr[0] = 0;
  56. }
  57. return hres;
  58. }
  59. HRESULT CFTEnumAssocInfo::Next(IAssocInfo** ppAI)
  60. {
  61. HRESULT hres = E_FAIL;
  62. TCHAR szStr[MAX_FTMAX];
  63. DWORD cchStr = ARRAYSIZE(szStr);
  64. AIINIT aiinitFlags = 0;
  65. *szStr = 0;
  66. switch(_aiinitFlags)
  67. {
  68. // We go through the registry
  69. case AIINIT_NONE:
  70. {
  71. switch(_asenumFlags & ASENUM_MAINMASK)
  72. {
  73. case ASENUM_EXT:
  74. hres = _EnumHKCR(_asenumFlags, szStr, &cchStr);
  75. aiinitFlags = AIINIT_EXT;
  76. break;
  77. case ASENUM_PROGID:
  78. hres = _EnumHKCR(_asenumFlags, szStr, &cchStr);
  79. aiinitFlags = AIINIT_PROGID;
  80. break;
  81. default:
  82. hres = E_INVALIDARG;
  83. break;
  84. }
  85. break;
  86. }
  87. // In theory, we go through the value linked to a progID
  88. case AIINIT_PROGID:
  89. {
  90. switch(_asenumFlags & ASENUM_MAINMASK)
  91. {
  92. case ASENUM_EXT:
  93. hres = _EnumHKCR(_asenumFlags, szStr, &cchStr);
  94. aiinitFlags = AIINIT_EXT;
  95. break;
  96. case ASENUM_ACTION:
  97. hres = _EnumProgIDActions(szStr, &cchStr);
  98. break;
  99. default:
  100. hres = E_INVALIDARG;
  101. break;
  102. }
  103. break;
  104. }
  105. default:
  106. hres = E_INVALIDARG;
  107. break;
  108. }
  109. if (S_OK==hres)
  110. {
  111. if (*szStr)
  112. {
  113. *ppAI = new CFTAssocInfo();
  114. if (*ppAI)
  115. {
  116. if (ASENUM_ACTION != (_asenumFlags & ASENUM_MAINMASK))
  117. hres = (*ppAI)->Init(aiinitFlags, szStr);
  118. else
  119. hres = (*ppAI)->InitComplex(AIINIT_PROGID, _szInitStr, AIINIT_ACTION, szStr);
  120. }
  121. else
  122. hres = E_OUTOFMEMORY;
  123. }
  124. else
  125. hres = E_FAIL;
  126. }
  127. return hres;
  128. }
  129. // This beast goes through the HKCR reg key and check that the
  130. // key meets the criteria of dwFlags (mostly extension vs progID)
  131. HRESULT CFTEnumAssocInfo::_EnumHKCR(ASENUM asenumFlags, LPTSTR pszStr,
  132. DWORD* pcchStr)
  133. {
  134. HRESULT hres = E_FAIL;
  135. BOOL fNext = TRUE;
  136. while (fNext)
  137. {
  138. // This will mean "no more item"
  139. hres = S_FALSE;
  140. DWORD cchStr = *pcchStr;
  141. LONG lRes = RegEnumKeyEx(HKEY_CLASSES_ROOT, _dwIndex, pszStr, &cchStr, NULL, NULL,
  142. NULL, NULL);
  143. ++_dwIndex;
  144. if (lRes != ERROR_NO_MORE_ITEMS)
  145. {
  146. if (TEXT('*') != *pszStr)
  147. {
  148. if (!_EnumKCRStop(asenumFlags, pszStr))
  149. {
  150. if (!_EnumKCRSkip(asenumFlags, pszStr))
  151. {
  152. hres = S_OK;
  153. fNext = FALSE;
  154. }
  155. }
  156. else
  157. {
  158. hres = S_FALSE;
  159. fNext = FALSE;
  160. }
  161. }
  162. }
  163. else
  164. {
  165. fNext = FALSE;
  166. }
  167. }
  168. // Did we found the first ext?
  169. if (!_fFirstExtFound && S_OK==hres && (TEXT('.') == *pszStr))
  170. {
  171. // Yes
  172. _fFirstExtFound = TRUE;
  173. }
  174. return hres;
  175. }
  176. HRESULT CFTEnumAssocInfo::_EnumProgIDActions(LPTSTR pszStr, DWORD* pcchStr)
  177. {
  178. // 5 for "shell"
  179. TCHAR szSubKey[MAX_PROGID + 5 + 1];
  180. HRESULT hres = S_OK;
  181. HKEY hKey = NULL;
  182. StrCpyN(szSubKey, _szInitStr, MAX_PROGID);
  183. StrCat(szSubKey, TEXT("\\shell"));
  184. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, szSubKey, 0, KEY_READ, &hKey))
  185. {
  186. LONG lRes = RegEnumKeyEx(hKey, _dwIndex, pszStr, pcchStr, NULL,
  187. NULL, NULL, NULL);
  188. if (ERROR_SUCCESS !=lRes)
  189. {
  190. if (ERROR_NO_MORE_ITEMS == lRes)
  191. hres = S_FALSE;
  192. else
  193. hres = E_FAIL;
  194. }
  195. #if 0
  196. else
  197. {
  198. TCHAR szNiceText[MAX_ACTIONDESCR];
  199. LONG lNiceText = ARRAYSIZE(szNiceText);
  200. #endif
  201. ++_dwIndex;
  202. #if 0
  203. // Check if there is nice text for the action
  204. if ((ERROR_SUCCESS == SHRegQueryValue(hKey, pszStr, szNiceText,
  205. &lNiceText)) && (lNiceText > SIZEOF(TCHAR)))
  206. {
  207. StrCpyN(pszStr, szNiceText, ARRAYSIZE(pszStr));
  208. }
  209. }
  210. #endif
  211. RegCloseKey(hKey);
  212. }
  213. return hres;
  214. }
  215. ///////////////////////////////////////////////////////////////////////////////
  216. // Helpers
  217. BOOL CFTEnumAssocInfo::_EnumKCRSkip(DWORD asenumFlags, LPTSTR pszExt)
  218. {
  219. BOOL fRet = FALSE;
  220. if (AIINIT_NONE == _aiinitFlags)
  221. {
  222. CFTAssocStore* pAssocStore = NULL;
  223. // Do we want the Exts?
  224. if (!(ASENUM_EXT & asenumFlags))
  225. {
  226. // No
  227. // Is the first char a '.'?
  228. if (TEXT('.') == *pszExt)
  229. {
  230. // Yes, skip this one
  231. fRet = TRUE;
  232. }
  233. }
  234. else
  235. {
  236. // Yes
  237. // Is the first char a '.'?
  238. if (TEXT('.') != *pszExt)
  239. {
  240. // No, skip it
  241. fRet = TRUE;
  242. }
  243. }
  244. // we want to skip all the ext having explorer.exe as the executable for
  245. // their default verb.
  246. if ((ASENUM_NOEXPLORERSHELLACTION & asenumFlags) && !fRet)
  247. {
  248. IQueryAssociations* pQA = NULL;
  249. ASSERT(ASENUM_EXT & asenumFlags);
  250. HRESULT hres = AssocCreate(CLSID_QueryAssociations, IID_IQueryAssociations,
  251. (LPVOID*)&pQA);
  252. if (SUCCEEDED(hres))
  253. {
  254. WCHAR szwExt[MAX_EXT];
  255. DWORD cchExt = ARRAYSIZE(szwExt);
  256. SHTCharToUnicode(pszExt, szwExt, ARRAYSIZE(szwExt));
  257. hres = pQA->Init(0, szwExt, NULL, NULL);
  258. if (SUCCEEDED(hres))
  259. {
  260. WCHAR szwExec[MAX_APPFRIENDLYNAME];
  261. DWORD cchExec = ARRAYSIZE(szwExec);
  262. hres = pQA->GetString(ASSOCF_VERIFY,
  263. ASSOCSTR_EXECUTABLE, NULL, szwExec, &cchExec);
  264. if (!StrCmpIW(PathFindFileNameW(szwExec), L"explorer.exe"))
  265. {
  266. fRet = TRUE;
  267. }
  268. }
  269. pQA->Release();
  270. }
  271. }
  272. if ((ASENUM_NOEXCLUDED & asenumFlags) && !fRet)
  273. {
  274. IAssocInfo* pAI = NULL;
  275. HRESULT hres = E_FAIL;
  276. if (!pAssocStore)
  277. pAssocStore = new CFTAssocStore();
  278. ASSERT(ASENUM_EXT & asenumFlags);
  279. if (pAssocStore)
  280. hres = pAssocStore->GetAssocInfo(pszExt, AIINIT_EXT, &pAI);
  281. if (SUCCEEDED(hres))
  282. {
  283. hres = pAI->GetBOOL(AIBOOL_EXCLUDE, &fRet);
  284. pAI->Release();
  285. }
  286. }
  287. if ((ASENUM_NOEXE & asenumFlags) && !fRet)
  288. {
  289. ASSERT(ASENUM_EXT & asenumFlags);
  290. fRet = PathIsExe(pszExt);
  291. }
  292. if ((ASENUM_ASSOC_YES & asenumFlags) &&
  293. (ASENUM_ASSOC_ALL != (ASENUM_ASSOC_ALL & asenumFlags)) && !fRet)
  294. {
  295. IAssocInfo* pAI = NULL;
  296. HRESULT hres = E_FAIL;
  297. if (!pAssocStore)
  298. pAssocStore = new CFTAssocStore();
  299. ASSERT(ASENUM_EXT & asenumFlags);
  300. if (pAssocStore)
  301. hres = pAssocStore->GetAssocInfo(pszExt, AIINIT_EXT, &pAI);
  302. if (SUCCEEDED(hres))
  303. {
  304. BOOL fExtAssociated = FALSE;
  305. hres = pAI->GetBOOL(AIBOOL_EXTASSOCIATED, &fExtAssociated);
  306. fRet = (fExtAssociated ? FALSE : TRUE);
  307. pAI->Release();
  308. }
  309. }
  310. if ((ASENUM_ASSOC_NO & asenumFlags) &&
  311. (ASENUM_ASSOC_ALL != (ASENUM_ASSOC_ALL & asenumFlags)) && !fRet)
  312. {
  313. IAssocInfo* pAI = NULL;
  314. HRESULT hres = E_FAIL;
  315. if (!pAssocStore)
  316. pAssocStore = new CFTAssocStore();
  317. ASSERT(ASENUM_EXT & asenumFlags);
  318. if (pAssocStore)
  319. hres = pAssocStore->GetAssocInfo(pszExt, AIINIT_EXT, &pAI);
  320. if (SUCCEEDED(hres))
  321. {
  322. hres = pAI->GetBOOL(AIBOOL_EXTASSOCIATED, &fRet);
  323. pAI->Release();
  324. }
  325. }
  326. if ((ASENUM_SHOWONLY & asenumFlags) && !fRet)
  327. {
  328. IAssocInfo* pAI = NULL;
  329. HRESULT hres = E_FAIL;
  330. if (!pAssocStore)
  331. pAssocStore = new CFTAssocStore();
  332. ASSERT(ASENUM_PROGID & asenumFlags);
  333. // I know pszExt is not an Extension but a progID...
  334. if (pAssocStore)
  335. hres = pAssocStore->GetAssocInfo(pszExt, AIINIT_PROGID, &pAI);
  336. if (SUCCEEDED(hres))
  337. {
  338. BOOL fTmpRet = FALSE;
  339. hres = pAI->GetBOOL(AIBOOL_SHOW, &fTmpRet);
  340. // If it has the show flag (FTA_Show), we don't skip it, so
  341. // invert the fTmpRet
  342. fRet = fTmpRet ? FALSE : TRUE;
  343. pAI->Release();
  344. }
  345. }
  346. if (pAssocStore)
  347. delete pAssocStore;
  348. }
  349. else
  350. {
  351. if (AIINIT_PROGID == _aiinitFlags)
  352. {
  353. fRet = TRUE;
  354. // Do we want the Exts?
  355. if (ASENUM_EXT & asenumFlags)
  356. {
  357. DWORD dwType = 0;
  358. TCHAR szProgID[MAX_PROGID];
  359. DWORD cbProgID = ARRAYSIZE(szProgID) * sizeof(TCHAR);
  360. LONG lRes = SHGetValue(HKEY_CLASSES_ROOT, pszExt, NULL,
  361. &dwType, szProgID, &cbProgID);
  362. if (ERROR_SUCCESS == lRes)
  363. {
  364. // Does it have the same progID?
  365. if (!lstrcmpi(szProgID, _szInitStr))
  366. {
  367. // Yes, don't skip
  368. fRet = FALSE;
  369. }
  370. }
  371. }
  372. }
  373. }
  374. return fRet;
  375. }
  376. BOOL CFTEnumAssocInfo::_EnumKCRStop(DWORD asenumFlags, LPTSTR pszExt)
  377. {
  378. BOOL fRet = FALSE;
  379. // NT returns the extension in alphabetical order, not Win9X
  380. // If we want only the extensions, and the first char is not a '.', then stop
  381. if (ASENUM_EXT & asenumFlags)
  382. {
  383. // Don't go out if we haven't found the first extension
  384. if ((TEXT('.') != *pszExt) && _fFirstExtFound)
  385. fRet = TRUE;
  386. }
  387. return fRet;
  388. }
  389. ///////////////////////////////////////////////////////////////////////////////
  390. // Non-implemented IEnum methods
  391. HRESULT CFTEnumAssocInfo::Clone(IEnumAssocInfo* pEnum)
  392. {
  393. // Will never be implemented
  394. return E_FAIL;
  395. }
  396. HRESULT CFTEnumAssocInfo::Skip(DWORD dwSkip)
  397. {
  398. return E_NOTIMPL;
  399. }
  400. HRESULT CFTEnumAssocInfo::Reset()
  401. {
  402. return E_NOTIMPL;
  403. }