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.

347 lines
7.9 KiB

  1. /*--------------------------------------------------------------------------*
  2. *
  3. * Microsoft Windows
  4. * Copyright (C) Microsoft Corporation, 1992 - 1999
  5. *
  6. * File: picon.cpp
  7. *
  8. * Contents: Implementation file for CPersistableIcon
  9. *
  10. * History: 19-Nov-98 jeffro Created
  11. *
  12. *--------------------------------------------------------------------------*/
  13. #include "picon.h"
  14. #include "stgio.h"
  15. #include "stddbg.h"
  16. #include "macros.h"
  17. #include "util.h"
  18. #include <comdef.h>
  19. #include <shellapi.h> // for ExtractIconEx
  20. #include <commctrl.h> // for HIMAGELIST
  21. /*
  22. * for comdbg.h (assumes client code is ATL-based)
  23. */
  24. #include <atlbase.h> // for CComModule
  25. extern CComModule _Module;
  26. #include "comdbg.h"
  27. const LPCWSTR g_pszCustomDataStorage = L"Custom Data";
  28. const LPCWSTR CPersistableIcon::s_pszIconFileStream = L"Icon";
  29. const LPCWSTR CPersistableIcon::s_pszIconBitsStream = L"Icon Bits";
  30. static HRESULT ReadIcon (IStream* pstm, CSmartIcon& icon);
  31. /*+-------------------------------------------------------------------------*
  32. * CPersistableIcon::~CPersistableIcon
  33. *
  34. *
  35. *--------------------------------------------------------------------------*/
  36. CPersistableIcon::~CPersistableIcon()
  37. {
  38. Cleanup();
  39. }
  40. /*+-------------------------------------------------------------------------*
  41. * CPersistableIcon::Cleanup
  42. *
  43. *
  44. *--------------------------------------------------------------------------*/
  45. void CPersistableIcon::Cleanup()
  46. {
  47. m_icon32.Release();
  48. m_icon16.Release();
  49. m_Data.Clear();
  50. }
  51. /*+-------------------------------------------------------------------------*
  52. * CPersistableIcon::operator=
  53. *
  54. *
  55. *--------------------------------------------------------------------------*/
  56. CPersistableIcon& CPersistableIcon::operator= (const CPersistableIconData& data)
  57. {
  58. if (&data != &m_Data)
  59. {
  60. m_Data = data;
  61. ExtractIcons ();
  62. }
  63. return (*this);
  64. }
  65. /*+-------------------------------------------------------------------------*
  66. * CPersistableIcon::GetIcon
  67. *
  68. * Returns an icon of the requested size.
  69. *
  70. * NOTE: this method cannot use SC's because it is used in mmcshext.dll,
  71. * which doesn't have access to mmcbase.dll, where SC is implemented.
  72. *--------------------------------------------------------------------------*/
  73. HRESULT CPersistableIcon::GetIcon (int nIconSize, CSmartIcon& icon) const
  74. {
  75. HRESULT hr = S_OK;
  76. switch (nIconSize)
  77. {
  78. /*
  79. * standard sizes can be returned directly
  80. */
  81. case 16: icon = m_icon16; break;
  82. case 32: icon = m_icon32; break;
  83. /*
  84. * non-standard sizes need to be scaled
  85. */
  86. default:
  87. /*
  88. * find the icon whose size is nearest to the requested size;
  89. * that one should scale with the most fidelity
  90. */
  91. const CSmartIcon& iconSrc = (abs (nIconSize-16) < abs (nIconSize-32))
  92. ? m_icon16
  93. : m_icon32;
  94. icon.Attach ((HICON) CopyImage ((HANDLE)(HICON) iconSrc, IMAGE_ICON,
  95. nIconSize, nIconSize, 0));
  96. /*
  97. * if the CopyImage failed, get the error code
  98. */
  99. if (icon == NULL)
  100. {
  101. hr = HRESULT_FROM_WIN32 (GetLastError());
  102. /*
  103. * just in case CopyImage failed without setting the last error
  104. */
  105. if (SUCCEEDED (hr))
  106. hr = E_FAIL;
  107. }
  108. break;
  109. }
  110. return (hr);
  111. }
  112. /*+-------------------------------------------------------------------------*
  113. * ExtractIcons
  114. *
  115. *
  116. *--------------------------------------------------------------------------*/
  117. bool CPersistableIcon::ExtractIcons ()
  118. {
  119. /*
  120. * clean out existing contents of our CSmartIcons
  121. */
  122. m_icon32.Release();
  123. m_icon16.Release();
  124. /*
  125. * extract the icons from the icon file
  126. */
  127. HICON hLargeIcon = NULL;
  128. HICON hSmallIcon = NULL;
  129. bool fSuccess = ExtractIconEx (m_Data.m_strIconFile.data(), m_Data.m_nIndex,
  130. &hLargeIcon, &hSmallIcon, 1);
  131. /*
  132. * if successful, attach them to our smart icons for resource management;
  133. * otherwise, clean up anything that might have been returned
  134. */
  135. if (fSuccess)
  136. {
  137. m_icon32.Attach (hLargeIcon);
  138. m_icon16.Attach (hSmallIcon);
  139. }
  140. else
  141. {
  142. if (hLargeIcon != NULL)
  143. DestroyIcon (hLargeIcon);
  144. if (hSmallIcon != NULL)
  145. DestroyIcon (hSmallIcon);
  146. }
  147. return (fSuccess);
  148. }
  149. /*+-------------------------------------------------------------------------*
  150. * CPersistableIcon::Load
  151. *
  152. *
  153. *--------------------------------------------------------------------------*/
  154. HRESULT CPersistableIcon::Load (LPCWSTR pszFilename)
  155. {
  156. HRESULT hr = E_FAIL;
  157. do // not a loop
  158. {
  159. IStoragePtr spRootStg;
  160. IStoragePtr spDefaultIconStg;
  161. hr = OpenDebugStorage (pszFilename,
  162. STGM_READ | STGM_SHARE_DENY_WRITE,
  163. &spRootStg);
  164. BREAK_ON_FAIL (hr);
  165. hr = OpenDebugStorage (spRootStg, g_pszCustomDataStorage,
  166. STGM_READ | STGM_SHARE_EXCLUSIVE,
  167. &spDefaultIconStg);
  168. BREAK_ON_FAIL (hr);
  169. hr = Load (spDefaultIconStg);
  170. } while (false);
  171. return (hr);
  172. }
  173. HRESULT CPersistableIcon::Load (IStorage* pStorage)
  174. {
  175. HRESULT hr;
  176. try
  177. {
  178. /*
  179. * read the icon data from the stream
  180. */
  181. IStreamPtr spStm;
  182. hr = OpenDebugStream (pStorage, s_pszIconFileStream,
  183. STGM_READ | STGM_SHARE_EXCLUSIVE,
  184. &spStm);
  185. THROW_ON_FAIL (hr);
  186. *spStm >> m_Data;
  187. hr = OpenDebugStream (pStorage, s_pszIconBitsStream,
  188. STGM_READ | STGM_SHARE_EXCLUSIVE,
  189. &spStm);
  190. THROW_ON_FAIL (hr);
  191. hr = ReadIcon (spStm, m_icon32);
  192. THROW_ON_FAIL (hr);
  193. hr = ReadIcon (spStm, m_icon16);
  194. THROW_ON_FAIL (hr);
  195. }
  196. catch (_com_error& err)
  197. {
  198. /*
  199. * Bug 393868: If anything failed, make sure we clean up anything
  200. * that was partially completed, to leave us in a coherent
  201. * (uninitialized) state.
  202. */
  203. Cleanup();
  204. hr = err.Error();
  205. }
  206. return (hr);
  207. }
  208. /*+-------------------------------------------------------------------------*
  209. * ReadIcon
  210. *
  211. *
  212. *--------------------------------------------------------------------------*/
  213. static HRESULT ReadIcon (IStream* pstm, CSmartIcon& icon)
  214. {
  215. HIMAGELIST himl = NULL;
  216. HRESULT hr = ReadCompatibleImageList (pstm, himl);
  217. if (himl != NULL)
  218. {
  219. icon.Attach (ImageList_GetIcon (himl, 0, ILD_NORMAL));
  220. if (icon != NULL)
  221. hr = S_OK;
  222. ImageList_Destroy (himl);
  223. }
  224. return (hr);
  225. }
  226. /*+-------------------------------------------------------------------------*
  227. * operator>>
  228. *
  229. * Reads a CPersistableIconData from a stream.
  230. *--------------------------------------------------------------------------*/
  231. IStream& operator>> (IStream& stm, CPersistableIconData& icon)
  232. {
  233. /*
  234. * Read the stream version
  235. */
  236. DWORD dwVersion;
  237. stm >> dwVersion;
  238. switch (dwVersion)
  239. {
  240. case 1:
  241. stm >> icon.m_nIndex;
  242. stm >> icon.m_strIconFile;
  243. break;
  244. /*
  245. * beta custom icon format, migrate it forward
  246. */
  247. case 0:
  248. {
  249. /*
  250. * Read the custom icon index
  251. */
  252. WORD wIconIndex;
  253. stm >> wIconIndex;
  254. icon.m_nIndex = wIconIndex;
  255. /*
  256. * Read the length, in bytes, of the filename
  257. */
  258. WORD cbFilename;
  259. stm >> cbFilename;
  260. /*
  261. * Read the custom icon filename (always in Unicode)
  262. */
  263. WCHAR wszFilename[MAX_PATH];
  264. if (cbFilename > sizeof (wszFilename))
  265. _com_issue_error (E_FAIL);
  266. DWORD cbRead;
  267. HRESULT hr = stm.Read (&wszFilename, cbFilename, &cbRead);
  268. THROW_ON_FAIL (hr);
  269. USES_CONVERSION;
  270. icon.m_strIconFile = W2T (wszFilename);
  271. break;
  272. }
  273. default:
  274. _com_issue_error (E_FAIL);
  275. break;
  276. }
  277. return (stm);
  278. }