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.

744 lines
22 KiB

  1. //
  2. //
  3. // assocapi.cpp
  4. //
  5. // Association APIs
  6. //
  7. //
  8. //
  9. #include "priv.h"
  10. #include <shstr.h>
  11. #include <msi.h>
  12. #include "assoc.h"
  13. #include <filetype.h>
  14. BOOL _PathAppend(LPCTSTR pszBase, LPCTSTR pszAppend, LPTSTR pszOut, DWORD cchOut);
  15. void _MakeAppPathKey(LPCTSTR pszApp, LPTSTR pszKey, DWORD cchKey)
  16. {
  17. if (_PathAppend(REGSTR_PATH_APPPATHS, pszApp, pszKey, cchKey))
  18. {
  19. // Currently we will only look up .EXE if an extension is not
  20. // specified
  21. if (*PathFindExtension(pszApp) == 0)
  22. {
  23. StrCatBuff(pszKey, TEXT(".exe"), cchKey);
  24. }
  25. }
  26. }
  27. void _MakeApplicationsKey(LPCWSTR pszApp, LPWSTR pszKey, DWORD cchKey)
  28. {
  29. if (_PathAppend(TEXT("Applications"), pszApp, pszKey, cchKey))
  30. {
  31. // Currently we will only look up .EXE if an extension is not
  32. // specified
  33. if (*PathFindExtension(pszApp) == 0)
  34. {
  35. StrCatBuff(pszKey, TEXT(".exe"), cchKey);
  36. }
  37. }
  38. }
  39. HRESULT _AssocOpenRegKey(HKEY hk, LPCTSTR pszSub, HKEY *phkOut, BOOL fCreate)
  40. {
  41. ASSERT(phkOut);
  42. *phkOut = NULL;
  43. if (!hk)
  44. return HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION);
  45. DWORD err;
  46. if (!fCreate)
  47. err = RegOpenKeyEx(hk, pszSub, 0, MAXIMUM_ALLOWED, phkOut);
  48. else
  49. err = RegCreateKeyEx(hk, pszSub, 0, NULL, REG_OPTION_NON_VOLATILE, MAXIMUM_ALLOWED, NULL, phkOut, NULL);
  50. if (ERROR_SUCCESS != err)
  51. {
  52. ASSERT(!*phkOut);
  53. return HRESULT_FROM_WIN32(err);
  54. }
  55. return S_OK;
  56. }
  57. LWSTDAPI AssocCreate(CLSID clsid, REFIID riid, LPVOID *ppvOut)
  58. {
  59. HRESULT hr = E_INVALIDARG;
  60. if (ppvOut)
  61. {
  62. if (IsEqualGUID(clsid, CLSID_QueryAssociations)
  63. || IsEqualGUID(clsid, IID_IQueryAssociations))
  64. {
  65. hr = SHCoCreateInstance(NULL, &CLSID_QueryAssociations, NULL, riid, ppvOut);
  66. }
  67. else
  68. hr = AssocCreateElement(clsid, riid, ppvOut);
  69. }
  70. return hr;
  71. }
  72. #define ASSOCF_INIT_ALL (ASSOCF_INIT_BYEXENAME | ASSOCF_INIT_DEFAULTTOFOLDER | ASSOCF_INIT_DEFAULTTOSTAR | ASSOCF_INIT_NOREMAPCLSID)
  73. LWSTDAPI AssocQueryStringW(ASSOCF flags, ASSOCSTR str, LPCWSTR pszAssoc, LPCWSTR pszExtra, LPWSTR pszOut, DWORD *pcchOut)
  74. {
  75. IQueryAssociations *passoc;
  76. HRESULT hr = AssocCreate(CLSID_QueryAssociations, IID_IQueryAssociations, (LPVOID *)&passoc);
  77. if (SUCCEEDED(hr))
  78. {
  79. hr = passoc->Init(flags & ASSOCF_INIT_ALL, pszAssoc, NULL, NULL);
  80. if (SUCCEEDED(hr))
  81. hr = passoc->GetString(flags, str, pszExtra, pszOut, pcchOut);
  82. passoc->Release();
  83. }
  84. return hr;
  85. }
  86. LWSTDAPI AssocQueryStringA(ASSOCF flags, ASSOCSTR str, LPCSTR pszAssoc, LPCSTR pszExtra, LPSTR pszOut, DWORD *pcchOut)
  87. {
  88. if (!pcchOut)
  89. return E_INVALIDARG;
  90. HRESULT hr = E_OUTOFMEMORY;
  91. SHSTRW strAssoc, strExtra;
  92. if (SUCCEEDED(strAssoc.SetStr(pszAssoc))
  93. && SUCCEEDED(strExtra.SetStr(pszExtra)))
  94. {
  95. SHSTRW strOut;
  96. DWORD cchIn = IS_INTRESOURCE(pcchOut) ? PtrToUlong(pcchOut) : *pcchOut;
  97. DWORD cch;
  98. LPTSTR pszTemp = NULL;
  99. if (pszOut)
  100. {
  101. strOut.SetSize(cchIn);
  102. cch = strOut.GetSize();
  103. pszTemp = strOut.GetInplaceStr();
  104. }
  105. hr = AssocQueryStringW(flags, str, strAssoc, strExtra, pszTemp, &cch);
  106. if (SUCCEEDED(hr))
  107. {
  108. cch = SHUnicodeToAnsi(strOut, pszOut, cchIn);
  109. if (!IS_INTRESOURCE(pcchOut))
  110. *pcchOut = cch;
  111. }
  112. }
  113. return hr;
  114. }
  115. LWSTDAPI AssocQueryStringByKeyW(ASSOCF flags, ASSOCSTR str, HKEY hkAssoc, LPCWSTR pszExtra, LPWSTR pszOut, DWORD *pcchOut)
  116. {
  117. IQueryAssociations *passoc;
  118. HRESULT hr = AssocCreate(CLSID_QueryAssociations, IID_IQueryAssociations, (LPVOID *)&passoc);
  119. if (SUCCEEDED(hr))
  120. {
  121. hr = passoc->Init(flags & ASSOCF_INIT_ALL, NULL, hkAssoc, NULL);
  122. if (SUCCEEDED(hr))
  123. hr = passoc->GetString(flags, str, pszExtra, pszOut, pcchOut);
  124. passoc->Release();
  125. }
  126. return hr;
  127. }
  128. LWSTDAPI AssocQueryStringByKeyA(ASSOCF flags, ASSOCSTR str, HKEY hkAssoc, LPCSTR pszExtra, LPSTR pszOut, DWORD *pcchOut)
  129. {
  130. if (!pcchOut)
  131. return E_INVALIDARG;
  132. HRESULT hr = E_OUTOFMEMORY;
  133. SHSTRW strExtra;
  134. if (SUCCEEDED(strExtra.SetStr(pszExtra)))
  135. {
  136. SHSTRW strOut;
  137. DWORD cchIn = IS_INTRESOURCE(pcchOut) ? PtrToUlong(pcchOut) : *pcchOut;
  138. DWORD cch;
  139. LPWSTR pszTemp = NULL;
  140. if (pszOut)
  141. {
  142. strOut.SetSize(cchIn);
  143. cch = strOut.GetSize();
  144. pszTemp = strOut.GetInplaceStr();
  145. }
  146. hr = AssocQueryStringByKeyW(flags, str, hkAssoc, strExtra, pszTemp, &cch);
  147. if (SUCCEEDED(hr))
  148. {
  149. cch = SHUnicodeToAnsi(strOut, pszOut, cchIn);
  150. if (!IS_INTRESOURCE(pcchOut))
  151. *pcchOut = cch;
  152. }
  153. }
  154. return hr;
  155. }
  156. LWSTDAPI AssocQueryKeyW(ASSOCF flags, ASSOCKEY key, LPCWSTR pszAssoc, LPCWSTR pszExtra, HKEY *phkey)
  157. {
  158. IQueryAssociations *passoc;
  159. HRESULT hr = AssocCreate(CLSID_QueryAssociations, IID_IQueryAssociations, (LPVOID *)&passoc);
  160. if (SUCCEEDED(hr))
  161. {
  162. hr = passoc->Init(flags & ASSOCF_INIT_ALL, pszAssoc, NULL, NULL);
  163. if (SUCCEEDED(hr))
  164. hr = passoc->GetKey(flags, key, pszExtra, phkey);
  165. passoc->Release();
  166. }
  167. return hr;
  168. }
  169. LWSTDAPI AssocQueryKeyA(ASSOCF flags, ASSOCKEY key, LPCSTR pszAssoc, LPCSTR pszExtra, HKEY *phkey)
  170. {
  171. HRESULT hr = E_OUTOFMEMORY;
  172. SHSTRW strAssoc, strExtra;
  173. if (SUCCEEDED(strAssoc.SetStr(pszAssoc))
  174. && SUCCEEDED(strExtra.SetStr(pszExtra)))
  175. {
  176. hr = AssocQueryKeyW(flags, key, strAssoc, strExtra, phkey);
  177. }
  178. return hr;
  179. }
  180. #define ISQUOTED(s) (TEXT('"') == *(s) && TEXT('"') == *((s) + lstrlen(s) - 1))
  181. BOOL _TrySubst(SHSTR& str, LPCTSTR psz)
  182. {
  183. BOOL fRet = FALSE;
  184. TCHAR szVar[MAX_PATH];
  185. DWORD cch = GetEnvironmentVariable(psz, szVar, SIZECHARS(szVar));
  186. if (cch && cch <= SIZECHARS(szVar))
  187. {
  188. if (0 == StrCmpNI(str, szVar, cch))
  189. {
  190. // we got a match.
  191. // size the buffer for the env var... +3 = (% + % + \0)
  192. SHSTR strT;
  193. if (S_OK == strT.SetStr(str.GetStr() + cch)
  194. && S_OK == str.SetSize(str.GetLen() - cch + lstrlen(psz) + 3)
  195. )
  196. {
  197. wnsprintf(str.GetInplaceStr(), str.GetSize(), TEXT("%%%s%%%s"), psz, strT.GetStr());
  198. fRet = TRUE;
  199. }
  200. }
  201. }
  202. return fRet;
  203. }
  204. BOOL _TryEnvSubst(SHSTR& str)
  205. {
  206. static LPCTSTR rgszEnv[] = {
  207. TEXT("USERPROFILE"),
  208. TEXT("ProgramFiles"),
  209. TEXT("SystemRoot"),
  210. TEXT("SystemDrive"),
  211. TEXT("windir"),
  212. NULL
  213. };
  214. LPCTSTR *ppsz = rgszEnv;
  215. BOOL fRet = FALSE;
  216. while (*ppsz && !fRet)
  217. {
  218. fRet = _TrySubst(str, *ppsz++);
  219. }
  220. return fRet;
  221. }
  222. HRESULT _MakeCommandString(ASSOCF *pflags, LPCTSTR pszExe, LPCTSTR pszArgs, SHSTR& str)
  223. {
  224. SHSTR strArgs;
  225. HRESULT hr;
  226. if (!pszArgs || !*pszArgs)
  227. {
  228. // default to just passing the
  229. // file name right in.
  230. // NOTE 16bit apps might have a problem with
  231. // this, but i request that the caller
  232. // specify that this is the case....
  233. pszArgs = TEXT("\"%1\"");
  234. }
  235. // else NO _ParseCommand()
  236. hr = str.SetStr(pszExe);
  237. if (S_OK == hr)
  238. {
  239. // check for quotes before doing env subst
  240. BOOL fNeedQuotes = (!ISQUOTED(str.GetStr()) && PathIsLFNFileSpec(str));
  241. // this will put environment vars into the string...
  242. if ((*pflags & ASSOCMAKEF_SUBSTENV) && _TryEnvSubst(str))
  243. {
  244. *pflags |= ASSOCMAKEF_USEEXPAND;
  245. }
  246. str.Trim();
  247. if (fNeedQuotes)
  248. {
  249. // 3 = " + " + \0
  250. if (S_OK == str.SetSize(str.GetLen() + 3))
  251. PathQuoteSpaces(str.GetInplaceStr());
  252. }
  253. hr = str.Append(TEXT(' '));
  254. if (S_OK == hr)
  255. {
  256. hr = str.Append(pszArgs);
  257. }
  258. }
  259. return hr;
  260. }
  261. HRESULT _AssocMakeCommand(ASSOCMAKEF flags, HKEY hkVerb, LPCWSTR pszExe, LPCWSTR pszArgs)
  262. {
  263. ASSERT(hkVerb && pszExe);
  264. SHSTR str;
  265. HRESULT hr = _MakeCommandString(&flags, pszExe, pszArgs, str);
  266. if (S_OK == hr)
  267. {
  268. DWORD dw = (flags & ASSOCMAKEF_USEEXPAND) ? REG_EXPAND_SZ : REG_SZ;
  269. DWORD err = SHSetValue(hkVerb, TEXT("command"), NULL, dw, (LPVOID) str.GetStr(), CbFromCch(str.GetLen() +1));
  270. hr = HRESULT_FROM_WIN32(err);
  271. }
  272. return hr;
  273. }
  274. LWSTDAPI AssocMakeShell(ASSOCMAKEF flags, HKEY hkProgid, LPCWSTR pszApplication, ASSOCSHELL *pShell)
  275. {
  276. HRESULT hr = E_INVALIDARG;
  277. if (hkProgid && pszApplication && pShell)
  278. {
  279. for (DWORD c = 0; c < pShell->cVerbs; c++)
  280. {
  281. ASSOCVERB *pverb = &pShell->rgVerbs[c];
  282. if (pverb->pszVerb)
  283. {
  284. TCHAR szVerbKey[MAX_PATH];
  285. HKEY hkVerb;
  286. _PathAppend(TEXT("shell"), pverb->pszVerb, szVerbKey, SIZECHARS(szVerbKey));
  287. if (c == pShell->iDefaultVerb)
  288. SHSetValue(hkProgid, TEXT("shell"), NULL, REG_SZ, pverb->pszVerb, CbFromCch(lstrlen(pverb->pszVerb) +1));
  289. // ASSOCMAKEF_FAILIFEXIST check if its ok to overwrite
  290. if (SUCCEEDED(_AssocOpenRegKey(hkProgid, szVerbKey, &hkVerb, FALSE)))
  291. {
  292. RegCloseKey(hkVerb);
  293. SHDeleteKey(hkProgid, szVerbKey);
  294. }
  295. if (SUCCEEDED(_AssocOpenRegKey(hkProgid, szVerbKey, &hkVerb, TRUE)))
  296. {
  297. if (pverb->pszTitle)
  298. SHSetValue(hkVerb, NULL, NULL, REG_SZ, pverb->pszTitle, CbFromCch(lstrlen(pverb->pszTitle) +1));
  299. hr = _AssocMakeCommand(flags, hkVerb, pverb->pszApplication ? pverb->pszApplication : pszApplication , pverb->pszParams);
  300. // if (SUCCEEDED(hr) && pverb->pDDEExec)
  301. // hr = _AssocMakeDDEExec(flags, hkVerb, pverb->pDDEExec);
  302. RegCloseKey(hkVerb);
  303. }
  304. }
  305. }
  306. }
  307. return hr;
  308. }
  309. HRESULT _OpenClasses(HKEY *phkOut)
  310. {
  311. *phkOut = NULL;
  312. DWORD err = RegCreateKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\classes"), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, phkOut, NULL);
  313. if (err)
  314. err = RegCreateKeyEx(HKEY_CURRENT_USER, TEXT("Software\\classes"), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, phkOut, NULL);
  315. return HRESULT_FROM_WIN32(err);
  316. }
  317. LWSTDAPI AssocMakeProgid(ASSOCMAKEF flags, LPCWSTR pszApplication, ASSOCPROGID *pProgid, HKEY *phkProgid)
  318. {
  319. HRESULT hr = E_INVALIDARG;
  320. if (pszApplication
  321. && pProgid
  322. && pProgid->cbSize >= sizeof(ASSOCPROGID)
  323. && pProgid->pszProgid
  324. && *pProgid->pszProgid)
  325. {
  326. HKEY hkRoot;
  327. if ((!(flags & ASSOCMAKEF_VERIFY) || PathFileExists(pszApplication))
  328. && SUCCEEDED(_OpenClasses(&hkRoot)))
  329. {
  330. HKEY hkProgid;
  331. // need to add support for ASSOCMAKEF_VOLATILE...
  332. hr = _AssocOpenRegKey(hkRoot, pProgid->pszProgid, &hkProgid, TRUE);
  333. if (SUCCEEDED(hr))
  334. {
  335. if (pProgid->pszFriendlyDocName)
  336. SHSetValue(hkProgid, NULL, NULL, REG_SZ, pProgid->pszFriendlyDocName, CbFromCch(lstrlen(pProgid->pszFriendlyDocName) +1));
  337. if (pProgid->pszDefaultIcon)
  338. SHSetValue(hkProgid, TEXT("DefaultIcon"), NULL, REG_SZ, pProgid->pszDefaultIcon, CbFromCch(lstrlen(pProgid->pszDefaultIcon) +1));
  339. if (pProgid->pShellKey)
  340. hr = AssocMakeShell(flags, hkProgid, pszApplication, pProgid->pShellKey);
  341. if (SUCCEEDED(hr) && pProgid->pszExtensions)
  342. {
  343. LPCTSTR psz = pProgid->pszExtensions;
  344. DWORD err = NOERROR;
  345. while (*psz && NOERROR == err)
  346. {
  347. err = SHSetValue(hkRoot, psz, NULL, REG_SZ, pProgid->pszProgid, CbFromCch(lstrlen(pProgid->pszProgid) + 1));
  348. psz += lstrlen(psz) + 1;
  349. }
  350. if (NOERROR != err)
  351. HRESULT_FROM_WIN32(err);
  352. }
  353. if (SUCCEEDED(hr) && phkProgid)
  354. *phkProgid = hkProgid;
  355. else
  356. RegCloseKey(hkProgid);
  357. }
  358. RegCloseKey(hkRoot);
  359. }
  360. }
  361. return hr;
  362. }
  363. HRESULT _AssocCopyVerb(HKEY hkSrc, HKEY hkDst, LPCTSTR pszVerb)
  364. {
  365. HRESULT hr = S_OK;
  366. TCHAR szKey[MAX_PATH];
  367. HKEY hkVerb;
  368. DWORD dwDisp;
  369. // only copy the verb component
  370. wnsprintf(szKey, SIZECHARS(szKey), TEXT("shell\\%s"), pszVerb);
  371. RegCreateKeyEx(hkDst, szKey, 0, NULL, 0,
  372. MAXIMUM_ALLOWED, NULL, &hkVerb, &dwDisp);
  373. // create a failure state here...
  374. if (hkVerb)
  375. {
  376. // we avoid overwriting old keys by checking the dwDisp
  377. if ((dwDisp == REG_CREATED_NEW_KEY) && SHCopyKey(hkSrc, pszVerb, hkVerb, 0L))
  378. hr = E_UNEXPECTED;
  379. RegCloseKey(hkVerb);
  380. }
  381. return hr;
  382. }
  383. typedef BOOL (*PFNALLOWVERB)(LPCWSTR psz, LPARAM param);
  384. LWSTDAPI _AssocCopyVerbs(HKEY hkSrc, HKEY hkDst, PFNALLOWVERB pfnAllow, LPARAM lParam)
  385. {
  386. HRESULT hr = E_INVALIDARG;
  387. HKEY hkEnum;
  388. if (SUCCEEDED(_AssocOpenRegKey(hkSrc, TEXT("shell"), &hkEnum, FALSE)))
  389. {
  390. TCHAR szVerb[MAX_PATH];
  391. DWORD cchVerb = SIZECHARS(szVerb);
  392. for (DWORD i = 0
  393. ; (NOERROR == RegEnumKeyEx(hkEnum, i, szVerb, &cchVerb, NULL, NULL, NULL, NULL))
  394. ; (cchVerb = SIZECHARS(szVerb)), i++)
  395. {
  396. if (!pfnAllow || pfnAllow(szVerb, lParam))
  397. hr = _AssocCopyVerb(hkEnum, hkDst, szVerb);
  398. }
  399. // switch to cbVerb here
  400. cchVerb = sizeof(szVerb);
  401. if (NOERROR == SHGetValue(hkEnum, NULL, NULL, NULL, szVerb, &cchVerb))
  402. {
  403. SHSetValue(hkDst, TEXT("shell"), NULL, REG_SZ, szVerb, cchVerb);
  404. }
  405. RegCloseKey(hkEnum);
  406. }
  407. return hr;
  408. }
  409. LWSTDAPI AssocCopyVerbs(HKEY hkSrc, HKEY hkDst)
  410. {
  411. return _AssocCopyVerbs(hkSrc, hkDst, NULL, NULL);
  412. }
  413. BOOL _IsMSIPerUserInstall(IQueryAssociations *pqa, ASSOCF flags, LPCWSTR pszVerb)
  414. {
  415. WCHAR sz[MAX_PATH];
  416. DWORD cb = sizeof(sz);
  417. if (SUCCEEDED(pqa->GetData(flags, ASSOCDATA_MSIDESCRIPTOR, pszVerb, sz, &cb)))
  418. {
  419. WCHAR szOut[3]; // bit enough for "1" or "0"
  420. cb = SIZECHARS(szOut);
  421. if (NOERROR == MsiGetProductInfoW(sz, INSTALLPROPERTY_ASSIGNMENTTYPE, szOut, &cb))
  422. {
  423. // The string "1" for the value represents machine installations,
  424. // while "0" represents user installations.
  425. if (0 == StrCmpW(szOut, L"0"))
  426. return TRUE;
  427. }
  428. }
  429. return FALSE;
  430. }
  431. typedef struct {
  432. IQueryAssociations *pqa;
  433. ASSOCF Qflags;
  434. LPCWSTR pszExe;
  435. BOOL fAllowPerUser;
  436. } QUERYEXECB;
  437. BOOL _AllowExeVerb(LPCWSTR pszVerb, QUERYEXECB *pqcb)
  438. {
  439. BOOL fRet = FALSE;
  440. WCHAR sz[MAX_PATH];
  441. if (SUCCEEDED(pqcb->pqa->GetString(pqcb->Qflags, ASSOCSTR_EXECUTABLE, pszVerb,
  442. sz, (LPDWORD)MAKEINTRESOURCE(SIZECHARS(sz)))))
  443. {
  444. if (0 == StrCmpIW(PathFindFileNameW(sz), pqcb->pszExe))
  445. {
  446. //
  447. // EXEs match so we should copy this verb.
  448. // but we need to block per-user installs by darwin being added to the
  449. // applications key, since other users wont be able to use them
  450. //
  451. if (_IsMSIPerUserInstall(pqcb->pqa, pqcb->Qflags, pszVerb))
  452. fRet = pqcb->fAllowPerUser;
  453. else
  454. fRet = TRUE;
  455. }
  456. }
  457. // todo mask off DARWIN per-user installs
  458. return fRet;
  459. }
  460. HRESULT _AssocCreateAppKey(LPCWSTR pszExe, BOOL fPerUser, HKEY *phk)
  461. {
  462. WCHAR szKey[MAX_PATH];
  463. wnsprintf(szKey, SIZECHARS(szKey), L"software\\classes\\applications\\%s", pszExe);
  464. if (*PathFindExtension(pszExe) == 0)
  465. {
  466. StrCatBuff(szKey, TEXT(".exe"), SIZECHARS(szKey));
  467. }
  468. return _AssocOpenRegKey(fPerUser ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE, szKey, phk, TRUE);
  469. }
  470. LWSTDAPI AssocMakeApplicationByKeyW(ASSOCMAKEF flags, HKEY hkSrc, LPCWSTR pszVerb)
  471. {
  472. WCHAR szPath[MAX_PATH];
  473. HRESULT hr = HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION);
  474. ASSOCF Qflags = (flags & ASSOCMAKEF_VERIFY) ? ASSOCF_VERIFY : 0;
  475. IQueryAssociations *pqa;
  476. AssocCreate(CLSID_QueryAssociations, IID_IQueryAssociations, (LPVOID *)&pqa);
  477. if (!pqa)
  478. return E_OUTOFMEMORY;
  479. if (SUCCEEDED(pqa->Init(0, NULL, hkSrc, NULL)))
  480. {
  481. if (SUCCEEDED(pqa->GetString(Qflags, ASSOCSTR_EXECUTABLE, pszVerb,
  482. szPath, (LPDWORD)MAKEINTRESOURCE(SIZECHARS(szPath))))
  483. && (0 != StrCmpW(szPath, TEXT("%1"))))
  484. {
  485. LPCWSTR pszExe = PathFindFileNameW(szPath);
  486. BOOL fPerUser = _IsMSIPerUserInstall(pqa, Qflags, pszVerb);
  487. HKEY hkDst;
  488. ASSERT(pszExe && *pszExe);
  489. // we have an exe to use
  490. // check to see if this Application already has
  491. // this verb installed
  492. DWORD cch;
  493. hr = AssocQueryString(Qflags | ASSOCF_OPEN_BYEXENAME, ASSOCSTR_COMMAND, pszExe,
  494. pszVerb, NULL, &cch);
  495. if (FAILED(hr) && SUCCEEDED(_AssocCreateAppKey(pszExe, fPerUser, &hkDst)))
  496. {
  497. QUERYEXECB qcb = {pqa, Qflags, pszExe, fPerUser};
  498. if (pszVerb)
  499. {
  500. if (_AllowExeVerb(pszVerb, &qcb))
  501. {
  502. HKEY hkSrcVerbs;
  503. if (SUCCEEDED(_AssocOpenRegKey(hkSrc, TEXT("shell"), &hkSrcVerbs, FALSE)))
  504. {
  505. hr = _AssocCopyVerb(hkSrcVerbs, hkDst, pszVerb);
  506. RegCloseKey(hkSrcVerbs);
  507. }
  508. else
  509. {
  510. hr = E_UNEXPECTED;
  511. }
  512. }
  513. }
  514. else
  515. {
  516. hr = _AssocCopyVerbs(hkSrc, hkDst, (PFNALLOWVERB)_AllowExeVerb, (LPARAM)&qcb);
  517. }
  518. RegCloseKey(hkDst);
  519. }
  520. // init the friendly name for later
  521. if ((flags & ASSOCMAKEF_VERIFY) && SUCCEEDED(hr))
  522. {
  523. AssocQueryString(ASSOCF_OPEN_BYEXENAME | Qflags, ASSOCSTR_FRIENDLYAPPNAME,
  524. pszExe, NULL, NULL, &cch);
  525. }
  526. }
  527. pqa->Release();
  528. }
  529. return hr;
  530. }
  531. LWSTDAPI AssocMakeApplicationByKeyA(ASSOCMAKEF flags, HKEY hkAssoc, LPCSTR pszVerb)
  532. {
  533. // convert pszVerb to wide char but preserve difference
  534. // between NULL and "" for AssocMakeApplicationByKeyW
  535. if (! pszVerb)
  536. return AssocMakeApplicationByKeyW(flags, hkAssoc, NULL);
  537. SHSTRW strVerb;
  538. HRESULT hr = strVerb.SetStr(pszVerb);
  539. if (SUCCEEDED(hr))
  540. hr = AssocMakeApplicationByKeyW(flags, hkAssoc, strVerb);
  541. return hr;
  542. }
  543. // This list needs to continue to be updated and we should try to keep parity with Office
  544. const LPCTSTR c_arszUnsafeExts[] =
  545. {
  546. TEXT(".ade"), TEXT(".adp"), TEXT(".asp"), TEXT(".bas"), TEXT(".bat"), TEXT(".chm"),
  547. TEXT(".cmd"), TEXT(".com"), TEXT(".cpl"), TEXT(".crt"), TEXT(".exe"), TEXT(".hlp"),
  548. TEXT(".hta"), TEXT(".inf"), TEXT(".ins"), TEXT(".isp"), TEXT(".its"), TEXT(".js"),
  549. TEXT(".jse"), TEXT(".lnk"), TEXT(".mdb"), TEXT(".mde"), TEXT(".mdt"), TEXT(".mdw"),
  550. TEXT(".msc"), TEXT(".msi"), TEXT(".msp"), TEXT(".mst"), TEXT(".pcd"), TEXT(".pif"),
  551. TEXT(".reg"), TEXT(".scr"), TEXT(".sct"), TEXT(".shb"), TEXT(".shs"), TEXT(".tmp"),
  552. TEXT(".url"), TEXT(".vb"), TEXT(".vbe"), TEXT(".vbs"), TEXT(".vsd"), TEXT(".vsmacros"),
  553. TEXT(".vss"), TEXT(".vst"), TEXT(".vsw"), TEXT(".ws"), TEXT(".wsc"), TEXT(".wsf"), TEXT(".wsh"),
  554. };
  555. typedef BOOL (*PFNSAFERIISEXECUTABLEFILETYPE)(LPCWSTR szFullPathname, BOOLEAN bFromShellExecute);
  556. LWSTDAPI_(BOOL) AssocIsDangerous(PCWSTR pszType)
  557. {
  558. #ifdef DEBUG
  559. // make sure our sort is good.
  560. static BOOL fCheckedUnsafe = FALSE;
  561. if (!fCheckedUnsafe)
  562. {
  563. for (int i = 1; i < ARRAYSIZE(c_arszUnsafeExts); i++)
  564. {
  565. ASSERT(0 > StrCmpIW(c_arszUnsafeExts[i-1], c_arszUnsafeExts[i]));
  566. }
  567. fCheckedUnsafe = TRUE;
  568. }
  569. #endif // DEBUG
  570. BOOL fDangerous = IsTypeInList(pszType, c_arszUnsafeExts, ARRAYSIZE(c_arszUnsafeExts));
  571. if (!fDangerous && pszType)
  572. {
  573. IQueryAssociations *passoc;
  574. HRESULT hr = AssocCreate(CLSID_QueryAssociations, IID_PPV_ARG(IQueryAssociations, &passoc));
  575. if (SUCCEEDED(hr))
  576. {
  577. hr = passoc->Init(NULL, pszType, NULL, NULL);
  578. if (SUCCEEDED(hr))
  579. {
  580. DWORD dwEditFlags;
  581. ULONG cb = sizeof(dwEditFlags);
  582. hr = passoc->GetData(NULL, ASSOCDATA_EDITFLAGS, NULL, &dwEditFlags, &cb);
  583. if (SUCCEEDED(hr))
  584. {
  585. fDangerous = dwEditFlags & FTA_AlwaysUnsafe;
  586. }
  587. }
  588. passoc->Release();
  589. }
  590. if (!fDangerous && IsOS(OS_WHISTLERORGREATER) && *pszType)
  591. {
  592. HMODULE hmod = LoadLibrary(TEXT("advapi32.dll"));
  593. if (hmod)
  594. {
  595. PFNSAFERIISEXECUTABLEFILETYPE pfnSaferiIsExecutableFileType =
  596. (PFNSAFERIISEXECUTABLEFILETYPE)GetProcAddress(hmod, "SaferiIsExecutableFileType");
  597. if (pfnSaferiIsExecutableFileType)
  598. fDangerous = pfnSaferiIsExecutableFileType(pszType, TRUE);
  599. FreeLibrary(hmod);
  600. }
  601. }
  602. }
  603. return fDangerous;
  604. }