[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