mirror of
https://github.com/reactos/reactos.git
synced 2024-11-05 22:26:39 +00:00
d7722f39fb
Note that even if the MS PSDK and MSDN documents an hypothetical ANSI version SHCreateFileExtractIconA(), this one never existed exported in any Windows version!
377 lines
10 KiB
C++
377 lines
10 KiB
C++
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS Registry namespace extension
|
|
* FILE: dll/win32/shell32/extracticon.c
|
|
* PURPOSE: Icon extraction
|
|
*
|
|
* PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org)
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(shell);
|
|
|
|
struct IconLocation
|
|
{
|
|
LPWSTR file;
|
|
UINT index;
|
|
};
|
|
|
|
class CExtractIcon :
|
|
public CComObjectRootEx<CComMultiThreadModelNoCS>,
|
|
public IDefaultExtractIconInit,
|
|
public IExtractIconW,
|
|
public IExtractIconA,
|
|
public IPersistFile
|
|
{
|
|
private:
|
|
UINT flags;
|
|
struct IconLocation defaultIcon;
|
|
struct IconLocation normalIcon;
|
|
struct IconLocation openIcon;
|
|
struct IconLocation shortcutIcon;
|
|
public:
|
|
CExtractIcon();
|
|
~CExtractIcon();
|
|
|
|
// IDefaultExtractIconInit
|
|
virtual HRESULT STDMETHODCALLTYPE SetDefaultIcon(LPCWSTR pszFile, int iIcon);
|
|
virtual HRESULT STDMETHODCALLTYPE SetFlags(UINT uFlags);
|
|
virtual HRESULT STDMETHODCALLTYPE SetKey(HKEY hkey);
|
|
virtual HRESULT STDMETHODCALLTYPE SetNormalIcon(LPCWSTR pszFile, int iIcon);
|
|
virtual HRESULT STDMETHODCALLTYPE SetOpenIcon(LPCWSTR pszFile, int iIcon);
|
|
virtual HRESULT STDMETHODCALLTYPE SetShortcutIcon(LPCWSTR pszFile, int iIcon);
|
|
|
|
// IExtractIconW
|
|
virtual HRESULT STDMETHODCALLTYPE GetIconLocation(UINT uFlags, LPWSTR szIconFile, UINT cchMax, int *piIndex, UINT *pwFlags);
|
|
virtual HRESULT STDMETHODCALLTYPE Extract(LPCWSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize);
|
|
|
|
// IExtractIconA
|
|
virtual HRESULT STDMETHODCALLTYPE GetIconLocation(UINT uFlags, LPSTR szIconFile, UINT cchMax, int *piIndex, UINT *pwFlags);
|
|
virtual HRESULT STDMETHODCALLTYPE Extract(LPCSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize);
|
|
|
|
// IPersist
|
|
virtual HRESULT STDMETHODCALLTYPE GetClassID(CLSID *pClassID);
|
|
virtual HRESULT STDMETHODCALLTYPE IsDirty();
|
|
|
|
// IPersistFile
|
|
virtual HRESULT STDMETHODCALLTYPE Load(LPCOLESTR pszFileName, DWORD dwMode);
|
|
virtual HRESULT STDMETHODCALLTYPE Save(LPCOLESTR pszFileName, BOOL fRemember);
|
|
virtual HRESULT STDMETHODCALLTYPE SaveCompleted(LPCOLESTR pszFileName);
|
|
virtual HRESULT STDMETHODCALLTYPE GetCurFile(LPOLESTR *ppszFileName);
|
|
|
|
BEGIN_COM_MAP(CExtractIcon)
|
|
COM_INTERFACE_ENTRY_IID(IID_IDefaultExtractIconInit, IDefaultExtractIconInit)
|
|
COM_INTERFACE_ENTRY_IID(IID_IExtractIconW, IExtractIconW)
|
|
COM_INTERFACE_ENTRY_IID(IID_IExtractIconA, IExtractIconA)
|
|
COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist)
|
|
COM_INTERFACE_ENTRY_IID(IID_IPersistFile, IPersistFile)
|
|
END_COM_MAP()
|
|
};
|
|
|
|
VOID DuplicateString(
|
|
LPCWSTR Source,
|
|
LPWSTR *Destination)
|
|
{
|
|
SIZE_T cb;
|
|
|
|
if (*Destination)
|
|
CoTaskMemFree(*Destination);
|
|
|
|
cb = (wcslen(Source) + 1) * sizeof(WCHAR);
|
|
*Destination = (LPWSTR)CoTaskMemAlloc(cb);
|
|
if (!*Destination)
|
|
return;
|
|
CopyMemory(*Destination, Source, cb);
|
|
}
|
|
|
|
CExtractIcon::CExtractIcon()
|
|
{
|
|
flags = 0;
|
|
memset(&defaultIcon, 0, sizeof(defaultIcon));
|
|
memset(&normalIcon, 0, sizeof(normalIcon));
|
|
memset(&openIcon, 0, sizeof(openIcon));
|
|
memset(&shortcutIcon, 0, sizeof(shortcutIcon));
|
|
}
|
|
|
|
CExtractIcon::~CExtractIcon()
|
|
{
|
|
if (defaultIcon.file) CoTaskMemFree(defaultIcon.file);
|
|
if (normalIcon.file) CoTaskMemFree(normalIcon.file);
|
|
if (openIcon.file) CoTaskMemFree(openIcon.file);
|
|
if (shortcutIcon.file) CoTaskMemFree(shortcutIcon.file);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CExtractIcon::SetDefaultIcon(
|
|
LPCWSTR pszFile,
|
|
int iIcon)
|
|
{
|
|
TRACE("(%p, %s, %d)\n", this, debugstr_w(pszFile), iIcon);
|
|
|
|
DuplicateString(pszFile, &defaultIcon.file);
|
|
if (!defaultIcon.file)
|
|
return E_OUTOFMEMORY;
|
|
defaultIcon.index = iIcon;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CExtractIcon::SetFlags(
|
|
UINT uFlags)
|
|
{
|
|
TRACE("(%p, 0x%x)\n", this, uFlags);
|
|
|
|
flags = uFlags;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CExtractIcon::SetKey(
|
|
HKEY hkey)
|
|
{
|
|
FIXME("(%p, %p)\n", this, hkey);
|
|
UNIMPLEMENTED;
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CExtractIcon::SetNormalIcon(
|
|
LPCWSTR pszFile,
|
|
int iIcon)
|
|
{
|
|
TRACE("(%p, %s, %d)\n", this, debugstr_w(pszFile), iIcon);
|
|
|
|
DuplicateString(pszFile, &normalIcon.file);
|
|
if (!normalIcon.file)
|
|
return E_OUTOFMEMORY;
|
|
normalIcon.index = iIcon;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CExtractIcon::SetOpenIcon(
|
|
LPCWSTR pszFile,
|
|
int iIcon)
|
|
{
|
|
TRACE("(%p, %s, %d)\n", this, debugstr_w(pszFile), iIcon);
|
|
|
|
DuplicateString(pszFile, &openIcon.file);
|
|
if (!openIcon.file)
|
|
return E_OUTOFMEMORY;
|
|
openIcon.index = iIcon;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CExtractIcon::SetShortcutIcon(
|
|
LPCWSTR pszFile,
|
|
int iIcon)
|
|
{
|
|
TRACE("(%p, %s, %d)\n", this, debugstr_w(pszFile), iIcon);
|
|
|
|
DuplicateString(pszFile, &shortcutIcon.file);
|
|
if (!shortcutIcon.file)
|
|
return E_OUTOFMEMORY;
|
|
shortcutIcon.index = iIcon;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CExtractIcon::GetIconLocation(
|
|
UINT uFlags,
|
|
LPWSTR szIconFile,
|
|
UINT cchMax,
|
|
int *piIndex,
|
|
UINT *pwFlags)
|
|
{
|
|
const struct IconLocation *icon = NULL;
|
|
SIZE_T cb;
|
|
|
|
TRACE("(%p, 0x%x, %s, 0x%x, %p, %p)\n", this, uFlags, debugstr_w(szIconFile), cchMax, piIndex, pwFlags);
|
|
|
|
if (!piIndex || !pwFlags)
|
|
return E_POINTER;
|
|
|
|
if (uFlags & GIL_DEFAULTICON)
|
|
icon = defaultIcon.file ? &defaultIcon : &normalIcon;
|
|
else if (uFlags & GIL_FORSHORTCUT)
|
|
icon = shortcutIcon.file ? &shortcutIcon : &normalIcon;
|
|
else if (uFlags & GIL_OPENICON)
|
|
icon = openIcon.file ? &openIcon : &normalIcon;
|
|
else
|
|
icon = &normalIcon;
|
|
|
|
if (!icon->file)
|
|
return E_FAIL;
|
|
|
|
cb = wcslen(icon->file) + 1;
|
|
if (cchMax < (UINT)cb)
|
|
return E_FAIL;
|
|
CopyMemory(szIconFile, icon->file, cb * sizeof(WCHAR));
|
|
*piIndex = icon->index;
|
|
*pwFlags = flags;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CExtractIcon::Extract(
|
|
LPCWSTR pszFile,
|
|
UINT nIconIndex,
|
|
HICON *phiconLarge,
|
|
HICON *phiconSmall,
|
|
UINT nIconSize)
|
|
{
|
|
TRACE("(%p, %s, %u, %p, %p, %u)\n", this, debugstr_w(pszFile), nIconIndex, phiconLarge, phiconSmall, nIconSize);
|
|
|
|
/* Nothing to do, ExtractIconW::GetIconLocation should be enough */
|
|
return S_FALSE;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CExtractIcon::GetIconLocation(
|
|
UINT uFlags,
|
|
LPSTR szIconFile,
|
|
UINT cchMax,
|
|
int *piIndex,
|
|
UINT *pwFlags)
|
|
{
|
|
LPWSTR szIconFileW = NULL;
|
|
HRESULT hr;
|
|
|
|
if (cchMax > 0)
|
|
{
|
|
szIconFileW = (LPWSTR)CoTaskMemAlloc(cchMax * sizeof(WCHAR));
|
|
if (!szIconFileW)
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
hr = GetIconLocation(uFlags, szIconFileW, cchMax, piIndex, pwFlags);
|
|
if (SUCCEEDED(hr) && cchMax > 0)
|
|
if (0 == WideCharToMultiByte(CP_ACP, 0, szIconFileW, cchMax, szIconFile, cchMax, NULL, NULL))
|
|
hr = E_FAIL;
|
|
|
|
if (szIconFileW)
|
|
CoTaskMemFree(szIconFileW);
|
|
return hr;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CExtractIcon::Extract(
|
|
LPCSTR pszFile,
|
|
UINT nIconIndex,
|
|
HICON *phiconLarge,
|
|
HICON *phiconSmall,
|
|
UINT nIconSize)
|
|
{
|
|
LPWSTR pszFileW = NULL;
|
|
HRESULT hr;
|
|
|
|
if (pszFile)
|
|
{
|
|
int nLength;
|
|
|
|
nLength = MultiByteToWideChar(CP_ACP, 0, pszFile, -1, NULL, 0);
|
|
if (nLength == 0)
|
|
return E_FAIL;
|
|
pszFileW = (LPWSTR)CoTaskMemAlloc(nLength * sizeof(WCHAR));
|
|
if (!pszFileW)
|
|
return E_OUTOFMEMORY;
|
|
if (!MultiByteToWideChar(CP_ACP, 0, pszFile, nLength, pszFileW, nLength))
|
|
{
|
|
CoTaskMemFree(pszFileW);
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
|
|
hr = Extract(pszFileW, nIconIndex, phiconLarge, phiconSmall, nIconSize);
|
|
|
|
if (pszFileW)
|
|
CoTaskMemFree(pszFileW);
|
|
return hr;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CExtractIcon::GetClassID(
|
|
CLSID *pClassID)
|
|
{
|
|
TRACE("(%p, %p)\n", this, pClassID);
|
|
|
|
if (!pClassID)
|
|
return E_POINTER;
|
|
|
|
*pClassID = GUID_NULL;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CExtractIcon::IsDirty()
|
|
{
|
|
FIXME("(%p)\n", this);
|
|
UNIMPLEMENTED;
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CExtractIcon::Load(
|
|
LPCOLESTR pszFileName,
|
|
DWORD dwMode)
|
|
{
|
|
FIXME("(%p, %s, %u)\n", this, debugstr_w(pszFileName), dwMode);
|
|
UNIMPLEMENTED;
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CExtractIcon::Save(
|
|
LPCOLESTR pszFileName,
|
|
BOOL fRemember)
|
|
{
|
|
FIXME("(%p, %s, %d)\n", this, debugstr_w(pszFileName), fRemember);
|
|
UNIMPLEMENTED;
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CExtractIcon::SaveCompleted(
|
|
LPCOLESTR pszFileName)
|
|
{
|
|
FIXME("(%p, %s)\n", this, debugstr_w(pszFileName));
|
|
UNIMPLEMENTED;
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CExtractIcon::GetCurFile(
|
|
LPOLESTR *ppszFileName)
|
|
{
|
|
FIXME("(%p, %p)\n", this, ppszFileName);
|
|
UNIMPLEMENTED;
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT WINAPI SHCreateDefaultExtractIcon(REFIID riid, void **ppv)
|
|
{
|
|
return ShellObjectCreator<CExtractIcon>(riid, ppv);
|
|
}
|
|
|
|
/*
|
|
* Partially implemented
|
|
* See apitests\shell32\SHCreateFileExtractIconW.cpp for details
|
|
* Currently (march 2018) our shell does not handle IExtractIconW with an invalid path,
|
|
* so this (wrong) implementation actually works better for us.
|
|
*/
|
|
EXTERN_C
|
|
HRESULT
|
|
WINAPI
|
|
SHCreateFileExtractIconW(
|
|
_In_ LPCWSTR pszFile,
|
|
_In_ DWORD dwFileAttributes,
|
|
_In_ REFIID riid,
|
|
_Outptr_ void **ppv)
|
|
{
|
|
SHFILEINFOW shfi;
|
|
ULONG_PTR firet = SHGetFileInfoW(pszFile, dwFileAttributes, &shfi, sizeof(shfi), SHGFI_USEFILEATTRIBUTES | SHGFI_ICONLOCATION);
|
|
HRESULT hr = E_FAIL;
|
|
if (firet)
|
|
{
|
|
CComPtr<IDefaultExtractIconInit> iconInit;
|
|
hr = SHCreateDefaultExtractIcon(IID_PPV_ARG(IDefaultExtractIconInit, &iconInit));
|
|
if (FAILED_UNEXPECTEDLY(hr))
|
|
return hr;
|
|
|
|
hr = iconInit->SetNormalIcon(shfi.szDisplayName, shfi.iIcon);
|
|
if (FAILED_UNEXPECTEDLY(hr))
|
|
return hr;
|
|
|
|
return iconInit->QueryInterface(riid, ppv);
|
|
}
|
|
if (FAILED_UNEXPECTEDLY(hr))
|
|
return hr;
|
|
|
|
return hr;
|
|
}
|