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.

473 lines
11 KiB

  1. /*
  2. * extricon.cpp - IExtractIcon implementation for CFusionShortcut class.
  3. */
  4. /* Headers
  5. **********/
  6. #include "project.hpp"
  7. #include <stdio.h> // for _snwprintf
  8. /* Global Constants
  9. *******************/
  10. const WCHAR g_cwzDefaultIconKey[] = L"manifestfile\\DefaultIcon";
  11. const HKEY g_hkeySettings = HKEY_CLASSES_ROOT;
  12. /* Module Constants
  13. *******************/
  14. const WCHAR s_cwzGenericIconFile[] = L"adfshell.dll";
  15. const int s_ciGenericIconFileIndex = 0;
  16. void TrimString(PWSTR pwzTrimMe, PCWSTR pwzTrimChars)
  17. {
  18. PWSTR pwz = pwzTrimMe;;
  19. PWSTR pwzStartMeat = NULL;
  20. if ( !pwzTrimMe || !pwzTrimChars )
  21. goto exit;
  22. // Trim leading characters.
  23. while (*pwz && wcschr(pwzTrimChars, *pwz))
  24. {
  25. //CharNext(pwz);
  26. if (*pwz != L'\0') // this really will not be false...
  27. pwz++;
  28. }
  29. pwzStartMeat = pwz;
  30. // Trim trailing characters.
  31. if (*pwz)
  32. {
  33. pwz += wcslen(pwz);
  34. //CharPrev(pwzStartMeat, pwz);
  35. if (pwz != pwzStartMeat) // this check is not really necessary...
  36. pwz--;
  37. if (pwz > pwzStartMeat)
  38. {
  39. while (wcschr(pwzTrimChars, *pwz))
  40. {
  41. //CharPrev(pwzStartMeat, pwz);
  42. if (pwz != pwzStartMeat) // this really will not be false...
  43. pwz--;
  44. }
  45. //CharNext(pwz);
  46. if (*pwz != L'\0') // this check is not really necessary...
  47. pwz++;
  48. ASSERT(pwz > pwzStartMeat);
  49. *pwz = L'\0';
  50. }
  51. }
  52. // Relocate stripped string.
  53. if (*pwzStartMeat && pwzStartMeat > pwzTrimMe)
  54. // (+ 1) for null terminator.
  55. // BUGBUG?: is this going to bite us later?
  56. MoveMemory(pwzTrimMe, pwzStartMeat, (wcslen(pwzStartMeat)+1) * sizeof(WCHAR));
  57. else if (!*pwzStartMeat)
  58. pwzTrimMe[0] = L'\0';
  59. else
  60. ASSERT(pwzStartMeat == pwzTrimMe);
  61. exit:
  62. return;
  63. }
  64. /*
  65. ** TrimWhiteSpace()
  66. **
  67. ** Trims leading and trailing white space from a string in place.
  68. **
  69. ** Arguments:
  70. **
  71. ** Returns:
  72. **
  73. ** Side Effects: none
  74. */
  75. void TrimWhiteSpace(PWSTR pwzTrimMe)
  76. {
  77. TrimString(pwzTrimMe, g_cwzWhiteSpace);
  78. // TrimString() validates pwzTrimMe on output.
  79. return;
  80. }
  81. /*
  82. ** GetRegKeyValue()
  83. **
  84. ** Retrieves the data from a registry key's value.
  85. **
  86. ** Arguments:
  87. **
  88. ** Returns:
  89. **
  90. ** Side Effects: none
  91. */
  92. LONG GetRegKeyValue(HKEY hkeyParent, PCWSTR pcwzSubKey,
  93. PCWSTR pcwzValue, PDWORD pdwValueType,
  94. PBYTE pbyteBuf, PDWORD pdwcbBufLen)
  95. {
  96. LONG lResult;
  97. HKEY hkeySubKey;
  98. ASSERT(IS_VALID_HANDLE(hkeyParent, KEY));
  99. ASSERT(! pcwzSubKey || ! pcwzValue || ! pdwValueType || ! pbyteBuf);
  100. lResult = RegOpenKeyEx(hkeyParent, pcwzSubKey, 0, KEY_QUERY_VALUE,
  101. &hkeySubKey);
  102. if (lResult == ERROR_SUCCESS)
  103. {
  104. LONG lResultClose;
  105. lResult = RegQueryValueEx(hkeySubKey, pcwzValue, NULL, pdwValueType,
  106. pbyteBuf, pdwcbBufLen);
  107. lResultClose = RegCloseKey(hkeySubKey);
  108. if (lResult == ERROR_SUCCESS)
  109. lResult = lResultClose;
  110. }
  111. return(lResult);
  112. }
  113. /*
  114. ** GetRegKeyStringValue()
  115. **
  116. ** Retrieves the data from a registry key's string value.
  117. **
  118. ** Arguments:
  119. **
  120. ** Returns: ERROR_CANTREAD if not string
  121. **
  122. ** Side Effects: none
  123. */
  124. LONG GetRegKeyStringValue(HKEY hkeyParent, PCWSTR pcwzSubKey,
  125. PCWSTR pcwzValue, PWSTR pwzBuf,
  126. PDWORD pdwcbBufLen)
  127. {
  128. LONG lResult;
  129. DWORD dwValueType;
  130. // GetRegKeyValue() will verify the parameters.
  131. lResult = GetRegKeyValue(hkeyParent, pcwzSubKey, pcwzValue, &dwValueType,
  132. (PBYTE)pwzBuf, pdwcbBufLen);
  133. if (lResult == ERROR_SUCCESS && dwValueType != REG_SZ)
  134. lResult = ERROR_CANTREAD;
  135. return(lResult);
  136. }
  137. /*
  138. ** GetDefaultRegKeyValue()
  139. **
  140. ** Retrieves the data from a registry key's default string value.
  141. **
  142. ** Arguments:
  143. **
  144. ** Returns:
  145. **
  146. ** Side Effects: none
  147. */
  148. LONG GetDefaultRegKeyValue(HKEY hkeyParent, PCWSTR pcwzSubKey,
  149. PWSTR pwzBuf, PDWORD pdwcbBufLen)
  150. {
  151. // GetRegKeyStringValue() will verify the parameters.
  152. return(GetRegKeyStringValue(hkeyParent, pcwzSubKey, NULL, pwzBuf,
  153. pdwcbBufLen));
  154. }
  155. /***************************** Private Functions *****************************/
  156. /*
  157. ** ParseIconEntry()
  158. **
  159. **
  160. ** Arguments:
  161. **
  162. ** Returns: S_OK if icon entry parsed successfully.
  163. ** S_FALSE if not (empty string).
  164. ** (get 0 if icon index empty, or
  165. ** if icon index parsing fails)
  166. **
  167. ** Side Effects: The contents of pwzIconEntry are modified.
  168. **
  169. */
  170. HRESULT ParseIconEntry(LPWSTR pwzIconEntry, PINT pniIcon)
  171. {
  172. HRESULT hr = S_OK;
  173. LPWSTR pwzComma;
  174. // caller GetGenericIcon() will verify the parameters.
  175. pwzComma = wcschr(pwzIconEntry, L',');
  176. if (pwzComma)
  177. {
  178. *pwzComma++ = L'\0';
  179. LPWSTR pwzStopString=NULL;
  180. *pniIcon = (int) wcstol(pwzComma, &pwzStopString, 10);
  181. }
  182. else
  183. {
  184. *pniIcon = 0;
  185. }
  186. TrimWhiteSpace(pwzIconEntry);
  187. if (pwzIconEntry[0] == L'\0')
  188. {
  189. hr = S_FALSE;
  190. }
  191. ASSERT(IsValidIconIndex(hr, pwzIconEntry, MAX_PATH, *pniIcon));
  192. return(hr);
  193. }
  194. /*
  195. ** GetFallBackGenericIcon()
  196. **
  197. **
  198. ** Arguments:
  199. **
  200. ** Returns: S_OK if fallback generic icon information retrieved
  201. ** successfully.
  202. ** E_FAIL if not.
  203. **
  204. ** Side Effects: none
  205. */
  206. HRESULT GetFallBackGenericIcon(LPWSTR pwzIconFile,
  207. UINT ucbIconFileBufLen,
  208. PINT pniIcon)
  209. {
  210. HRESULT hr = S_OK;
  211. // Fall back to first icon in this module.
  212. // caller GetGenericIcon() will verify the parameters.
  213. if (ucbIconFileBufLen >= ( sizeof(s_cwzGenericIconFile) / sizeof(WCHAR) ))
  214. {
  215. wcscpy(pwzIconFile, s_cwzGenericIconFile);
  216. *pniIcon = s_ciGenericIconFileIndex;
  217. }
  218. else
  219. {
  220. hr = E_FAIL;
  221. }
  222. ASSERT(IsValidIconIndex(hr, pwzIconFile, ucbIconFileBufLen, *pniIcon));
  223. return(hr);
  224. }
  225. /*
  226. ** GetGenericIcon()
  227. **
  228. **
  229. ** Arguments:
  230. **
  231. ** Returns: S_OK if generic icon information retrieved successfully.
  232. ** Otherwise error (E_FAIL).
  233. **
  234. ** Side Effects: none
  235. */
  236. // assumptions: always structure the reg key value and fallback path so that the iconfile
  237. // can be found by the shell!!
  238. // should also consider making it a fully qualify path
  239. // finally the iconfile must exist
  240. HRESULT GetGenericIcon(LPWSTR pwzIconFile,
  241. UINT ucbIconFileBufLen, PINT pniIcon)
  242. {
  243. HRESULT hr = S_OK;
  244. DWORD dwcbLen = ucbIconFileBufLen;
  245. // caller GetIconLocation() will verify parameters
  246. ASSERT(IS_VALID_HANDLE(g_hkeySettings, KEY));
  247. if (GetDefaultRegKeyValue(g_hkeySettings, g_cwzDefaultIconKey, pwzIconFile, &dwcbLen)
  248. == ERROR_SUCCESS)
  249. hr = ParseIconEntry(pwzIconFile, pniIcon);
  250. else
  251. {
  252. // no icon entry
  253. hr = S_FALSE;
  254. }
  255. if (hr == S_FALSE)
  256. hr = GetFallBackGenericIcon(pwzIconFile, ucbIconFileBufLen, pniIcon);
  257. ASSERT(IsValidIconIndex(hr, pwzIconFile, ucbIconFileBufLen, *pniIcon));
  258. return(hr);
  259. }
  260. /********************************** Methods **********************************/
  261. HRESULT STDMETHODCALLTYPE CFusionShortcut::GetIconLocation(UINT uInFlags,
  262. LPWSTR pwzIconFile,
  263. UINT ucbIconFileBufLen,
  264. PINT pniIcon,
  265. PUINT puOutFlags)
  266. {
  267. // is there any pref hit by doing this logic/probing here?
  268. // maybe this can be done in IPersistFile::Load instead?
  269. // always attempt to return S_OK or S_FALSE
  270. // only exception is that one case of E_INVALIDARG right below
  271. HRESULT hr=S_OK;
  272. if (!pwzIconFile || !pniIcon || ucbIconFileBufLen <= 0)
  273. {
  274. // should this return S_FALSE anyway so that the default shell icon is used?
  275. hr = E_INVALIDARG;
  276. goto exit;
  277. }
  278. if (IS_FLAG_CLEAR(uInFlags, GIL_OPENICON))
  279. {
  280. // .. this get the path ...
  281. hr = GetIconLocation(pwzIconFile, ucbIconFileBufLen, pniIcon);
  282. if (hr == S_OK && GetFileAttributes(pwzIconFile) == (DWORD)-1)
  283. {
  284. // if the file specified by iconfile does not exist, try again in working dir
  285. // it can be a relative path...
  286. // see note in shlink.cpp for string array size
  287. LPWSTR pwzWorkingDir = new WCHAR[ucbIconFileBufLen];
  288. hr = GetWorkingDirectory(pwzWorkingDir, ucbIconFileBufLen);
  289. if (hr != S_OK)
  290. hr = S_FALSE;
  291. else
  292. {
  293. LPWSTR pwzPath = new WCHAR[ucbIconFileBufLen];
  294. // working dir does not end w/ '\'
  295. _snwprintf(pwzPath, ucbIconFileBufLen, L"%s\\%s", pwzWorkingDir, pwzIconFile);
  296. if (GetFileAttributes(pwzPath) == (DWORD)-1)
  297. hr = S_FALSE;
  298. else
  299. wcscpy(pwzIconFile, pwzPath);
  300. delete [] pwzPath;
  301. }
  302. delete [] pwzWorkingDir;
  303. }
  304. // BUGBUG?: change to '!= S_OK'?
  305. // no need because GetIconLocation(,,) only returns S_OK/S_FALSE here
  306. if (hr == S_FALSE)
  307. {
  308. if (m_pwzPath)
  309. {
  310. // no icon file, use the entry point...
  311. // BUGBUG?: passing NULL as PWIN32_FIND_DATA will assert..
  312. hr = GetPath(pwzIconFile, ucbIconFileBufLen, NULL, SLGP_SHORTPATH); //?????? 0);
  313. if (hr != S_OK || GetFileAttributes(pwzIconFile) == (DWORD)-1)
  314. hr = S_FALSE;
  315. *pniIcon = 0;
  316. }
  317. /*else
  318. hr = S_FALSE;*/
  319. if (hr == S_FALSE)
  320. {
  321. // ... there's nothing?
  322. // Use generic URL icon.
  323. // see assumptions on GetGenericIcon()
  324. hr = GetGenericIcon(pwzIconFile, ucbIconFileBufLen, pniIcon);
  325. if (FAILED(hr))
  326. // worst case: ask shell to use its generic icon
  327. hr = S_FALSE;
  328. }
  329. }
  330. }
  331. else
  332. // No "open look" icon.
  333. hr = S_FALSE;
  334. if (hr != S_OK)
  335. {
  336. // see shelllink?
  337. if (ucbIconFileBufLen > 0)
  338. *pwzIconFile = L'\0';
  339. *pniIcon = 0;
  340. }
  341. exit:
  342. if (puOutFlags)
  343. *puOutFlags = 0;
  344. // ignore puOutFlags == NULL case
  345. ASSERT(IsValidIconIndex(hr, pwzIconFile, ucbIconFileBufLen, *pniIcon))// &&
  346. return(hr);
  347. }
  348. HRESULT STDMETHODCALLTYPE CFusionShortcut::Extract(LPCWSTR pcwzIconFile,
  349. UINT uiIcon,
  350. HICON* phiconLarge,
  351. HICON* phiconSmall,
  352. UINT ucIconSize)
  353. {
  354. HRESULT hr;
  355. ASSERT(IsValidIconIndex(S_OK, pcwzIconFile, MAX_PATH, uiIcon));
  356. // FEATURE: Validate ucIconSize here.
  357. if (phiconLarge)
  358. *phiconLarge = NULL;
  359. if (phiconSmall)
  360. *phiconSmall = NULL;
  361. // Use caller's default implementation of ExtractIcon().
  362. // GetIconLocation() should return good path and index
  363. hr = S_FALSE;
  364. ASSERT((hr == S_OK &&
  365. IS_VALID_HANDLE(*phiconLarge, ICON) &&
  366. IS_VALID_HANDLE(*phiconSmall, ICON)) ||
  367. (hr != S_OK &&
  368. ! *phiconLarge &&
  369. ! *phiconSmall));
  370. return(hr);
  371. }