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.

595 lines
14 KiB

  1. /*
  2. * extricon.cpp - IExtractIcon implementation for URL class.
  3. */
  4. /* Headers
  5. **********/
  6. #include "project.hpp"
  7. #pragma hdrstop
  8. #include "assoc.h"
  9. /* Global Constants
  10. *******************/
  11. #pragma data_seg(DATA_SEG_READ_ONLY)
  12. extern const char g_cszURLDefaultIconKey[] = "InternetShortcut\\DefaultIcon";
  13. extern const HKEY g_hkeyURLSettings = HKEY_LOCAL_MACHINE;
  14. #pragma data_seg()
  15. /* Module Constants
  16. *******************/
  17. #pragma data_seg(DATA_SEG_READ_ONLY)
  18. PRIVATE_DATA const char s_cszDefaultIconSubKey[] = "DefaultIcon";
  19. PRIVATE_DATA const char s_cszGenericURLIconFile[] = "url.dll";
  20. PRIVATE_DATA const int s_ciGenericURLIcon = 0;
  21. // IExtractIcon::GetIconLocation() flag combinations
  22. PRIVATE_DATA const int ALL_GIL_IN_FLAGS = (GIL_OPENICON |
  23. GIL_FORSHELL);
  24. PRIVATE_DATA const int ALL_GIL_OUT_FLAGS = (GIL_SIMULATEDOC |
  25. GIL_PERINSTANCE |
  26. GIL_PERCLASS |
  27. GIL_NOTFILENAME |
  28. GIL_DONTCACHE);
  29. #pragma data_seg()
  30. /***************************** Private Functions *****************************/
  31. /*
  32. ** ParseIconEntry()
  33. **
  34. **
  35. **
  36. ** Arguments:
  37. **
  38. ** Returns: S_OK if icon entry parsed successfully.
  39. ** E_FAIL if not.
  40. **
  41. ** Side Effects: The contents of pszIconEntry are destroyed.
  42. **
  43. ** pszIconEntry and pszIconFile may be the same.
  44. */
  45. PRIVATE_CODE HRESULT ParseIconEntry(PSTR pszIconEntry, PSTR pszIconFile,
  46. UINT ucbIconFileBufLen, PINT pniIcon)
  47. {
  48. HRESULT hr;
  49. PSTR pszComma;
  50. ASSERT(IS_VALID_STRING_PTR(pszIconEntry, STR));
  51. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszIconFile, STR, ucbIconFileBufLen));
  52. ASSERT(IS_VALID_WRITE_PTR(pniIcon, INT));
  53. pszComma = StrChr(pszIconEntry, ',');
  54. if (pszComma)
  55. {
  56. *pszComma++ = '\0';
  57. TrimWhiteSpace(pszComma);
  58. *pniIcon = StringToInt(pszComma);
  59. }
  60. else
  61. {
  62. *pniIcon = 0;
  63. WARNING_OUT(("ParseIconEntry(): No icon index in entry %s. Using icon index 0.",
  64. pszIconEntry));
  65. }
  66. TrimWhiteSpace(pszIconEntry);
  67. if ((UINT)lstrlen(pszIconEntry) < ucbIconFileBufLen)
  68. {
  69. lstrcpy(pszIconFile, pszIconEntry);
  70. hr = S_OK;
  71. TRACE_OUT(("ParseIconEntry(): Parsed icon file %s, index %d.",
  72. pszIconFile,
  73. *pniIcon));
  74. }
  75. else
  76. {
  77. hr = S_FALSE;
  78. // (+ 1) for null terminator.
  79. WARNING_OUT(("ParseIconEntry(): Icon file buffer too small for icon file %s (%u bytes supplied, %lu bytes required).",
  80. pszIconEntry,
  81. ucbIconFileBufLen,
  82. lstrlen(pszIconEntry) + 1));
  83. }
  84. ASSERT(IsValidIconIndex(hr, pszIconFile, ucbIconFileBufLen, *pniIcon));
  85. return(hr);
  86. }
  87. /*
  88. ** GetURLIcon()
  89. **
  90. **
  91. **
  92. ** Arguments:
  93. **
  94. ** Returns: S_OK if icon information retrieved successfully.
  95. ** S_FALSE if no icon entry for this URL.
  96. ** Otherwise error.
  97. **
  98. ** Side Effects: none
  99. */
  100. PRIVATE_CODE HRESULT GetURLIcon(HKEY hkey, PCSTR pcszKey, PSTR pszIconFile,
  101. UINT ucbIconFileBufLen, PINT pniIcon)
  102. {
  103. HRESULT hr;
  104. DWORD dwcbLen = ucbIconFileBufLen;
  105. ASSERT(IS_VALID_HANDLE(hkey, KEY));
  106. ASSERT(IS_VALID_STRING_PTR(pcszKey, CSTR));
  107. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszIconFile, STR, ucbIconFileBufLen));
  108. ASSERT(IS_VALID_WRITE_PTR(pniIcon, INT));
  109. if (GetDefaultRegKeyValue(hkey, pcszKey, pszIconFile, &dwcbLen)
  110. == ERROR_SUCCESS)
  111. hr = ParseIconEntry(pszIconFile, pszIconFile, ucbIconFileBufLen,
  112. pniIcon);
  113. else
  114. {
  115. // No protocol handler.
  116. hr = S_FALSE;
  117. TRACE_OUT(("GetURLIcon(): Couldn't get default value for key %s.",
  118. pcszKey));
  119. }
  120. ASSERT(IsValidIconIndex(hr, pszIconFile, ucbIconFileBufLen, *pniIcon));
  121. return(hr);
  122. }
  123. /*
  124. ** GetFallBackGenericURLIcon()
  125. **
  126. **
  127. **
  128. ** Arguments:
  129. **
  130. ** Returns: S_OK if fallback generic icon information retrieved
  131. ** successfully.
  132. ** E_FAIL if not.
  133. **
  134. ** Side Effects: none
  135. */
  136. PRIVATE_CODE HRESULT GetFallBackGenericURLIcon(PSTR pszIconFile,
  137. UINT ucbIconFileBufLen,
  138. PINT pniIcon)
  139. {
  140. HRESULT hr;
  141. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszIconFile, STR, ucbIconFileBufLen));
  142. ASSERT(IS_VALID_WRITE_PTR(pniIcon, INT));
  143. // Fall back to first icon in this module.
  144. if (ucbIconFileBufLen >= sizeof(s_cszGenericURLIconFile))
  145. {
  146. lstrcpy(pszIconFile, s_cszGenericURLIconFile);
  147. *pniIcon = s_ciGenericURLIcon;
  148. hr = S_OK;
  149. TRACE_OUT(("GetFallBackGenericURLIcon(): Using generic URL icon file %s, index %d.",
  150. s_cszGenericURLIconFile,
  151. s_ciGenericURLIcon));
  152. }
  153. else
  154. {
  155. hr = E_FAIL;
  156. WARNING_OUT(("GetFallBackGenericURLIcon(): Icon file buffer too small for generic icon file %s (%u bytes supplied, %lu bytes required).",
  157. s_cszGenericURLIconFile,
  158. ucbIconFileBufLen,
  159. sizeof(s_cszGenericURLIconFile)));
  160. }
  161. ASSERT(IsValidIconIndex(hr, pszIconFile, ucbIconFileBufLen, *pniIcon));
  162. return(hr);
  163. }
  164. /*
  165. ** GetGenericURLIcon()
  166. **
  167. **
  168. **
  169. ** Arguments:
  170. **
  171. ** Returns: S_OK if generic icon information retrieved successfully.
  172. ** Otherwise error.
  173. **
  174. ** Side Effects: none
  175. */
  176. PRIVATE_CODE HRESULT GetGenericURLIcon(PSTR pszIconFile,
  177. UINT ucbIconFileBufLen, PINT pniIcon)
  178. {
  179. HRESULT hr;
  180. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszIconFile, STR, ucbIconFileBufLen));
  181. ASSERT(IS_VALID_WRITE_PTR(pniIcon, INT));
  182. hr = GetURLIcon(g_hkeyURLProtocols, g_cszURLDefaultIconKey, pszIconFile,
  183. ucbIconFileBufLen, pniIcon);
  184. if (hr == S_FALSE)
  185. hr = GetFallBackGenericURLIcon(pszIconFile, ucbIconFileBufLen, pniIcon);
  186. ASSERT(IsValidIconIndex(hr, pszIconFile, ucbIconFileBufLen, *pniIcon));
  187. return(hr);
  188. }
  189. /****************************** Public Functions *****************************/
  190. /*
  191. ** StringToInt()
  192. **
  193. **
  194. **
  195. ** Arguments:
  196. **
  197. ** Returns:
  198. **
  199. ** Side Effects: none
  200. **
  201. ** Stops at first non-digit character encountered.
  202. */
  203. PUBLIC_CODE int StringToInt(PCSTR pcsz)
  204. {
  205. int nResult = 0;
  206. BOOL bNegative;
  207. #ifdef DEBUG
  208. PCSTR pcszStart = pcsz;
  209. #endif
  210. ASSERT(IS_VALID_STRING_PTR(pcsz, CSTR));
  211. if (*pcsz == '-')
  212. {
  213. bNegative = TRUE;
  214. pcsz++;
  215. }
  216. else
  217. bNegative = FALSE;
  218. while (IsDigit(*pcsz))
  219. {
  220. ASSERT(nResult <= INT_MAX / 10);
  221. nResult *= 10;
  222. ASSERT(nResult <= INT_MAX - (*pcsz - '0'));
  223. nResult += *pcsz++ - '0';
  224. }
  225. if (*pcsz) {
  226. WARNING_OUT(("StringToInt(): Stopped at non-digit character %c in string %s.",
  227. *pcsz,
  228. pcszStart));
  229. }
  230. // nResult may be any value.
  231. return(bNegative ? - nResult : nResult);
  232. }
  233. PUBLIC_CODE BOOL IsWhiteSpace(char ch)
  234. {
  235. return((ch && StrChr(g_cszWhiteSpace, ch)) ? TRUE : FALSE);
  236. }
  237. PUBLIC_CODE BOOL AnyMeat(PCSTR pcsz)
  238. {
  239. ASSERT(! pcsz ||
  240. IS_VALID_STRING_PTR(pcsz, CSTR));
  241. return(pcsz ? StrSpn(pcsz, g_cszWhiteSpace) < lstrlen(pcsz) : FALSE);
  242. }
  243. PUBLIC_CODE HRESULT CopyURLProtocol(PCSTR pcszURL, PSTR *ppszProtocol)
  244. {
  245. HRESULT hr;
  246. PARSEDURL pu;
  247. ASSERT(IS_VALID_STRING_PTR(pcszURL, CSTR));
  248. ASSERT(IS_VALID_WRITE_PTR(ppszProtocol, PSTR));
  249. *ppszProtocol = NULL;
  250. pu.cbSize = sizeof(pu);
  251. hr = ParseURL(pcszURL, &pu);
  252. if (hr == S_OK)
  253. {
  254. // (+ 1) for null terminator.
  255. *ppszProtocol = new(char[pu.cchProtocol + 1]);
  256. if (*ppszProtocol)
  257. {
  258. // (+ 1) for null terminator.
  259. lstrcpyn(*ppszProtocol, pu.pszProtocol, pu.cchProtocol + 1);
  260. ASSERT((UINT)lstrlen(*ppszProtocol) == pu.cchProtocol);
  261. }
  262. else
  263. hr = E_OUTOFMEMORY;
  264. }
  265. ASSERT(FAILED(hr) ||
  266. (hr == S_OK &&
  267. IS_VALID_STRING_PTR(*ppszProtocol, STR)));
  268. return(hr);
  269. }
  270. PUBLIC_CODE HRESULT CopyURLSuffix(PCSTR pcszURL, PSTR *ppszSuffix)
  271. {
  272. HRESULT hr;
  273. PARSEDURL pu;
  274. ASSERT(IS_VALID_STRING_PTR(pcszURL, CSTR));
  275. ASSERT(IS_VALID_WRITE_PTR(ppszSuffix, PSTR));
  276. *ppszSuffix = NULL;
  277. hr = ParseURL(pcszURL, &pu);
  278. if (hr == S_OK)
  279. {
  280. // (+ 1) for null terminator.
  281. *ppszSuffix = new(char[pu.cchSuffix + 1]);
  282. if (*ppszSuffix)
  283. {
  284. // (+ 1) for null terminator.
  285. lstrcpyn(*ppszSuffix, pu.pszSuffix, pu.cchSuffix + 1);
  286. ASSERT((UINT)lstrlen(*ppszSuffix) == pu.cchSuffix);
  287. hr = S_OK;
  288. }
  289. else
  290. hr = E_OUTOFMEMORY;
  291. }
  292. ASSERT(FAILED(hr) ||
  293. IS_VALID_STRING_PTR(*ppszSuffix, STR));
  294. return(hr);
  295. }
  296. PUBLIC_CODE HRESULT GetProtocolKey(PCSTR pcszProtocol, PCSTR pcszSubKey,
  297. PSTR *ppszKey)
  298. {
  299. HRESULT hr;
  300. ULONG ulcbKeyLen;
  301. ASSERT(IS_VALID_STRING_PTR(pcszProtocol, STR));
  302. ASSERT(IS_VALID_STRING_PTR(pcszSubKey, CSTR));
  303. ASSERT(IS_VALID_WRITE_PTR(ppszKey, PSTR));
  304. // (+ 1) for possible separator.
  305. // (+ 1) for null terminator.
  306. ulcbKeyLen = lstrlen(pcszProtocol) + 1 + lstrlen(pcszSubKey) + 1;
  307. *ppszKey = new(char[ulcbKeyLen]);
  308. if (*ppszKey)
  309. {
  310. lstrcpy(*ppszKey, pcszProtocol);
  311. PathAppend(*ppszKey, pcszSubKey);
  312. ASSERT((UINT)lstrlen(*ppszKey) < ulcbKeyLen);
  313. hr = S_OK;
  314. }
  315. else
  316. hr = E_OUTOFMEMORY;
  317. ASSERT((hr == S_OK &&
  318. IS_VALID_STRING_PTR(*ppszKey, STR)) ||
  319. hr == E_OUTOFMEMORY);
  320. return(hr);
  321. }
  322. PUBLIC_CODE HRESULT GetURLKey(PCSTR pcszURL, PCSTR pcszSubKey, PSTR *pszKey)
  323. {
  324. HRESULT hr;
  325. PSTR pszProtocol;
  326. ASSERT(IS_VALID_STRING_PTR(pcszURL, CSTR));
  327. ASSERT(IS_VALID_STRING_PTR(pcszSubKey, CSTR));
  328. ASSERT(IS_VALID_WRITE_PTR(pszKey, PSTR));
  329. *pszKey = NULL;
  330. hr = CopyURLProtocol(pcszURL, &pszProtocol);
  331. if (hr == S_OK)
  332. {
  333. hr = GetProtocolKey(pszProtocol, pcszSubKey, pszKey);
  334. delete pszProtocol;
  335. pszProtocol = NULL;
  336. }
  337. ASSERT((hr == S_OK &&
  338. IS_VALID_STRING_PTR(*pszKey, STR)) ||
  339. FAILED(hr));
  340. return(hr);
  341. }
  342. /********************************** Methods **********************************/
  343. HRESULT STDMETHODCALLTYPE InternetShortcut::GetIconLocation(
  344. UINT uInFlags,
  345. PSTR pszIconFile,
  346. UINT ucbIconFileBufLen,
  347. PINT pniIcon,
  348. PUINT puOutFlags)
  349. {
  350. HRESULT hr;
  351. DebugEntry(InternetShortcut::GetIconLocation);
  352. ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
  353. ASSERT(FLAGS_ARE_VALID(uInFlags, ALL_GIL_IN_FLAGS));
  354. ASSERT(IS_VALID_WRITE_BUFFER_PTR(pszIconFile, STR, ucbIconFileBufLen));
  355. ASSERT(IS_VALID_WRITE_PTR(pniIcon, INT));
  356. ASSERT(IS_VALID_WRITE_PTR(puOutFlags, UINT));
  357. if (IS_FLAG_CLEAR(uInFlags, GIL_OPENICON))
  358. {
  359. hr = GetIconLocation(pszIconFile, ucbIconFileBufLen, pniIcon);
  360. if (hr != S_OK)
  361. {
  362. if (m_pszURL)
  363. {
  364. PSTR pszDefaultIconKey;
  365. // Look up URL icon based on protocol handler.
  366. hr = GetURLKey(m_pszURL, s_cszDefaultIconSubKey,
  367. &pszDefaultIconKey);
  368. if (hr == S_OK)
  369. {
  370. hr = GetURLIcon(g_hkeyURLProtocols, pszDefaultIconKey,
  371. pszIconFile, ucbIconFileBufLen, pniIcon);
  372. delete pszDefaultIconKey;
  373. pszDefaultIconKey = NULL;
  374. }
  375. }
  376. else
  377. hr = S_FALSE;
  378. if (hr == S_FALSE)
  379. {
  380. // Use generic URL icon.
  381. hr = GetGenericURLIcon(pszIconFile, ucbIconFileBufLen, pniIcon);
  382. if (hr == S_OK) {
  383. TRACE_OUT(("InternetShortcut::GetIconLocation(): Using generic URL icon."));
  384. }
  385. }
  386. if (hr == S_OK)
  387. {
  388. char rgchFullPath[MAX_PATH_LEN];
  389. hr = FullyQualifyPath(pszIconFile, rgchFullPath,
  390. sizeof(rgchFullPath));
  391. if (hr == S_OK)
  392. {
  393. if ((UINT)lstrlen(rgchFullPath) < ucbIconFileBufLen)
  394. lstrcpy(pszIconFile, rgchFullPath);
  395. else
  396. hr = E_FAIL;
  397. }
  398. }
  399. }
  400. }
  401. else
  402. // No "open look" icon.
  403. hr = S_FALSE;
  404. if (hr != S_OK)
  405. {
  406. if (ucbIconFileBufLen > 0)
  407. *pszIconFile = '\0';
  408. *pniIcon = 0;
  409. }
  410. *puOutFlags = 0;
  411. ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
  412. ASSERT(IsValidIconIndex(hr, pszIconFile, ucbIconFileBufLen, *pniIcon) &&
  413. FLAGS_ARE_VALID(*puOutFlags, ALL_GIL_OUT_FLAGS));
  414. DebugExitHRESULT(InternetShortcut::GetIconLocation, hr);
  415. return(hr);
  416. }
  417. #pragma warning(disable:4100) /* "unreferenced formal parameter" warning */
  418. HRESULT STDMETHODCALLTYPE InternetShortcut::Extract(PCSTR pcszIconFile,
  419. UINT uiIcon,
  420. PHICON phiconLarge,
  421. PHICON phiconSmall,
  422. UINT ucIconSize)
  423. {
  424. HRESULT hr;
  425. DebugEntry(InternetShortcut::Extract);
  426. ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
  427. ASSERT(IS_VALID_STRING_PTR(pcszIconFile, CSTR));
  428. ASSERT(IsValidIconIndex(S_OK, pcszIconFile, MAX_PATH_LEN, uiIcon));
  429. ASSERT(IS_VALID_WRITE_PTR(phiconLarge, HICON));
  430. ASSERT(IS_VALID_WRITE_PTR(phiconSmall, HICON));
  431. // FEATURE: Validate ucIconSize here.
  432. *phiconLarge = NULL;
  433. *phiconSmall = NULL;
  434. // Use caller's default implementation of ExtractIcon().
  435. hr = S_FALSE;
  436. ASSERT(IS_VALID_STRUCT_PTR(this, CInternetShortcut));
  437. ASSERT((hr == S_OK &&
  438. IS_VALID_HANDLE(*phiconLarge, ICON) &&
  439. IS_VALID_HANDLE(*phiconSmall, ICON)) ||
  440. (hr != S_OK &&
  441. ! *phiconLarge &&
  442. ! *phiconSmall));
  443. DebugExitHRESULT(InternetShortcut::Extract, hr);
  444. return(hr);
  445. }
  446. #pragma warning(default:4100) /* "unreferenced formal parameter" warning */