Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52673 Signed-off-by: Jinoh Kang jinoh.kang.kr@gmail.com
-- v4: shell32: Partially implement IShellItemImageFactory (icon only, no thumbnail).
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 | 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);
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them if they are indeed new. Note that rare failures and failures with always changing text (e.g. because of memory addresses) can cause false positives. If this is what happened, then fixing those would really help.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=117053
Your paranoid android.
=== w1064v1809 (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)
=== 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:4976: Test failed: Didn't expect a WM_USER_NOTIFY message (event: 4000000) shlfolder.c:4976: Test failed: Didn't expect a WM_USER_NOTIFY message (event: 4000000) shlfolder.c:4976: Test failed: Didn't expect a WM_USER_NOTIFY message (event: 4000000) shlfolder.c:4976: Test failed: Didn't expect a WM_USER_NOTIFY message (event: 40000)
=== w1064v1809 (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)
=== w1064 (64 bit report) ===
shell32: shlfolder.c:4976: Test failed: Didn't expect a WM_USER_NOTIFY message (event: 3)
=== w1064_2qxl (64 bit report) ===
shell32: shlfolder.c:4959: Test failed: MKDIR: expected notification type 8, 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)
=== w1064_adm (64 bit report) ===
shell32: shlfolder.c:4976: Test failed: Didn't expect a WM_USER_NOTIFY message (event: 40000)
=== w10pro64 (64 bit report) ===
shell32: 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) 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: 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: 3)
=== w10pro64_en_AE_u8 (64 bit report) ===
shell32: shlfolder.c:4976: Test failed: Didn't expect a WM_USER_NOTIFY message (event: 10) 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: 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: 3)
=== w10pro64_ar (64 bit report) ===
shell32: shlfolder.c:4976: Test failed: Didn't expect a WM_USER_NOTIFY message (event: 40000)
=== w10pro64_ja (64 bit report) ===
shell32: shlfolder.c:4976: Test failed: Didn't expect a WM_USER_NOTIFY message (event: 10) shlfolder.c:4976: Test failed: Didn't expect a WM_USER_NOTIFY message (event: 3)
=== w10pro64_zh_CN (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) 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)