<div dir="auto"><div><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Apr 25, 2022, 1:44 AM Jinoh Kang <<a href="mailto:jinoh.kang.kr@gmail.com">jinoh.kang.kr@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Wine-Bug: <a href="https://bugs.winehq.org/show_bug.cgi?id=52673" rel="noreferrer noreferrer" target="_blank">https://bugs.winehq.org/show_bug.cgi?id=52673</a><br>
Signed-off-by: Jinoh Kang <<a href="mailto:jinoh.kang.kr@gmail.com" target="_blank" rel="noreferrer">jinoh.kang.kr@gmail.com</a>><br>
---<br>
<br>
Notes:<br>
    v1 -> v2: no changes<br>
<br>
    v3 -> v4:<br>
    - Remove patch "shell32: Factor out ShellItem_get_uiobject."<br>
    - Use IShellItem2_BindToHandler instead of factoring out<br>
      ShellItem_get_uiobject<br>
    - Use CreateCompatibleDC(NULL) instead of GetDC(NULL)<br>
    - Remove new dependency on win32u, use GetIconInfo instead<br>
    - Remove new dependency on windowcodecs, use gdiplus instead<br>
<br>
    v4 -> v5: revert to using windowscodecs<br>
<br>
 dlls/shell32/Makefile.in       |   2 +-<br>
 dlls/shell32/shellitem.c       | 195 ++++++++++++++++++++++++++++++++-<br>
 dlls/shell32/tests/shlfolder.c |   2 -<br>
 3 files changed, 193 insertions(+), 6 deletions(-)<br>
<br>
diff --git a/dlls/shell32/Makefile.in b/dlls/shell32/Makefile.in<br>
index eeb6cd63d60..0cfaac8e9cc 100644<br>
--- a/dlls/shell32/Makefile.in<br>
+++ b/dlls/shell32/Makefile.in<br>
@@ -2,7 +2,7 @@ EXTRADEFS = -D_SHELL32_<br>
 MODULE    = shell32.dll<br>
 IMPORTLIB = shell32<br>
 IMPORTS   = uuid shlwapi user32 gdi32 advapi32<br>
-DELAYIMPORTS = ole32 oleaut32 shdocvw version comctl32 gdiplus<br>
+DELAYIMPORTS = ole32 oleaut32 shdocvw version comctl32 gdiplus windowscodecs<br>
<br>
 C_SRCS = \<br>
        appbar.c \<br>
diff --git a/dlls/shell32/shellitem.c b/dlls/shell32/shellitem.c<br>
index 0381fa67f0d..a1b3bc57c66 100644<br>
--- a/dlls/shell32/shellitem.c<br>
+++ b/dlls/shell32/shellitem.c<br>
@@ -31,9 +31,12 @@<br>
 #include "pidl.h"<br>
 #include "shell32_main.h"<br>
 #include "debughlp.h"<br>
+#include "wincodec.h"<br>
<br>
 WINE_DEFAULT_DEBUG_CHANNEL(shell);<br>
