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.

656 lines
16 KiB

  1. /*
  2. * urlassoc.c - URL Type association routines.
  3. */
  4. #include "priv.h"
  5. #include "ishcut.h"
  6. #include <filetype.h>
  7. #include <shlwapip.h>
  8. #include "assocurl.h"
  9. #include "resource.h"
  10. #include <intshctp.h>
  11. #include <mluisupp.h>
  12. #define c_szURLProtocol TEXT("URL Protocol")
  13. #define c_szEditFlags TEXT("EditFlags")
  14. #define c_szMIMETypeSubKeyFmt TEXT("MIME\\Database\\Content Type\\%s")
  15. #define c_szShellOpenCmdSubKeyFmt TEXT("%s\\shell\\open\\command")
  16. #define c_szAppOpenCmdFmt TEXT("%s %%1")
  17. #define c_szDefaultIconSubKeyFmt TEXT("%s\\DefaultIcon")
  18. #define c_szDefaultProtocolIcon TEXT("shdocvw.dll,-105")
  19. /***************************** Private Functions *****************************/
  20. extern "C" {
  21. /*
  22. ** RegisterAppAsURLProtocolHandler()
  23. **
  24. ** Under HKEY_CLASSES_ROOT\url-protocol\shell\open\command, add default value =
  25. ** "c:\foo\bar.exe %1".
  26. **
  27. ** Arguments:
  28. **
  29. ** Returns:
  30. **
  31. ** Side Effects: none
  32. */
  33. BOOL
  34. RegisterAppAsURLProtocolHandler(
  35. LPCTSTR pcszProtocol,
  36. LPCTSTR pcszApp)
  37. {
  38. BOOL bResult = FALSE;
  39. DWORD cbShellOpen;
  40. LPTSTR pszShellOpen;
  41. ASSERT(IS_VALID_STRING_PTR(pcszProtocol, -1));
  42. ASSERT(IS_VALID_STRING_PTR(pcszApp, -1));
  43. /* (+ 1) for null terminator. */
  44. cbShellOpen = SIZEOF(c_szShellOpenCmdSubKeyFmt) +
  45. CbFromCch(1 + lstrlen(pcszProtocol));
  46. pszShellOpen = (LPTSTR)LocalAlloc(LPTR, cbShellOpen);
  47. if (pszShellOpen)
  48. {
  49. DWORD cbAppOpen;
  50. LPTSTR pszAppOpen;
  51. /* FEATURE: We should quote pcszApp here only if it contains spaces. */
  52. /* (+ 1) for null terminator. */
  53. cbAppOpen = SIZEOF(c_szAppOpenCmdFmt) +
  54. CbFromCch(1 + lstrlen(pcszApp));
  55. pszAppOpen = (LPTSTR)LocalAlloc(LPTR, cbAppOpen);
  56. if (pszAppOpen)
  57. {
  58. wnsprintf(pszShellOpen, cbShellOpen / sizeof(TCHAR),
  59. c_szShellOpenCmdSubKeyFmt, pcszProtocol);
  60. wnsprintf(pszAppOpen, cbAppOpen / sizeof(TCHAR), c_szAppOpenCmdFmt,
  61. pcszApp);
  62. /* (+ 1) for null terminator. */
  63. bResult = (NO_ERROR == SHSetValue(HKEY_CLASSES_ROOT, pszShellOpen, NULL,
  64. REG_SZ, pszAppOpen,
  65. CbFromCch(lstrlen(pszAppOpen) + 1)));
  66. LocalFree(pszAppOpen);
  67. pszAppOpen = NULL;
  68. }
  69. LocalFree(pszShellOpen);
  70. pszShellOpen = NULL;
  71. }
  72. return(bResult);
  73. }
  74. /*
  75. ** RegisterURLProtocolDescription()
  76. **
  77. ** Under HKEY_CLASSES_ROOT\url-protocol, add default value =
  78. ** URL:Url-protocol Protocol.
  79. **
  80. ** Arguments:
  81. **
  82. ** Returns:
  83. **
  84. ** Side Effects: none
  85. */
  86. BOOL
  87. RegisterURLProtocolDescription(
  88. LPCTSTR pcszProtocol)
  89. {
  90. BOOL bResult = FALSE;
  91. LPTSTR pszProtocolCopy = NULL;
  92. ASSERT(IS_VALID_STRING_PTR(pcszProtocol, -1));
  93. if (Str_SetPtr(&pszProtocolCopy, pcszProtocol))
  94. {
  95. TCHAR szDescriptionFmt[MAX_PATH];
  96. /*
  97. * Convert first character of protocol to upper case for description
  98. * string.
  99. */
  100. *pszProtocolCopy = (TCHAR) (DWORD_PTR) CharUpper((LPTSTR)(DWORD_PTR)*pszProtocolCopy);
  101. if (MLLoadString(IDS_URL_DESC_FORMAT, szDescriptionFmt, SIZECHARS(szDescriptionFmt)))
  102. {
  103. TCHAR szDescription[MAX_PATH];
  104. if ((UINT)lstrlen(szDescriptionFmt) + (UINT)lstrlen(pszProtocolCopy)
  105. < SIZECHARS(szDescription))
  106. {
  107. wnsprintf(szDescription, ARRAYSIZE(szDescription), szDescriptionFmt,
  108. pszProtocolCopy);
  109. /* (+ 1) for null terminator. */
  110. bResult = (NO_ERROR == SHSetValue(HKEY_CLASSES_ROOT, pcszProtocol, NULL,
  111. REG_SZ, szDescription,
  112. CbFromCch(lstrlen(szDescription) + 1)));
  113. }
  114. }
  115. Str_SetPtr(&pszProtocolCopy, NULL);
  116. }
  117. return(bResult);
  118. }
  119. /*
  120. ** RegisterURLProtocolFlags()
  121. **
  122. ** Under HKEY_CLASSES_ROOT\url-protocol, add EditFlags = FTA_Show.
  123. **
  124. ** Arguments:
  125. **
  126. ** Returns:
  127. **
  128. ** Side Effects: none
  129. */
  130. BOOL
  131. RegisterURLProtocolFlags(
  132. LPCTSTR pcszProtocol)
  133. {
  134. DWORD dwEditFlags = FTA_Show;
  135. ASSERT(IS_VALID_STRING_PTR(pcszProtocol, -1));
  136. /* FEATURE: What about preserving any existing EditFlags here? */
  137. return NO_ERROR == SHSetValue(HKEY_CLASSES_ROOT, pcszProtocol, c_szEditFlags,
  138. REG_BINARY, &dwEditFlags, SIZEOF(dwEditFlags));
  139. }
  140. /*
  141. ** RegisterURLProtocol()
  142. **
  143. ** Under HKEY_CLASSES_ROOT\url-protocol, add URL Protocol = "".
  144. **
  145. ** Arguments:
  146. **
  147. ** Returns:
  148. **
  149. ** Side Effects: none
  150. */
  151. BOOL
  152. RegisterURLProtocol(
  153. LPCTSTR pcszProtocol)
  154. {
  155. ASSERT(IS_VALID_STRING_PTR(pcszProtocol, -1));
  156. // REVIEW (scotth): what does this value mean??
  157. /* (+ 1) for null terminator. */
  158. return NO_ERROR == SHSetValue(HKEY_CLASSES_ROOT, pcszProtocol, c_szURLProtocol,
  159. REG_SZ, c_szNULL, CbFromCch(1));
  160. }
  161. /*
  162. ** RegisterURLProtocolDefaultIcon()
  163. **
  164. ** Under HKEY_CLASSES_ROOT\url-protocol\DefaultIcon, add default value =
  165. ** app.exe,0.
  166. **
  167. ** Arguments:
  168. **
  169. ** Returns:
  170. **
  171. ** Side Effects: none
  172. */
  173. BOOL
  174. RegisterURLProtocolDefaultIcon(
  175. LPCTSTR pcszProtocol)
  176. {
  177. BOOL bResult = FALSE;
  178. DWORD cbAlloc;
  179. LPTSTR pszT;
  180. ASSERT(IS_VALID_STRING_PTR(pcszProtocol, -1));
  181. /* (+ 1) for null terminator. */
  182. cbAlloc = SIZEOF(c_szDefaultIconSubKeyFmt) +
  183. CbFromCch(1 + lstrlen(pcszProtocol));
  184. pszT = (LPTSTR)LocalAlloc(LPTR, cbAlloc);
  185. if (pszT)
  186. {
  187. wnsprintf(pszT, cbAlloc / sizeof(TCHAR), c_szDefaultIconSubKeyFmt,
  188. pcszProtocol);
  189. bResult = (NO_ERROR == SHSetValue(HKEY_CLASSES_ROOT, pszT, NULL, REG_SZ,
  190. c_szDefaultProtocolIcon,
  191. SIZEOF(c_szDefaultProtocolIcon)));
  192. LocalFree(pszT);
  193. pszT = NULL;
  194. }
  195. return(bResult);
  196. }
  197. BOOL
  198. AllowedToRegisterMIMEType(
  199. LPCTSTR pcszMIMEContentType)
  200. {
  201. BOOL bResult;
  202. bResult = (0 != StrCmpI(pcszMIMEContentType, TEXT("application/octet-stream")) &&
  203. 0 != StrCmpI(pcszMIMEContentType, TEXT("application/octet-string")));
  204. return(bResult);
  205. }
  206. BOOL
  207. RegisterMIMEAssociation(
  208. LPCTSTR pcszFile,
  209. LPCTSTR pcszMIMEContentType)
  210. {
  211. BOOL bResult;
  212. LPCTSTR pcszExtension;
  213. ASSERT(IS_VALID_STRING_PTR(pcszFile, -1));
  214. ASSERT(IS_VALID_STRING_PTR(pcszMIMEContentType, -1));
  215. pcszExtension = PathFindExtension(pcszFile);
  216. /*
  217. * Don't allow association of flag unknown MIME types
  218. * application/octet-stream and application/octet-string.
  219. */
  220. if (EVAL(*pcszExtension) &&
  221. AllowedToRegisterMIMEType(pcszMIMEContentType))
  222. {
  223. bResult = (RegisterMIMETypeForExtension(pcszExtension, pcszMIMEContentType) &&
  224. RegisterExtensionForMIMEType(pcszExtension, pcszMIMEContentType));
  225. }
  226. else
  227. bResult = FALSE;
  228. return(bResult);
  229. }
  230. BOOL
  231. RegisterURLAssociation(
  232. LPCTSTR pcszProtocol,
  233. LPCTSTR pcszApp)
  234. {
  235. ASSERT(IS_VALID_STRING_PTR(pcszProtocol, -1));
  236. ASSERT(IS_VALID_STRING_PTR(pcszApp, -1));
  237. return(RegisterAppAsURLProtocolHandler(pcszProtocol, pcszApp) &&
  238. RegisterURLProtocolDescription(pcszProtocol) &&
  239. RegisterURLProtocol(pcszProtocol) &&
  240. RegisterURLProtocolFlags(pcszProtocol) &&
  241. RegisterURLProtocolDefaultIcon(pcszProtocol));
  242. }
  243. HRESULT
  244. MyMIMEAssociationDialog(
  245. HWND hwndParent,
  246. DWORD dwInFlags,
  247. LPCTSTR pcszFile,
  248. LPCTSTR pcszMIMEContentType,
  249. LPTSTR pszAppBuf,
  250. UINT cchAppBuf)
  251. {
  252. HRESULT hr;
  253. OPENASINFO oainfo;
  254. ASSERT(IS_VALID_HANDLE(hwndParent, WND));
  255. ASSERT(FLAGS_ARE_VALID(dwInFlags, ALL_MIMEASSOCDLG_FLAGS));
  256. ASSERT(IS_VALID_STRING_PTR(pcszFile, -1));
  257. ASSERT(IS_VALID_STRING_PTR(pcszMIMEContentType, -1));
  258. ASSERT(IS_VALID_WRITE_BUFFER(pszAppBuf, TCHAR, cchAppBuf));
  259. /* Use default file name if not supplied by caller. */
  260. if (cchAppBuf > 0)
  261. *pszAppBuf = '\0';
  262. oainfo.pcszFile = pcszFile;
  263. oainfo.pcszClass = pcszMIMEContentType;
  264. oainfo.dwInFlags = 0;
  265. if (IsFlagSet(dwInFlags, MIMEASSOCDLG_FL_REGISTER_ASSOC))
  266. {
  267. SetFlag(oainfo.dwInFlags, (OAIF_ALLOW_REGISTRATION |
  268. OAIF_REGISTER_EXT));
  269. }
  270. #if 0 // FEATURE (scotth): fix this
  271. hr = OpenAsDialog(hwndParent, &oainfo);
  272. #else
  273. hr = E_FAIL;
  274. #endif
  275. if (hr == S_OK &&
  276. IsFlagSet(dwInFlags, MIMEASSOCDLG_FL_REGISTER_ASSOC))
  277. {
  278. hr = RegisterMIMEAssociation(pcszFile, pcszMIMEContentType) ? S_OK
  279. : E_OUTOFMEMORY;
  280. }
  281. if (SUCCEEDED(hr))
  282. StrCpyN(pszAppBuf, oainfo.szApp, cchAppBuf);
  283. ASSERT(! cchAppBuf ||
  284. (IS_VALID_STRING_PTR(pszAppBuf, -1) &&
  285. EVAL((UINT)lstrlen(pszAppBuf) < cchAppBuf)));
  286. ASSERT(SUCCEEDED(hr) ||
  287. (! cchAppBuf ||
  288. EVAL(! *pszAppBuf)));
  289. return(hr);
  290. }
  291. HRESULT
  292. MyURLAssociationDialog(
  293. HWND hwndParent,
  294. DWORD dwInFlags,
  295. LPCTSTR pcszFile,
  296. LPCTSTR pcszURL,
  297. LPTSTR pszAppBuf,
  298. UINT cchAppBuf)
  299. {
  300. HRESULT hr;
  301. LPTSTR pszProtocol;
  302. ASSERT(IS_VALID_HANDLE(hwndParent, WND));
  303. ASSERT(FLAGS_ARE_VALID(dwInFlags, ALL_URLASSOCDLG_FLAGS));
  304. ASSERT(IsFlagSet(dwInFlags, URLASSOCDLG_FL_USE_DEFAULT_NAME) ||
  305. IS_VALID_STRING_PTR(pcszFile, -1));
  306. ASSERT(IS_VALID_STRING_PTR(pcszURL, -1));
  307. ASSERT(IS_VALID_WRITE_BUFFER(pszAppBuf, TCHAR, cchAppBuf));
  308. /* Use URL protocol as class name. */
  309. if (cchAppBuf > 0)
  310. *pszAppBuf = '\0';
  311. hr = CopyURLProtocol(pcszURL, &pszProtocol, NULL);
  312. if (hr == S_OK)
  313. {
  314. TCHAR szInternetShortcut[MAX_PATH];
  315. OPENASINFO oainfo;
  316. /* Use default file name if not supplied by caller. */
  317. if (IsFlagSet(dwInFlags, URLASSOCDLG_FL_USE_DEFAULT_NAME) &&
  318. EVAL(MLLoadString(IDS_INTERNET_SHORTCUT,
  319. szInternetShortcut,
  320. SIZECHARS(szInternetShortcut))))
  321. {
  322. pcszFile = szInternetShortcut;
  323. }
  324. oainfo.pcszFile = pcszFile;
  325. oainfo.pcszClass = pszProtocol;
  326. oainfo.dwInFlags = 0;
  327. if (IsFlagSet(dwInFlags, URLASSOCDLG_FL_REGISTER_ASSOC))
  328. SetFlag(oainfo.dwInFlags, OAIF_ALLOW_REGISTRATION);
  329. #if 0 // FEATURE (scotth): fix this
  330. hr = OpenAsDialog(hwndParent, &oainfo);
  331. #else
  332. hr = E_FAIL;
  333. #endif
  334. if (hr == S_OK &&
  335. IsFlagSet(dwInFlags, URLASSOCDLG_FL_REGISTER_ASSOC))
  336. {
  337. hr = RegisterURLAssociation(pszProtocol, oainfo.szApp) ? S_OK
  338. : E_OUTOFMEMORY;
  339. }
  340. if (SUCCEEDED(hr))
  341. StrCpyN(pszAppBuf, oainfo.szApp, cchAppBuf);
  342. LocalFree(pszProtocol);
  343. pszProtocol = NULL;
  344. }
  345. ASSERT(! cchAppBuf ||
  346. (IS_VALID_STRING_PTR(pszAppBuf, -1) &&
  347. EVAL((UINT)lstrlen(pszAppBuf) < cchAppBuf)));
  348. ASSERT(SUCCEEDED(hr) ||
  349. (! cchAppBuf ||
  350. EVAL(! *pszAppBuf)));
  351. return(hr);
  352. }
  353. #ifdef DEBUG
  354. BOOL
  355. IsValidPCOPENASINFO(
  356. POPENASINFO poainfo)
  357. {
  358. return(IS_VALID_READ_PTR(poainfo, OPENASINFO) &&
  359. IS_VALID_STRING_PTR(poainfo->pcszFile, -1) &&
  360. (! poainfo->pcszClass ||
  361. IS_VALID_STRING_PTR(poainfo->pcszClass, -1)) &&
  362. FLAGS_ARE_VALID(poainfo->dwInFlags, OAIF_ALL) &&
  363. (! *poainfo->szApp ||
  364. IS_VALID_STRING_PTR(poainfo->szApp, -1)));
  365. }
  366. #endif /* DEBUG */
  367. /***************************** Exported Functions ****************************/
  368. /*----------------------------------------------------------
  369. Purpose: Invoke the MIME-type association dialog.
  370. Returns: standard hresult
  371. Cond: This API must conform to MIMEAssociationDialog semantics as
  372. defined in intshcut.h. URL.DLL auto-forwards to this API in
  373. Nashville.
  374. */
  375. STDAPI
  376. AssociateMIME(
  377. HWND hwndParent,
  378. DWORD dwInFlags,
  379. LPCTSTR pcszFile,
  380. LPCTSTR pcszMIMEContentType,
  381. LPTSTR pszAppBuf,
  382. UINT cchAppBuf)
  383. {
  384. HRESULT hr;
  385. /* Verify parameters. */
  386. #ifdef EXPV
  387. if (IS_VALID_HANDLE(hwndParent, WND) &&
  388. IS_VALID_STRING_PTR(pcszFile, -1) &&
  389. IS_VALID_STRING_PTR(pcszMIMEContentType, -1) &&
  390. IS_VALID_WRITE_BUFFER(pszAppBuf, TCHAR, cchAppBuf))
  391. {
  392. if (FLAGS_ARE_VALID(dwInFlags, ALL_MIMEASSOCDLG_FLAGS))
  393. {
  394. #endif
  395. hr = MyMIMEAssociationDialog(hwndParent, dwInFlags, pcszFile,
  396. pcszMIMEContentType, pszAppBuf,
  397. cchAppBuf);
  398. #ifdef EXPV
  399. }
  400. else
  401. hr = E_FLAGS;
  402. }
  403. else
  404. hr = E_POINTER;
  405. #endif
  406. return(hr);
  407. }
  408. STDAPI
  409. AssociateMIMEA(
  410. HWND hwndParent,
  411. DWORD dwInFlags,
  412. LPCSTR pcszFile,
  413. LPCSTR pcszMIMEContentType,
  414. LPSTR pszAppBuf,
  415. UINT cchAppBuf)
  416. {
  417. HRESULT hres;
  418. WCHAR wszFile[MAX_PATH];
  419. WCHAR wszMIMEType[MAX_PATH];
  420. LPWSTR pwszT;
  421. MultiByteToWideChar(CP_ACP, 0, pcszFile, -1, wszFile, SIZECHARS(wszFile));
  422. MultiByteToWideChar(CP_ACP, 0, pcszMIMEContentType, -1, wszMIMEType,
  423. SIZECHARS(wszMIMEType));
  424. *pszAppBuf = '\0';
  425. pwszT = (LPWSTR)LocalAlloc(LPTR, CbFromCch(cchAppBuf));
  426. if (pwszT)
  427. {
  428. hres = AssociateMIME(hwndParent, dwInFlags, wszFile, wszMIMEType,
  429. pwszT, cchAppBuf);
  430. if (SUCCEEDED(hres))
  431. {
  432. WideCharToMultiByte(CP_ACP, 0, pwszT, -1, pszAppBuf, cchAppBuf, NULL, NULL);
  433. }
  434. LocalFree(pwszT);
  435. pwszT = NULL;
  436. }
  437. else
  438. {
  439. hres = E_OUTOFMEMORY;
  440. }
  441. return hres;
  442. }
  443. /*----------------------------------------------------------
  444. Purpose: Invoke the URL association dialog.
  445. Returns: standard hresult
  446. Cond: This API must conform to URLAssociationDialog semantics as
  447. defined in intshcut.h. URL.DLL auto-forwards to this API in
  448. Nashville.
  449. */
  450. STDAPI
  451. AssociateURL(
  452. HWND hwndParent,
  453. DWORD dwInFlags,
  454. LPCTSTR pcszFile,
  455. LPCTSTR pcszURL,
  456. LPTSTR pszAppBuf,
  457. UINT cchAppBuf)
  458. {
  459. HRESULT hr;
  460. /* Verify parameters. */
  461. #ifdef EXPV
  462. if (IS_VALID_HANDLE(hwndParent, WND) &&
  463. (IsFlagSet(dwInFlags, URLASSOCDLG_FL_USE_DEFAULT_NAME) ||
  464. IS_VALID_STRING_PTR(pcszFile, -1)) &&
  465. IS_VALID_STRING_PTR(pcszURL, -1) &&
  466. IS_VALID_WRITE_BUFFER(pszAppBuf, TCHAR, cchAppBuf))
  467. {
  468. if (FLAGS_ARE_VALID(dwInFlags, ALL_URLASSOCDLG_FLAGS))
  469. {
  470. #endif
  471. hr = MyURLAssociationDialog(hwndParent, dwInFlags, pcszFile, pcszURL,
  472. pszAppBuf, cchAppBuf);
  473. #ifdef EXPV
  474. }
  475. else
  476. hr = E_FLAGS;
  477. }
  478. else
  479. hr = E_POINTER;
  480. #endif
  481. return(hr);
  482. }
  483. STDAPI
  484. AssociateURLA(
  485. HWND hwndParent,
  486. DWORD dwInFlags,
  487. LPCSTR pcszFile,
  488. LPCSTR pcszURL,
  489. LPSTR pszAppBuf,
  490. UINT cchAppBuf)
  491. {
  492. HRESULT hres;
  493. WCHAR wszFile[MAX_PATH];
  494. WCHAR wszURL[INTERNET_MAX_URL_LENGTH];
  495. LPWSTR pwszT;
  496. MultiByteToWideChar(CP_ACP, 0, pcszFile, -1, wszFile, SIZECHARS(wszFile));
  497. MultiByteToWideChar(CP_ACP, 0, pcszURL, -1, wszURL, SIZECHARS(wszURL));
  498. *pszAppBuf = '\0';
  499. pwszT = (LPWSTR)LocalAlloc(LPTR, CbFromCch(cchAppBuf));
  500. if (pwszT)
  501. {
  502. hres = AssociateURL(hwndParent, dwInFlags, wszFile, wszURL,
  503. pwszT, cchAppBuf);
  504. if (SUCCEEDED(hres))
  505. {
  506. WideCharToMultiByte(CP_ACP, 0, pwszT, -1, pszAppBuf, cchAppBuf, NULL, NULL);
  507. }
  508. LocalFree(pwszT);
  509. pwszT = NULL;
  510. }
  511. else
  512. {
  513. hres = E_OUTOFMEMORY;
  514. }
  515. return hres;
  516. }
  517. }; // extern "C"