Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52673 Signed-off-by: Jinoh Kang jinoh.kang.kr@gmail.com
From: Jinoh Kang jinoh.kang.kr@gmail.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52673 Signed-off-by: Jinoh Kang jinoh.kang.kr@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);
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=116256
Your paranoid android.
=== w1064v1809 (32 bit report) ===
shell32: shlfolder.c:4976: Test failed: Didn't expect a WM_USER_NOTIFY message (event: 40000)
=== w1064 (32 bit report) ===
shell32: shlfolder.c:4976: Test failed: Didn't expect a WM_USER_NOTIFY message (event: 3)
=== w1064_tsign (32 bit report) ===
shell32: shlfolder.c:4959: Test failed: CREATE: expected notification type 2, got: 40000 shlfolder.c:4966: Test failed: GetDisplayNameOf failed: 0x80070057 shlfolder.c:4976: Test failed: Didn't expect a WM_USER_NOTIFY message (event: 2)
=== w10pro64 (32 bit report) ===
shell32: shlfolder.c:4959: Test failed: MKDIR: expected notification type 8, got: 4000000 shlfolder.c:4966: Test failed: GetDisplayNameOf failed: 0x80070057 shlfolder.c:4967: Test failed: Expected PIDL to be NULL shlfolder.c:4976: Test failed: Didn't expect a WM_USER_NOTIFY message (event: 3) shlfolder.c:4976: Test failed: Didn't expect a WM_USER_NOTIFY message (event: 3) shlfolder.c:4976: Test failed: Didn't expect a WM_USER_NOTIFY message (event: 3) shlfolder.c:4976: Test failed: Didn't expect a WM_USER_NOTIFY message (event: 3)
=== w1064v1809 (64 bit report) ===
shell32: shlfolder.c:4976: Test failed: Didn't expect a WM_USER_NOTIFY message (event: 40000)
=== w1064 (64 bit report) ===
shell32: shlfolder.c:4976: Test failed: Didn't expect a WM_USER_NOTIFY message (event: 40000)
=== w1064_2qxl (64 bit report) ===
shell32: shlfolder.c:4959: Test failed: CREATE: expected notification type 2, got: 40000 shlfolder.c:4966: Test failed: GetDisplayNameOf failed: 0x80070057 shlfolder.c:4976: Test failed: Didn't expect a WM_USER_NOTIFY message (event: 2)
=== w1064_adm (64 bit report) ===
shell32: shlfolder.c:4976: Test failed: Didn't expect a WM_USER_NOTIFY message (event: 40000)
=== w1064_tsign (64 bit report) ===
shell32: shlfolder.c:4959: Test failed: RMDIR: expected notification type 10, got: 40000 shlfolder.c:4966: Test failed: GetDisplayNameOf failed: 0x80070057 shlfolder.c:4976: Test failed: Didn't expect a WM_USER_NOTIFY message (event: 10)
=== w10pro64 (64 bit report) ===
shell32: shlfolder.c:4976: Test failed: Didn't expect a WM_USER_NOTIFY message (event: 3) shlfolder.c:4976: Test failed: Didn't expect a WM_USER_NOTIFY message (event: 3) shlfolder.c:4976: Test failed: Didn't expect a WM_USER_NOTIFY message (event: 3)
=== w10pro64_en_AE_u8 (64 bit report) ===
shell32: shlfolder.c:4976: Test failed: Didn't expect a WM_USER_NOTIFY message (event: 40000)
=== w10pro64_ar (64 bit report) ===
shell32: shlfolder.c:4976: Test failed: Didn't expect a WM_USER_NOTIFY message (event: 40000) shlfolder.c:4976: Test failed: Didn't expect a WM_USER_NOTIFY message (event: 3)
=== w10pro64_ja (64 bit report) ===
shell32: shlfolder.c:4976: Test failed: Didn't expect a WM_USER_NOTIFY message (event: 2) shlfolder.c:4959: Test failed: RMDIR: expected notification type 10, got: 40000 shlfolder.c:4966: Test failed: GetDisplayNameOf failed: 0x80070057 shlfolder.c:4976: Test failed: Didn't expect a WM_USER_NOTIFY message (event: 10)
=== w10pro64_zh_CN (64 bit report) ===
shell32: shlfolder.c:4976: Test failed: Didn't expect a WM_USER_NOTIFY message (event: 3) shlfolder.c:4976: Test failed: Didn't expect a WM_USER_NOTIFY message (event: 3) shlfolder.c:4976: Test failed: Didn't expect a WM_USER_NOTIFY message (event: 3) shlfolder.c:4976: Test failed: Didn't expect a WM_USER_NOTIFY message (event: 3) shlfolder.c:4976: Test failed: Didn't expect a WM_USER_NOTIFY message (event: 3) shlfolder.c:4959: Test failed: CREATE: expected notification type 2, got: 40000 shlfolder.c:4966: Test failed: GetDisplayNameOf failed: 0x80070057 shlfolder.c:4976: Test failed: Didn't expect a WM_USER_NOTIFY message (event: 3)