<br>
+HRESULT WINAPI WICCreateImagingFactory_Proxy(UINT, IWICImagingFactory**);<br>
+<br>
 typedef struct _ShellItem {<br>
     IShellItem2             IShellItem2_iface;<br>
     LONG                    ref;<br>
@@ -565,17 +568,203 @@ static ULONG WINAPI ShellItem_IShellItemImageFactory_Release(IShellItemImageFact<br>
     return IShellItem2_Release(&This->IShellItem2_iface);<br>
 }<br>
<br>
+static HRESULT ShellItem_get_icons(ShellItem *This, SIZE size, HICON *big_icon, HICON *small_icon)<br>
+{<br>
+    HRESULT hr;<br>
+    IBindCtx *pbc;<br>
+    IExtractIconW *ei;<br>
+    WCHAR icon_file[MAX_PATH];<br>
+    INT source_index;<br>
+    UINT gil_in_flags = 0, gil_out_flags;<br>
+    INT iconsize;<br>
+<br>
+    iconsize = min(<a href="http://size.cx" rel="noreferrer noreferrer" target="_blank">size.cx</a>, <a href="http://size.cy" rel="noreferrer noreferrer" target="_blank">size.cy</a>);<br>
+    if (iconsize <= 0 || iconsize > 0x7fff)<br>
+        iconsize = 0x7fff;<br>
+<br>
+    hr = CreateBindCtx(0, &pbc);<br>
+    if (FAILED(hr)) goto done;<br>
+<br>
+    hr = IShellItem2_BindToHandler(&This->IShellItem2_iface, pbc, &BHID_SFUIObject,<br>
+                                   &IID_IExtractIconW, (void **)&ei);<br>
+    IBindCtx_Release(pbc);<br>
+    if (FAILED(hr)) goto done;<br>
+<br>
+    hr = IExtractIconW_GetIconLocation(ei, gil_in_flags, icon_file, MAX_PATH, &source_index, &gil_out_flags);<br>
+    if (FAILED(hr)) goto free_ei;<br>
+<br>
+    if (!(gil_out_flags & GIL_NOTFILENAME))<br>
+    {<br>
+        UINT ei_res;<br>
+<br>
+        if (source_index == -1)<br>
+            source_index = 0;  /* special case for some control panel applications */<br>
+<br>
+        FIXME("%s %d\n", debugstr_w(icon_file), source_index);<br>
+        ei_res = ExtractIconExW(icon_file, source_index, big_icon, small_icon, 1);<br>
+        if (!ei_res || ei_res == (UINT)-1)<br>
+        {<br>
+            WARN("Failed to extract icon.\n");<br>
+            hr = E_FAIL;<br>
+        }<br>
+    }<br>
+    else<br>
+    {<br>
+        hr = IExtractIconW_Extract(ei, icon_file, source_index, big_icon, small_icon, MAKELONG(iconsize, iconsize));<br>
+    }<br>
+<br>
+free_ei:<br>
+    IExtractIconW_Release(ei);<br>
+done:<br>
+    return hr;<br>
+}<br>
+<br>
+static HICON choose_best_icon(HICON *icons, UINT count, SIZE size_limit, SIZE *out_size)<br>
+{<br>
+    HICON best_icon = NULL;<br>
+    SIZE best_size = {0, 0};<br>
+    UINT i;<br>
+<br>
+    for (i = 0; i < count; i++)<br>
+    {<br>
+        ICONINFO iinfo;<br>
+        BITMAP bm;<br>
+        SIZE size;<br>
+        BOOL is_color, ret;<br>
+<br>
+        if (!icons[i] || !GetIconInfo(icons[i], &iinfo)) continue;<br>
+<br>
+        is_color = iinfo.hbmColor != NULL;<br>
+        ret = GetObjectW(is_color ? iinfo.hbmColor : iinfo.hbmMask, sizeof(bm), &bm);<br>
+        DeleteObject(iinfo.hbmColor);<br>
+        DeleteObject(iinfo.hbmMask);<br>
+        if (!ret) continue;<br>
+<br>
+        <a href="http://size.cx" rel="noreferrer noreferrer" target="_blank">size.cx</a> = bm.bmWidth;<br>
+        <a href="http://size.cy" rel="noreferrer noreferrer" target="_blank">size.cy</a> = is_color ? abs(bm.bmHeight) : abs(bm.bmHeight) / 2;<br>
+<br>
+        if (!best_icon || (<a href="http://best_size.cx" rel="noreferrer noreferrer" target="_blank">best_size.cx</a> < <a href="http://size.cx" rel="noreferrer noreferrer" target="_blank">size.cx</a> && <a href="http://size.cx" rel="noreferrer noreferrer" target="_blank">size.cx</a> <= <a href="http://size_limit.cx" rel="noreferrer noreferrer" target="_blank">size_limit.cx</a> &&<br>
+                           <a href="http://best_size.cy" rel="noreferrer noreferrer" target="_blank">best_size.cy</a> < <a href="http://size.cy" rel="noreferrer noreferrer" target="_blank">size.cy</a> && <a href="http://size.cy" rel="noreferrer noreferrer" target="_blank">size.cy</a> <= <a href="http://size_limit.cy" rel="noreferrer noreferrer" target="_blank">size_limit.cy</a>))<br>
+        {<br>
+            best_icon = icons[i];<br>
+            best_size = size;<br>
+        }<br>
+    }<br>
+<br>
+    *out_size = best_size;<br>
+    return best_icon;<br>
+}<br>
+<br>
+static HRESULT ShellItem_get_icon_bitmap(ShellItem *This, IWICImagingFactory *imgfactory,<br>
+                                         SIZE size, SIIGBF flags, IWICBitmap **bitmap)<br>
+{<br>
+    HRESULT hr;<br>
+    HICON icons[2] = { NULL, NULL }, best_icon;<br>
+    SIZE best_icon_size;<br>
+    UINT i;<br>
+<br>
+    *bitmap = NULL;<br>
+<br>
+    hr = ShellItem_get_icons(This, size, &icons[0], &icons[1]);<br>
+    if (FAILED(hr)) return hr;<br>
+<br>
+    best_icon = choose_best_icon(icons, ARRAY_SIZE(icons), size, &best_icon_size);<br>
+    for (i = 0; i < ARRAY_SIZE(icons); i++)<br>
+        if (icons[i] && icons[i] != best_icon) DeleteObject(icons[i]);<br>
+<br>
+    if (!best_icon) return E_FAIL;<br>
+<br>
+    hr = IWICImagingFactory_CreateBitmapFromHICON(imgfactory, best_icon, bitmap);<br>
+    DeleteObject(best_icon);<br>
+    return hr;<br>
+}<br>
+<br>
+static HRESULT convert_wicbitmapsource_to_gdi(IWICImagingFactory *imgfactory,<br>
+                                              IWICBitmapSource *bitmapsource, HBITMAP *gdibitmap)<br>
+{<br>
+    BITMAPINFOHEADER bmi;<br>
+    HRESULT hr;<br>
+    UINT width, height;<br>
+    IWICBitmapSource *newsrc;<br>
+    HDC dc;<br>
+    HBITMAP bm;<br>
+    void *bits;<br>
+<br>
+    *gdibitmap = NULL;<br>
+<br>
+    hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA, bitmapsource, &newsrc);<br>
+    if (FAILED(hr)) goto done;<br>
+<br>
+    hr = IWICBitmapSource_GetSize(newsrc, &width, &height);<br>
+    if (FAILED(hr)) goto free_newsrc;<br>
+<br>
+    dc = CreateCompatibleDC(NULL);<br>
+    if (!dc)<br>
+    {<br>
+        hr = E_FAIL;<br>
+        goto free_newsrc;<br>
+    }<br>
+<br>
+    memset(&bmi, 0, sizeof(bmi));<br>
+    bmi.biSize = sizeof(bmi);<br>
+    bmi.biWidth = width;<br>
+    bmi.biHeight = -height;<br>
+    bmi.biPlanes = 1;<br>
+    bmi.biBitCount = 32;<br>
+    bmi.biCompression = BI_RGB;<br>
+<br>
+    bm = CreateDIBSection(dc, (const BITMAPINFO *)&bmi, DIB_RGB_COLORS, &bits, NULL, 0);<br>
+    DeleteDC(dc);<br>
+    if (!bm)<br>
+    {<br>
+        WARN("Cannot create bitmap.\n");<br>
+        hr = E_FAIL;<br>
+        goto free_newsrc;<br>
+    }<br>
+<br>
+    hr = IWICBitmapSource_CopyPixels(newsrc, NULL, width * 4, width * height * 4, bits);<br>
+    if (FAILED(hr))<br>
+    {<br>
+        DeleteObject(bm);<br>
+        goto free_newsrc;<br>
+    }<br>
+<br>
+    hr = S_OK;<br>
+    *gdibitmap = bm;<br>
+<br>
+free_newsrc:<br>
+    IWICBitmapSource_Release(newsrc);<br>
+done:<br>
+    return hr;<br>
+}<br>
+<br>
 static HRESULT WINAPI ShellItem_IShellItemImageFactory_GetImage(IShellItemImageFactory *iface,<br>
     SIZE size, SIIGBF flags, HBITMAP *phbm)<br>
 {<br>
     ShellItem *This = impl_from_IShellItemImageFactory(iface);<br>
+    HRESULT hr;<br>
+    IWICImagingFactory *imgfactory;<br>
+    IWICBitmap *bitmap = NULL;<br>
     static int once;<br>
<br>
     if (!once++)<br>
-        FIXME("%p ({%lu, %lu} %d %p): stub\n", This, <a href="http://size.cx" rel="noreferrer noreferrer" target="_blank">size.cx</a>, <a href="http://size.cy" rel="noreferrer noreferrer" target="_blank">size.cy</a>, flags, phbm);<br>
+        FIXME("%p ({%lu, %lu} %d %p): partial stub\n", This, <a href="http://size.cx" rel="noreferrer noreferrer" target="_blank">size.cx</a>, <a href="http://size.cy" rel="noreferrer noreferrer" target="_blank">size.cy</a>, flags, phbm);<br>
<br>
-    *phbm = NULL;<br></blockquote></div></div><div dir="auto"><br></div><div dir="auto">This line shouldn't be deleted.</div><div dir="auto"><br></div><div dir="auto"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
-    return E_NOTIMPL;<br>
+    if (flags != SIIGBF_BIGGERSIZEOK) return E_NOTIMPL;<br>
+<br>
+    hr = WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &imgfactory);<br>
+    if (SUCCEEDED(hr))<br>
+    {<br>
+        hr = ShellItem_get_icon_bitmap(This, imgfactory, size, flags, &bitmap);<br>
+        if (SUCCEEDED(hr))<br>
+        {<br>
+            hr = convert_wicbitmapsource_to_gdi(imgfactory, (IWICBitmapSource *)bitmap, phbm);<br>
+            IWICBitmap_Release(bitmap);<br>
+        }<br>
+        IWICImagingFactory_Release(imgfactory);<br>
+    }<br>
+<br>
+    return hr;<br>
 }<br>
