[PATCH 1/1] shell32: Partially implement IShellItemImageFactory (icon only, no thumbnail).
Jinoh Kang
wine at gitlab.winehq.org
Sun Jun 5 11:35:56 CDT 2022
From: Jinoh Kang <jinoh.kang.kr at gmail.com>
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52673
Signed-off-by: Jinoh Kang <jinoh.kang.kr at gmail.com>
---
dlls/shell32/Makefile.in | 2 +-
dlls/shell32/shellitem.c | 161 ++++++++++++++++++++++++++++++++-
dlls/shell32/tests/shlfolder.c | 1 -
3 files changed, 160 insertions(+), 4 deletions(-)
diff --git a/dlls/shell32/Makefile.in b/dlls/shell32/Makefile.in
index 9e2395126fc..95afa482de5 100644
--- a/dlls/shell32/Makefile.in
+++ b/dlls/shell32/Makefile.in
@@ -1,7 +1,7 @@
MODULE = shell32.dll
IMPORTLIB = shell32
IMPORTS = uuid shlwapi user32 gdi32 advapi32
-DELAYIMPORTS = ole32 oleaut32 shdocvw version comctl32 gdiplus
+DELAYIMPORTS = ole32 oleaut32 shdocvw version comctl32 gdiplus windowscodecs
C_SRCS = \
appbar.c \
diff --git a/dlls/shell32/shellitem.c b/dlls/shell32/shellitem.c
index 3e8bd24a429..a1d893487e9 100644
--- a/dlls/shell32/shellitem.c
+++ b/dlls/shell32/shellitem.c
@@ -31,9 +31,13 @@
#include "pidl.h"
#include "shell32_main.h"
#include "debughlp.h"
+#include "wincodec.h"
+#include "commoncontrols.h"
WINE_DEFAULT_DEBUG_CHANNEL(shell);
+HRESULT WINAPI WICCreateImagingFactory_Proxy(UINT, IWICImagingFactory**);
+
typedef struct _ShellItem {
IShellItem2 IShellItem2_iface;
LONG ref;
@@ -565,17 +569,170 @@ static ULONG WINAPI ShellItem_IShellItemImageFactory_Release(IShellItemImageFact
return IShellItem2_Release(&This->IShellItem2_iface);
}
+static HICON get_icon_via_cache(LPCWSTR icon_file, INT source_index, DWORD flags, SIZE size)
+{
+ HRESULT hr;
+ HICON icon = NULL;
+ int i, ic_index;
+ IImageList *icon_list = NULL;
+
+ if (source_index == -1)
+ source_index = 0; /* special case for some control panel applications */
+
+ for (i = 0; i <= SHIL_LAST; i++)
+ {
+ IImageList *cur_list;
+ int cx, cy;
+
+ hr = SHGetImageList(i, &IID_IImageList, (void **)&cur_list);
+ if (SUCCEEDED(hr))
+ {
+ hr = IImageList_GetIconSize(cur_list, &cx, &cy);
+ if (SUCCEEDED(hr) && cx == size.cx && cy == size.cy)
+ {
+ icon_list = cur_list;
+ break;
+ }
+ IImageList_Release(cur_list);
+ }
+ }
+
+ if (icon_list)
+ {
+ ic_index = SIC_GetIconIndex(icon_file, source_index, flags);
+ if (ic_index != -1)
+ {
+ hr = IImageList_GetIcon(icon_list, ic_index, ILD_NORMAL, &icon);
+ if (FAILED(hr)) icon = NULL;
+ }
+ IImageList_Release(icon_list);
+ }
+ return icon;
+}
+
+static HRESULT ShellItem_get_icon(ShellItem *This, SIZE size, HICON *icon)
+{
+ HRESULT hr;
+ IExtractIconW *ei;
+ WCHAR icon_file[MAX_PATH];
+ INT source_index;
+ UINT gil_out_flags;
+ HICON cached_icon;
+
+ hr = IShellItem2_BindToHandler(&This->IShellItem2_iface, NULL, &BHID_SFUIObject,
+ &IID_IExtractIconW, (void **)&ei);
+ if (FAILED(hr)) goto done;
+
+ hr = IExtractIconW_GetIconLocation(ei, 0, icon_file, MAX_PATH, &source_index, &gil_out_flags);
+ if (FAILED(hr)) goto free_ei;
+
+ if (!(gil_out_flags & (GIL_NOTFILENAME | GIL_DONTCACHE)) &&
+ (cached_icon = get_icon_via_cache(icon_file, source_index, 0, size)))
+ {
+ *icon = cached_icon;
+ hr = S_OK;
+ }
+ else
+ {
+ INT iconsize = min(size.cx, size.cy);
+ if (iconsize <= 0 || iconsize > 0x7fff)
+ iconsize = 0x7fff;
+ hr = IExtractIconW_Extract(ei, icon_file, source_index, icon, NULL, MAKELONG(0, iconsize));
+ }
+
+free_ei:
+ IExtractIconW_Release(ei);
+done:
+ return hr;
+}
+
+static HRESULT convert_wicbitmapsource_to_gdi(IWICImagingFactory *imgfactory,
+ IWICBitmapSource *bitmapsource, HBITMAP *gdibitmap)
+{
+ BITMAPINFOHEADER bmi;
+ HRESULT hr;
+ UINT width, height;
+ IWICBitmapSource *newsrc;
+ HBITMAP bm;
+ void *bits;
+
+ *gdibitmap = NULL;
+
+ hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA, bitmapsource, &newsrc);
+ if (FAILED(hr)) goto done;
+
+ hr = IWICBitmapSource_GetSize(newsrc, &width, &height);
+ if (FAILED(hr)) goto free_newsrc;
+
+ memset(&bmi, 0, sizeof(bmi));
+ bmi.biSize = sizeof(bmi);
+ bmi.biWidth = width;
+ bmi.biHeight = -height;
+ bmi.biPlanes = 1;
+ bmi.biBitCount = 32;
+ bmi.biCompression = BI_RGB;
+
+ bm = CreateDIBSection(NULL, (const BITMAPINFO *)&bmi, DIB_RGB_COLORS, &bits, NULL, 0);
+ if (!bm)
+ {
+ WARN("Cannot create bitmap.\n");
+ hr = E_FAIL;
+ goto free_newsrc;
+ }
+
+ hr = IWICBitmapSource_CopyPixels(newsrc, NULL, width * 4, width * height * 4, bits);
+ if (FAILED(hr))
+ {
+ DeleteObject(bm);
+ goto free_newsrc;
+ }
+
+ hr = S_OK;
+ *gdibitmap = bm;
+
+free_newsrc:
+ IWICBitmapSource_Release(newsrc);
+done:
+ return hr;
+}
+
static HRESULT WINAPI ShellItem_IShellItemImageFactory_GetImage(IShellItemImageFactory *iface,
SIZE size, SIIGBF flags, HBITMAP *phbm)
{
ShellItem *This = impl_from_IShellItemImageFactory(iface);
+ HRESULT hr;
+ IWICImagingFactory *imgfactory;
+ IWICBitmap *bitmap = NULL;
static int once;
if (!once++)
- FIXME("%p ({%lu, %lu} %d %p): stub\n", This, size.cx, size.cy, flags, phbm);
+ FIXME("%p ({%lu, %lu} %d %p): partial stub\n", This, size.cx, size.cy, flags, phbm);
*phbm = NULL;
- return E_NOTIMPL;
+
+ if (flags != SIIGBF_BIGGERSIZEOK) return E_NOTIMPL;
+
+ hr = WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &imgfactory);
+ if (SUCCEEDED(hr))
+ {
+ HICON hicon;
+
+ hr = ShellItem_get_icon(This, size, &hicon);
+ if (SUCCEEDED(hr))
+ {
+ hr = IWICImagingFactory_CreateBitmapFromHICON(imgfactory, hicon, &bitmap);
+ DeleteObject(hicon);
+
+ if (SUCCEEDED(hr))
+ {
+ hr = convert_wicbitmapsource_to_gdi(imgfactory, (IWICBitmapSource *)bitmap, phbm);
+ IWICBitmap_Release(bitmap);
+ }
+ }
+ IWICImagingFactory_Release(imgfactory);
+ }
+
+ return hr;
}
static const IShellItemImageFactoryVtbl ShellItem_IShellItemImageFactory_Vtbl = {
diff --git a/dlls/shell32/tests/shlfolder.c b/dlls/shell32/tests/shlfolder.c
index da606a9e707..49614aed3c4 100644
--- a/dlls/shell32/tests/shlfolder.c
+++ b/dlls/shell32/tests/shlfolder.c
@@ -4456,7 +4456,6 @@ static void test_IShellItemImageFactory(void)
ret = IShellItemImageFactory_GetImage(siif, size, SIIGBF_BIGGERSIZEOK, &hbm);
IShellItemImageFactory_Release(siif);
- todo_wine
ok(ret == S_OK, "GetImage returned %lx\n", ret);
ok(FAILED(ret) == !hbm, "result = %lx but bitmap = %p\n", ret, hbm);
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/190
More information about the wine-devel
mailing list