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.

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