[PATCH v4 1/1] shell32: Partially implement IShellItemImageFactory (icon only, no thumbnail).
Jinoh Kang
wine at gitlab.winehq.org
Wed Jun 15 10:35:49 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 | 177 ++++++++++++++++++++++++++++++++-
dlls/shell32/tests/shlfolder.c | 1 -
3 files changed, 175 insertions(+), 5 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..84dd597b02c 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,184 @@ static ULONG WINAPI ShellItem_IShellItemImageFactory_Release(IShellItemImageFact
return IShellItem2_Release(&This->IShellItem2_iface);
}
+static IImageList *get_system_imagelist_by_size(SIZE size)
+{
+ int i;
+
+ for (i = 0; i <= SHIL_LAST; i++)
+ {
+ IImageList *cur_list;
+
+ if (SUCCEEDED(SHGetImageList(i, &IID_IImageList, (void **)&cur_list)))
+ {
+ int cx, cy;
+
+ if (SUCCEEDED(IImageList_GetIconSize(cur_list, &cx, &cy)) &&
+ cx == size.cx && cy == size.cy)
+ {
+ return cur_list;
+ }
+
+ IImageList_Release(cur_list);
+ }
+ }
+
+ return NULL;
+}
+
+static HICON get_icon_via_cache(LPCWSTR icon_file, INT source_index, DWORD flags, SIZE size)
+{
+ IImageList *icon_list;
+ int ic_index;
+ HICON icon;
+
+ if (!(icon_list = get_system_imagelist_by_size(size))) return NULL;
+
+ if ((ic_index = SIC_GetIconIndex(icon_file, source_index, flags)) != INVALID_INDEX)
+ {
+ if (FAILED(IImageList_GetIcon(icon_list, ic_index, ILD_NORMAL, &icon)))
+ {
+ icon = NULL;
+ }
+ }
+ IImageList_Release(icon_list);
+
+ return icon;
+}
+
+static HRESULT ShellItem_get_icon(ShellItem *This, SIZE size, HICON *icon)
+{
+ IExtractIconW *extracticon;
+ WCHAR icon_file[MAX_PATH];
+ INT icon_source_index;
+ UINT gil_out_flags;
+ HICON cached_icon;
+ HRESULT hr;
+
+ if (FAILED(hr = IShellItem2_BindToHandler(&This->IShellItem2_iface, NULL, &BHID_SFUIObject,
+ &IID_IExtractIconW, (void **)&extracticon)))
+ {
+ goto done;
+ }
+
+ if (FAILED(hr = IExtractIconW_GetIconLocation(extracticon, 0, icon_file, ARRAY_SIZE(icon_file),
+ &icon_source_index, &gil_out_flags)))
+ {
+ goto free_extracticon;
+ }
+
+ if (!(gil_out_flags & (GIL_NOTFILENAME | GIL_DONTCACHE)) &&
+ (cached_icon = get_icon_via_cache(icon_file, icon_source_index, 0, size)))
+ {
+ *icon = cached_icon;
+ hr = S_OK;
+ }
+ else
+ {
+ LONG iconsize = min(size.cx, size.cy);
+ if (iconsize <= 0 || iconsize > 0x7fff)
+ iconsize = 0x7fff;
+ hr = IExtractIconW_Extract(extracticon, icon_file, icon_source_index,
+ icon, NULL, MAKELONG(0, iconsize));
+ }
+
+free_extracticon:
+ IExtractIconW_Release(extracticon);
+done:
+ return hr;
+}
+
+static HRESULT convert_wicbitmapsource_to_gdi(IWICImagingFactory *imgfactory,
+ IWICBitmapSource *bitmapsource, HBITMAP *gdibitmap)
+{
+ IWICBitmapSource *newsrc;
+ UINT width, height;
+ BITMAPINFO bmi;
+ HBITMAP bm;
+ void *bits;
+ HRESULT hr;
+
+ *gdibitmap = NULL;
+
+ if (FAILED(hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA, bitmapsource, &newsrc)))
+ {
+ goto done;
+ }
+
+ if (FAILED(hr = IWICBitmapSource_GetSize(newsrc, &width, &height)))
+ {
+ goto free_newsrc;
+ }
+
+ memset(&bmi, 0, sizeof(bmi));
+ bmi.bmiHeader.biSize = sizeof(bmi);
+ bmi.bmiHeader.biWidth = width;
+ bmi.bmiHeader.biHeight = -height;
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 32;
+ bmi.bmiHeader.biCompression = BI_RGB;
+
+ if (!(bm = CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, &bits, NULL, 0)))
+ {
+ WARN("Cannot create bitmap.\n");
+ hr = E_FAIL;
+ goto free_newsrc;
+ }
+
+ if (FAILED(hr = IWICBitmapSource_CopyPixels(newsrc, NULL, width * 4, width * height * 4, bits)))
+ {
+ 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)
+ SIZE size, SIIGBF flags, HBITMAP *phbm)
{
ShellItem *This = impl_from_IShellItemImageFactory(iface);
+ IWICImagingFactory *imgfactory;
+ IWICBitmap *bitmap = NULL;
static int once;
+ HICON hicon;
+ HRESULT hr;
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;
+
+ if (FAILED(hr = WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &imgfactory)))
+ {
+ return hr;
+ }
+
+ if (SUCCEEDED(hr = ShellItem_get_icon(This, size, &hicon)))
+ {
+ if (FAILED(hr = IWICImagingFactory_CreateBitmapFromHICON(imgfactory, hicon, &bitmap)))
+ {
+ bitmap = NULL;
+ }
+ DeleteObject(hicon);
+ }
+
+ if (bitmap)
+ {
+ 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