2 * Unit tests for shelllinks
4 * Copyright 2004 Mike McCormack
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.
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.
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
30 #include "commoncontrols.h"
31 #include "wine/test.h"
33 #include "shell32_test.h"
35 #ifndef SLDF_HAS_LOGO3ID
36 # define SLDF_HAS_LOGO3ID 0x00000800 /* not available in the Vista SDK */
39 static void (WINAPI
*pILFree
)(LPITEMIDLIST
);
40 static BOOL (WINAPI
*pILIsEqual
)(LPCITEMIDLIST
, LPCITEMIDLIST
);
41 static HRESULT (WINAPI
*pSHILCreateFromPath
)(LPCWSTR
, LPITEMIDLIST
*,DWORD
*);
42 static HRESULT (WINAPI
*pSHDefExtractIconA
)(LPCSTR
, int, UINT
, HICON
*, HICON
*, UINT
);
43 static HRESULT (WINAPI
*pSHGetStockIconInfo
)(SHSTOCKICONID
, UINT
, SHSTOCKICONINFO
*);
44 static DWORD (WINAPI
*pGetLongPathNameA
)(LPCSTR
, LPSTR
, DWORD
);
45 static DWORD (WINAPI
*pGetShortPathNameA
)(LPCSTR
, LPSTR
, DWORD
);
46 static UINT (WINAPI
*pSHExtractIconsW
)(LPCWSTR
, int, int, int, HICON
*, UINT
*, UINT
, UINT
);
47 static BOOL (WINAPI
*pIsProcessDPIAware
)(void);
49 static const GUID _IID_IShellLinkDataList
= {
50 0x45e2b4ae, 0xb1c3, 0x11d0,
51 { 0xb9, 0x2f, 0x00, 0xa0, 0xc9, 0x03, 0x12, 0xe1 }
55 /* For some reason SHILCreateFromPath does not work on Win98 and
56 * SHSimpleIDListFromPathA does not work on NT4. But if we call both we
57 * get what we want on all platforms.
59 static LPITEMIDLIST (WINAPI
*pSHSimpleIDListFromPathAW
)(LPCVOID
);
61 static LPITEMIDLIST
path_to_pidl(const char* path
)
65 if (!pSHSimpleIDListFromPathAW
)
67 HMODULE hdll
=GetModuleHandleA("shell32.dll");
68 pSHSimpleIDListFromPathAW
=(void*)GetProcAddress(hdll
, (char*)162);
69 if (!pSHSimpleIDListFromPathAW
)
70 win_skip("SHSimpleIDListFromPathAW not found in shell32.dll\n");
74 /* pSHSimpleIDListFromPathAW maps to A on non NT platforms */
75 if (pSHSimpleIDListFromPathAW
&& (GetVersion() & 0x80000000))
76 pidl
=pSHSimpleIDListFromPathAW(path
);
84 len
=MultiByteToWideChar(CP_ACP
, 0, path
, -1, NULL
, 0);
85 pathW
=HeapAlloc(GetProcessHeap(), 0, len
*sizeof(WCHAR
));
86 MultiByteToWideChar(CP_ACP
, 0, path
, -1, pathW
, len
);
88 r
=pSHILCreateFromPath(pathW
, &pidl
, NULL
);
89 ok(r
== S_OK
, "SHILCreateFromPath failed (0x%08x)\n", r
);
90 HeapFree(GetProcessHeap(), 0, pathW
);
97 * Test manipulation of an IShellLink's properties.
100 static void test_get_set(void)
104 IShellLinkW
*slW
= NULL
;
105 char mypath
[MAX_PATH
];
106 char buffer
[INFOTIPSIZE
];
107 LPITEMIDLIST pidl
, tmp_pidl
;
112 r
= CoCreateInstance(&CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
,
113 &IID_IShellLinkA
, (LPVOID
*)&sl
);
114 ok(r
== S_OK
, "no IID_IShellLinkA (0x%08x)\n", r
);
118 /* Test Getting / Setting the description */
119 strcpy(buffer
,"garbage");
120 r
= IShellLinkA_GetDescription(sl
, buffer
, sizeof(buffer
));
121 ok(r
== S_OK
, "GetDescription failed (0x%08x)\n", r
);
122 ok(*buffer
=='\0', "GetDescription returned '%s'\n", buffer
);
124 str
="Some description";
125 r
= IShellLinkA_SetDescription(sl
, str
);
126 ok(r
== S_OK
, "SetDescription failed (0x%08x)\n", r
);
128 strcpy(buffer
,"garbage");
129 r
= IShellLinkA_GetDescription(sl
, buffer
, sizeof(buffer
));
130 ok(r
== S_OK
, "GetDescription failed (0x%08x)\n", r
);
131 ok(strcmp(buffer
,str
)==0, "GetDescription returned '%s'\n", buffer
);
133 r
= IShellLinkA_SetDescription(sl
, NULL
);
134 ok(r
== S_OK
, "SetDescription failed (0x%08x)\n", r
);
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(*buffer
=='\0' || broken(strcmp(buffer
,str
)==0), "GetDescription returned '%s'\n", buffer
); /* NT4 */
141 /* Test Getting / Setting the work directory */
142 strcpy(buffer
,"garbage");
143 r
= IShellLinkA_GetWorkingDirectory(sl
, buffer
, sizeof(buffer
));
144 ok(r
== S_OK
, "GetWorkingDirectory failed (0x%08x)\n", r
);
145 ok(*buffer
=='\0', "GetWorkingDirectory returned '%s'\n", buffer
);
147 str
="c:\\nonexistent\\directory";
148 r
= IShellLinkA_SetWorkingDirectory(sl
, str
);
149 ok(r
== S_OK
, "SetWorkingDirectory failed (0x%08x)\n", r
);
151 strcpy(buffer
,"garbage");
152 r
= IShellLinkA_GetWorkingDirectory(sl
, buffer
, sizeof(buffer
));
153 ok(r
== S_OK
, "GetWorkingDirectory failed (0x%08x)\n", r
);
154 ok(lstrcmpiA(buffer
,str
)==0, "GetWorkingDirectory returned '%s'\n", buffer
);
156 /* Test Getting / Setting the path */
157 strcpy(buffer
,"garbage");
158 r
= IShellLinkA_GetPath(sl
, buffer
, sizeof(buffer
), NULL
, SLGP_RAWPATH
);
159 todo_wine
ok(r
== S_FALSE
|| broken(r
== S_OK
) /* NT4/W2K */, "GetPath failed (0x%08x)\n", r
);
160 ok(*buffer
=='\0', "GetPath returned '%s'\n", buffer
);
162 CoCreateInstance(&CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
,
163 &IID_IShellLinkW
, (LPVOID
*)&slW
);
164 if (!slW
/* Win9x */ || !pGetLongPathNameA
/* NT4 */)
165 skip("SetPath with NULL parameter crashes on Win9x and some NT4\n");
168 IShellLinkW_Release(slW
);
169 r
= IShellLinkA_SetPath(sl
, NULL
);
170 ok(r
==E_INVALIDARG
||
171 broken(r
==S_OK
), /* Some Win95 and NT4 */
172 "SetPath returned wrong error (0x%08x)\n", r
);
175 r
= IShellLinkA_SetPath(sl
, "");
176 ok(r
==S_OK
, "SetPath failed (0x%08x)\n", r
);
178 strcpy(buffer
,"garbage");
179 r
= IShellLinkA_GetPath(sl
, buffer
, sizeof(buffer
), NULL
, SLGP_RAWPATH
);
180 todo_wine
ok(r
== S_FALSE
, "GetPath failed (0x%08x)\n", r
);
181 ok(*buffer
=='\0', "GetPath returned '%s'\n", buffer
);
183 /* Win98 returns S_FALSE, but WinXP returns S_OK */
184 str
="c:\\nonexistent\\file";
185 r
= IShellLinkA_SetPath(sl
, str
);
186 ok(r
==S_FALSE
|| r
==S_OK
, "SetPath failed (0x%08x)\n", r
);
188 strcpy(buffer
,"garbage");
189 r
= IShellLinkA_GetPath(sl
, buffer
, sizeof(buffer
), NULL
, SLGP_RAWPATH
);
190 ok(r
== S_OK
, "GetPath failed (0x%08x)\n", r
);
191 ok(lstrcmpiA(buffer
,str
)==0, "GetPath returned '%s'\n", buffer
);
193 /* Get some real path to play with */
194 GetWindowsDirectoryA( mypath
, sizeof(mypath
)-12 );
195 strcat(mypath
, "\\regedit.exe");
197 /* Test the interaction of SetPath and SetIDList */
199 r
= IShellLinkA_GetIDList(sl
, &tmp_pidl
);
200 ok(r
== S_OK
, "GetIDList failed (0x%08x)\n", r
);
205 strcpy(buffer
,"garbage");
206 ret
= SHGetPathFromIDListA(tmp_pidl
, buffer
);
207 ok(ret
, "SHGetPathFromIDListA failed\n");
209 ok(lstrcmpiA(buffer
,str
)==0, "GetIDList returned '%s'\n", buffer
);
213 pidl
=path_to_pidl(mypath
);
214 ok(pidl
!=NULL
, "path_to_pidl returned a NULL pidl\n");
218 LPITEMIDLIST second_pidl
;
220 r
= IShellLinkA_SetIDList(sl
, pidl
);
221 ok(r
== S_OK
, "SetIDList failed (0x%08x)\n", r
);
224 r
= IShellLinkA_GetIDList(sl
, &tmp_pidl
);
225 ok(r
== S_OK
, "GetIDList failed (0x%08x)\n", r
);
226 ok(tmp_pidl
&& pILIsEqual(pidl
, tmp_pidl
),
227 "GetIDList returned an incorrect pidl\n");
229 r
= IShellLinkA_GetIDList(sl
, &second_pidl
);
230 ok(r
== S_OK
, "GetIDList failed (0x%08x)\n", r
);
231 ok(second_pidl
&& pILIsEqual(pidl
, second_pidl
),
232 "GetIDList returned an incorrect pidl\n");
233 ok(second_pidl
!= tmp_pidl
, "pidls are the same\n");
235 pILFree(second_pidl
);
239 strcpy(buffer
,"garbage");
240 r
= IShellLinkA_GetPath(sl
, buffer
, sizeof(buffer
), NULL
, SLGP_RAWPATH
);
241 ok(r
== S_OK
, "GetPath failed (0x%08x)\n", r
);
243 ok(lstrcmpiA(buffer
, mypath
)==0, "GetPath returned '%s'\n", buffer
);
246 /* test path with quotes (IShellLinkA_SetPath returns S_FALSE on W2K and below and S_OK on XP and above */
247 r
= IShellLinkA_SetPath(sl
, "\"c:\\nonexistent\\file\"");
248 ok(r
==S_FALSE
|| r
== S_OK
, "SetPath failed (0x%08x)\n", r
);
250 strcpy(buffer
,"garbage");
251 r
= IShellLinkA_GetPath(sl
, buffer
, sizeof(buffer
), NULL
, SLGP_RAWPATH
);
252 ok(r
==S_OK
, "GetPath failed (0x%08x)\n", r
);
253 todo_wine
ok(!strcmp(buffer
, "C:\\nonexistent\\file") ||
254 broken(!strcmp(buffer
, "C:\\\"c:\\nonexistent\\file\"")), /* NT4 */
255 "case doesn't match\n");
257 r
= IShellLinkA_SetPath(sl
, "\"c:\\foo");
258 ok(r
==S_FALSE
|| r
== S_OK
|| r
== E_INVALIDARG
/* Vista */, "SetPath failed (0x%08x)\n", r
);
260 r
= IShellLinkA_SetPath(sl
, "\"\"c:\\foo");
261 ok(r
==S_FALSE
|| r
== S_OK
|| r
== E_INVALIDARG
/* Vista */, "SetPath failed (0x%08x)\n", r
);
263 r
= IShellLinkA_SetPath(sl
, "c:\\foo\"");
264 ok(r
==S_FALSE
|| r
== S_OK
|| r
== E_INVALIDARG
/* Vista */, "SetPath failed (0x%08x)\n", r
);
266 r
= IShellLinkA_SetPath(sl
, "\"\"c:\\foo\"");
267 ok(r
==S_FALSE
|| r
== S_OK
|| r
== E_INVALIDARG
/* Vista */, "SetPath failed (0x%08x)\n", r
);
269 r
= IShellLinkA_SetPath(sl
, "\"\"c:\\foo\"\"");
270 ok(r
==S_FALSE
|| r
== S_OK
|| r
== E_INVALIDARG
/* Vista */, "SetPath failed (0x%08x)\n", r
);
272 /* Test Getting / Setting the arguments */
273 strcpy(buffer
,"garbage");
274 r
= IShellLinkA_GetArguments(sl
, buffer
, sizeof(buffer
));
275 ok(r
== S_OK
, "GetArguments failed (0x%08x)\n", r
);
276 ok(*buffer
=='\0', "GetArguments returned '%s'\n", buffer
);
278 str
="param1 \"spaced param2\"";
279 r
= IShellLinkA_SetArguments(sl
, str
);
280 ok(r
== S_OK
, "SetArguments failed (0x%08x)\n", r
);
282 strcpy(buffer
,"garbage");
283 r
= IShellLinkA_GetArguments(sl
, buffer
, sizeof(buffer
));
284 ok(r
== S_OK
, "GetArguments failed (0x%08x)\n", r
);
285 ok(strcmp(buffer
,str
)==0, "GetArguments returned '%s'\n", buffer
);
287 strcpy(buffer
,"garbage");
288 r
= IShellLinkA_SetArguments(sl
, NULL
);
289 ok(r
== S_OK
, "SetArguments failed (0x%08x)\n", r
);
290 r
= IShellLinkA_GetArguments(sl
, buffer
, sizeof(buffer
));
291 ok(r
== S_OK
, "GetArguments failed (0x%08x)\n", r
);
292 ok(!buffer
[0] || strcmp(buffer
,str
)==0, "GetArguments returned '%s'\n", buffer
);
294 strcpy(buffer
,"garbage");
295 r
= IShellLinkA_SetArguments(sl
, "");
296 ok(r
== S_OK
, "SetArguments failed (0x%08x)\n", r
);
297 r
= IShellLinkA_GetArguments(sl
, buffer
, sizeof(buffer
));
298 ok(r
== S_OK
, "GetArguments failed (0x%08x)\n", r
);
299 ok(!buffer
[0], "GetArguments returned '%s'\n", buffer
);
301 /* Test Getting / Setting showcmd */
303 r
= IShellLinkA_GetShowCmd(sl
, &i
);
304 ok(r
== S_OK
, "GetShowCmd failed (0x%08x)\n", r
);
305 ok(i
==SW_SHOWNORMAL
, "GetShowCmd returned %d\n", i
);
307 r
= IShellLinkA_SetShowCmd(sl
, SW_SHOWMAXIMIZED
);
308 ok(r
== S_OK
, "SetShowCmd failed (0x%08x)\n", r
);
311 r
= IShellLinkA_GetShowCmd(sl
, &i
);
312 ok(r
== S_OK
, "GetShowCmd failed (0x%08x)\n", r
);
313 ok(i
==SW_SHOWMAXIMIZED
, "GetShowCmd returned %d'\n", i
);
315 /* Test Getting / Setting the icon */
317 strcpy(buffer
,"garbage");
318 r
= IShellLinkA_GetIconLocation(sl
, buffer
, sizeof(buffer
), &i
);
319 ok(r
== S_OK
, "GetIconLocation failed (0x%08x)\n", r
);
320 ok(*buffer
=='\0', "GetIconLocation returned '%s'\n", buffer
);
321 ok(i
==0, "GetIconLocation returned %d\n", i
);
323 str
="c:\\nonexistent\\file";
324 r
= IShellLinkA_SetIconLocation(sl
, str
, 0xbabecafe);
325 ok(r
== S_OK
, "SetIconLocation failed (0x%08x)\n", r
);
328 r
= IShellLinkA_GetIconLocation(sl
, buffer
, sizeof(buffer
), &i
);
329 ok(r
== S_OK
, "GetIconLocation failed (0x%08x)\n", r
);
330 ok(lstrcmpiA(buffer
,str
)==0, "GetIconLocation returned '%s'\n", buffer
);
331 ok(i
==0xbabecafe, "GetIconLocation returned %d'\n", i
);
333 /* Test Getting / Setting the hot key */
335 r
= IShellLinkA_GetHotkey(sl
, &w
);
336 ok(r
== S_OK
, "GetHotkey failed (0x%08x)\n", r
);
337 ok(w
==0, "GetHotkey returned %d\n", w
);
339 r
= IShellLinkA_SetHotkey(sl
, 0x5678);
340 ok(r
== S_OK
, "SetHotkey failed (0x%08x)\n", r
);
343 r
= IShellLinkA_GetHotkey(sl
, &w
);
344 ok(r
== S_OK
, "GetHotkey failed (0x%08x)\n", r
);
345 ok(w
==0x5678, "GetHotkey returned %d'\n", w
);
347 IShellLinkA_Release(sl
);
352 * Test saving and loading .lnk files
355 #define lok ok_(__FILE__, line)
356 #define check_lnk(a,b,c) check_lnk_(__LINE__, (a), (b), (c))
358 void create_lnk_(int line
, const WCHAR
* path
, lnk_desc_t
* desc
, int save_fails
)
364 r
= CoCreateInstance(&CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
,
365 &IID_IShellLinkA
, (LPVOID
*)&sl
);
366 lok(r
== S_OK
, "no IID_IShellLinkA (0x%08x)\n", r
);
370 if (desc
->description
)
372 r
= IShellLinkA_SetDescription(sl
, desc
->description
);
373 lok(r
== S_OK
, "SetDescription failed (0x%08x)\n", r
);
377 r
= IShellLinkA_SetWorkingDirectory(sl
, desc
->workdir
);
378 lok(r
== S_OK
, "SetWorkingDirectory failed (0x%08x)\n", r
);
382 r
= IShellLinkA_SetPath(sl
, desc
->path
);
383 lok(SUCCEEDED(r
), "SetPath failed (0x%08x)\n", r
);
387 r
= IShellLinkA_SetIDList(sl
, desc
->pidl
);
388 lok(r
== S_OK
, "SetIDList failed (0x%08x)\n", r
);
392 r
= IShellLinkA_SetArguments(sl
, desc
->arguments
);
393 lok(r
== S_OK
, "SetArguments failed (0x%08x)\n", r
);
397 r
= IShellLinkA_SetShowCmd(sl
, desc
->showcmd
);
398 lok(r
== S_OK
, "SetShowCmd failed (0x%08x)\n", r
);
402 r
= IShellLinkA_SetIconLocation(sl
, desc
->icon
, desc
->icon_id
);
403 lok(r
== S_OK
, "SetIconLocation failed (0x%08x)\n", r
);
407 r
= IShellLinkA_SetHotkey(sl
, desc
->hotkey
);
408 lok(r
== S_OK
, "SetHotkey failed (0x%08x)\n", r
);
411 r
= IShellLinkA_QueryInterface(sl
, &IID_IPersistFile
, (void**)&pf
);
412 lok(r
== S_OK
, "no IID_IPersistFile (0x%08x)\n", r
);
420 IPersistFile_GetCurFile(pf
, NULL
);
423 /* test GetCurFile before ::Save */
424 str
= (LPWSTR
)0xdeadbeef;
425 r
= IPersistFile_GetCurFile(pf
, &str
);
427 broken(r
== S_OK
), /* shell32 < 5.0 */
429 lok(str
== NULL
, "got %p\n", str
);
431 r
= IPersistFile_Save(pf
, path
, TRUE
);
432 todo_wine_if (save_fails
)
433 lok(r
== S_OK
, "save failed (0x%08x)\n", r
);
435 /* test GetCurFile after ::Save */
436 r
= IPersistFile_GetCurFile(pf
, &str
);
437 lok(r
== S_OK
, "got 0x%08x\n", r
);
439 broken(str
== NULL
), /* shell32 < 5.0 */
440 "Didn't expect NULL\n");
445 lok(!winetest_strcmpW(path
, str
), "Expected %s, got %s\n",
446 wine_dbgstr_w(path
), wine_dbgstr_w(str
));
448 SHGetMalloc(&pmalloc
);
449 IMalloc_Free(pmalloc
, str
);
452 win_skip("GetCurFile fails on shell32 < 5.0\n");
454 IPersistFile_Release(pf
);
457 IShellLinkA_Release(sl
);
460 static void check_lnk_(int line
, const WCHAR
* path
, lnk_desc_t
* desc
, int todo
)
465 char buffer
[INFOTIPSIZE
];
468 r
= CoCreateInstance(&CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
,
469 &IID_IShellLinkA
, (LPVOID
*)&sl
);
470 lok(r
== S_OK
, "no IID_IShellLinkA (0x%08x)\n", r
);
474 r
= IShellLinkA_QueryInterface(sl
, &IID_IPersistFile
, (LPVOID
*)&pf
);
475 lok(r
== S_OK
, "no IID_IPersistFile (0x%08x)\n", r
);
478 IShellLinkA_Release(sl
);
482 /* test GetCurFile before ::Load */
483 str
= (LPWSTR
)0xdeadbeef;
484 r
= IPersistFile_GetCurFile(pf
, &str
);
486 broken(r
== S_OK
), /* shell32 < 5.0 */
488 lok(str
== NULL
, "got %p\n", str
);
490 r
= IPersistFile_Load(pf
, path
, STGM_READ
);
491 lok(r
== S_OK
, "load failed (0x%08x)\n", r
);
493 /* test GetCurFile after ::Save */
494 r
= IPersistFile_GetCurFile(pf
, &str
);
495 lok(r
== S_OK
, "got 0x%08x\n", r
);
497 broken(str
== NULL
), /* shell32 < 5.0 */
498 "Didn't expect NULL\n");
503 lok(!winetest_strcmpW(path
, str
), "Expected %s, got %s\n",
504 wine_dbgstr_w(path
), wine_dbgstr_w(str
));
506 SHGetMalloc(&pmalloc
);
507 IMalloc_Free(pmalloc
, str
);
510 win_skip("GetCurFile fails on shell32 < 5.0\n");
512 IPersistFile_Release(pf
);
515 IShellLinkA_Release(sl
);
519 if (desc
->description
)
521 strcpy(buffer
,"garbage");
522 r
= IShellLinkA_GetDescription(sl
, buffer
, sizeof(buffer
));
523 lok(r
== S_OK
, "GetDescription failed (0x%08x)\n", r
);
524 todo_wine_if ((todo
& 0x1) != 0)
525 lok(strcmp(buffer
, desc
->description
)==0, "GetDescription returned '%s' instead of '%s'\n",
526 buffer
, desc
->description
);
530 strcpy(buffer
,"garbage");
531 r
= IShellLinkA_GetWorkingDirectory(sl
, buffer
, sizeof(buffer
));
532 lok(r
== S_OK
, "GetWorkingDirectory failed (0x%08x)\n", r
);
533 todo_wine_if ((todo
& 0x2) != 0)
534 lok(lstrcmpiA(buffer
, desc
->workdir
)==0, "GetWorkingDirectory returned '%s' instead of '%s'\n",
535 buffer
, desc
->workdir
);
539 strcpy(buffer
,"garbage");
540 r
= IShellLinkA_GetPath(sl
, buffer
, sizeof(buffer
), NULL
, SLGP_RAWPATH
);
541 lok(SUCCEEDED(r
), "GetPath failed (0x%08x)\n", r
);
542 todo_wine_if ((todo
& 0x4) != 0)
543 lok(lstrcmpiA(buffer
, desc
->path
)==0, "GetPath returned '%s' instead of '%s'\n",
548 LPITEMIDLIST pidl
=NULL
;
549 r
= IShellLinkA_GetIDList(sl
, &pidl
);
550 lok(r
== S_OK
, "GetIDList failed (0x%08x)\n", r
);
551 todo_wine_if ((todo
& 0x8) != 0)
552 lok(pILIsEqual(pidl
, desc
->pidl
), "GetIDList returned an incorrect pidl\n");
557 r
= IShellLinkA_GetShowCmd(sl
, &i
);
558 lok(r
== S_OK
, "GetShowCmd failed (0x%08x)\n", r
);
559 todo_wine_if ((todo
& 0x10) != 0)
560 lok(i
==desc
->showcmd
, "GetShowCmd returned 0x%0x instead of 0x%0x\n",
566 strcpy(buffer
,"garbage");
567 r
= IShellLinkA_GetIconLocation(sl
, buffer
, sizeof(buffer
), &i
);
568 lok(r
== S_OK
, "GetIconLocation failed (0x%08x)\n", r
);
569 todo_wine_if ((todo
& 0x20) != 0) {
570 lok(lstrcmpiA(buffer
, desc
->icon
)==0, "GetIconLocation returned '%s' instead of '%s'\n",
572 lok(i
==desc
->icon_id
, "GetIconLocation returned 0x%0x instead of 0x%0x\n",
579 r
= IShellLinkA_GetHotkey(sl
, &i
);
580 lok(r
== S_OK
, "GetHotkey failed (0x%08x)\n", r
);
581 todo_wine_if ((todo
& 0x40) != 0)
582 lok(i
==desc
->hotkey
, "GetHotkey returned 0x%04x instead of 0x%04x\n",
586 IShellLinkA_Release(sl
);
589 static void test_load_save(void)
591 WCHAR lnkfile
[MAX_PATH
];
592 char lnkfileA
[MAX_PATH
];
593 static const char lnkfileA_name
[] = "\\test.lnk";
596 char mypath
[MAX_PATH
];
597 char mydir
[MAX_PATH
];
598 char realpath
[MAX_PATH
];
603 if (!pGetLongPathNameA
)
605 win_skip("GetLongPathNameA is not available\n");
609 /* Don't used a fixed path for the test.lnk file */
610 GetTempPathA(MAX_PATH
, lnkfileA
);
611 lstrcatA(lnkfileA
, lnkfileA_name
);
612 MultiByteToWideChar(CP_ACP
, 0, lnkfileA
, -1, lnkfile
, MAX_PATH
);
614 /* Save an empty .lnk file */
615 memset(&desc
, 0, sizeof(desc
));
616 create_lnk(lnkfile
, &desc
, 0);
618 /* It should come back as a bunch of empty strings */
624 check_lnk(lnkfile
, &desc
, 0x0);
626 /* Point a .lnk file to nonexistent files */
628 desc
.workdir
="c:\\Nonexitent\\work\\directory";
629 desc
.path
="c:\\nonexistent\\path";
633 desc
.icon
="c:\\nonexistent\\icon\\file";
636 create_lnk(lnkfile
, &desc
, 0);
637 check_lnk(lnkfile
, &desc
, 0x0);
639 r
=GetModuleFileNameA(NULL
, mypath
, sizeof(mypath
));
640 ok(r
<sizeof(mypath
), "GetModuleFileName failed (%d)\n", r
);
641 strcpy(mydir
, mypath
);
642 p
=strrchr(mydir
, '\\');
646 /* IShellLink returns path in long form */
647 if (!pGetLongPathNameA(mypath
, realpath
, MAX_PATH
)) strcpy( realpath
, mypath
);
649 /* Overwrite the existing lnk file and point it to existing files */
650 desc
.description
="test 2";
654 desc
.arguments
="/option1 /option2 \"Some string\"";
655 desc
.showcmd
=SW_SHOWNORMAL
;
659 create_lnk(lnkfile
, &desc
, 0);
660 check_lnk(lnkfile
, &desc
, 0x0);
662 /* Test omitting .exe from an absolute path */
663 p
=strrchr(realpath
, '.');
667 desc
.description
="absolute path without .exe";
671 desc
.arguments
="/option1 /option2 \"Some string\"";
672 desc
.showcmd
=SW_SHOWNORMAL
;
676 create_lnk(lnkfile
, &desc
, 0);
677 strcat(realpath
, ".exe");
678 check_lnk(lnkfile
, &desc
, 0x4);
680 /* Overwrite the existing lnk file and test link to a command on the path */
681 desc
.description
="command on path";
683 desc
.path
="rundll32.exe";
685 desc
.arguments
="/option1 /option2 \"Some string\"";
686 desc
.showcmd
=SW_SHOWNORMAL
;
690 create_lnk(lnkfile
, &desc
, 0);
691 /* Check that link is created to proper location */
692 SearchPathA( NULL
, desc
.path
, NULL
, MAX_PATH
, realpath
, NULL
);
694 check_lnk(lnkfile
, &desc
, 0x0);
696 /* Test omitting .exe from a command on the path */
697 desc
.description
="command on path without .exe";
699 desc
.path
="rundll32";
701 desc
.arguments
="/option1 /option2 \"Some string\"";
702 desc
.showcmd
=SW_SHOWNORMAL
;
706 create_lnk(lnkfile
, &desc
, 0);
707 /* Check that link is created to proper location */
708 SearchPathA( NULL
, "rundll32", NULL
, MAX_PATH
, realpath
, NULL
);
710 check_lnk(lnkfile
, &desc
, 0x4);
712 /* Create a temporary non-executable file */
713 r
=GetTempPathA(sizeof(mypath
), mypath
);
714 ok(r
<sizeof(mypath
), "GetTempPath failed (%d), err %d\n", r
, GetLastError());
715 r
=pGetLongPathNameA(mypath
, mydir
, sizeof(mydir
));
716 ok(r
<sizeof(mydir
), "GetLongPathName failed (%d), err %d\n", r
, GetLastError());
717 p
=strrchr(mydir
, '\\');
721 strcpy(mypath
, mydir
);
722 strcat(mypath
, "\\test.txt");
723 hf
= CreateFileA(mypath
, GENERIC_WRITE
, 0, NULL
,
724 CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
727 /* Overwrite the existing lnk file and test link to an existing non-executable file */
728 desc
.description
="non-executable file";
733 desc
.showcmd
=SW_SHOWNORMAL
;
737 create_lnk(lnkfile
, &desc
, 0);
738 check_lnk(lnkfile
, &desc
, 0x0);
740 r
=pGetShortPathNameA(mydir
, mypath
, sizeof(mypath
));
741 ok(r
<sizeof(mypath
), "GetShortPathName failed (%d), err %d\n", r
, GetLastError());
743 strcpy(realpath
, mypath
);
744 strcat(realpath
, "\\test.txt");
745 strcat(mypath
, "\\\\test.txt");
747 /* Overwrite the existing lnk file and test link to a short path with double backslashes */
748 desc
.description
="non-executable file";
753 desc
.showcmd
=SW_SHOWNORMAL
;
757 create_lnk(lnkfile
, &desc
, 0);
759 check_lnk(lnkfile
, &desc
, 0x0);
761 r
= DeleteFileA(mypath
);
762 ok(r
, "failed to delete file %s (%d)\n", mypath
, GetLastError());
764 /* Create a temporary .bat file */
765 strcpy(mypath
, mydir
);
766 strcat(mypath
, "\\test.bat");
767 hf
= CreateFileA(mypath
, GENERIC_WRITE
, 0, NULL
,
768 CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
771 strcpy(realpath
, mypath
);
773 p
=strrchr(mypath
, '.');
777 /* Try linking to the .bat file without the extension */
778 desc
.description
="batch file";
783 desc
.showcmd
=SW_SHOWNORMAL
;
787 create_lnk(lnkfile
, &desc
, 0);
788 desc
.path
= realpath
;
789 check_lnk(lnkfile
, &desc
, 0x4);
791 r
= DeleteFileA(realpath
);
792 ok(r
, "failed to delete file %s (%d)\n", realpath
, GetLastError());
794 /* FIXME: Also test saving a .lnk pointing to a pidl that cannot be
795 * represented as a path.
798 /* DeleteFileW is not implemented on Win9x */
799 r
=DeleteFileA(lnkfileA
);
800 ok(r
, "failed to delete link '%s' (%d)\n", lnkfileA
, GetLastError());
803 static void test_datalink(void)
805 static const WCHAR lnk
[] = {
806 ':',':','{','9','d','b','1','1','8','6','e','-','4','0','d','f','-','1',
807 '1','d','1','-','a','a','8','c','-','0','0','c','0','4','f','b','6','7',
808 '8','6','3','}',':','2','6',',','!','!','g','x','s','f','(','N','g',']',
809 'q','F','`','H','{','L','s','A','C','C','E','S','S','F','i','l','e','s',
810 '>','p','l','T',']','j','I','{','j','f','(','=','1','&','L','[','-','8',
811 '1','-',']',':',':',0 };
812 static const WCHAR comp
[] = {
813 '2','6',',','!','!','g','x','s','f','(','N','g',']','q','F','`','H','{',
814 'L','s','A','C','C','E','S','S','F','i','l','e','s','>','p','l','T',']',
815 'j','I','{','j','f','(','=','1','&','L','[','-','8','1','-',']',0 };
816 IShellLinkDataList
*dl
= NULL
;
817 IShellLinkW
*sl
= NULL
;
820 EXP_DARWIN_LINK
*dar
;
822 r
= CoCreateInstance( &CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
,
823 &IID_IShellLinkW
, (LPVOID
*)&sl
);
825 broken(r
== E_NOINTERFACE
), /* Win9x */
826 "CoCreateInstance failed (0x%08x)\n", r
);
829 win_skip("no shelllink\n");
833 r
= IShellLinkW_QueryInterface( sl
, &_IID_IShellLinkDataList
, (LPVOID
*) &dl
);
835 broken(r
== E_NOINTERFACE
), /* NT4 */
836 "IShellLinkW_QueryInterface failed (0x%08x)\n", r
);
840 win_skip("no datalink interface\n");
841 IShellLinkW_Release( sl
);
846 r
= IShellLinkDataList_GetFlags( dl
, &flags
);
847 ok( r
== S_OK
, "GetFlags failed\n");
848 ok( flags
== 0, "GetFlags returned wrong flags\n");
851 r
= IShellLinkDataList_CopyDataBlock( dl
, EXP_DARWIN_ID_SIG
, (LPVOID
*) &dar
);
852 ok( r
== E_FAIL
, "CopyDataBlock failed\n");
853 ok( dar
== NULL
, "should be null\n");
855 if (!pGetLongPathNameA
/* NT4 */)
856 skip("SetPath with NULL parameter crashes on NT4\n");
859 r
= IShellLinkW_SetPath(sl
, NULL
);
860 ok(r
== E_INVALIDARG
, "SetPath returned wrong error (0x%08x)\n", r
);
863 r
= IShellLinkW_SetPath(sl
, lnk
);
864 ok(r
== S_OK
, "SetPath failed\n");
868 /* the following crashes */
869 IShellLinkDataList_GetFlags( dl
, NULL
);
873 r
= IShellLinkDataList_GetFlags( dl
, &flags
);
874 ok( r
== S_OK
, "GetFlags failed\n");
875 /* SLDF_HAS_LOGO3ID is no longer supported on Vista+, filter it out */
876 ok( (flags
& (~ SLDF_HAS_LOGO3ID
)) == SLDF_HAS_DARWINID
,
877 "GetFlags returned wrong flags\n");
880 r
= IShellLinkDataList_CopyDataBlock( dl
, EXP_DARWIN_ID_SIG
, (LPVOID
*) &dar
);
881 ok( r
== S_OK
, "CopyDataBlock failed\n");
883 ok( dar
&& ((DATABLOCK_HEADER
*)dar
)->dwSignature
== EXP_DARWIN_ID_SIG
, "signature wrong\n");
884 ok( dar
&& 0==lstrcmpW(dar
->szwDarwinID
, comp
), "signature wrong\n");
888 IShellLinkDataList_Release( dl
);
889 IShellLinkW_Release( sl
);
892 static void test_shdefextracticon(void)
894 HICON hiconlarge
=NULL
, hiconsmall
=NULL
;
897 if (!pSHDefExtractIconA
)
899 win_skip("SHDefExtractIconA is unavailable\n");
903 res
= pSHDefExtractIconA("shell32.dll", 0, 0, &hiconlarge
, &hiconsmall
, MAKELONG(16,24));
904 ok(SUCCEEDED(res
), "SHDefExtractIconA failed, res=%x\n", res
);
905 ok(hiconlarge
!= NULL
, "got null hiconlarge\n");
906 ok(hiconsmall
!= NULL
, "got null hiconsmall\n");
907 DestroyIcon(hiconlarge
);
908 DestroyIcon(hiconsmall
);
911 res
= pSHDefExtractIconA("shell32.dll", 0, 0, NULL
, &hiconsmall
, MAKELONG(16,24));
912 ok(SUCCEEDED(res
), "SHDefExtractIconA failed, res=%x\n", res
);
913 ok(hiconsmall
!= NULL
, "got null hiconsmall\n");
914 DestroyIcon(hiconsmall
);
916 res
= pSHDefExtractIconA("shell32.dll", 0, 0, NULL
, NULL
, MAKELONG(16,24));
917 ok(SUCCEEDED(res
), "SHDefExtractIconA failed, res=%x\n", res
);
920 static void test_GetIconLocation(void)
924 char buffer
[INFOTIPSIZE
], mypath
[MAX_PATH
];
929 r
= CoCreateInstance(&CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
,
930 &IID_IShellLinkA
, (LPVOID
*)&sl
);
931 ok(r
== S_OK
, "no IID_IShellLinkA (0x%08x)\n", r
);
936 strcpy(buffer
, "garbage");
937 r
= IShellLinkA_GetIconLocation(sl
, buffer
, sizeof(buffer
), &i
);
938 ok(r
== S_OK
, "GetIconLocation failed (0x%08x)\n", r
);
939 ok(*buffer
== '\0', "GetIconLocation returned '%s'\n", buffer
);
940 ok(i
== 0, "GetIconLocation returned %d\n", i
);
942 str
= "c:\\some\\path";
943 r
= IShellLinkA_SetPath(sl
, str
);
944 ok(r
== S_FALSE
|| r
== S_OK
, "SetPath failed (0x%08x)\n", r
);
947 strcpy(buffer
, "garbage");
948 r
= IShellLinkA_GetIconLocation(sl
, buffer
, sizeof(buffer
), &i
);
949 ok(r
== S_OK
, "GetIconLocation failed (0x%08x)\n", r
);
950 ok(*buffer
== '\0', "GetIconLocation returned '%s'\n", buffer
);
951 ok(i
== 0, "GetIconLocation returned %d\n", i
);
953 GetWindowsDirectoryA(mypath
, sizeof(mypath
) - 12);
954 strcat(mypath
, "\\regedit.exe");
955 pidl
= path_to_pidl(mypath
);
956 r
= IShellLinkA_SetIDList(sl
, pidl
);
957 ok(r
== S_OK
, "SetPath failed (0x%08x)\n", r
);
961 strcpy(buffer
, "garbage");
962 r
= IShellLinkA_GetIconLocation(sl
, buffer
, sizeof(buffer
), &i
);
963 ok(r
== S_OK
, "GetIconLocation failed (0x%08x)\n", r
);
964 ok(*buffer
== '\0', "GetIconLocation returned '%s'\n", buffer
);
965 ok(i
== 0, "GetIconLocation returned %d\n", i
);
967 str
= "c:\\nonexistent\\file";
968 r
= IShellLinkA_SetIconLocation(sl
, str
, 0xbabecafe);
969 ok(r
== S_OK
, "SetIconLocation failed (0x%08x)\n", r
);
972 r
= IShellLinkA_GetIconLocation(sl
, buffer
, sizeof(buffer
), &i
);
973 ok(r
== S_OK
, "GetIconLocation failed (0x%08x)\n", r
);
974 ok(lstrcmpiA(buffer
,str
) == 0, "GetIconLocation returned '%s'\n", buffer
);
975 ok(i
== 0xbabecafe, "GetIconLocation returned %d'\n", i
);
977 IShellLinkA_Release(sl
);
980 static void test_SHGetStockIconInfo(void)
982 BYTE buffer
[sizeof(SHSTOCKICONINFO
) + 16];
983 SHSTOCKICONINFO
*sii
= (SHSTOCKICONINFO
*) buffer
;
987 /* not present before vista */
988 if (!pSHGetStockIconInfo
)
990 win_skip("SHGetStockIconInfo not available\n");
994 /* negative values are handled */
995 memset(buffer
, '#', sizeof(buffer
));
996 sii
->cbSize
= sizeof(SHSTOCKICONINFO
);
997 hr
= pSHGetStockIconInfo(SIID_INVALID
, SHGSI_ICONLOCATION
, sii
);
998 ok(hr
== E_INVALIDARG
, "-1: got 0x%x (expected E_INVALIDARG)\n", hr
);
1000 /* max. id for vista is 140 (no definition exists for this value) */
1001 for (i
= SIID_DOCNOASSOC
; i
<= SIID_CLUSTEREDDRIVE
; i
++)
1003 memset(buffer
, '#', sizeof(buffer
));
1004 sii
->cbSize
= sizeof(SHSTOCKICONINFO
);
1005 hr
= pSHGetStockIconInfo(i
, SHGSI_ICONLOCATION
, sii
);
1008 "%3d: got 0x%x, iSysImageIndex: 0x%x, iIcon: 0x%x (expected S_OK)\n",
1009 i
, hr
, sii
->iSysImageIndex
, sii
->iIcon
);
1011 if ((hr
== S_OK
) && (winetest_debug
> 1))
1012 trace("%3d: got iSysImageIndex %3d, iIcon %3d and %s\n", i
, sii
->iSysImageIndex
,
1013 sii
->iIcon
, wine_dbgstr_w(sii
->szPath
));
1016 /* test invalid icons indices that are invalid for all platforms */
1017 for (i
= SIID_MAX_ICONS
; i
< (SIID_MAX_ICONS
+ 25) ; i
++)
1019 memset(buffer
, '#', sizeof(buffer
));
1020 sii
->cbSize
= sizeof(SHSTOCKICONINFO
);
1021 hr
= pSHGetStockIconInfo(i
, SHGSI_ICONLOCATION
, sii
);
1022 ok(hr
== E_INVALIDARG
, "%3d: got 0x%x (expected E_INVALIDARG)\n", i
, hr
);
1024 ok(sii
->iSysImageIndex
== -1, "%d: got iSysImageIndex %d\n", i
, sii
->iSysImageIndex
);
1025 ok(sii
->iIcon
== -1, "%d: got iIcon %d\n", i
, sii
->iIcon
);
1029 /* test more returned SHSTOCKICONINFO elements without extra flags */
1030 memset(buffer
, '#', sizeof(buffer
));
1031 sii
->cbSize
= sizeof(SHSTOCKICONINFO
);
1032 hr
= pSHGetStockIconInfo(SIID_FOLDER
, SHGSI_ICONLOCATION
, sii
);
1033 ok(hr
== S_OK
, "got 0x%x (expected S_OK)\n", hr
);
1034 ok(!sii
->hIcon
, "got %p (expected NULL)\n", sii
->hIcon
);
1035 ok(sii
->iSysImageIndex
== -1, "got %d (expected -1)\n", sii
->iSysImageIndex
);
1037 /* the exact size is required of the struct */
1038 memset(buffer
, '#', sizeof(buffer
));
1039 sii
->cbSize
= sizeof(SHSTOCKICONINFO
) + 2;
1040 hr
= pSHGetStockIconInfo(SIID_FOLDER
, SHGSI_ICONLOCATION
, sii
);
1041 ok(hr
== E_INVALIDARG
, "+2: got 0x%x, iSysImageIndex: 0x%x, iIcon: 0x%x\n", hr
, sii
->iSysImageIndex
, sii
->iIcon
);
1043 memset(buffer
, '#', sizeof(buffer
));
1044 sii
->cbSize
= sizeof(SHSTOCKICONINFO
) + 1;
1045 hr
= pSHGetStockIconInfo(SIID_FOLDER
, SHGSI_ICONLOCATION
, sii
);
1046 ok(hr
== E_INVALIDARG
, "+1: got 0x%x, iSysImageIndex: 0x%x, iIcon: 0x%x\n", hr
, sii
->iSysImageIndex
, sii
->iIcon
);
1048 memset(buffer
, '#', sizeof(buffer
));
1049 sii
->cbSize
= sizeof(SHSTOCKICONINFO
) - 1;
1050 hr
= pSHGetStockIconInfo(SIID_FOLDER
, SHGSI_ICONLOCATION
, sii
);
1051 ok(hr
== E_INVALIDARG
, "-1: got 0x%x, iSysImageIndex: 0x%x, iIcon: 0x%x\n", hr
, sii
->iSysImageIndex
, sii
->iIcon
);
1053 memset(buffer
, '#', sizeof(buffer
));
1054 sii
->cbSize
= sizeof(SHSTOCKICONINFO
) - 2;
1055 hr
= pSHGetStockIconInfo(SIID_FOLDER
, SHGSI_ICONLOCATION
, sii
);
1056 ok(hr
== E_INVALIDARG
, "-2: got 0x%x, iSysImageIndex: 0x%x, iIcon: 0x%x\n", hr
, sii
->iSysImageIndex
, sii
->iIcon
);
1058 /* there is a NULL check for the struct */
1059 hr
= pSHGetStockIconInfo(SIID_FOLDER
, SHGSI_ICONLOCATION
, NULL
);
1060 ok(hr
== E_INVALIDARG
, "NULL: got 0x%x\n", hr
);
1063 static void test_SHExtractIcons(void)
1065 static const WCHAR notepadW
[] = {'n','o','t','e','p','a','d','.','e','x','e',0};
1066 static const WCHAR shell32W
[] = {'s','h','e','l','l','3','2','.','d','l','l',0};
1067 static const WCHAR emptyW
[] = {0};
1072 if (!pSHExtractIconsW
)
1074 win_skip("SHExtractIconsW not available\n");
1078 ret
= pSHExtractIconsW(emptyW
, 0, 16, 16, icons
, ids
, 1, 0);
1079 ok(ret
== ~0u, "got %u\n", ret
);
1081 ret
= pSHExtractIconsW(notepadW
, 0, 16, 16, NULL
, NULL
, 1, 0);
1082 ok(ret
== 1 || broken(ret
== 2) /* win2k */, "got %u\n", ret
);
1084 icons
[0] = (HICON
)0xdeadbeef;
1085 ret
= pSHExtractIconsW(notepadW
, 0, 16, 16, icons
, NULL
, 1, 0);
1086 ok(ret
== 1, "got %u\n", ret
);
1087 ok(icons
[0] != (HICON
)0xdeadbeef, "icon not set\n");
1088 DestroyIcon(icons
[0]);
1090 icons
[0] = (HICON
)0xdeadbeef;
1091 ids
[0] = 0xdeadbeef;
1092 ret
= pSHExtractIconsW(notepadW
, 0, 16, 16, icons
, ids
, 1, 0);
1093 ok(ret
== 1, "got %u\n", ret
);
1094 ok(icons
[0] != (HICON
)0xdeadbeef, "icon not set\n");
1095 ok(ids
[0] != 0xdeadbeef, "id not set\n");
1096 DestroyIcon(icons
[0]);
1098 ret
= pSHExtractIconsW(shell32W
, 0, 16, 16, NULL
, NULL
, 0, 0);
1099 ret2
= pSHExtractIconsW(shell32W
, 4, MAKELONG(32,16), MAKELONG(32,16), NULL
, NULL
, 256, 0);
1100 ok(ret
&& ret
== ret2
,
1101 "icon count should be independent of requested icon sizes and base icon index\n");
1103 ret
= pSHExtractIconsW(shell32W
, 0, 16, 16, icons
, ids
, 0, 0);
1104 ok(ret
== ~0u || !ret
/* < vista */, "got %u\n", ret
);
1106 ret
= pSHExtractIconsW(shell32W
, 0, 16, 16, icons
, ids
, 3, 0);
1107 ok(ret
== 3, "got %u\n", ret
);
1108 for (i
= 0; i
< ret
; i
++) DestroyIcon(icons
[i
]);
1110 /* count must be a multiple of two when getting two sizes */
1111 ret
= pSHExtractIconsW(shell32W
, 0, MAKELONG(16,32), MAKELONG(16,32), icons
, ids
, 3, 0);
1112 ok(!ret
/* vista */ || ret
== 4, "got %u\n", ret
);
1113 for (i
= 0; i
< ret
; i
++) DestroyIcon(icons
[i
]);
1115 ret
= pSHExtractIconsW(shell32W
, 0, MAKELONG(16,32), MAKELONG(16,32), icons
, ids
, 4, 0);
1116 ok(ret
== 4, "got %u\n", ret
);
1117 for (i
= 0; i
< ret
; i
++) DestroyIcon(icons
[i
]);
1120 static void test_propertystore(void)
1127 hr
= CoCreateInstance(&CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
,
1128 &IID_IShellLinkA
, (void**)&linkA
);
1129 ok(hr
== S_OK
, "got 0x%08x\n", hr
);
1131 hr
= IShellLinkA_QueryInterface(linkA
, &IID_IShellLinkW
, (void**)&linkW
);
1132 ok(hr
== S_OK
, "got 0x%08x\n", hr
);
1134 hr
= IShellLinkA_QueryInterface(linkA
, &IID_IPropertyStore
, (void**)&ps
);
1136 IPropertyStoreCache
*pscache
;
1138 IPropertyStore_Release(ps
);
1140 hr
= IShellLinkW_QueryInterface(linkW
, &IID_IPropertyStore
, (void**)&ps
);
1141 ok(hr
== S_OK
, "got 0x%08x\n", hr
);
1143 hr
= IPropertyStore_QueryInterface(ps
, &IID_IPropertyStoreCache
, (void**)&pscache
);
1144 ok(hr
== E_NOINTERFACE
, "got 0x%08x\n", hr
);
1146 IPropertyStore_Release(ps
);
1149 win_skip("IShellLink doesn't support IPropertyStore.\n");
1151 IShellLinkA_Release(linkA
);
1152 IShellLinkW_Release(linkW
);
1155 static void test_ExtractIcon(void)
1157 static const WCHAR nameW
[] = {'\\','e','x','t','r','a','c','t','i','c','o','n','_','t','e','s','t','.','t','x','t',0};
1158 static const WCHAR shell32W
[] = {'s','h','e','l','l','3','2','.','d','l','l',0};
1159 WCHAR pathW
[MAX_PATH
];
1160 HICON hicon
, hicon2
;
1161 char path
[MAX_PATH
];
1167 /* specified instance handle */
1168 hicon
= ExtractIconA(GetModuleHandleA("shell32.dll"), NULL
, 0);
1170 ok(hicon
== NULL
, "Got icon %p\n", hicon
);
1171 hicon2
= ExtractIconA(GetModuleHandleA("shell32.dll"), "shell32.dll", -1);
1172 ok(hicon2
!= NULL
, "Got icon %p\n", hicon2
);
1174 /* existing index */
1175 hicon
= ExtractIconA(NULL
, "shell32.dll", 0);
1176 ok(hicon
!= NULL
&& HandleToLong(hicon
) != -1, "Got icon %p\n", hicon
);
1179 /* returns number of resources */
1180 hicon
= ExtractIconA(NULL
, "shell32.dll", -1);
1181 ok(HandleToLong(hicon
) > 1 && hicon
== hicon2
, "Got icon %p\n", hicon
);
1183 /* invalid index, valid dll name */
1184 hicon
= ExtractIconA(NULL
, "shell32.dll", 3000);
1185 ok(hicon
== NULL
, "Got icon %p\n", hicon
);
1187 /* Create a temporary non-executable file */
1188 GetTempPathA(sizeof(path
), path
);
1189 strcat(path
, "\\extracticon_test.txt");
1190 file
= CreateFileA(path
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
1191 ok(file
!= INVALID_HANDLE_VALUE
, "Failed to create a test file\n");
1194 hicon
= ExtractIconA(NULL
, path
, 0);
1196 ok(hicon
== NULL
, "Got icon %p\n", hicon
);
1198 hicon
= ExtractIconA(NULL
, path
, -1);
1199 ok(hicon
== NULL
, "Got icon %p\n", hicon
);
1201 hicon
= ExtractIconA(NULL
, path
, 1);
1203 ok(hicon
== NULL
, "Got icon %p\n", hicon
);
1205 r
= DeleteFileA(path
);
1206 ok(r
, "failed to delete file %s (%d)\n", path
, GetLastError());
1208 /* same for W variant */
1211 /* specified instance handle, crashes on XP, 2k3 */
1212 hicon
= ExtractIconW(GetModuleHandleA("shell32.dll"), NULL
, 0);
1213 ok(hicon
== NULL
, "Got icon %p\n", hicon
);
1215 hicon2
= ExtractIconW(GetModuleHandleA("shell32.dll"), shell32W
, -1);
1216 ok(hicon2
!= NULL
, "Got icon %p\n", hicon2
);
1218 /* existing index */
1219 hicon
= ExtractIconW(NULL
, shell32W
, 0);
1220 ok(hicon
!= NULL
&& HandleToLong(hicon
) != -1, "Got icon %p\n", hicon
);
1221 GetIconInfo(hicon
, &info
);
1222 GetObjectW(info
.hbmColor
, sizeof(bm
), &bm
);
1223 ok(bm
.bmWidth
== GetSystemMetrics(SM_CXICON
), "got %d\n", bm
.bmWidth
);
1224 ok(bm
.bmHeight
== GetSystemMetrics(SM_CYICON
), "got %d\n", bm
.bmHeight
);
1227 /* returns number of resources */
1228 hicon
= ExtractIconW(NULL
, shell32W
, -1);
1229 ok(HandleToLong(hicon
) > 1 && hicon
== hicon2
, "Got icon %p\n", hicon
);
1231 /* invalid index, valid dll name */
1232 hicon
= ExtractIconW(NULL
, shell32W
, 3000);
1233 ok(hicon
== NULL
, "Got icon %p\n", hicon
);
1235 /* Create a temporary non-executable file */
1236 GetTempPathW(sizeof(pathW
)/sizeof(pathW
[0]), pathW
);
1237 lstrcatW(pathW
, nameW
);
1238 file
= CreateFileW(pathW
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
1239 ok(file
!= INVALID_HANDLE_VALUE
, "Failed to create a test file\n");
1242 hicon
= ExtractIconW(NULL
, pathW
, 0);
1244 ok(hicon
== NULL
, "Got icon %p\n", hicon
);
1246 hicon
= ExtractIconW(NULL
, pathW
, -1);
1247 ok(hicon
== NULL
, "Got icon %p\n", hicon
);
1249 hicon
= ExtractIconW(NULL
, pathW
, 1);
1251 ok(hicon
== NULL
, "Got icon %p\n", hicon
);
1253 r
= DeleteFileW(pathW
);
1254 ok(r
, "failed to delete file %s (%d)\n", path
, GetLastError());
1257 static void test_ExtractAssociatedIcon(void)
1259 char pathA
[MAX_PATH
];
1266 hicon
= ExtractAssociatedIconA(NULL
, pathA
, &index
);
1268 ok(hicon
!= NULL
, "Got icon %p\n", hicon
);
1269 ok(!*pathA
, "Unexpected path %s\n", pathA
);
1270 ok(index
== 0, "Unexpected index %u\n", index
);
1276 strcpy(pathA
, "shell32.dll");
1277 hicon
= ExtractAssociatedIconA(NULL
, pathA
, &index
);
1278 ok(hicon
!= NULL
, "Got icon %p\n", hicon
);
1279 ok(!strcmp(pathA
, "shell32.dll"), "Unexpected path %s\n", pathA
);
1280 ok(index
== 0, "Unexpected index %u\n", index
);
1283 /* valid dll name, invalid index */
1285 strcpy(pathA
, "user32.dll");
1286 hicon
= ExtractAssociatedIconA(NULL
, pathA
, &index
);
1287 CharLowerBuffA(pathA
, strlen(pathA
));
1289 ok(hicon
!= NULL
, "Got icon %p\n", hicon
);
1290 ok(!!strstr(pathA
, "shell32.dll"), "Unexpected path %s\n", pathA
);
1292 ok(index
!= 5000, "Unexpected index %u\n", index
);
1295 /* associated icon */
1297 strcpy(pathA
, "dummy.exe");
1298 hicon
= ExtractAssociatedIconA(NULL
, pathA
, &index
);
1299 CharLowerBuffA(pathA
, strlen(pathA
));
1301 ok(hicon
!= NULL
, "Got icon %p\n", hicon
);
1302 ok(!!strstr(pathA
, "shell32.dll"), "Unexpected path %s\n", pathA
);
1304 ok(index
!= 0xcaca, "Unexpected index %u\n", index
);
1308 static int get_shell_icon_size(void)
1311 DWORD value
= 32, size
= sizeof(buf
), type
;
1314 if (!RegOpenKeyA( HKEY_CURRENT_USER
, "Control Panel\\Desktop\\WindowMetrics", &key
))
1316 if (!RegQueryValueExA( key
, "Shell Icon Size", NULL
, &type
, (BYTE
*)buf
, &size
) && type
== REG_SZ
)
1317 value
= atoi( buf
);
1323 static void test_SHGetImageList(void)
1326 IImageList
*list
, *list2
;
1329 ULONG start_refs
, refs
;
1330 int i
, width
, height
, expect
;
1331 BOOL dpi_aware
= pIsProcessDPIAware
&& pIsProcessDPIAware();
1333 hr
= SHGetImageList( SHIL_LARGE
, &IID_IImageList
, (void **)&list
);
1334 ok( hr
== S_OK
, "got %08x\n", hr
);
1335 start_refs
= IImageList_AddRef( list
);
1336 IImageList_Release( list
);
1338 hr
= SHGetImageList( SHIL_LARGE
, &IID_IImageList
, (void **)&list2
);
1339 ok( hr
== S_OK
, "got %08x\n", hr
);
1340 ok( list
== list2
, "lists differ\n" );
1341 refs
= IImageList_AddRef( list
);
1342 IImageList_Release( list
);
1343 ok( refs
== start_refs
+ 1, "got %d, start_refs %d\n", refs
, start_refs
);
1344 IImageList_Release( list2
);
1346 hr
= SHGetImageList( SHIL_SMALL
, &IID_IImageList
, (void **)&list2
);
1347 ok( hr
== S_OK
, "got %08x\n", hr
);
1349 ret
= Shell_GetImageLists( &lg
, &sm
);
1350 ok( ret
, "got %d\n", ret
);
1351 ok( lg
== (HIMAGELIST
)list
, "mismatch\n" );
1352 ok( sm
== (HIMAGELIST
)list2
, "mismatch\n" );
1354 /* Shell_GetImageLists doesn't take a reference */
1355 refs
= IImageList_AddRef( list
);
1356 IImageList_Release( list
);
1357 ok( refs
== start_refs
, "got %d, start_refs %d\n", refs
, start_refs
);
1359 IImageList_Release( list2
);
1360 IImageList_Release( list
);
1362 /* Test the icon sizes */
1363 for (i
= 0; i
<= SHIL_LAST
; i
++)
1365 hr
= SHGetImageList( i
, &IID_IImageList
, (void **)&list
);
1366 todo_wine_if(i
== SHIL_EXTRALARGE
|| i
== SHIL_JUMBO
)
1368 broken( i
== SHIL_JUMBO
&& hr
== E_INVALIDARG
), /* XP and 2003 */
1369 "%d: got %08x\n", i
, hr
);
1370 if (FAILED(hr
)) continue;
1371 IImageList_GetIconSize( list
, &width
, &height
);
1375 if (dpi_aware
) expect
= GetSystemMetrics( SM_CXICON
);
1376 else expect
= get_shell_icon_size();
1379 if (dpi_aware
) expect
= GetSystemMetrics( SM_CXICON
) / 2;
1380 else expect
= GetSystemMetrics( SM_CXSMICON
);
1382 case SHIL_EXTRALARGE
:
1383 expect
= (GetSystemMetrics( SM_CXICON
) * 3) / 2;
1386 expect
= GetSystemMetrics( SM_CXSMICON
);
1392 todo_wine_if(i
== SHIL_SYSSMALL
&& dpi_aware
&& expect
!= GetSystemMetrics( SM_CXICON
) / 2)
1394 ok( width
== expect
, "%d: got %d expect %d\n", i
, width
, expect
);
1395 ok( height
== expect
, "%d: got %d expect %d\n", i
, height
, expect
);
1397 IImageList_Release( list
);
1401 START_TEST(shelllink
)
1404 HMODULE hmod
= GetModuleHandleA("shell32.dll");
1405 HMODULE hkernel32
= GetModuleHandleA("kernel32.dll");
1406 HMODULE huser32
= GetModuleHandleA("user32.dll");
1408 pILFree
= (void *)GetProcAddress(hmod
, (LPSTR
)155);
1409 pILIsEqual
= (void *)GetProcAddress(hmod
, (LPSTR
)21);
1410 pSHILCreateFromPath
= (void *)GetProcAddress(hmod
, (LPSTR
)28);
1411 pSHDefExtractIconA
= (void *)GetProcAddress(hmod
, "SHDefExtractIconA");
1412 pSHGetStockIconInfo
= (void *)GetProcAddress(hmod
, "SHGetStockIconInfo");
1413 pGetLongPathNameA
= (void *)GetProcAddress(hkernel32
, "GetLongPathNameA");
1414 pGetShortPathNameA
= (void *)GetProcAddress(hkernel32
, "GetShortPathNameA");
1415 pSHExtractIconsW
= (void *)GetProcAddress(hmod
, "SHExtractIconsW");
1416 pIsProcessDPIAware
= (void *)GetProcAddress(huser32
, "IsProcessDPIAware");
1418 r
= CoInitialize(NULL
);
1419 ok(r
== S_OK
, "CoInitialize failed (0x%08x)\n", r
);
1426 test_shdefextracticon();
1427 test_GetIconLocation();
1428 test_SHGetStockIconInfo();
1429 test_SHExtractIcons();
1430 test_propertystore();
1432 test_ExtractAssociatedIcon();
1433 test_SHGetImageList();