<br>
 static const IShellItemImageFactoryVtbl ShellItem_IShellItemImageFactory_Vtbl = {<br>
diff --git a/dlls/shell32/tests/shlfolder.c b/dlls/shell32/tests/shlfolder.c<br>
index 78f199eaafc..507b3b1eac5 100644<br>
--- a/dlls/shell32/tests/shlfolder.c<br>
+++ b/dlls/shell32/tests/shlfolder.c<br>
@@ -4464,11 +4464,9 @@ static void test_IShellItemImageFactory(void)<br>
                 ok(!GetModuleHandleA("windowscodecs.dll"), "WIC should not have already been loaded\n");<br>
<br>
                 ret = IShellItemImageFactory_GetImage(siif, size, SIIGBF_BIGGERSIZEOK, &hbm);<br>
-                todo_wine<br>
                 ok(ret == S_OK || broken(ret == E_PENDING /* win7 */), "GetImage returned %lx\n", ret);<br>
                 ok(FAILED(ret) == !hbm, "result = %lx but bitmap = %p\n", ret, hbm);<br>
<br>
-                todo_wine<br>
                 ok(!!GetModuleHandleA("windowscodecs.dll"), "WIC should have been loaded\n");<br>
<br>
                 if (SUCCEEDED(ret) && hbm)<br>
-- <br>
2.34.1<br>
<br>
</blockquote></div></div></div>