ReactOS  0.4.15-dev-1070-ge1a01de
SHCreateFileExtractIconW.cpp
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS API tests
3  * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE: Test for SHCreateFileExtractIconW
5  * COPYRIGHT: Copyright 2017,2018 Mark Jansen (mark.jansen@reactos.org)
6  */
7 
8 #include "shelltest.h"
9 
10 #include <wincon.h>
11 #include <wingdi.h>
12 #include <stdio.h>
13 #include <shellutils.h>
14 
15 HRESULT (STDAPICALLTYPE *pSHCreateFileExtractIconW)(LPCWSTR pszFile, DWORD dwFileAttributes, REFIID riid, void **ppv);
16 
17 struct TestData
18 {
19  const WCHAR* Name;
21 };
22 
23 static TestData IconTests[] =
24 {
25  { L"xxx.zip", FILE_ATTRIBUTE_NORMAL },
26  { L"xxx.zip", FILE_ATTRIBUTE_DIRECTORY },
27  { L"xxx.exe", FILE_ATTRIBUTE_NORMAL },
28  { L"xxx.exe", FILE_ATTRIBUTE_DIRECTORY },
29  { L"xxx.dll", FILE_ATTRIBUTE_NORMAL },
30  { L"xxx.dll", FILE_ATTRIBUTE_DIRECTORY },
31  { L"xxx.txt", FILE_ATTRIBUTE_NORMAL },
32  { L"xxx.txt", FILE_ATTRIBUTE_DIRECTORY },
35 };
36 
37 struct TestIID
38 {
39  const GUID* IID;
42 };
43 
45 {
46  { &IID_IDefaultExtractIconInit, E_NOINTERFACE, E_NOINTERFACE },
47  { &IID_IExtractIconW, S_OK, S_OK },
48  { &IID_IExtractIconA, S_OK, S_OK },
51 };
52 
53 
54 static void ExtractOneBitmap(HBITMAP hbm, CComHeapPtr<BYTE>& data, DWORD& size)
55 {
58 
59  CComHeapPtr<BITMAPINFO> pInfoBM;
60 
61  pInfoBM.AllocateBytes(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
62  memset(pInfoBM, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
63  pInfoBM->bmiHeader.biSize = sizeof(pInfoBM->bmiHeader);
64  if (!GetDIBits(hdc, hbm, 0, 0, NULL, pInfoBM, DIB_RGB_COLORS))
65  return;
66 
67  size = pInfoBM->bmiHeader.biSizeImage;
68  data.Allocate(size);
69  GetDIBits(hdc, hbm, 0, pInfoBM->bmiHeader.biHeight, data, pInfoBM, DIB_RGB_COLORS);
70 
72  DeleteDC(hdc);
73 }
74 
75 static bool GetIconData(HICON icon, CComHeapPtr<BYTE>& colorData, DWORD& colorSize, CComHeapPtr<BYTE>& maskData, DWORD& maskSize)
76 {
77  ICONINFO iconinfo;
78 
79  if (!GetIconInfo(icon, &iconinfo))
80  return false;
81 
82  ExtractOneBitmap(iconinfo.hbmColor, colorData, colorSize);
83  ExtractOneBitmap(iconinfo.hbmMask, maskData, maskSize);
84 
85  DeleteObject(iconinfo.hbmColor);
86  DeleteObject(iconinfo.hbmMask);
87 
88  return true;
89 }
90 
91 
93 {
95  HMODULE shell32 = LoadLibraryA("shell32.dll");
96  HICON myIcon;
97  pSHCreateFileExtractIconW = (HRESULT (__stdcall *)(LPCWSTR, DWORD, REFIID, void **))GetProcAddress(shell32, "SHCreateFileExtractIconW");
98 
99  /* Show that icons returned are always the same */
100  UINT tryFlags[4] = { 0, GIL_FORSHORTCUT, GIL_OPENICON };
101 
103 
105  {
106  SHFILEINFOW shfi;
107  ULONG_PTR firet = SHGetFileInfoW(CurrentModule, 0, &shfi, sizeof(shfi), SHGFI_ICON);
108  myIcon = shfi.hIcon;
109  if (!firet)
110  {
111  skip("Unable to get my own icon\n");
112  return;
113  }
114  }
115 
116  if (!pSHCreateFileExtractIconW)
117  {
118  skip("SHCreateFileExtractIconW not available\n");
119  return;
120  }
121 
122  for (size_t n = 0; n < _countof(InterfaceTests); ++n)
123  {
124  {
125  CComPtr<IUnknown> spUnknown;
126  HRESULT hr = pSHCreateFileExtractIconW(L"test.txt", FILE_ATTRIBUTE_NORMAL, *InterfaceTests[n].IID, (void**)&spUnknown);
127  ok(hr == InterfaceTests[n].ExpectedCreate, "Expected hr to be 0x%lx, was 0x%lx for %u\n", InterfaceTests[n].ExpectedCreate, hr, n);
128  }
129 
130  {
131  CComPtr<IUnknown> spUnknown, spUnknown2;
132  HRESULT hr = pSHCreateFileExtractIconW(L"test.txt", FILE_ATTRIBUTE_NORMAL, IID_PPV_ARG(IUnknown, &spUnknown));
133  ok(hr == S_OK, "Expected hr to be S_OK, was 0x%lx for %u\n", hr, n);
134 
135  hr = spUnknown->QueryInterface(*InterfaceTests[n].IID, (void**)&spUnknown2);
136  ok(hr == InterfaceTests[n].ExpectedQueryInterface, "Expected hr to be 0x%lx, was 0x%lx for %u\n", InterfaceTests[n].ExpectedQueryInterface, hr, n);
137  }
138  }
139 
140  for (size_t n = 0; n < _countof(IconTests); ++n)
141  {
142  TestData& cur = IconTests[n];
143  bool useMyIcon = false;
144 
145  if (cur.Name == NULL)
146  {
147  cur.Name = CurrentModule;
148  useMyIcon = true;
149  }
150 
151  CComPtr<IExtractIconW> spExtract;
152  HRESULT hr = pSHCreateFileExtractIconW(cur.Name, cur.dwFlags, IID_PPV_ARG(IExtractIconW, &spExtract));
153  ok(hr == S_OK, "Expected hr to be S_OK, was 0x%lx for %S(%lx)\n", hr, cur.Name, cur.dwFlags);
154 
155  if (!SUCCEEDED(hr))
156  continue;
157 
158  /* Show that GIL_DEFAULTICON does not work. */
159  {
160  int ilIndex = -1;
161  UINT wFlags = 0xdeaddead;
163 
164  hr = spExtract->GetIconLocation(GIL_DEFAULTICON, Buffer, _countof(Buffer), &ilIndex, &wFlags);
165  ok(hr == S_FALSE, "Expected hr to be S_FALSE, was 0x%lx for %S(0x%lx)\n", hr, cur.Name, cur.dwFlags);
166  }
167 
168 
169  for (UINT idFlags = 0; idFlags < _countof(tryFlags); ++idFlags)
170  {
171  int ilIndex = -1;
172  UINT wFlags = 0xdeaddead;
174 
175  hr = spExtract->GetIconLocation(tryFlags[idFlags], Buffer, _countof(Buffer), &ilIndex, &wFlags);
176  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]);
177  if (!SUCCEEDED(hr))
178  continue;
179 
180  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]);
181  ok(!wcscmp(Buffer, L"*"), "Expected '*', was '%S' for %S(0x%lx,0x%x)\n", Buffer, cur.Name, cur.dwFlags, tryFlags[idFlags]);
182 
183  HICON ico;
184  hr = spExtract->Extract(Buffer, ilIndex, &ico, NULL, 0);
185 
186  /* Visualize the icon extracted for whoever is stepping through this code. */
187  HWND console = GetConsoleWindow();
188  SendMessage(console, WM_SETICON, ICON_BIG, (LPARAM)ico);
189  SendMessage(console, WM_SETICON, ICON_SMALL, (LPARAM)ico);
190 
191  CComHeapPtr<BYTE> colorData, maskData;
192  DWORD colorSize = 0, maskSize = 0;
193 
194  GetIconData(ico, colorData, colorSize, maskData, maskSize);
195 
196  if (!colorSize || !maskSize)
197  continue;
198 
199  SHFILEINFOW shfi;
200  ULONG_PTR firet = SHGetFileInfoW(cur.Name, cur.dwFlags, &shfi, sizeof(shfi), SHGFI_USEFILEATTRIBUTES | SHGFI_ICON | SHGFI_SYSICONINDEX);
201 
202  if (!firet)
203  continue;
204 
205  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]);
206 
207 
208  CComHeapPtr<BYTE> colorDataRef, maskDataRef;
209  DWORD colorSizeRef = 0, maskSizeRef = 0;
210  GetIconData(shfi.hIcon, colorDataRef, colorSizeRef, maskDataRef, maskSizeRef);
211 
212  ok(colorSizeRef == colorSize, "Expected %lu, was %lu for %S(0x%lx,0x%x)\n", colorSizeRef, colorSize, cur.Name, cur.dwFlags, tryFlags[idFlags]);
213  ok(maskSizeRef == maskSize, "Expected %lu, was %lu for %S(0x%lx,0x%x)\n", maskSizeRef, maskSize, cur.Name, cur.dwFlags, tryFlags[idFlags]);
214 
215  if (colorSizeRef == colorSize)
216  {
217  ok(!memcmp(colorData, colorDataRef, colorSize), "Expected equal colorData for %S(0x%lx,0x%x)\n", cur.Name, cur.dwFlags, tryFlags[idFlags]);
218  }
219 
220  if (maskSizeRef == maskSize)
221  {
222  ok(!memcmp(maskData, maskDataRef, maskSize), "Expected equal maskData for %S(0x%lx,0x%x)\n", cur.Name, cur.dwFlags, tryFlags[idFlags]);
223  }
224 
225  if (useMyIcon)
226  {
227  colorDataRef.Free();
228  maskDataRef.Free();
229  colorSizeRef = maskSizeRef = 0;
230  GetIconData(myIcon, colorDataRef, colorSizeRef, maskDataRef, maskSizeRef);
231 
232  ok(colorSizeRef == colorSize, "Expected %lu, was %lu for %S(0x%lx,0x%x)\n", colorSizeRef, colorSize, cur.Name, cur.dwFlags, tryFlags[idFlags]);
233  ok(maskSizeRef == maskSize, "Expected %lu, was %lu for %S(0x%lx,0x%x)\n", maskSizeRef, maskSize, cur.Name, cur.dwFlags, tryFlags[idFlags]);
234 
235  if (colorSizeRef == colorSize)
236  {
237  /* In case requested filetype does not match, the exe icon is not used! */
239  {
240  ok(memcmp(colorData, colorDataRef, colorSize), "Expected colorData to be changed for %S(0x%lx,0x%x)\n", cur.Name, cur.dwFlags, tryFlags[idFlags]);
241  }
242  else
243  {
244  ok(!memcmp(colorData, colorDataRef, colorSize), "Expected equal colorData for %S(0x%lx,0x%x)\n", cur.Name, cur.dwFlags, tryFlags[idFlags]);
245  }
246  }
247 
248  // Mask is not reliable for some reason
249  //if (maskSizeRef == maskSize)
250  //{
251  // ok(!memcmp(maskData, maskDataRef, maskSize), "Expected equal maskData for %S(0x%lx,0x%lx)\n", cur.Name, cur.dwFlags);
252  //}
253  }
254  }
255  }
256 }
DWORD WINAPI GetModuleFileNameW(HINSTANCE hModule, LPWSTR lpFilename, DWORD nSize)
Definition: loader.c:600
#define SHGFI_SYSICONINDEX
Definition: shellapi.h:169
static HICON
Definition: imagelist.c:84
#define REFIID
Definition: guiddef.h:118
#define E_NOINTERFACE
Definition: winerror.h:2364
int memcmp(void *Buffer1, void *Buffer2, ACPI_SIZE Count)
Definition: utclib.c:112
HRESULT hr
Definition: shlfolder.c:183
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
const GUID IID_IPersist
Definition: proxy.cpp:14
const WCHAR * Name
static HDC
Definition: imagelist.c:92
GLdouble n
Definition: glext.h:7729
HGDIOBJ WINAPI SelectObject(_In_ HDC, _In_ HGDIOBJ)
Definition: dc.c:1499
BOOL WINAPI DeleteObject(_In_ HGDIOBJ)
HDC WINAPI CreateCompatibleDC(_In_opt_ HDC hdc)
#define IID_PPV_ARG(Itype, ppType)
#define DWORD
Definition: nt_native.h:44
BOOL WINAPI GetIconInfo(_In_ HICON, _Out_ PICONINFO)
Definition: cursoricon.c:2014
HRESULT ExpectedQueryInterface
#define ICON_SMALL
Definition: tnclass.cpp:48
uint32_t ULONG_PTR
Definition: typedefs.h:65
START_TEST(SHCreateFileExtractIconW)
static HANDLE shell32
Definition: animate.c:36
HBITMAP hbmMask
Definition: winuser.h:3101
HINSTANCE WINAPI DECLSPEC_HOTPATCH LoadLibraryA(LPCSTR lpLibFileName)
Definition: loader.c:111
#define S_FALSE
Definition: winerror.h:2357
smooth NULL
Definition: ftsmooth.c:416
LONG_PTR LPARAM
Definition: windef.h:208
HBITMAP hbmColor
Definition: winuser.h:3102
Definition: bufpool.h:45
#define FILE_ATTRIBUTE_DIRECTORY
Definition: nt_native.h:705
PLOADER_MODULE CurrentModule
Definition: mboot.c:66
GLsizeiptr size
Definition: glext.h:5919
ULONG RGBQUAD
Definition: precomp.h:50
__wchar_t WCHAR
Definition: xmlstorage.h:180
DWORD_PTR WINAPI SHGetFileInfoW(LPCWSTR path, DWORD dwFileAttributes, SHFILEINFOW *psfi, UINT sizeofpsfi, UINT flags)
Definition: shell32_main.c:413
LONG HRESULT
Definition: typedefs.h:79
#define _countof(array)
Definition: sndvol32.h:68
DWORD REFIID riid
#define MAX_PATH
Definition: compat.h:34
unsigned long DWORD
Definition: ntddk_ex.h:95
#define __stdcall
Definition: typedefs.h:25
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
#define SHGFI_USEFILEATTRIBUTES
Definition: shellapi.h:179
EXTERN_C HRESULT WINAPI SHCreateFileExtractIconW(LPCWSTR pszPath, DWORD dwFileAttributes, REFIID riid, void **ppv)
#define FILE_ATTRIBUTE_NORMAL
Definition: compat.h:137
static bool GetIconData(HICON icon, CComHeapPtr< BYTE > &colorData, DWORD &colorSize, CComHeapPtr< BYTE > &maskData, DWORD &maskSize)
static const WCHAR L[]
Definition: oid.c:1250
HDC hdc
Definition: main.c:9
#define STDAPICALLTYPE
Definition: guid.c:3
HICON hIcon
Definition: shellapi.h:370
_In_ DWORD _Out_ _In_ WORD wFlags
Definition: wincon.h:534
_Check_return_ _CRTIMP int __cdecl wcscmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
#define S_OK
Definition: intsafe.h:51
HRESULT(STDAPICALLTYPE *pSHCreateFileExtractIconW)(LPCWSTR pszFile
BOOL WINAPI DeleteDC(_In_ HDC)
static void ExtractOneBitmap(HBITMAP hbm, CComHeapPtr< BYTE > &data, DWORD &size)
_In_ HBITMAP hbm
Definition: ntgdi.h:2776
#define ok(value,...)
Definition: atltest.h:57
unsigned int UINT
Definition: ndis.h:50
static TestIID InterfaceTests[]
static TestData IconTests[]
#define skip(...)
Definition: atltest.h:64
HRESULT WINAPI CoInitialize(LPVOID lpReserved)
Definition: compobj.c:1964
const GUID IID_IPersistFile
int WINAPI GetDIBits(_In_ HDC hdc, _In_ HBITMAP hbm, _In_ UINT start, _In_ UINT cLines, _Out_opt_ LPVOID lpvBits, _At_((LPBITMAPINFOHEADER) lpbmi, _Inout_) LPBITMAPINFO lpbmi, _In_ UINT usage)
DWORD dwFileAttributes
#define SendMessage
Definition: winuser.h:5818
#define GetProcAddress(x, y)
Definition: compat.h:501
static HBITMAP
Definition: button.c:44
#define DIB_RGB_COLORS
Definition: wingdi.h:366
#define SHGFI_ICON
Definition: shellapi.h:162
#define memset(x, y, z)
Definition: compat.h:39
DWORD REFIID void ** ppv
#define SUCCEEDED(hr)
Definition: intsafe.h:49
#define ICON_BIG
Definition: tnclass.cpp:51
HWND WINAPI DECLSPEC_HOTPATCH GetConsoleWindow(VOID)
Definition: console.c:2730