/* * PROJECT: ReactOS API tests * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) * PURPOSE: Test for SHCreateFileExtractIconW * COPYRIGHT: Copyright 2017,2018 Mark Jansen (mark.jansen@reactos.org) */ #include "shelltest.h" #include #include ULONG DbgPrint(PCH Format,...); #include HRESULT (STDAPICALLTYPE *pSHCreateFileExtractIconW)(LPCWSTR pszFile, DWORD dwFileAttributes, REFIID riid, void **ppv); struct TestData { const WCHAR* Name; DWORD dwFlags; }; static TestData IconTests[] = { { 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 }, }; struct TestIID { const GUID* IID; HRESULT ExpectedCreate; HRESULT ExpectedQueryInterface; }; static TestIID InterfaceTests[] = { { &IID_IDefaultExtractIconInit, E_NOINTERFACE, E_NOINTERFACE }, { &IID_IExtractIconW, S_OK, S_OK }, { &IID_IExtractIconA, S_OK, S_OK }, { &IID_IPersist, E_NOINTERFACE, E_NOINTERFACE }, { &IID_IPersistFile, E_NOINTERFACE, E_NOINTERFACE }, }; 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"); /* Show that icons returned are always the same */ UINT tryFlags[4] = { 0, GIL_FORSHORTCUT, GIL_OPENICON }; 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(InterfaceTests); ++n) { { CComPtr spUnknown; HRESULT hr = pSHCreateFileExtractIconW(L"test.txt", FILE_ATTRIBUTE_NORMAL, *InterfaceTests[n].IID, (void**)&spUnknown); ok(hr == InterfaceTests[n].ExpectedCreate, "Expected hr to be 0x%lx, was 0x%lx for %u\n", InterfaceTests[n].ExpectedCreate, hr, n); } { CComPtr spUnknown, spUnknown2; HRESULT hr = pSHCreateFileExtractIconW(L"test.txt", FILE_ATTRIBUTE_NORMAL, IID_PPV_ARG(IUnknown, &spUnknown)); ok(hr == S_OK, "Expected hr to be S_OK, was 0x%lx for %u\n", hr, n); hr = spUnknown->QueryInterface(*InterfaceTests[n].IID, (void**)&spUnknown2); ok(hr == InterfaceTests[n].ExpectedQueryInterface, "Expected hr to be 0x%lx, was 0x%lx for %u\n", InterfaceTests[n].ExpectedQueryInterface, hr, n); } } for (size_t n = 0; n < _countof(IconTests); ++n) { TestData& cur = IconTests[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; /* Show that GIL_DEFAULTICON does not work. */ { int ilIndex = -1; UINT wFlags = 0xdeaddead; WCHAR Buffer[MAX_PATH]; hr = spExtract->GetIconLocation(GIL_DEFAULTICON, Buffer, _countof(Buffer), &ilIndex, &wFlags); ok(hr == S_FALSE, "Expected hr to be S_FALSE, was 0x%lx for %S(0x%lx)\n", hr, cur.Name, cur.dwFlags); } for (UINT idFlags = 0; idFlags < _countof(tryFlags); ++idFlags) { int ilIndex = -1; UINT wFlags = 0xdeaddead; WCHAR Buffer[MAX_PATH]; hr = spExtract->GetIconLocation(tryFlags[idFlags], Buffer, _countof(Buffer), &ilIndex, &wFlags); ok(hr == S_OK, "Expected hr to be S_OK, was 0x%lx for %S(0x%lx,0x%x)\n", hr, cur.Name, cur.dwFlags, tryFlags[idFlags]); if (!SUCCEEDED(hr)) continue; ok(wFlags & (GIL_NOTFILENAME|GIL_PERCLASS), "Expected GIL_NOTFILENAME|GIL_PERCLASS to be set for %S(0x%lx,0x%x)\n", cur.Name, cur.dwFlags, tryFlags[idFlags]); ok(!wcscmp(Buffer, L"*"), "Expected '*', was '%S' for %S(0x%lx,0x%x)\n", Buffer, cur.Name, cur.dwFlags, tryFlags[idFlags]); 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 | SHGFI_SYSICONINDEX); if (!firet) continue; ok(shfi.iIcon == ilIndex, "Expected ilIndex to be 0%x, was 0x%x for %S(0x%lx,0x%x)\n", shfi.iIcon, ilIndex, cur.Name, cur.dwFlags, tryFlags[idFlags]); CComHeapPtr colorDataRef, maskDataRef; DWORD colorSizeRef = 0, maskSizeRef = 0; GetIconData(shfi.hIcon, colorDataRef, colorSizeRef, maskDataRef, maskSizeRef); ok(colorSizeRef == colorSize, "Expected %lu, was %lu for %S(0x%lx,0x%x)\n", colorSizeRef, colorSize, cur.Name, cur.dwFlags, tryFlags[idFlags]); ok(maskSizeRef == maskSize, "Expected %lu, was %lu for %S(0x%lx,0x%x)\n", maskSizeRef, maskSize, cur.Name, cur.dwFlags, tryFlags[idFlags]); if (colorSizeRef == colorSize) { ok(!memcmp(colorData, colorDataRef, colorSize), "Expected equal colorData for %S(0x%lx,0x%x)\n", cur.Name, cur.dwFlags, tryFlags[idFlags]); } if (maskSizeRef == maskSize) { ok(!memcmp(maskData, maskDataRef, maskSize), "Expected equal maskData for %S(0x%lx,0x%x)\n", cur.Name, cur.dwFlags, tryFlags[idFlags]); } if (useMyIcon) { colorDataRef.Free(); maskDataRef.Free(); colorSizeRef = maskSizeRef = 0; GetIconData(myIcon, colorDataRef, colorSizeRef, maskDataRef, maskSizeRef); ok(colorSizeRef == colorSize, "Expected %lu, was %lu for %S(0x%lx,0x%x)\n", colorSizeRef, colorSize, cur.Name, cur.dwFlags, tryFlags[idFlags]); ok(maskSizeRef == maskSize, "Expected %lu, was %lu for %S(0x%lx,0x%x)\n", maskSizeRef, maskSize, cur.Name, cur.dwFlags, tryFlags[idFlags]); if (colorSizeRef == colorSize) { /* In case 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(0x%lx,0x%x)\n", cur.Name, cur.dwFlags, tryFlags[idFlags]); } else { ok(!memcmp(colorData, colorDataRef, colorSize), "Expected equal colorData for %S(0x%lx,0x%x)\n", cur.Name, cur.dwFlags, tryFlags[idFlags]); } } // Mask is not reliable for some reason //if (maskSizeRef == maskSize) //{ // ok(!memcmp(maskData, maskDataRef, maskSize), "Expected equal maskData for %S(0x%lx,0x%lx)\n", cur.Name, cur.dwFlags); //} } } } }