Reactos
1/*
2 * Unit tests for shelllinks
3 *
4 * Copyright 2004 Mike McCormack
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 *
20 */
21
22#define COBJMACROS
23
24#include "initguid.h"
25#include "windows.h"
26#include "shlguid.h"
27#include "shobjidl.h"
28#include "shlobj.h"
29#include "shellapi.h"
30#include "commoncontrols.h"
31
32#include "wine/heap.h"
33#include "wine/test.h"
34
35#include "shell32_test.h"
36
37#ifdef __REACTOS__
38#include <reactos/undocshell.h>
39#endif
40
41#ifndef SLDF_HAS_LOGO3ID
42# define SLDF_HAS_LOGO3ID 0x00000800 /* not available in the Vista SDK */
43#endif
44
45static void (WINAPI *pILFree)(LPITEMIDLIST);
46static BOOL (WINAPI *pILIsEqual)(LPCITEMIDLIST, LPCITEMIDLIST);
47static HRESULT (WINAPI *pSHILCreateFromPath)(LPCWSTR, LPITEMIDLIST *,DWORD*);
48static HRESULT (WINAPI *pSHGetFolderLocation)(HWND,INT,HANDLE,DWORD,PIDLIST_ABSOLUTE*);
49static HRESULT (WINAPI *pSHDefExtractIconA)(LPCSTR, int, UINT, HICON*, HICON*, UINT);
50static HRESULT (WINAPI *pSHGetStockIconInfo)(SHSTOCKICONID, UINT, SHSTOCKICONINFO *);
51static DWORD (WINAPI *pGetLongPathNameA)(LPCSTR, LPSTR, DWORD);
52static DWORD (WINAPI *pGetShortPathNameA)(LPCSTR, LPSTR, DWORD);
53static UINT (WINAPI *pSHExtractIconsW)(LPCWSTR, int, int, int, HICON *, UINT *, UINT, UINT);
54static BOOL (WINAPI *pIsProcessDPIAware)(void);
55
56static const GUID _IID_IShellLinkDataList = {
57 0x45e2b4ae, 0xb1c3, 0x11d0,
58 { 0xb9, 0x2f, 0x00, 0xa0, 0xc9, 0x03, 0x12, 0xe1 }
59};
60
61
62/* For some reason SHILCreateFromPath does not work on Win98 and
63 * SHSimpleIDListFromPathA does not work on NT4. But if we call both we
64 * get what we want on all platforms.
65 */
66static LPITEMIDLIST (WINAPI *pSHSimpleIDListFromPathAW)(LPCVOID);
67
68static LPITEMIDLIST path_to_pidl(const char* path)
69{
70 LPITEMIDLIST pidl;
71
72 if (!pSHSimpleIDListFromPathAW)
73 {
74 HMODULE hdll=GetModuleHandleA("shell32.dll");
75 pSHSimpleIDListFromPathAW=(void*)GetProcAddress(hdll, (char*)162);
76 if (!pSHSimpleIDListFromPathAW)
77 win_skip("SHSimpleIDListFromPathAW not found in shell32.dll\n");
78 }
79
80 pidl=NULL;
81 /* pSHSimpleIDListFromPathAW maps to A on non NT platforms */
82 if (pSHSimpleIDListFromPathAW && (GetVersion() & 0x80000000))
83 pidl=pSHSimpleIDListFromPathAW(path);
84
85 if (!pidl)
86 {
87 WCHAR* pathW;
88 HRESULT r;
89 int len;
90
91 len=MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
92 pathW = heap_alloc(len * sizeof(WCHAR));
93 MultiByteToWideChar(CP_ACP, 0, path, -1, pathW, len);
94
95 r=pSHILCreateFromPath(pathW, &pidl, NULL);
96 ok(r == S_OK, "SHILCreateFromPath failed (0x%08x)\n", r);
97 heap_free(pathW);
98 }
99 return pidl;
100}
101
102
103/*
104 * Test manipulation of an IShellLink's properties.
105 */
106
107static void test_get_set(void)
108{
109 HRESULT r;
110 IShellLinkA *sl;
111 IShellLinkW *slW = NULL;
112 char mypath[MAX_PATH];
113 char buffer[INFOTIPSIZE];
114 WIN32_FIND_DATAA finddata;
115 LPITEMIDLIST pidl, tmp_pidl;
116 const char * str;
117 int i;
118 WORD w;
119
120 r = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
121 &IID_IShellLinkA, (LPVOID*)&sl);
122 ok(r == S_OK, "no IID_IShellLinkA (0x%08x)\n", r);
123 if (r != S_OK)
124 return;
125
126 /* Test Getting / Setting the description */
127 strcpy(buffer,"garbage");
128 r = IShellLinkA_GetDescription(sl, buffer, sizeof(buffer));
129 ok(r == S_OK, "GetDescription failed (0x%08x)\n", r);
130 ok(*buffer=='\0', "GetDescription returned '%s'\n", buffer);
131
132 str="Some description";
133 r = IShellLinkA_SetDescription(sl, str);
134 ok(r == S_OK, "SetDescription failed (0x%08x)\n", r);
135
136 strcpy(buffer,"garbage");
137 r = IShellLinkA_GetDescription(sl, buffer, sizeof(buffer));
138 ok(r == S_OK, "GetDescription failed (0x%08x)\n", r);
139 ok(strcmp(buffer,str)==0, "GetDescription returned '%s'\n", buffer);
140
141 r = IShellLinkA_SetDescription(sl, NULL);
142 ok(r == S_OK, "SetDescription failed (0x%08x)\n", r);
143
144 strcpy(buffer,"garbage");
145 r = IShellLinkA_GetDescription(sl, buffer, sizeof(buffer));
146 ok(r == S_OK, "GetDescription failed (0x%08x)\n", r);
147 ok(*buffer=='\0' || broken(strcmp(buffer,str)==0), "GetDescription returned '%s'\n", buffer); /* NT4 */
148
149 /* Test Getting / Setting the work directory */
150 strcpy(buffer,"garbage");
151 r = IShellLinkA_GetWorkingDirectory(sl, buffer, sizeof(buffer));
152 ok(r == S_OK, "GetWorkingDirectory failed (0x%08x)\n", r);
153 ok(*buffer=='\0', "GetWorkingDirectory returned '%s'\n", buffer);
154
155 str="c:\\nonexistent\\directory";
156 r = IShellLinkA_SetWorkingDirectory(sl, str);
157 ok(r == S_OK, "SetWorkingDirectory failed (0x%08x)\n", r);
158
159 strcpy(buffer,"garbage");
160 r = IShellLinkA_GetWorkingDirectory(sl, buffer, sizeof(buffer));
161 ok(r == S_OK, "GetWorkingDirectory failed (0x%08x)\n", r);
162 ok(lstrcmpiA(buffer,str)==0, "GetWorkingDirectory returned '%s'\n", buffer);
163
164 /* Test Getting / Setting the path */
165 strcpy(buffer,"garbage");
166 r = IShellLinkA_GetPath(sl, buffer, sizeof(buffer), NULL, SLGP_RAWPATH);
167 ok(r == S_FALSE || broken(r == S_OK) /* NT4/W2K */, "GetPath failed (0x%08x)\n", r);
168 ok(*buffer=='\0', "GetPath returned '%s'\n", buffer);
169
170 strcpy(buffer,"garbage");
171 memset(&finddata, 0xaa, sizeof(finddata));
172 r = IShellLinkA_GetPath(sl, buffer, sizeof(buffer), &finddata, SLGP_RAWPATH);
173 ok(r == S_FALSE || broken(r == S_OK) /* NT4/W2K */, "GetPath failed (0x%08x)\n", r);
174 ok(*buffer=='\0', "GetPath returned '%s'\n", buffer);
175 ok(finddata.dwFileAttributes == 0, "unexpected attributes %x\n", finddata.dwFileAttributes);
176 ok(finddata.cFileName[0] == 0, "unexpected filename '%s'\n", finddata.cFileName);
177
178 r = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
179 &IID_IShellLinkW, (LPVOID*)&slW);
180 ok(r == S_OK, "CoCreateInstance failed (0x%08x)\n", r);
181 if (!slW /* Win9x */ || !pGetLongPathNameA /* NT4 */)
182 skip("SetPath with NULL parameter crashes on Win9x and some NT4\n");
183 else
184 {
185 IShellLinkW_Release(slW);
186 r = IShellLinkA_SetPath(sl, NULL);
187 ok(r==E_INVALIDARG ||
188 broken(r==S_OK), /* Some Win95 and NT4 */
189 "SetPath returned wrong error (0x%08x)\n", r);
190 }
191
192 r = IShellLinkA_SetPath(sl, "");
193 ok(r==S_OK, "SetPath failed (0x%08x)\n", r);
194
195 strcpy(buffer,"garbage");
196 r = IShellLinkA_GetPath(sl, buffer, sizeof(buffer), NULL, SLGP_RAWPATH);
197 ok(r == S_FALSE, "GetPath failed (0x%08x)\n", r);
198 ok(*buffer=='\0', "GetPath returned '%s'\n", buffer);
199
200 /* Win98 returns S_FALSE, but WinXP returns S_OK */
201 str="c:\\nonexistent\\file";
202 r = IShellLinkA_SetPath(sl, str);
203 ok(r==S_FALSE || r==S_OK, "SetPath failed (0x%08x)\n", r);
204
205 strcpy(buffer,"garbage");
206 r = IShellLinkA_GetPath(sl, buffer, sizeof(buffer), NULL, SLGP_RAWPATH);
207 ok(r == S_OK, "GetPath failed (0x%08x)\n", r);
208 ok(lstrcmpiA(buffer,str)==0, "GetPath returned '%s'\n", buffer);
209
210 strcpy(buffer,"garbage");
211 memset(&finddata, 0xaa, sizeof(finddata));
212 r = IShellLinkA_GetPath(sl, buffer, sizeof(buffer), &finddata, SLGP_RAWPATH);
213 ok(r == S_OK, "GetPath failed (0x%08x)\n", r);
214 ok(lstrcmpiA(buffer,str)==0, "GetPath returned '%s'\n", buffer);
215 ok(finddata.dwFileAttributes == 0, "unexpected attributes %x\n", finddata.dwFileAttributes);
216 ok(lstrcmpiA(finddata.cFileName, "file") == 0, "unexpected filename '%s'\n", finddata.cFileName);
217
218 /* Get some real path to play with */
219 GetWindowsDirectoryA( mypath, sizeof(mypath)-12 );
220 strcat(mypath, "\\regedit.exe");
221
222 /* Test the interaction of SetPath and SetIDList */
223 tmp_pidl=NULL;
224 r = IShellLinkA_GetIDList(sl, &tmp_pidl);
225 ok(r == S_OK, "GetIDList failed (0x%08x)\n", r);
226 if (r == S_OK)
227 {
228 BOOL ret;
229
230 strcpy(buffer,"garbage");
231 ret = SHGetPathFromIDListA(tmp_pidl, buffer);
232 ok(ret, "SHGetPathFromIDListA failed\n");
233 if (ret)
234 ok(lstrcmpiA(buffer,str)==0, "GetIDList returned '%s'\n", buffer);
235 pILFree(tmp_pidl);
236 }
237
238 pidl=path_to_pidl(mypath);
239 ok(pidl!=NULL, "path_to_pidl returned a NULL pidl\n");
240
241 if (pidl)
242 {
243 LPITEMIDLIST second_pidl;
244
245 r = IShellLinkA_SetIDList(sl, pidl);
246 ok(r == S_OK, "SetIDList failed (0x%08x)\n", r);
247
248 tmp_pidl=NULL;
249 r = IShellLinkA_GetIDList(sl, &tmp_pidl);
250 ok(r == S_OK, "GetIDList failed (0x%08x)\n", r);
251 ok(tmp_pidl && pILIsEqual(pidl, tmp_pidl),
252 "GetIDList returned an incorrect pidl\n");
253
254 r = IShellLinkA_GetIDList(sl, &second_pidl);
255 ok(r == S_OK, "GetIDList failed (0x%08x)\n", r);
256 ok(second_pidl && pILIsEqual(pidl, second_pidl),
257 "GetIDList returned an incorrect pidl\n");
258 ok(second_pidl != tmp_pidl, "pidls are the same\n");
259
260 pILFree(second_pidl);
261 pILFree(tmp_pidl);
262 pILFree(pidl);
263
264 strcpy(buffer,"garbage");
265 r = IShellLinkA_GetPath(sl, buffer, sizeof(buffer), NULL, SLGP_RAWPATH);
266 ok(r == S_OK, "GetPath failed (0x%08x)\n", r);
267 ok(lstrcmpiA(buffer, mypath)==0, "GetPath returned '%s'\n", buffer);
268
269 strcpy(buffer,"garbage");
270 memset(&finddata, 0xaa, sizeof(finddata));
271 r = IShellLinkA_GetPath(sl, buffer, sizeof(buffer), &finddata, SLGP_RAWPATH);
272 ok(r == S_OK, "GetPath failed (0x%08x)\n", r);
273 ok(lstrcmpiA(buffer, mypath)==0, "GetPath returned '%s'\n", buffer);
274 ok(finddata.dwFileAttributes != 0, "unexpected attributes %x\n", finddata.dwFileAttributes);
275 ok(lstrcmpiA(finddata.cFileName, "regedit.exe") == 0, "unexpected filename '%s'\n", finddata.cFileName);
276 }
277
278 if (pSHGetFolderLocation)
279 {
280 LPITEMIDLIST pidl_controls;
281
282 r = pSHGetFolderLocation(NULL, CSIDL_CONTROLS, NULL, 0, &pidl_controls);
283 ok(r == S_OK, "SHGetFolderLocation failed (0x%08x)\n", r);
284
285 r = IShellLinkA_SetIDList(sl, pidl_controls);
286 ok(r == S_OK, "SetIDList failed (0x%08x)\n", r);
287
288 strcpy(buffer,"garbage");
289 r = IShellLinkA_GetPath(sl, buffer, sizeof(buffer), NULL, SLGP_RAWPATH);
290 ok(r == S_FALSE, "GetPath failed (0x%08x)\n", r);
291 ok(buffer[0] == 0, "GetPath returned '%s'\n", buffer);
292
293 strcpy(buffer,"garbage");
294 memset(&finddata, 0xaa, sizeof(finddata));
295 r = IShellLinkA_GetPath(sl, buffer, sizeof(buffer), &finddata, SLGP_RAWPATH);
296 ok(r == S_FALSE, "GetPath failed (0x%08x)\n", r);
297 ok(buffer[0] == 0, "GetPath returned '%s'\n", buffer);
298 ok(finddata.dwFileAttributes == 0, "unexpected attributes %x\n", finddata.dwFileAttributes);
299 ok(finddata.cFileName[0] == 0, "unexpected filename '%s'\n", finddata.cFileName);
300
301 pILFree(pidl_controls);
302 }
303
304 /* test path with quotes (IShellLinkA_SetPath returns S_FALSE on W2K and below and S_OK on XP and above */
305 r = IShellLinkA_SetPath(sl, "\"c:\\nonexistent\\file\"");
306 ok(r==S_FALSE || r == S_OK, "SetPath failed (0x%08x)\n", r);
307
308 strcpy(buffer,"garbage");
309 r = IShellLinkA_GetPath(sl, buffer, sizeof(buffer), NULL, SLGP_RAWPATH);
310 ok(r==S_OK, "GetPath failed (0x%08x)\n", r);
311 todo_wine ok(!strcmp(buffer, "C:\\nonexistent\\file") ||
312 broken(!strcmp(buffer, "C:\\\"c:\\nonexistent\\file\"")), /* NT4 */
313 "case doesn't match\n");
314
315 r = IShellLinkA_SetPath(sl, "\"c:\\foo");
316 ok(r==S_FALSE || r == S_OK || r == E_INVALIDARG /* Vista */, "SetPath failed (0x%08x)\n", r);
317
318 r = IShellLinkA_SetPath(sl, "\"\"c:\\foo");
319 ok(r==S_FALSE || r == S_OK || r == E_INVALIDARG /* Vista */, "SetPath failed (0x%08x)\n", r);
320
321 r = IShellLinkA_SetPath(sl, "c:\\foo\"");
322 ok(r==S_FALSE || r == S_OK || r == E_INVALIDARG /* Vista */, "SetPath failed (0x%08x)\n", r);
323
324 r = IShellLinkA_SetPath(sl, "\"\"c:\\foo\"");
325 ok(r==S_FALSE || r == S_OK || r == E_INVALIDARG /* Vista */, "SetPath failed (0x%08x)\n", r);
326
327 r = IShellLinkA_SetPath(sl, "\"\"c:\\foo\"\"");
328 ok(r==S_FALSE || r == S_OK || r == E_INVALIDARG /* Vista */, "SetPath failed (0x%08x)\n", r);
329
330 /* Test Getting / Setting the arguments */
331 strcpy(buffer,"garbage");
332 r = IShellLinkA_GetArguments(sl, buffer, sizeof(buffer));
333 ok(r == S_OK, "GetArguments failed (0x%08x)\n", r);
334 ok(*buffer=='\0', "GetArguments returned '%s'\n", buffer);
335
336 str="param1 \"spaced param2\"";
337 r = IShellLinkA_SetArguments(sl, str);
338 ok(r == S_OK, "SetArguments failed (0x%08x)\n", r);
339
340 strcpy(buffer,"garbage");
341 r = IShellLinkA_GetArguments(sl, buffer, sizeof(buffer));
342 ok(r == S_OK, "GetArguments failed (0x%08x)\n", r);
343 ok(strcmp(buffer,str)==0, "GetArguments returned '%s'\n", buffer);
344
345 strcpy(buffer,"garbage");
346 r = IShellLinkA_SetArguments(sl, NULL);
347 ok(r == S_OK, "SetArguments failed (0x%08x)\n", r);
348 r = IShellLinkA_GetArguments(sl, buffer, sizeof(buffer));
349 ok(r == S_OK, "GetArguments failed (0x%08x)\n", r);
350 ok(!buffer[0] || strcmp(buffer,str)==0, "GetArguments returned '%s'\n", buffer);
351
352 strcpy(buffer,"garbage");
353 r = IShellLinkA_SetArguments(sl, "");
354 ok(r == S_OK, "SetArguments failed (0x%08x)\n", r);
355 r = IShellLinkA_GetArguments(sl, buffer, sizeof(buffer));
356 ok(r == S_OK, "GetArguments failed (0x%08x)\n", r);
357 ok(!buffer[0], "GetArguments returned '%s'\n", buffer);
358
359 /* Test Getting / Setting showcmd */
360 i=0xdeadbeef;
361 r = IShellLinkA_GetShowCmd(sl, &i);
362 ok(r == S_OK, "GetShowCmd failed (0x%08x)\n", r);
363 ok(i==SW_SHOWNORMAL, "GetShowCmd returned %d\n", i);
364
365 r = IShellLinkA_SetShowCmd(sl, SW_SHOWMAXIMIZED);
366 ok(r == S_OK, "SetShowCmd failed (0x%08x)\n", r);
367
368 i=0xdeadbeef;
369 r = IShellLinkA_GetShowCmd(sl, &i);
370 ok(r == S_OK, "GetShowCmd failed (0x%08x)\n", r);
371 ok(i==SW_SHOWMAXIMIZED, "GetShowCmd returned %d'\n", i);
372
373 /* Test Getting / Setting the icon */
374 i=0xdeadbeef;
375 strcpy(buffer,"garbage");
376 r = IShellLinkA_GetIconLocation(sl, buffer, sizeof(buffer), &i);
377 ok(r == S_OK, "GetIconLocation failed (0x%08x)\n", r);
378 ok(*buffer=='\0', "GetIconLocation returned '%s'\n", buffer);
379 ok(i==0, "GetIconLocation returned %d\n", i);
380
381 str="c:\\nonexistent\\file";
382 r = IShellLinkA_SetIconLocation(sl, str, 0xbabecafe);
383 ok(r == S_OK, "SetIconLocation failed (0x%08x)\n", r);
384
385 i=0xdeadbeef;
386 r = IShellLinkA_GetIconLocation(sl, buffer, sizeof(buffer), &i);
387 ok(r == S_OK, "GetIconLocation failed (0x%08x)\n", r);
388 ok(lstrcmpiA(buffer,str)==0, "GetIconLocation returned '%s'\n", buffer);
389 ok(i==0xbabecafe, "GetIconLocation returned %d'\n", i);
390
391 /* Test Getting / Setting the hot key */
392 w=0xbeef;
393 r = IShellLinkA_GetHotkey(sl, &w);
394 ok(r == S_OK, "GetHotkey failed (0x%08x)\n", r);
395 ok(w==0, "GetHotkey returned %d\n", w);
396
397 r = IShellLinkA_SetHotkey(sl, 0x5678);
398 ok(r == S_OK, "SetHotkey failed (0x%08x)\n", r);
399
400 w=0xbeef;
401 r = IShellLinkA_GetHotkey(sl, &w);
402 ok(r == S_OK, "GetHotkey failed (0x%08x)\n", r);
403 ok(w==0x5678, "GetHotkey returned %d'\n", w);
404
405 IShellLinkA_Release(sl);
406}
407
408
409/*
410 * Test saving and loading .lnk files
411 */
412
413#define lok ok_(__FILE__, line)
414#define check_lnk(a,b,c) check_lnk_(__LINE__, (a), (b), (c))
415
416void create_lnk_(int line, const WCHAR* path, lnk_desc_t* desc, int save_fails)
417{
418 HRESULT r;
419 IShellLinkA *sl;
420 IPersistFile *pf;
421
422 r = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
423 &IID_IShellLinkA, (LPVOID*)&sl);
424 lok(r == S_OK, "no IID_IShellLinkA (0x%08x)\n", r);
425 if (r != S_OK)
426 return;
427
428 if (desc->description)
429 {
430 r = IShellLinkA_SetDescription(sl, desc->description);
431 lok(r == S_OK, "SetDescription failed (0x%08x)\n", r);
432 }
433 if (desc->workdir)
434 {
435 r = IShellLinkA_SetWorkingDirectory(sl, desc->workdir);
436 lok(r == S_OK, "SetWorkingDirectory failed (0x%08x)\n", r);
437 }
438 if (desc->path)
439 {
440 r = IShellLinkA_SetPath(sl, desc->path);
441 lok(SUCCEEDED(r), "SetPath failed (0x%08x)\n", r);
442 }
443 if (desc->pidl)
444 {
445 r = IShellLinkA_SetIDList(sl, desc->pidl);
446 lok(r == S_OK, "SetIDList failed (0x%08x)\n", r);
447 }
448 if (desc->arguments)
449 {
450 r = IShellLinkA_SetArguments(sl, desc->arguments);
451 lok(r == S_OK, "SetArguments failed (0x%08x)\n", r);
452 }
453 if (desc->showcmd)
454 {
455 r = IShellLinkA_SetShowCmd(sl, desc->showcmd);
456 lok(r == S_OK, "SetShowCmd failed (0x%08x)\n", r);
457 }
458 if (desc->icon)
459 {
460 r = IShellLinkA_SetIconLocation(sl, desc->icon, desc->icon_id);
461 lok(r == S_OK, "SetIconLocation failed (0x%08x)\n", r);
462 }
463 if (desc->hotkey)
464 {
465 r = IShellLinkA_SetHotkey(sl, desc->hotkey);
466 lok(r == S_OK, "SetHotkey failed (0x%08x)\n", r);
467 }
468
469 r = IShellLinkA_QueryInterface(sl, &IID_IPersistFile, (void**)&pf);
470 lok(r == S_OK, "no IID_IPersistFile (0x%08x)\n", r);
471 if (r == S_OK)
472 {
473 LPOLESTR str;
474
475 if (0)
476 {
477 /* crashes on XP */
478 IPersistFile_GetCurFile(pf, NULL);
479 }
480
481 /* test GetCurFile before ::Save */
482 str = (LPWSTR)0xdeadbeef;
483 r = IPersistFile_GetCurFile(pf, &str);
484 lok(r == S_FALSE ||
485 broken(r == S_OK), /* shell32 < 5.0 */
486 "got 0x%08x\n", r);
487 lok(str == NULL, "got %p\n", str);
488
489 r = IPersistFile_Save(pf, path, TRUE);
490 todo_wine_if (save_fails)
491 lok(r == S_OK, "save failed (0x%08x)\n", r);
492
493 /* test GetCurFile after ::Save */
494 r = IPersistFile_GetCurFile(pf, &str);
495 lok(r == S_OK, "got 0x%08x\n", r);
496 lok(str != NULL ||
497 broken(str == NULL), /* shell32 < 5.0 */
498 "Didn't expect NULL\n");
499 if (str != NULL)
500 {
501 IMalloc *pmalloc;
502
503 lok(!winetest_strcmpW(path, str), "Expected %s, got %s\n",
504 wine_dbgstr_w(path), wine_dbgstr_w(str));
505
506 SHGetMalloc(&pmalloc);
507 IMalloc_Free(pmalloc, str);
508 }
509 else
510 win_skip("GetCurFile fails on shell32 < 5.0\n");
511
512 IPersistFile_Release(pf);
513 }
514
515 IShellLinkA_Release(sl);
516}
517
518static void check_lnk_(int line, const WCHAR* path, lnk_desc_t* desc, int todo)
519{
520 HRESULT r;
521 IShellLinkA *sl;
522 IPersistFile *pf;
523 char buffer[INFOTIPSIZE];
524 LPOLESTR str;
525
526 r = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
527 &IID_IShellLinkA, (LPVOID*)&sl);
528 lok(r == S_OK, "no IID_IShellLinkA (0x%08x)\n", r);
529 if (r != S_OK)
530 return;
531
532 r = IShellLinkA_QueryInterface(sl, &IID_IPersistFile, (LPVOID*)&pf);
533 lok(r == S_OK, "no IID_IPersistFile (0x%08x)\n", r);
534 if (r != S_OK)
535 {
536 IShellLinkA_Release(sl);
537 return;
538 }
539
540 /* test GetCurFile before ::Load */
541 str = (LPWSTR)0xdeadbeef;
542 r = IPersistFile_GetCurFile(pf, &str);
543 lok(r == S_FALSE ||
544 broken(r == S_OK), /* shell32 < 5.0 */
545 "got 0x%08x\n", r);
546 lok(str == NULL, "got %p\n", str);
547
548 r = IPersistFile_Load(pf, path, STGM_READ);
549 lok(r == S_OK, "load failed (0x%08x)\n", r);
550
551 /* test GetCurFile after ::Save */
552 r = IPersistFile_GetCurFile(pf, &str);
553 lok(r == S_OK, "got 0x%08x\n", r);
554 lok(str != NULL ||
555 broken(str == NULL), /* shell32 < 5.0 */
556 "Didn't expect NULL\n");
557 if (str != NULL)
558 {
559 IMalloc *pmalloc;
560
561 lok(!winetest_strcmpW(path, str), "Expected %s, got %s\n",
562 wine_dbgstr_w(path), wine_dbgstr_w(str));
563
564 SHGetMalloc(&pmalloc);
565 IMalloc_Free(pmalloc, str);
566 }
567 else
568 win_skip("GetCurFile fails on shell32 < 5.0\n");
569
570 IPersistFile_Release(pf);
571 if (r != S_OK)
572 {
573 IShellLinkA_Release(sl);
574 return;
575 }
576
577 if (desc->description)
578 {
579 strcpy(buffer,"garbage");
580 r = IShellLinkA_GetDescription(sl, buffer, sizeof(buffer));
581 lok(r == S_OK, "GetDescription failed (0x%08x)\n", r);
582 todo_wine_if ((todo & 0x1) != 0)
583 lok(strcmp(buffer, desc->description)==0, "GetDescription returned '%s' instead of '%s'\n",
584 buffer, desc->description);
585 }
586 if (desc->workdir)
587 {
588 strcpy(buffer,"garbage");
589 r = IShellLinkA_GetWorkingDirectory(sl, buffer, sizeof(buffer));
590 lok(r == S_OK, "GetWorkingDirectory failed (0x%08x)\n", r);
591 todo_wine_if ((todo & 0x2) != 0)
592 lok(lstrcmpiA(buffer, desc->workdir)==0, "GetWorkingDirectory returned '%s' instead of '%s'\n",
593 buffer, desc->workdir);
594 }
595 if (desc->path)
596 {
597 strcpy(buffer,"garbage");
598 r = IShellLinkA_GetPath(sl, buffer, sizeof(buffer), NULL, SLGP_RAWPATH);
599 lok(SUCCEEDED(r), "GetPath failed (0x%08x)\n", r);
600 todo_wine_if ((todo & 0x4) != 0)
601 lok(lstrcmpiA(buffer, desc->path)==0, "GetPath returned '%s' instead of '%s'\n",
602 buffer, desc->path);
603 }
604 if (desc->pidl)
605 {
606 LPITEMIDLIST pidl=NULL;
607 r = IShellLinkA_GetIDList(sl, &pidl);
608 lok(r == S_OK, "GetIDList failed (0x%08x)\n", r);
609 todo_wine_if ((todo & 0x8) != 0)
610 lok(pILIsEqual(pidl, desc->pidl), "GetIDList returned an incorrect pidl\n");
611 }
612 if (desc->showcmd)
613 {
614 int i=0xdeadbeef;
615 r = IShellLinkA_GetShowCmd(sl, &i);
616 lok(r == S_OK, "GetShowCmd failed (0x%08x)\n", r);
617 todo_wine_if ((todo & 0x10) != 0)
618 lok(i==desc->showcmd, "GetShowCmd returned 0x%0x instead of 0x%0x\n",
619 i, desc->showcmd);
620 }
621 if (desc->icon)
622 {
623 int i=0xdeadbeef;
624 strcpy(buffer,"garbage");
625 r = IShellLinkA_GetIconLocation(sl, buffer, sizeof(buffer), &i);
626 lok(r == S_OK, "GetIconLocation failed (0x%08x)\n", r);
627 todo_wine_if ((todo & 0x20) != 0) {
628 lok(lstrcmpiA(buffer, desc->icon)==0, "GetIconLocation returned '%s' instead of '%s'\n",
629 buffer, desc->icon);
630 lok(i==desc->icon_id, "GetIconLocation returned 0x%0x instead of 0x%0x\n",
631 i, desc->icon_id);
632 }
633 }
634 if (desc->hotkey)
635 {
636 WORD i=0xbeef;
637 r = IShellLinkA_GetHotkey(sl, &i);
638 lok(r == S_OK, "GetHotkey failed (0x%08x)\n", r);
639 todo_wine_if ((todo & 0x40) != 0)
640 lok(i==desc->hotkey, "GetHotkey returned 0x%04x instead of 0x%04x\n",
641 i, desc->hotkey);
642 }
643
644 IShellLinkA_Release(sl);
645}
646
647static void test_load_save(void)
648{
649 WCHAR lnkfile[MAX_PATH];
650 char lnkfileA[MAX_PATH];
651 static const char lnkfileA_name[] = "\\test.lnk";
652
653 lnk_desc_t desc;
654 char mypath[MAX_PATH];
655 char mydir[MAX_PATH];
656 char realpath[MAX_PATH];
657 char* p;
658 HANDLE hf;
659 DWORD r;
660
661 if (!pGetLongPathNameA)
662 {
663 win_skip("GetLongPathNameA is not available\n");
664 return;
665 }
666
667 /* Don't used a fixed path for the test.lnk file */
668 GetTempPathA(MAX_PATH, lnkfileA);
669 lstrcatA(lnkfileA, lnkfileA_name);
670 MultiByteToWideChar(CP_ACP, 0, lnkfileA, -1, lnkfile, MAX_PATH);
671
672 /* Save an empty .lnk file */
673 memset(&desc, 0, sizeof(desc));
674 create_lnk(lnkfile, &desc, 0);
675
676 /* It should come back as a bunch of empty strings */
677 desc.description="";
678 desc.workdir="";
679 desc.path="";
680 desc.arguments="";
681 desc.icon="";
682 check_lnk(lnkfile, &desc, 0x0);
683
684 /* Point a .lnk file to nonexistent files */
685 desc.description="";
686 desc.workdir="c:\\Nonexitent\\work\\directory";
687 desc.path="c:\\nonexistent\\path";
688 desc.pidl=NULL;
689 desc.arguments="";
690 desc.showcmd=0;
691 desc.icon="c:\\nonexistent\\icon\\file";
692 desc.icon_id=1234;
693 desc.hotkey=0;
694 create_lnk(lnkfile, &desc, 0);
695 check_lnk(lnkfile, &desc, 0x0);
696
697 r=GetModuleFileNameA(NULL, mypath, sizeof(mypath));
698 ok(r<sizeof(mypath), "GetModuleFileName failed (%d)\n", r);
699 strcpy(mydir, mypath);
700 p=strrchr(mydir, '\\');
701 if (p)
702 *p='\0';
703
704 /* IShellLink returns path in long form */
705 if (!pGetLongPathNameA(mypath, realpath, MAX_PATH)) strcpy( realpath, mypath );
706
707 /* Overwrite the existing lnk file and point it to existing files */
708 desc.description="test 2";
709 desc.workdir=mydir;
710 desc.path=realpath;
711 desc.pidl=NULL;
712 desc.arguments="/option1 /option2 \"Some string\"";
713 desc.showcmd=SW_SHOWNORMAL;
714 desc.icon=mypath;
715 desc.icon_id=0;
716 desc.hotkey=0x1234;
717 create_lnk(lnkfile, &desc, 0);
718 check_lnk(lnkfile, &desc, 0x0);
719
720 /* Test omitting .exe from an absolute path */
721 p=strrchr(realpath, '.');
722 if (p)
723 *p='\0';
724
725 desc.description="absolute path without .exe";
726 desc.workdir=mydir;
727 desc.path=realpath;
728 desc.pidl=NULL;
729 desc.arguments="/option1 /option2 \"Some string\"";
730 desc.showcmd=SW_SHOWNORMAL;
731 desc.icon=mypath;
732 desc.icon_id=0;
733 desc.hotkey=0x1234;
734 create_lnk(lnkfile, &desc, 0);
735 strcat(realpath, ".exe");
736 check_lnk(lnkfile, &desc, 0x4);
737
738 /* Overwrite the existing lnk file and test link to a command on the path */
739 desc.description="command on path";
740 desc.workdir=mypath;
741 desc.path="rundll32.exe";
742 desc.pidl=NULL;
743 desc.arguments="/option1 /option2 \"Some string\"";
744 desc.showcmd=SW_SHOWNORMAL;
745 desc.icon=mypath;
746 desc.icon_id=0;
747 desc.hotkey=0x1234;
748 create_lnk(lnkfile, &desc, 0);
749 /* Check that link is created to proper location */
750 SearchPathA( NULL, desc.path, NULL, MAX_PATH, realpath, NULL);
751 desc.path=realpath;
752 check_lnk(lnkfile, &desc, 0x0);
753
754 /* Test omitting .exe from a command on the path */
755 desc.description="command on path without .exe";
756 desc.workdir=mypath;
757 desc.path="rundll32";
758 desc.pidl=NULL;
759 desc.arguments="/option1 /option2 \"Some string\"";
760 desc.showcmd=SW_SHOWNORMAL;
761 desc.icon=mypath;
762 desc.icon_id=0;
763 desc.hotkey=0x1234;
764 create_lnk(lnkfile, &desc, 0);
765 /* Check that link is created to proper location */
766 SearchPathA( NULL, "rundll32", NULL, MAX_PATH, realpath, NULL);
767 desc.path=realpath;
768 check_lnk(lnkfile, &desc, 0x4);
769
770 /* Create a temporary non-executable file */
771 r=GetTempPathA(sizeof(mypath), mypath);
772 ok(r<sizeof(mypath), "GetTempPath failed (%d), err %d\n", r, GetLastError());
773 r=pGetLongPathNameA(mypath, mydir, sizeof(mydir));
774 ok(r<sizeof(mydir), "GetLongPathName failed (%d), err %d\n", r, GetLastError());
775 p=strrchr(mydir, '\\');
776 if (p)
777 *p='\0';
778
779 strcpy(mypath, mydir);
780 strcat(mypath, "\\test.txt");
781 hf = CreateFileA(mypath, GENERIC_WRITE, 0, NULL,
782 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
783 CloseHandle(hf);
784
785 /* Overwrite the existing lnk file and test link to an existing non-executable file */
786 desc.description="non-executable file";
787 desc.workdir=mydir;
788 desc.path=mypath;
789 desc.pidl=NULL;
790 desc.arguments="";
791 desc.showcmd=SW_SHOWNORMAL;
792 desc.icon=mypath;
793 desc.icon_id=0;
794 desc.hotkey=0x1234;
795 create_lnk(lnkfile, &desc, 0);
796 check_lnk(lnkfile, &desc, 0x0);
797
798 r=pGetShortPathNameA(mydir, mypath, sizeof(mypath));
799 ok(r<sizeof(mypath), "GetShortPathName failed (%d), err %d\n", r, GetLastError());
800
801 strcpy(realpath, mypath);
802 strcat(realpath, "\\test.txt");
803 strcat(mypath, "\\\\test.txt");
804
805 /* Overwrite the existing lnk file and test link to a short path with double backslashes */
806 desc.description="non-executable file";
807 desc.workdir=mydir;
808 desc.path=mypath;
809 desc.pidl=NULL;
810 desc.arguments="";
811 desc.showcmd=SW_SHOWNORMAL;
812 desc.icon=mypath;
813 desc.icon_id=0;
814 desc.hotkey=0x1234;
815 create_lnk(lnkfile, &desc, 0);
816 desc.path=realpath;
817 check_lnk(lnkfile, &desc, 0x0);
818
819 r = DeleteFileA(mypath);
820 ok(r, "failed to delete file %s (%d)\n", mypath, GetLastError());
821
822 /* Create a temporary .bat file */
823 strcpy(mypath, mydir);
824 strcat(mypath, "\\test.bat");
825 hf = CreateFileA(mypath, GENERIC_WRITE, 0, NULL,
826 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
827 CloseHandle(hf);
828
829 strcpy(realpath, mypath);
830
831 p=strrchr(mypath, '.');
832 if (p)
833 *p='\0';
834
835 /* Try linking to the .bat file without the extension */
836 desc.description="batch file";
837 desc.workdir=mydir;
838 desc.path=mypath;
839 desc.pidl=NULL;
840 desc.arguments="";
841 desc.showcmd=SW_SHOWNORMAL;
842 desc.icon=mypath;
843 desc.icon_id=0;
844 desc.hotkey=0x1234;
845 create_lnk(lnkfile, &desc, 0);
846 desc.path = realpath;
847 check_lnk(lnkfile, &desc, 0x4);
848
849 r = DeleteFileA(realpath);
850 ok(r, "failed to delete file %s (%d)\n", realpath, GetLastError());
851
852 /* FIXME: Also test saving a .lnk pointing to a pidl that cannot be
853 * represented as a path.
854 */
855
856 /* DeleteFileW is not implemented on Win9x */
857 r=DeleteFileA(lnkfileA);
858 ok(r, "failed to delete link '%s' (%d)\n", lnkfileA, GetLastError());
859}
860
861static void test_datalink(void)
862{
863 static const WCHAR lnk[] = {
864 ':',':','{','9','d','b','1','1','8','6','e','-','4','0','d','f','-','1',
865 '1','d','1','-','a','a','8','c','-','0','0','c','0','4','f','b','6','7',
866 '8','6','3','}',':','2','6',',','!','!','g','x','s','f','(','N','g',']',
867 'q','F','`','H','{','L','s','A','C','C','E','S','S','F','i','l','e','s',
868 '>','p','l','T',']','j','I','{','j','f','(','=','1','&','L','[','-','8',
869 '1','-',']',':',':',0 };
870 static const WCHAR comp[] = {
871 '2','6',',','!','!','g','x','s','f','(','N','g',']','q','F','`','H','{',
872 'L','s','A','C','C','E','S','S','F','i','l','e','s','>','p','l','T',']',
873 'j','I','{','j','f','(','=','1','&','L','[','-','8','1','-',']',0 };
874 IShellLinkDataList *dl = NULL;
875 IShellLinkW *sl = NULL;
876 HRESULT r;
877 DWORD flags = 0;
878 EXP_DARWIN_LINK *dar;
879
880 r = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
881 &IID_IShellLinkW, (LPVOID*)&sl );
882 ok( r == S_OK ||
883 broken(r == E_NOINTERFACE), /* Win9x */
884 "CoCreateInstance failed (0x%08x)\n", r);
885 if (!sl)
886 {
887 win_skip("no shelllink\n");
888 return;
889 }
890
891 r = IShellLinkW_QueryInterface( sl, &_IID_IShellLinkDataList, (LPVOID*) &dl );
892 ok( r == S_OK ||
893 broken(r == E_NOINTERFACE), /* NT4 */
894 "IShellLinkW_QueryInterface failed (0x%08x)\n", r);
895
896 if (!dl)
897 {
898 win_skip("no datalink interface\n");
899 IShellLinkW_Release( sl );
900 return;
901 }
902
903 flags = 0;
904 r = IShellLinkDataList_GetFlags( dl, &flags );
905 ok( r == S_OK, "GetFlags failed\n");
906 ok( flags == 0, "GetFlags returned wrong flags\n");
907
908 dar = (void*)-1;
909 r = IShellLinkDataList_CopyDataBlock( dl, EXP_DARWIN_ID_SIG, (LPVOID*) &dar );
910 ok( r == E_FAIL, "CopyDataBlock failed\n");
911 ok( dar == NULL, "should be null\n");
912
913 if (!pGetLongPathNameA /* NT4 */)
914 skip("SetPath with NULL parameter crashes on NT4\n");
915 else
916 {
917 r = IShellLinkW_SetPath(sl, NULL);
918 ok(r == E_INVALIDARG, "SetPath returned wrong error (0x%08x)\n", r);
919 }
920
921 r = IShellLinkW_SetPath(sl, lnk);
922 ok(r == S_OK, "SetPath failed\n");
923
924if (0)
925{
926 /* the following crashes */
927 IShellLinkDataList_GetFlags( dl, NULL );
928}
929
930 flags = 0;
931 r = IShellLinkDataList_GetFlags( dl, &flags );
932 ok( r == S_OK, "GetFlags failed\n");
933 /* SLDF_HAS_LOGO3ID is no longer supported on Vista+, filter it out */
934 ok( (flags & (~ SLDF_HAS_LOGO3ID)) == SLDF_HAS_DARWINID,
935 "GetFlags returned wrong flags\n");
936
937 dar = NULL;
938 r = IShellLinkDataList_CopyDataBlock( dl, EXP_DARWIN_ID_SIG, (LPVOID*) &dar );
939 ok( r == S_OK, "CopyDataBlock failed\n");
940
941 ok( dar && ((DATABLOCK_HEADER*)dar)->dwSignature == EXP_DARWIN_ID_SIG, "signature wrong\n");
942 ok( dar && 0==lstrcmpW(dar->szwDarwinID, comp ), "signature wrong\n");
943
944 LocalFree( dar );
945
946 IShellLinkDataList_Release( dl );
947 IShellLinkW_Release( sl );
948}
949
950static void test_shdefextracticon(void)
951{
952 HICON hiconlarge=NULL, hiconsmall=NULL;
953 HRESULT res;
954
955 if (!pSHDefExtractIconA)
956 {
957 win_skip("SHDefExtractIconA is unavailable\n");
958 return;
959 }
960
961 res = pSHDefExtractIconA("shell32.dll", 0, 0, &hiconlarge, &hiconsmall, MAKELONG(16,24));
962 ok(SUCCEEDED(res), "SHDefExtractIconA failed, res=%x\n", res);
963 ok(hiconlarge != NULL, "got null hiconlarge\n");
964 ok(hiconsmall != NULL, "got null hiconsmall\n");
965 DestroyIcon(hiconlarge);
966 DestroyIcon(hiconsmall);
967
968 hiconsmall = NULL;
969 res = pSHDefExtractIconA("shell32.dll", 0, 0, NULL, &hiconsmall, MAKELONG(16,24));
970 ok(SUCCEEDED(res), "SHDefExtractIconA failed, res=%x\n", res);
971 ok(hiconsmall != NULL, "got null hiconsmall\n");
972 DestroyIcon(hiconsmall);
973
974 res = pSHDefExtractIconA("shell32.dll", 0, 0, NULL, NULL, MAKELONG(16,24));
975 ok(SUCCEEDED(res), "SHDefExtractIconA failed, res=%x\n", res);
976}
977
978static void test_GetIconLocation(void)
979{
980 IShellLinkW *slW;
981 IShellLinkA *sl;
982 const char *str;
983 char buffer[INFOTIPSIZE], mypath[MAX_PATH];
984 int i;
985 HRESULT r;
986 LPITEMIDLIST pidl;
987
988 r = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
989 &IID_IShellLinkA, (LPVOID*)&sl);
990 ok(r == S_OK, "no IID_IShellLinkA (0x%08x)\n", r);
991 if(r != S_OK)
992 return;
993
994 i = 0xdeadbeef;
995 strcpy(buffer, "garbage");
996 r = IShellLinkA_GetIconLocation(sl, buffer, sizeof(buffer), &i);
997 ok(r == S_OK, "GetIconLocation failed (0x%08x)\n", r);
998 ok(*buffer == '\0', "GetIconLocation returned '%s'\n", buffer);
999 ok(i == 0, "GetIconLocation returned %d\n", i);
1000
1001 str = "c:\\some\\path";
1002 r = IShellLinkA_SetPath(sl, str);
1003 ok(r == S_FALSE || r == S_OK, "SetPath failed (0x%08x)\n", r);
1004
1005 i = 0xdeadbeef;
1006 strcpy(buffer, "garbage");
1007 r = IShellLinkA_GetIconLocation(sl, buffer, sizeof(buffer), &i);
1008 ok(r == S_OK, "GetIconLocation failed (0x%08x)\n", r);
1009 ok(*buffer == '\0', "GetIconLocation returned '%s'\n", buffer);
1010 ok(i == 0, "GetIconLocation returned %d\n", i);
1011
1012 GetWindowsDirectoryA(mypath, sizeof(mypath) - 12);
1013 strcat(mypath, "\\regedit.exe");
1014 pidl = path_to_pidl(mypath);
1015 r = IShellLinkA_SetIDList(sl, pidl);
1016 ok(r == S_OK, "SetPath failed (0x%08x)\n", r);
1017 pILFree(pidl);
1018
1019 i = 0xdeadbeef;
1020 strcpy(buffer, "garbage");
1021 r = IShellLinkA_GetIconLocation(sl, buffer, sizeof(buffer), &i);
1022 ok(r == S_OK, "GetIconLocation failed (0x%08x)\n", r);
1023 ok(*buffer == '\0', "GetIconLocation returned '%s'\n", buffer);
1024 ok(i == 0, "GetIconLocation returned %d\n", i);
1025
1026 str = "c:\\nonexistent\\file";
1027 r = IShellLinkA_SetIconLocation(sl, str, 0xbabecafe);
1028 ok(r == S_OK, "SetIconLocation failed (0x%08x)\n", r);
1029
1030 i = 0xdeadbeef;
1031 r = IShellLinkA_GetIconLocation(sl, buffer, sizeof(buffer), &i);
1032 ok(r == S_OK, "GetIconLocation failed (0x%08x)\n", r);
1033 ok(lstrcmpiA(buffer,str) == 0, "GetIconLocation returned '%s'\n", buffer);
1034 ok(i == 0xbabecafe, "GetIconLocation returned %#x.\n", i);
1035
1036 r = IShellLinkA_SetIconLocation(sl, NULL, 0xcafefe);
1037 ok(r == S_OK, "SetIconLocation failed (0x%08x)\n", r);
1038
1039 i = 0xdeadbeef;
1040 r = IShellLinkA_GetIconLocation(sl, buffer, sizeof(buffer), &i);
1041 ok(r == S_OK, "GetIconLocation failed (0x%08x)\n", r);
1042 ok(!*buffer, "GetIconLocation returned '%s'\n", buffer);
1043 ok(i == 0xcafefe, "GetIconLocation returned %#x.\n", i);
1044
1045 r = IShellLinkA_QueryInterface(sl, &IID_IShellLinkW, (void **)&slW);
1046 ok(SUCCEEDED(r), "Failed to get IShellLinkW, hr %#x.\n", r);
1047
1048 str = "c:\\nonexistent\\file";
1049 r = IShellLinkA_SetIconLocation(sl, str, 0xbabecafe);
1050 ok(r == S_OK, "SetIconLocation failed (0x%08x)\n", r);
1051
1052 r = IShellLinkA_SetIconLocation(sl, NULL, 0xcafefe);
1053 ok(r == S_OK, "SetIconLocation failed (0x%08x)\n", r);
1054
1055 i = 0xdeadbeef;
1056 r = IShellLinkA_GetIconLocation(sl, buffer, sizeof(buffer), &i);
1057 ok(r == S_OK, "GetIconLocation failed (0x%08x)\n", r);
1058 ok(!*buffer, "GetIconLocation returned '%s'\n", buffer);
1059 ok(i == 0xcafefe, "GetIconLocation returned %#x.\n", i);
1060
1061 IShellLinkW_Release(slW);
1062 IShellLinkA_Release(sl);
1063}
1064
1065static void test_SHGetStockIconInfo(void)
1066{
1067 BYTE buffer[sizeof(SHSTOCKICONINFO) + 16];
1068 SHSTOCKICONINFO *sii = (SHSTOCKICONINFO *) buffer;
1069 HRESULT hr;
1070 INT i;
1071
1072 /* not present before vista */
1073 if (!pSHGetStockIconInfo)
1074 {
1075 win_skip("SHGetStockIconInfo not available\n");
1076 return;
1077 }
1078
1079 /* negative values are handled */
1080 memset(buffer, '#', sizeof(buffer));
1081 sii->cbSize = sizeof(SHSTOCKICONINFO);
1082 hr = pSHGetStockIconInfo(SIID_INVALID, SHGSI_ICONLOCATION, sii);
1083 ok(hr == E_INVALIDARG, "-1: got 0x%x (expected E_INVALIDARG)\n", hr);
1084
1085 /* max. id for vista is 140 (no definition exists for this value) */
1086 for (i = SIID_DOCNOASSOC; i <= SIID_CLUSTEREDDRIVE; i++)
1087 {
1088 memset(buffer, '#', sizeof(buffer));
1089 sii->cbSize = sizeof(SHSTOCKICONINFO);
1090 hr = pSHGetStockIconInfo(i, SHGSI_ICONLOCATION, sii);
1091
1092 ok(hr == S_OK,
1093 "%3d: got 0x%x, iSysImageIndex: 0x%x, iIcon: 0x%x (expected S_OK)\n",
1094 i, hr, sii->iSysImageIndex, sii->iIcon);
1095
1096 if ((hr == S_OK) && (winetest_debug > 1))
1097 trace("%3d: got iSysImageIndex %3d, iIcon %3d and %s\n", i, sii->iSysImageIndex,
1098 sii->iIcon, wine_dbgstr_w(sii->szPath));
1099 }
1100
1101 /* test invalid icons indices that are invalid for all platforms */
1102 for (i = SIID_MAX_ICONS; i < (SIID_MAX_ICONS + 25) ; i++)
1103 {
1104 memset(buffer, '#', sizeof(buffer));
1105 sii->cbSize = sizeof(SHSTOCKICONINFO);
1106 hr = pSHGetStockIconInfo(i, SHGSI_ICONLOCATION, sii);
1107 ok(hr == E_INVALIDARG, "%3d: got 0x%x (expected E_INVALIDARG)\n", i, hr);
1108 todo_wine {
1109 ok(sii->iSysImageIndex == -1, "%d: got iSysImageIndex %d\n", i, sii->iSysImageIndex);
1110 ok(sii->iIcon == -1, "%d: got iIcon %d\n", i, sii->iIcon);
1111 }
1112 }
1113
1114 /* test more returned SHSTOCKICONINFO elements without extra flags */
1115 memset(buffer, '#', sizeof(buffer));
1116 sii->cbSize = sizeof(SHSTOCKICONINFO);
1117 hr = pSHGetStockIconInfo(SIID_FOLDER, SHGSI_ICONLOCATION, sii);
1118 ok(hr == S_OK, "got 0x%x (expected S_OK)\n", hr);
1119 ok(!sii->hIcon, "got %p (expected NULL)\n", sii->hIcon);
1120 ok(sii->iSysImageIndex == -1, "got %d (expected -1)\n", sii->iSysImageIndex);
1121
1122 /* the exact size is required of the struct */
1123 memset(buffer, '#', sizeof(buffer));
1124 sii->cbSize = sizeof(SHSTOCKICONINFO) + 2;
1125 hr = pSHGetStockIconInfo(SIID_FOLDER, SHGSI_ICONLOCATION, sii);
1126 ok(hr == E_INVALIDARG, "+2: got 0x%x, iSysImageIndex: 0x%x, iIcon: 0x%x\n", hr, sii->iSysImageIndex, sii->iIcon);
1127
1128 memset(buffer, '#', sizeof(buffer));
1129 sii->cbSize = sizeof(SHSTOCKICONINFO) + 1;
1130 hr = pSHGetStockIconInfo(SIID_FOLDER, SHGSI_ICONLOCATION, sii);
1131 ok(hr == E_INVALIDARG, "+1: got 0x%x, iSysImageIndex: 0x%x, iIcon: 0x%x\n", hr, sii->iSysImageIndex, sii->iIcon);
1132
1133 memset(buffer, '#', sizeof(buffer));
1134 sii->cbSize = sizeof(SHSTOCKICONINFO) - 1;
1135 hr = pSHGetStockIconInfo(SIID_FOLDER, SHGSI_ICONLOCATION, sii);
1136 ok(hr == E_INVALIDARG, "-1: got 0x%x, iSysImageIndex: 0x%x, iIcon: 0x%x\n", hr, sii->iSysImageIndex, sii->iIcon);
1137
1138 memset(buffer, '#', sizeof(buffer));
1139 sii->cbSize = sizeof(SHSTOCKICONINFO) - 2;
1140 hr = pSHGetStockIconInfo(SIID_FOLDER, SHGSI_ICONLOCATION, sii);
1141 ok(hr == E_INVALIDARG, "-2: got 0x%x, iSysImageIndex: 0x%x, iIcon: 0x%x\n", hr, sii->iSysImageIndex, sii->iIcon);
1142
1143 /* there is a NULL check for the struct */
1144 hr = pSHGetStockIconInfo(SIID_FOLDER, SHGSI_ICONLOCATION, NULL);
1145 ok(hr == E_INVALIDARG, "NULL: got 0x%x\n", hr);
1146
1147 for(i = 0; i < 140; i++) /* highest on wvista, i > 140 gives E_INVALIDARG, win7 can go higher */
1148 {
1149 memset(buffer, 0, sizeof(buffer));
1150 sii->cbSize = sizeof(SHSTOCKICONINFO);
1151 hr = pSHGetStockIconInfo(i, SHGSI_ICON | SHGSI_SMALLICON, sii);
1152 ok(hr == S_OK, "got 0x%x (expected S_OK)\n", hr);
1153 ok(sii->hIcon != NULL, "got NULL, expected an icon handle\n");
1154 ok(sii->iIcon != 0, "got unexpected 0 for SIID %d\n", i); /* howto find out exact sii->iIcon value??? */
1155 ok(sii->iSysImageIndex == -1, "got %d (expected -1)\n", sii->iSysImageIndex);
1156 ok(DestroyIcon(sii->hIcon), "DestroyIcon failed\n");
1157 if (winetest_debug > 1)
1158 trace("%3d: got iSysImageIndex %3d, iIcon %3d and %s\n", i, sii->iSysImageIndex,
1159 sii->iIcon, wine_dbgstr_w(sii->szPath));
1160 }
1161}
1162
1163static void test_SHExtractIcons(void)
1164{
1165 static const WCHAR notepadW[] = {'n','o','t','e','p','a','d','.','e','x','e',0};
1166 static const WCHAR shell32W[] = {'s','h','e','l','l','3','2','.','d','l','l',0};
1167 static const WCHAR emptyW[] = {0};
1168 UINT ret, ret2;
1169 HICON icons[256];
1170 UINT ids[256], i;
1171
1172 if (!pSHExtractIconsW)
1173 {
1174 win_skip("SHExtractIconsW not available\n");
1175 return;
1176 }
1177
1178 ret = pSHExtractIconsW(emptyW, 0, 16, 16, icons, ids, 1, 0);
1179 ok(ret == ~0u, "got %u\n", ret);
1180
1181 ret = pSHExtractIconsW(notepadW, 0, 16, 16, NULL, NULL, 1, 0);
1182 ok(ret == 1 || broken(ret == 2) /* win2k */, "got %u\n", ret);
1183
1184 icons[0] = (HICON)0xdeadbeef;
1185 ret = pSHExtractIconsW(notepadW, 0, 16, 16, icons, NULL, 1, 0);
1186 ok(ret == 1, "got %u\n", ret);
1187 ok(icons[0] != (HICON)0xdeadbeef, "icon not set\n");
1188 DestroyIcon(icons[0]);
1189
1190 icons[0] = (HICON)0xdeadbeef;
1191 ids[0] = 0xdeadbeef;
1192 ret = pSHExtractIconsW(notepadW, 0, 16, 16, icons, ids, 1, 0);
1193 ok(ret == 1, "got %u\n", ret);
1194 ok(icons[0] != (HICON)0xdeadbeef, "icon not set\n");
1195 ok(ids[0] != 0xdeadbeef, "id not set\n");
1196 DestroyIcon(icons[0]);
1197
1198 ret = pSHExtractIconsW(shell32W, 0, 16, 16, NULL, NULL, 0, 0);
1199 ret2 = pSHExtractIconsW(shell32W, 4, MAKELONG(32,16), MAKELONG(32,16), NULL, NULL, 256, 0);
1200 ok(ret && ret == ret2,
1201 "icon count should be independent of requested icon sizes and base icon index\n");
1202
1203 ret = pSHExtractIconsW(shell32W, 0, 16, 16, icons, ids, 0, 0);
1204 ok(ret == ~0u || !ret /* < vista */, "got %u\n", ret);
1205
1206 ret = pSHExtractIconsW(shell32W, 0, 16, 16, icons, ids, 3, 0);
1207 ok(ret == 3, "got %u\n", ret);
1208 for (i = 0; i < ret; i++) DestroyIcon(icons[i]);
1209
1210 /* count must be a multiple of two when getting two sizes */
1211 ret = pSHExtractIconsW(shell32W, 0, MAKELONG(16,32), MAKELONG(16,32), icons, ids, 3, 0);
1212 ok(!ret /* vista */ || ret == 4, "got %u\n", ret);
1213 for (i = 0; i < ret; i++) DestroyIcon(icons[i]);
1214
1215 ret = pSHExtractIconsW(shell32W, 0, MAKELONG(16,32), MAKELONG(16,32), icons, ids, 4, 0);
1216 ok(ret == 4, "got %u\n", ret);
1217 for (i = 0; i < ret; i++) DestroyIcon(icons[i]);
1218}
1219
1220static void test_propertystore(void)
1221{
1222 IShellLinkA *linkA;
1223 IShellLinkW *linkW;
1224 IPropertyStore *ps;
1225 HRESULT hr;
1226
1227 hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
1228 &IID_IShellLinkA, (void**)&linkA);
1229 ok(hr == S_OK, "got 0x%08x\n", hr);
1230
1231 hr = IShellLinkA_QueryInterface(linkA, &IID_IShellLinkW, (void**)&linkW);
1232 ok(hr == S_OK, "got 0x%08x\n", hr);
1233
1234 hr = IShellLinkA_QueryInterface(linkA, &IID_IPropertyStore, (void**)&ps);
1235 if (hr == S_OK) {
1236 IPropertyStoreCache *pscache;
1237
1238 IPropertyStore_Release(ps);
1239
1240 hr = IShellLinkW_QueryInterface(linkW, &IID_IPropertyStore, (void**)&ps);
1241 ok(hr == S_OK, "got 0x%08x\n", hr);
1242
1243 hr = IPropertyStore_QueryInterface(ps, &IID_IPropertyStoreCache, (void**)&pscache);
1244 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
1245
1246 IPropertyStore_Release(ps);
1247 }
1248 else
1249 win_skip("IShellLink doesn't support IPropertyStore.\n");
1250
1251 IShellLinkA_Release(linkA);
1252 IShellLinkW_Release(linkW);
1253}
1254
1255static void test_ExtractIcon(void)
1256{
1257 static const WCHAR nameW[] = {'\\','e','x','t','r','a','c','t','i','c','o','n','_','t','e','s','t','.','t','x','t',0};
1258 static const WCHAR shell32W[] = {'s','h','e','l','l','3','2','.','d','l','l',0};
1259 WCHAR pathW[MAX_PATH];
1260 HICON hicon, hicon2;
1261 char path[MAX_PATH];
1262 HANDLE file;
1263 int r;
1264 ICONINFO info;
1265 BITMAP bm;
1266
1267 /* specified instance handle */
1268 hicon = ExtractIconA(GetModuleHandleA("shell32.dll"), NULL, 0);
1269todo_wine
1270 ok(hicon == NULL, "Got icon %p\n", hicon);
1271 hicon2 = ExtractIconA(GetModuleHandleA("shell32.dll"), "shell32.dll", -1);
1272 ok(hicon2 != NULL, "Got icon %p\n", hicon2);
1273
1274 /* existing index */
1275 hicon = ExtractIconA(NULL, "shell32.dll", 0);
1276 ok(hicon != NULL && HandleToLong(hicon) != -1, "Got icon %p\n", hicon);
1277 DestroyIcon(hicon);
1278
1279 /* returns number of resources */
1280 hicon = ExtractIconA(NULL, "shell32.dll", -1);
1281 ok(HandleToLong(hicon) > 1 && hicon == hicon2, "Got icon %p\n", hicon);
1282
1283 /* invalid index, valid dll name */
1284 hicon = ExtractIconA(NULL, "shell32.dll", 3000);
1285 ok(hicon == NULL, "Got icon %p\n", hicon);
1286
1287 /* Create a temporary non-executable file */
1288 GetTempPathA(sizeof(path), path);
1289 strcat(path, "\\extracticon_test.txt");
1290 file = CreateFileA(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1291 ok(file != INVALID_HANDLE_VALUE, "Failed to create a test file\n");
1292 CloseHandle(file);
1293
1294 hicon = ExtractIconA(NULL, path, 0);
1295todo_wine
1296 ok(hicon == NULL, "Got icon %p\n", hicon);
1297
1298 hicon = ExtractIconA(NULL, path, -1);
1299 ok(hicon == NULL, "Got icon %p\n", hicon);
1300
1301 hicon = ExtractIconA(NULL, path, 1);
1302todo_wine
1303 ok(hicon == NULL, "Got icon %p\n", hicon);
1304
1305 r = DeleteFileA(path);
1306 ok(r, "failed to delete file %s (%d)\n", path, GetLastError());
1307
1308 /* same for W variant */
1309if (0)
1310{
1311 /* specified instance handle, crashes on XP, 2k3 */
1312 hicon = ExtractIconW(GetModuleHandleA("shell32.dll"), NULL, 0);
1313 ok(hicon == NULL, "Got icon %p\n", hicon);
1314}
1315 hicon2 = ExtractIconW(GetModuleHandleA("shell32.dll"), shell32W, -1);
1316 ok(hicon2 != NULL, "Got icon %p\n", hicon2);
1317
1318 /* existing index */
1319 hicon = ExtractIconW(NULL, shell32W, 0);
1320 ok(hicon != NULL && HandleToLong(hicon) != -1, "Got icon %p\n", hicon);
1321 GetIconInfo(hicon, &info);
1322 GetObjectW(info.hbmColor, sizeof(bm), &bm);
1323 ok(bm.bmWidth == GetSystemMetrics(SM_CXICON), "got %d\n", bm.bmWidth);
1324 ok(bm.bmHeight == GetSystemMetrics(SM_CYICON), "got %d\n", bm.bmHeight);
1325 DestroyIcon(hicon);
1326
1327 /* returns number of resources */
1328 hicon = ExtractIconW(NULL, shell32W, -1);
1329 ok(HandleToLong(hicon) > 1 && hicon == hicon2, "Got icon %p\n", hicon);
1330
1331 /* invalid index, valid dll name */
1332 hicon = ExtractIconW(NULL, shell32W, 3000);
1333 ok(hicon == NULL, "Got icon %p\n", hicon);
1334
1335 /* Create a temporary non-executable file */
1336 GetTempPathW(ARRAY_SIZE(pathW), pathW);
1337 lstrcatW(pathW, nameW);
1338 file = CreateFileW(pathW, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1339 ok(file != INVALID_HANDLE_VALUE, "Failed to create a test file\n");
1340 CloseHandle(file);
1341
1342 hicon = ExtractIconW(NULL, pathW, 0);
1343todo_wine
1344 ok(hicon == NULL, "Got icon %p\n", hicon);
1345
1346 hicon = ExtractIconW(NULL, pathW, -1);
1347 ok(hicon == NULL, "Got icon %p\n", hicon);
1348
1349 hicon = ExtractIconW(NULL, pathW, 1);
1350todo_wine
1351 ok(hicon == NULL, "Got icon %p\n", hicon);
1352
1353 r = DeleteFileW(pathW);
1354 ok(r, "failed to delete file %s (%d)\n", path, GetLastError());
1355}
1356
1357static void test_ExtractAssociatedIcon(void)
1358{
1359 char pathA[MAX_PATH];
1360 HICON hicon;
1361 WORD index;
1362
1363 /* empty path */
1364 index = 0;
1365 *pathA = 0;
1366 hicon = ExtractAssociatedIconA(NULL, pathA, &index);
1367todo_wine {
1368 ok(hicon != NULL, "Got icon %p\n", hicon);
1369 ok(!*pathA, "Unexpected path %s\n", pathA);
1370 ok(index == 0, "Unexpected index %u\n", index);
1371}
1372 DestroyIcon(hicon);
1373
1374 /* by index */
1375 index = 0;
1376 strcpy(pathA, "shell32.dll");
1377 hicon = ExtractAssociatedIconA(NULL, pathA, &index);
1378 ok(hicon != NULL, "Got icon %p\n", hicon);
1379 ok(!strcmp(pathA, "shell32.dll"), "Unexpected path %s\n", pathA);
1380 ok(index == 0, "Unexpected index %u\n", index);
1381 DestroyIcon(hicon);
1382
1383 /* valid dll name, invalid index */
1384 index = 5000;
1385 strcpy(pathA, "user32.dll");
1386 hicon = ExtractAssociatedIconA(NULL, pathA, &index);
1387 CharLowerBuffA(pathA, strlen(pathA));
1388todo_wine {
1389 ok(hicon != NULL, "Got icon %p\n", hicon);
1390 ok(!!strstr(pathA, "shell32.dll"), "Unexpected path %s\n", pathA);
1391}
1392 ok(index != 5000, "Unexpected index %u\n", index);
1393 DestroyIcon(hicon);
1394
1395 /* associated icon */
1396 index = 0xcaca;
1397 strcpy(pathA, "dummy.exe");
1398 hicon = ExtractAssociatedIconA(NULL, pathA, &index);
1399 CharLowerBuffA(pathA, strlen(pathA));
1400todo_wine {
1401 ok(hicon != NULL, "Got icon %p\n", hicon);
1402 ok(!!strstr(pathA, "shell32.dll"), "Unexpected path %s\n", pathA);
1403}
1404 ok(index != 0xcaca, "Unexpected index %u\n", index);
1405 DestroyIcon(hicon);
1406}
1407
1408static int get_shell_icon_size(void)
1409{
1410 char buf[10];
1411 DWORD value = 32, size = sizeof(buf), type;
1412 HKEY key;
1413
1414 if (!RegOpenKeyA( HKEY_CURRENT_USER, "Control Panel\\Desktop\\WindowMetrics", &key ))
1415 {
1416 if (!RegQueryValueExA( key, "Shell Icon Size", NULL, &type, (BYTE *)buf, &size ) && type == REG_SZ)
1417 value = atoi( buf );
1418 RegCloseKey( key );
1419 }
1420 return value;
1421}
1422
1423static void test_SHGetImageList(void)
1424{
1425 HRESULT hr;
1426 IImageList *list, *list2;
1427 BOOL ret;
1428 HIMAGELIST lg, sm;
1429 ULONG start_refs, refs;
1430 int i, width, height, expect;
1431 BOOL dpi_aware = pIsProcessDPIAware && pIsProcessDPIAware();
1432
1433 hr = SHGetImageList( SHIL_LARGE, &IID_IImageList, (void **)&list );
1434 ok( hr == S_OK, "got %08x\n", hr );
1435 start_refs = IImageList_AddRef( list );
1436 IImageList_Release( list );
1437
1438 hr = SHGetImageList( SHIL_LARGE, &IID_IImageList, (void **)&list2 );
1439 ok( hr == S_OK, "got %08x\n", hr );
1440 ok( list == list2, "lists differ\n" );
1441 refs = IImageList_AddRef( list );
1442 IImageList_Release( list );
1443 ok( refs == start_refs + 1, "got %d, start_refs %d\n", refs, start_refs );
1444 IImageList_Release( list2 );
1445
1446 hr = SHGetImageList( SHIL_SMALL, &IID_IImageList, (void **)&list2 );
1447 ok( hr == S_OK, "got %08x\n", hr );
1448
1449 ret = Shell_GetImageLists( &lg, &sm );
1450 ok( ret, "got %d\n", ret );
1451 ok( lg == (HIMAGELIST)list, "mismatch\n" );
1452 ok( sm == (HIMAGELIST)list2, "mismatch\n" );
1453
1454 /* Shell_GetImageLists doesn't take a reference */
1455 refs = IImageList_AddRef( list );
1456 IImageList_Release( list );
1457 ok( refs == start_refs, "got %d, start_refs %d\n", refs, start_refs );
1458
1459 IImageList_Release( list2 );
1460 IImageList_Release( list );
1461
1462 /* Test the icon sizes */
1463 for (i = 0; i <= SHIL_LAST; i++)
1464 {
1465 hr = SHGetImageList( i, &IID_IImageList, (void **)&list );
1466 ok( hr == S_OK || broken( i == SHIL_JUMBO && hr == E_INVALIDARG ), /* XP and 2003 */
1467 "%d: got %08x\n", i, hr );
1468 if (FAILED(hr)) continue;
1469 IImageList_GetIconSize( list, &width, &height );
1470 switch (i)
1471 {
1472 case SHIL_LARGE:
1473 if (dpi_aware) expect = GetSystemMetrics( SM_CXICON );
1474 else expect = get_shell_icon_size();
1475 break;
1476 case SHIL_SMALL:
1477 if (dpi_aware) expect = GetSystemMetrics( SM_CXICON ) / 2;
1478 else expect = GetSystemMetrics( SM_CXSMICON );
1479 break;
1480 case SHIL_EXTRALARGE:
1481 expect = (GetSystemMetrics( SM_CXICON ) * 3) / 2;
1482 break;
1483 case SHIL_SYSSMALL:
1484 expect = GetSystemMetrics( SM_CXSMICON );
1485 break;
1486 case SHIL_JUMBO:
1487 expect = 256;
1488 break;
1489 }
1490 todo_wine_if(i == SHIL_SYSSMALL && dpi_aware && expect != GetSystemMetrics( SM_CXICON ) / 2)
1491 {
1492 ok( width == expect, "%d: got %d expect %d\n", i, width, expect );
1493 ok( height == expect, "%d: got %d expect %d\n", i, height, expect );
1494 }
1495 IImageList_Release( list );
1496 }
1497}
1498
1499START_TEST(shelllink)
1500{
1501 HRESULT r;
1502 HMODULE hmod = GetModuleHandleA("shell32.dll");
1503 HMODULE hkernel32 = GetModuleHandleA("kernel32.dll");
1504 HMODULE huser32 = GetModuleHandleA("user32.dll");
1505
1506 pILFree = (void *)GetProcAddress(hmod, (LPSTR)155);
1507 pILIsEqual = (void *)GetProcAddress(hmod, (LPSTR)21);
1508 pSHILCreateFromPath = (void *)GetProcAddress(hmod, (LPSTR)28);
1509 pSHGetFolderLocation = (void *)GetProcAddress(hmod, "SHGetFolderLocation");
1510 pSHDefExtractIconA = (void *)GetProcAddress(hmod, "SHDefExtractIconA");
1511 pSHGetStockIconInfo = (void *)GetProcAddress(hmod, "SHGetStockIconInfo");
1512 pGetLongPathNameA = (void *)GetProcAddress(hkernel32, "GetLongPathNameA");
1513 pGetShortPathNameA = (void *)GetProcAddress(hkernel32, "GetShortPathNameA");
1514 pSHExtractIconsW = (void *)GetProcAddress(hmod, "SHExtractIconsW");
1515 pIsProcessDPIAware = (void *)GetProcAddress(huser32, "IsProcessDPIAware");
1516
1517 r = CoInitialize(NULL);
1518 ok(r == S_OK, "CoInitialize failed (0x%08x)\n", r);
1519 if (r != S_OK)
1520 return;
1521
1522 test_get_set();
1523 test_load_save();
1524 test_datalink();
1525 test_shdefextracticon();
1526 test_GetIconLocation();
1527 test_SHGetStockIconInfo();
1528 test_SHExtractIcons();
1529 test_propertystore();
1530 test_ExtractIcon();
1531 test_ExtractAssociatedIcon();
1532 test_SHGetImageList();
1533
1534 CoUninitialize();
1535}