From: Mark Jansen Date: Fri, 8 Dec 2017 23:51:56 +0000 (+0100) Subject: [SHELL32_APITEST] Add test for SHCreateFileExtractIconW X-Git-Tag: 0.4.9-dev~720 X-Git-Url: https://git.reactos.org/?p=reactos.git;a=commitdiff_plain;h=4ac511405f69535076bbdabfc2710891978e5d02;ds=sidebyside [SHELL32_APITEST] Add test for SHCreateFileExtractIconW CORE-14082 --- diff --git a/modules/rostests/apitests/shell32/1.ico b/modules/rostests/apitests/shell32/1.ico new file mode 100644 index 00000000000..0b2dee3cc61 Binary files /dev/null and b/modules/rostests/apitests/shell32/1.ico differ diff --git a/modules/rostests/apitests/shell32/CMakeLists.txt b/modules/rostests/apitests/shell32/CMakeLists.txt index 65d0f6c504e..48c41820c97 100644 --- a/modules/rostests/apitests/shell32/CMakeLists.txt +++ b/modules/rostests/apitests/shell32/CMakeLists.txt @@ -14,10 +14,12 @@ add_executable(shell32_apitest CShellLink.cpp menu.cpp PathResolve.cpp + SHCreateFileExtractIconW.cpp ShellExecuteEx.cpp shelltest.cpp SHParseDisplayName.cpp testlist.c + resource.rc ${CMAKE_CURRENT_BINARY_DIR}/shell32_apitest.def) target_link_libraries(shell32_apitest wine uuid ${PSEH_LIB}) set_module_type(shell32_apitest win32cui) diff --git a/modules/rostests/apitests/shell32/SHCreateFileExtractIconW.cpp b/modules/rostests/apitests/shell32/SHCreateFileExtractIconW.cpp new file mode 100644 index 00000000000..38247dabe3d --- /dev/null +++ b/modules/rostests/apitests/shell32/SHCreateFileExtractIconW.cpp @@ -0,0 +1,204 @@ +/* + * PROJECT: ReactOS API tests + * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) + * PURPOSE: Test for SHCreateFileExtractIconW + * COPYRIGHT: Copyright 2017 Mark Jansen (mark.jansen@reactos.org) + */ + +#include "shelltest.h" +#include +#include +ULONG DbgPrint(PCH Format,...); +#include +#include +#include + + +HRESULT (STDAPICALLTYPE *pSHCreateFileExtractIconW)(LPCWSTR pszFile, DWORD dwFileAttributes, REFIID riid, void **ppv); + +struct test_data +{ + const WCHAR* Name; + DWORD dwFlags; +}; + +static test_data Tests[] = +{ + { L"xxx.zip", FILE_ATTRIBUTE_NORMAL }, + { L"xxx.zip", FILE_ATTRIBUTE_DIRECTORY }, + { L"xxx.exe", FILE_ATTRIBUTE_NORMAL }, + { L"xxx.exe", FILE_ATTRIBUTE_DIRECTORY }, + { L"xxx.dll", FILE_ATTRIBUTE_NORMAL }, + { L"xxx.dll", FILE_ATTRIBUTE_DIRECTORY }, + { L"xxx.txt", FILE_ATTRIBUTE_NORMAL }, + { L"xxx.txt", FILE_ATTRIBUTE_DIRECTORY }, + { NULL, FILE_ATTRIBUTE_NORMAL }, + { NULL, FILE_ATTRIBUTE_DIRECTORY }, +}; + + +static void ExtractOneBitmap(HBITMAP hbm, CComHeapPtr& data, DWORD& size) +{ + HDC hdc = CreateCompatibleDC(NULL); + HGDIOBJ obj = SelectObject(hdc, hbm); + + CComHeapPtr pInfoBM; + + pInfoBM.AllocateBytes(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)); + memset(pInfoBM, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)); + pInfoBM->bmiHeader.biSize = sizeof(pInfoBM->bmiHeader); + if (!GetDIBits(hdc, hbm, 0, 0, NULL, pInfoBM, DIB_RGB_COLORS)) + return; + + size = pInfoBM->bmiHeader.biSizeImage; + data.Allocate(size); + GetDIBits(hdc, hbm, 0, pInfoBM->bmiHeader.biHeight, data, pInfoBM, DIB_RGB_COLORS); + + SelectObject(hdc, obj); + DeleteDC(hdc); +} + +static bool GetIconData(HICON icon, CComHeapPtr& colorData, DWORD& colorSize, CComHeapPtr& maskData, DWORD& maskSize) +{ + ICONINFO iconinfo; + + if (!GetIconInfo(icon, &iconinfo)) + return false; + + ExtractOneBitmap(iconinfo.hbmColor, colorData, colorSize); + ExtractOneBitmap(iconinfo.hbmMask, maskData, maskSize); + + DeleteObject(iconinfo.hbmColor); + DeleteObject(iconinfo.hbmMask); + + return true; +} + + +START_TEST(SHCreateFileExtractIconW) +{ + WCHAR CurrentModule[MAX_PATH]; + HMODULE shell32 = LoadLibraryA("shell32.dll"); + HICON myIcon; + pSHCreateFileExtractIconW = (HRESULT (__stdcall *)(LPCWSTR, DWORD, REFIID, void **))GetProcAddress(shell32, "SHCreateFileExtractIconW"); + + CoInitialize(NULL); + + GetModuleFileNameW(NULL, CurrentModule, _countof(CurrentModule)); + { + SHFILEINFOW shfi; + ULONG_PTR firet = SHGetFileInfoW(CurrentModule, 0, &shfi, sizeof(shfi), SHGFI_ICON); + myIcon = shfi.hIcon; + if (!firet) + { + skip("Unable to get my own icon\n"); + return; + } + } + + if (!pSHCreateFileExtractIconW) + { + skip("SHCreateFileExtractIconW not available\n"); + return; + } + + for (size_t n = 0; n < _countof(Tests); ++n) + { + test_data& cur = Tests[n]; + bool useMyIcon = false; + + if (cur.Name == NULL) + { + cur.Name = CurrentModule; + useMyIcon = true; + } + + CComPtr spExtract; + HRESULT hr = pSHCreateFileExtractIconW(cur.Name, cur.dwFlags, IID_PPV_ARG(IExtractIconW, &spExtract)); + ok(hr == S_OK, "Expected hr to be S_OK, was 0x%lx for %S(%lx)\n", hr, cur.Name, cur.dwFlags); + + if (!SUCCEEDED(hr)) + continue; + + int ilIndex = -1; + UINT wFlags = 0xdeaddead; + WCHAR Buffer[MAX_PATH]; + + hr = spExtract->GetIconLocation(0, Buffer, _countof(Buffer), &ilIndex, &wFlags); + ok(hr == S_OK, "Expected hr to be S_OK, was 0x%lx for %S(%lx)\n", hr, cur.Name, cur.dwFlags); + if (!SUCCEEDED(hr)) + continue; + + ok(wFlags & (GIL_NOTFILENAME|GIL_PERCLASS), "Expected GIL_NOTFILENAME|GIL_PERCLASS to be set for %S(%lx)\n", cur.Name, cur.dwFlags); + ok(!wcscmp(Buffer, L"*"), "Expected '*', was '%S' for %S(%lx)\n", Buffer, cur.Name, cur.dwFlags); + + HICON ico; + hr = spExtract->Extract(Buffer, ilIndex, &ico, NULL, 0); + + /* Visualize the icon extracted for whoever is stepping through this code. */ + HWND console = GetConsoleWindow(); + SendMessage(console, WM_SETICON, ICON_BIG, (LPARAM)ico); + SendMessage(console, WM_SETICON, ICON_SMALL, (LPARAM)ico); + + CComHeapPtr colorData, maskData; + DWORD colorSize = 0, maskSize = 0; + + GetIconData(ico, colorData, colorSize, maskData, maskSize); + + if (!colorSize || !maskSize) + continue; + + SHFILEINFOW shfi; + ULONG_PTR firet = SHGetFileInfoW(cur.Name, cur.dwFlags, &shfi, sizeof(shfi), SHGFI_USEFILEATTRIBUTES | SHGFI_ICON); + + if (!firet) + continue; + + CComHeapPtr colorDataRef, maskDataRef; + DWORD colorSizeRef = 0, maskSizeRef = 0; + GetIconData(shfi.hIcon, colorDataRef, colorSizeRef, maskDataRef, maskSizeRef); + + ok(colorSizeRef == colorSize, "Expected %lu, was %lu for %S(%lx)\n", colorSizeRef, colorSize, cur.Name, cur.dwFlags); + ok(maskSizeRef == maskSize, "Expected %lu, was %lu for %S(%lx)\n", maskSizeRef, maskSize, cur.Name, cur.dwFlags); + + if (colorSizeRef == colorSize) + { + ok(!memcmp(colorData, colorDataRef, colorSize), "Expected equal colorData for %S(%lx)\n", cur.Name, cur.dwFlags); + } + + if (maskSizeRef == maskSize) + { + ok(!memcmp(maskData, maskDataRef, maskSize), "Expected equal maskData for %S(%lx)\n", cur.Name, cur.dwFlags); + } + + if (useMyIcon) + { + colorDataRef.Free(); + maskDataRef.Free(); + colorSizeRef = maskSizeRef = 0; + GetIconData(myIcon, colorDataRef, colorSizeRef, maskDataRef, maskSizeRef); + + ok(colorSizeRef == colorSize, "Expected %lu, was %lu for %S(%lx)\n", colorSizeRef, colorSize, cur.Name, cur.dwFlags); + ok(maskSizeRef == maskSize, "Expected %lu, was %lu for %S(%lx)\n", maskSizeRef, maskSize, cur.Name, cur.dwFlags); + + if (colorSizeRef == colorSize) + { + /* Incase requested filetype does not match, the exe icon is not used! */ + if (cur.dwFlags == FILE_ATTRIBUTE_DIRECTORY) + { + ok(memcmp(colorData, colorDataRef, colorSize), "Expected colorData to be changed for %S(%lx)\n", cur.Name, cur.dwFlags); + } + else + { + ok(!memcmp(colorData, colorDataRef, colorSize), "Expected equal colorData for %S(%lx)\n", cur.Name, cur.dwFlags); + } + } + + // Mask is not reliable for some reason + //if (maskSizeRef == maskSize) + //{ + // ok(!memcmp(maskData, maskDataRef, maskSize), "Expected equal maskData for %S(%lx)\n", cur.Name, cur.dwFlags); + //} + } + } +} diff --git a/modules/rostests/apitests/shell32/resource.rc b/modules/rostests/apitests/shell32/resource.rc new file mode 100644 index 00000000000..89a0f853a89 --- /dev/null +++ b/modules/rostests/apitests/shell32/resource.rc @@ -0,0 +1,5 @@ +#include + +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL + +1 ICON "1.ico" diff --git a/modules/rostests/apitests/shell32/testlist.c b/modules/rostests/apitests/shell32/testlist.c index 769f5878000..b0a86380465 100644 --- a/modules/rostests/apitests/shell32/testlist.c +++ b/modules/rostests/apitests/shell32/testlist.c @@ -11,6 +11,7 @@ extern void func_CShellDesktop(void); extern void func_CShellLink(void); extern void func_menu(void); extern void func_PathResolve(void); +extern void func_SHCreateFileExtractIconW(void); extern void func_ShellExecuteEx(void); extern void func_SHParseDisplayName(void); @@ -24,6 +25,7 @@ const struct test winetest_testlist[] = { "CShellLink", func_CShellLink }, { "menu", func_menu }, { "PathResolve", func_PathResolve }, + { "SHCreateFileExtractIconW", func_SHCreateFileExtractIconW }, { "ShellExecuteEx", func_ShellExecuteEx }, { "SHParseDisplayName", func_SHParseDisplayName }, { 0, 0 }