1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Registry namespace extension 4 * FILE: dll/win32/shell32/extracticon.c 5 * PURPOSE: Icon extraction 6 * 7 * PROGRAMMERS: Herv� Poussineau (hpoussin@reactos.org) 8 */ 9 10 #include "precomp.h" 11 12 WINE_DEFAULT_DEBUG_CHANNEL(shell); 13 14 struct IconLocation 15 { 16 LPWSTR file; 17 UINT index; 18 }; 19 20 class CExtractIcon : 21 public CComObjectRootEx<CComMultiThreadModelNoCS>, 22 public IDefaultExtractIconInit, 23 public IExtractIconW, 24 public IExtractIconA, 25 public IPersistFile 26 { 27 private: 28 UINT flags; 29 struct IconLocation defaultIcon; 30 struct IconLocation normalIcon; 31 struct IconLocation openIcon; 32 struct IconLocation shortcutIcon; 33 public: 34 CExtractIcon(); 35 ~CExtractIcon(); 36 37 // IDefaultExtractIconInit 38 virtual HRESULT STDMETHODCALLTYPE SetDefaultIcon(LPCWSTR pszFile, int iIcon); 39 virtual HRESULT STDMETHODCALLTYPE SetFlags(UINT uFlags); 40 virtual HRESULT STDMETHODCALLTYPE SetKey(HKEY hkey); 41 virtual HRESULT STDMETHODCALLTYPE SetNormalIcon(LPCWSTR pszFile, int iIcon); 42 virtual HRESULT STDMETHODCALLTYPE SetOpenIcon(LPCWSTR pszFile, int iIcon); 43 virtual HRESULT STDMETHODCALLTYPE SetShortcutIcon(LPCWSTR pszFile, int iIcon); 44 45 // IExtractIconW 46 virtual HRESULT STDMETHODCALLTYPE GetIconLocation(UINT uFlags, LPWSTR szIconFile, UINT cchMax, int *piIndex, UINT *pwFlags); 47 virtual HRESULT STDMETHODCALLTYPE Extract(LPCWSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize); 48 49 // IExtractIconA 50 virtual HRESULT STDMETHODCALLTYPE GetIconLocation(UINT uFlags, LPSTR szIconFile, UINT cchMax, int *piIndex, UINT *pwFlags); 51 virtual HRESULT STDMETHODCALLTYPE Extract(LPCSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize); 52 53 // IPersist 54 virtual HRESULT STDMETHODCALLTYPE GetClassID(CLSID *pClassID); 55 virtual HRESULT STDMETHODCALLTYPE IsDirty(); 56 57 // IPersistFile 58 virtual HRESULT STDMETHODCALLTYPE Load(LPCOLESTR pszFileName, DWORD dwMode); 59 virtual HRESULT STDMETHODCALLTYPE Save(LPCOLESTR pszFileName, BOOL fRemember); 60 virtual HRESULT STDMETHODCALLTYPE SaveCompleted(LPCOLESTR pszFileName); 61 virtual HRESULT STDMETHODCALLTYPE GetCurFile(LPOLESTR *ppszFileName); 62 63 BEGIN_COM_MAP(CExtractIcon) 64 COM_INTERFACE_ENTRY_IID(IID_IDefaultExtractIconInit, IDefaultExtractIconInit) 65 COM_INTERFACE_ENTRY_IID(IID_IExtractIconW, IExtractIconW) 66 COM_INTERFACE_ENTRY_IID(IID_IExtractIconA, IExtractIconA) 67 COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist) 68 COM_INTERFACE_ENTRY_IID(IID_IPersistFile, IPersistFile) 69 END_COM_MAP() 70 }; 71 72 VOID DuplicateString( 73 LPCWSTR Source, 74 LPWSTR *Destination) 75 { 76 SIZE_T cb; 77 78 if (*Destination) 79 CoTaskMemFree(*Destination); 80 81 cb = (wcslen(Source) + 1) * sizeof(WCHAR); 82 *Destination = (LPWSTR)CoTaskMemAlloc(cb); 83 if (!*Destination) 84 return; 85 CopyMemory(*Destination, Source, cb); 86 } 87 88 CExtractIcon::CExtractIcon() 89 { 90 flags = 0; 91 memset(&defaultIcon, 0, sizeof(defaultIcon)); 92 memset(&normalIcon, 0, sizeof(normalIcon)); 93 memset(&openIcon, 0, sizeof(openIcon)); 94 memset(&shortcutIcon, 0, sizeof(shortcutIcon)); 95 } 96 97 CExtractIcon::~CExtractIcon() 98 { 99 if (defaultIcon.file) CoTaskMemFree(defaultIcon.file); 100 if (normalIcon.file) CoTaskMemFree(normalIcon.file); 101 if (openIcon.file) CoTaskMemFree(openIcon.file); 102 if (shortcutIcon.file) CoTaskMemFree(shortcutIcon.file); 103 } 104 105 HRESULT STDMETHODCALLTYPE CExtractIcon::SetDefaultIcon( 106 LPCWSTR pszFile, 107 int iIcon) 108 { 109 TRACE("(%p, %s, %d)\n", this, debugstr_w(pszFile), iIcon); 110 111 DuplicateString(pszFile, &defaultIcon.file); 112 if (!defaultIcon.file) 113 return E_OUTOFMEMORY; 114 defaultIcon.index = iIcon; 115 return S_OK; 116 } 117 118 HRESULT STDMETHODCALLTYPE CExtractIcon::SetFlags( 119 UINT uFlags) 120 { 121 TRACE("(%p, 0x%x)\n", this, uFlags); 122 123 flags = uFlags; 124 return S_OK; 125 } 126 127 HRESULT STDMETHODCALLTYPE CExtractIcon::SetKey( 128 HKEY hkey) 129 { 130 FIXME("(%p, %p)\n", this, hkey); 131 UNIMPLEMENTED; 132 return E_NOTIMPL; 133 } 134 135 HRESULT STDMETHODCALLTYPE CExtractIcon::SetNormalIcon( 136 LPCWSTR pszFile, 137 int iIcon) 138 { 139 TRACE("(%p, %s, %d)\n", this, debugstr_w(pszFile), iIcon); 140 141 DuplicateString(pszFile, &normalIcon.file); 142 if (!normalIcon.file) 143 return E_OUTOFMEMORY; 144 normalIcon.index = iIcon; 145 return S_OK; 146 } 147 148 HRESULT STDMETHODCALLTYPE CExtractIcon::SetOpenIcon( 149 LPCWSTR pszFile, 150 int iIcon) 151 { 152 TRACE("(%p, %s, %d)\n", this, debugstr_w(pszFile), iIcon); 153 154 DuplicateString(pszFile, &openIcon.file); 155 if (!openIcon.file) 156 return E_OUTOFMEMORY; 157 openIcon.index = iIcon; 158 return S_OK; 159 } 160 161 HRESULT STDMETHODCALLTYPE CExtractIcon::SetShortcutIcon( 162 LPCWSTR pszFile, 163 int iIcon) 164 { 165 TRACE("(%p, %s, %d)\n", this, debugstr_w(pszFile), iIcon); 166 167 DuplicateString(pszFile, &shortcutIcon.file); 168 if (!shortcutIcon.file) 169 return E_OUTOFMEMORY; 170 shortcutIcon.index = iIcon; 171 return S_OK; 172 } 173 174 HRESULT STDMETHODCALLTYPE CExtractIcon::GetIconLocation( 175 UINT uFlags, 176 LPWSTR szIconFile, 177 UINT cchMax, 178 int *piIndex, 179 UINT *pwFlags) 180 { 181 const struct IconLocation *icon = NULL; 182 SIZE_T cb; 183 184 TRACE("(%p, 0x%x, %s, 0x%x, %p, %p)\n", this, uFlags, debugstr_w(szIconFile), cchMax, piIndex, pwFlags); 185 186 if (!piIndex || !pwFlags) 187 return E_POINTER; 188 189 if (uFlags & GIL_DEFAULTICON) 190 icon = defaultIcon.file ? &defaultIcon : &normalIcon; 191 else if (uFlags & GIL_FORSHORTCUT) 192 icon = shortcutIcon.file ? &shortcutIcon : &normalIcon; 193 else if (uFlags & GIL_OPENICON) 194 icon = openIcon.file ? &openIcon : &normalIcon; 195 else 196 icon = &normalIcon; 197 198 if (!icon->file) 199 return E_FAIL; 200 201 cb = wcslen(icon->file) + 1; 202 if (cchMax < (UINT)cb) 203 return E_FAIL; 204 CopyMemory(szIconFile, icon->file, cb * sizeof(WCHAR)); 205 *piIndex = icon->index; 206 *pwFlags = flags; 207 return S_OK; 208 } 209 210 HRESULT STDMETHODCALLTYPE CExtractIcon::Extract( 211 LPCWSTR pszFile, 212 UINT nIconIndex, 213 HICON *phiconLarge, 214 HICON *phiconSmall, 215 UINT nIconSize) 216 { 217 TRACE("(%p, %s, %u, %p, %p, %u)\n", this, debugstr_w(pszFile), nIconIndex, phiconLarge, phiconSmall, nIconSize); 218 219 /* Nothing to do, ExtractIconW::GetIconLocation should be enough */ 220 return S_FALSE; 221 } 222 223 HRESULT STDMETHODCALLTYPE CExtractIcon::GetIconLocation( 224 UINT uFlags, 225 LPSTR szIconFile, 226 UINT cchMax, 227 int *piIndex, 228 UINT *pwFlags) 229 { 230 LPWSTR szIconFileW = NULL; 231 HRESULT hr; 232 233 if (cchMax > 0) 234 { 235 szIconFileW = (LPWSTR)CoTaskMemAlloc(cchMax * sizeof(WCHAR)); 236 if (!szIconFileW) 237 return E_OUTOFMEMORY; 238 } 239 240 hr = GetIconLocation(uFlags, szIconFileW, cchMax, piIndex, pwFlags); 241 if (SUCCEEDED(hr) && cchMax > 0) 242 if (0 == WideCharToMultiByte(CP_ACP, 0, szIconFileW, cchMax, szIconFile, cchMax, NULL, NULL)) 243 hr = E_FAIL; 244 245 if (szIconFileW) 246 CoTaskMemFree(szIconFileW); 247 return hr; 248 } 249 250 HRESULT STDMETHODCALLTYPE CExtractIcon::Extract( 251 LPCSTR pszFile, 252 UINT nIconIndex, 253 HICON *phiconLarge, 254 HICON *phiconSmall, 255 UINT nIconSize) 256 { 257 LPWSTR pszFileW = NULL; 258 HRESULT hr; 259 260 if (pszFile) 261 { 262 int nLength; 263 264 nLength = MultiByteToWideChar(CP_ACP, 0, pszFile, -1, NULL, 0); 265 if (nLength == 0) 266 return E_FAIL; 267 pszFileW = (LPWSTR)CoTaskMemAlloc(nLength * sizeof(WCHAR)); 268 if (!pszFileW) 269 return E_OUTOFMEMORY; 270 if (!MultiByteToWideChar(CP_ACP, 0, pszFile, nLength, pszFileW, nLength)) 271 { 272 CoTaskMemFree(pszFileW); 273 return E_FAIL; 274 } 275 } 276 277 hr = Extract(pszFileW, nIconIndex, phiconLarge, phiconSmall, nIconSize); 278 279 if (pszFileW) 280 CoTaskMemFree(pszFileW); 281 return hr; 282 } 283 284 HRESULT STDMETHODCALLTYPE CExtractIcon::GetClassID( 285 CLSID *pClassID) 286 { 287 TRACE("(%p, %p)\n", this, pClassID); 288 289 if (!pClassID) 290 return E_POINTER; 291 292 *pClassID = GUID_NULL; 293 return S_OK; 294 } 295 296 HRESULT STDMETHODCALLTYPE CExtractIcon::IsDirty() 297 { 298 FIXME("(%p)\n", this); 299 UNIMPLEMENTED; 300 return E_NOTIMPL; 301 } 302 303 HRESULT STDMETHODCALLTYPE CExtractIcon::Load( 304 LPCOLESTR pszFileName, 305 DWORD dwMode) 306 { 307 FIXME("(%p, %s, %u)\n", this, debugstr_w(pszFileName), dwMode); 308 UNIMPLEMENTED; 309 return E_NOTIMPL; 310 } 311 312 HRESULT STDMETHODCALLTYPE CExtractIcon::Save( 313 LPCOLESTR pszFileName, 314 BOOL fRemember) 315 { 316 FIXME("(%p, %s, %d)\n", this, debugstr_w(pszFileName), fRemember); 317 UNIMPLEMENTED; 318 return E_NOTIMPL; 319 } 320 321 HRESULT STDMETHODCALLTYPE CExtractIcon::SaveCompleted( 322 LPCOLESTR pszFileName) 323 { 324 FIXME("(%p, %s)\n", this, debugstr_w(pszFileName)); 325 UNIMPLEMENTED; 326 return E_NOTIMPL; 327 } 328 329 HRESULT STDMETHODCALLTYPE CExtractIcon::GetCurFile( 330 LPOLESTR *ppszFileName) 331 { 332 FIXME("(%p, %p)\n", this, ppszFileName); 333 UNIMPLEMENTED; 334 return E_NOTIMPL; 335 } 336 337 HRESULT WINAPI SHCreateDefaultExtractIcon(REFIID riid, void **ppv) 338 { 339 return ShellObjectCreator<CExtractIcon>(riid, ppv); 340 } 341 342 /* 343 * Partially implemented 344 * See apitests\shell32\SHCreateFileExtractIconW.cpp for details 345 * Currently (march 2018) our shell does not handle IExtractIconW with an invalid path, 346 * so this (wrong) implementation actually works better for us. 347 */ 348 EXTERN_C HRESULT 349 WINAPI 350 SHCreateFileExtractIconW(LPCWSTR pszPath, 351 DWORD dwFileAttributes, 352 REFIID riid, 353 void **ppv) 354 { 355 SHFILEINFOW shfi; 356 ULONG_PTR firet = SHGetFileInfoW(pszPath, dwFileAttributes, &shfi, sizeof(shfi), SHGFI_USEFILEATTRIBUTES | SHGFI_ICONLOCATION); 357 HRESULT hr = E_FAIL; 358 if (firet) 359 { 360 CComPtr<IDefaultExtractIconInit> iconInit; 361 hr = SHCreateDefaultExtractIcon(IID_PPV_ARG(IDefaultExtractIconInit, &iconInit)); 362 if (FAILED_UNEXPECTEDLY(hr)) 363 return hr; 364 365 hr = iconInit->SetNormalIcon(shfi.szDisplayName, shfi.iIcon); 366 if (FAILED_UNEXPECTEDLY(hr)) 367 return hr; 368 369 return iconInit->QueryInterface(riid, ppv); 370 } 371 if (FAILED_UNEXPECTEDLY(hr)) 372 return hr; 373 374 return hr; 375 } 376 377