2 * PROJECT: ReactOS api tests
3 * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory
4 * PURPOSE: Test for CShellLink
5 * PROGRAMMER: Andreas Maier
13 #include <shellutils.h>
15 /* Test IShellLink::SetPath with environment-variables, existing, non-existing, ...*/
21 /* Test 1 - hrGetPathX = IShellLink::GetPath(pathOutX, ... , flagsX); */
32 } TEST_SHELL_LINK_DEF
;
34 static TEST_SHELL_LINK_DEF linkTestList
[] =
38 L
"%comspec%", SLGP_SHORTPATH
, S_OK
, TRUE
,
39 L
"%comspec%", SLGP_RAWPATH
, S_OK
, FALSE
42 L
"%anyvar%", E_INVALIDARG
,
43 L
"", SLGP_SHORTPATH
, S_FALSE
, FALSE
,
44 L
"", SLGP_RAWPATH
, S_FALSE
, FALSE
47 L
"%anyvar%%comspec%", S_OK
,
48 L
"c:\\%anyvar%%comspec%", SLGP_SHORTPATH
, S_OK
, TRUE
,
49 L
"%anyvar%%comspec%", SLGP_RAWPATH
, S_OK
, FALSE
53 L
"%temp%", SLGP_SHORTPATH
, S_OK
, TRUE
,
54 L
"%temp%", SLGP_RAWPATH
, S_OK
, FALSE
58 L
"%systemroot%\\system32\\%shell%", SLGP_SHORTPATH
, S_OK
, TRUE
,
59 L
"%shell%", SLGP_RAWPATH
, S_OK
, FALSE
62 L
"u:\\anypath\\%anyvar%", S_OK
,
63 L
"u:\\anypath\\%anyvar%", SLGP_SHORTPATH
, S_OK
, TRUE
,
64 L
"u:\\anypath\\%anyvar%", SLGP_RAWPATH
, S_OK
, FALSE
68 L
"c:\\temp", SLGP_SHORTPATH
, S_OK
, FALSE
,
69 L
"c:\\temp", SLGP_RAWPATH
, S_OK
, FALSE
73 L
"%comspec%", SLGP_SHORTPATH
, S_OK
, TRUE
,
74 L
"%comspec%", SLGP_RAWPATH
, S_OK
, TRUE
77 L
"%systemroot%\\non-existent-file", S_OK
,
78 L
"%systemroot%\\non-existent-file", SLGP_SHORTPATH
, S_OK
, TRUE
,
79 L
"%systemroot%\\non-existent-file", SLGP_RAWPATH
, S_OK
, FALSE
82 L
"c:\\non-existent-path\\non-existent-file", S_OK
,
83 L
"c:\\non-existent-path\\non-existent-file", SLGP_SHORTPATH
, S_OK
, FALSE
,
84 L
"c:\\non-existent-path\\non-existent-file", SLGP_RAWPATH
, S_OK
, FALSE
87 L
"non-existent-file", E_INVALIDARG
,
88 L
"", SLGP_SHORTPATH
, S_FALSE
, FALSE
,
89 L
"", SLGP_RAWPATH
, S_FALSE
, FALSE
95 test_checklinkpath(UINT i
, TEST_SHELL_LINK_DEF
* testDef
)
97 static WCHAR evVar
[MAX_PATH
];
99 HRESULT hr
, expectedHr
;
100 WCHAR wPathOut
[MAX_PATH
];
102 PCWSTR expectedPathOut
;
103 CComPtr
<IShellLinkW
> psl
;
107 hr
= CoCreateInstance(CLSID_ShellLink
,
109 CLSCTX_INPROC_SERVER
,
110 IID_PPV_ARG(IShellLinkW
, &psl
));
111 ok(hr
== S_OK
, "CoCreateInstance, hr = 0x%lx\n", hr
);
114 skip("Could not instantiate CShellLink\n");
118 hr
= psl
->SetPath(testDef
->pathIn
);
119 ok(hr
== testDef
->hrSetPath
, "IShellLink::SetPath(%d), got hr = 0x%lx, expected 0x%lx\n", i
, hr
, testDef
->hrSetPath
);
121 expectedPathOut
= NULL
;
122 for (i1
= 0; i1
<= 1; i1
++)
124 if (i1
== 0) /* Usually SLGP_SHORTPATH */
126 flags
= testDef
->flags1
;
127 expandPathOut
= testDef
->expandPathOut1
;
128 expectedPathOut
= testDef
->pathOut1
;
129 expectedHr
= testDef
->hrGetPath1
;
131 else // if (i1 == 1) /* Usually SLGP_RAWPATH */
133 flags
= testDef
->flags2
;
134 expandPathOut
= testDef
->expandPathOut2
;
135 expectedPathOut
= testDef
->pathOut2
;
136 expectedHr
= testDef
->hrGetPath2
;
139 /* Patch some variables */
142 ExpandEnvironmentStringsW(expectedPathOut
, evVar
, _countof(evVar
));
143 DPRINT("** %S **\n",evVar
);
144 expectedPathOut
= evVar
;
147 hr
= psl
->GetPath(wPathOut
, _countof(wPathOut
), NULL
, flags
);
149 "IShellLink::GetPath(%d), flags 0x%lx, got hr = 0x%lx, expected 0x%lx\n",
150 i
, flags
, hr
, expectedHr
);
151 ok(wcsicmp(wPathOut
, expectedPathOut
) == 0,
152 "IShellLink::GetPath(%d), flags 0x%lx, in %S, got %S, expected %S\n",
153 i
, flags
, testDef
->pathIn
, wPathOut
, expectedPathOut
);
163 /* Needed for test */
164 SetEnvironmentVariableW(L
"shell", L
"cmd.exe");
166 for (i
= 0; i
< _countof(linkTestList
); ++i
)
168 DPRINT("IShellLink-Test(%d): %S\n", i
, linkTestList
[i
].pathIn
);
169 test_checklinkpath(i
, &linkTestList
[i
]);
172 SetEnvironmentVariableW(L
"shell",NULL
);
177 TestDescription(void)
180 CComPtr
<IShellLinkW
> psl
;
182 PCWSTR testDescription
= L
"This is a test description";
184 /* Test SetDescription */
185 hr
= CoCreateInstance(CLSID_ShellLink
,
187 CLSCTX_INPROC_SERVER
,
188 IID_PPV_ARG(IShellLinkW
, &psl
));
189 ok(hr
== S_OK
, "CoCreateInstance, hr = 0x%lx\n", hr
);
192 skip("Could not instantiate CShellLink\n");
196 memset(buffer
, 0x55, sizeof(buffer
));
197 hr
= psl
->GetDescription(buffer
, RTL_NUMBER_OF(buffer
));
198 ok(hr
== S_OK
, "IShellLink::GetDescription returned hr = 0x%lx\n", hr
);
199 ok(buffer
[0] == 0, "buffer[0] = %x\n", buffer
[0]);
200 ok(buffer
[1] == 0x5555, "buffer[1] = %x\n", buffer
[1]);
202 hr
= psl
->SetDescription(testDescription
);
203 ok(hr
== S_OK
, "IShellLink::SetDescription returned hr = 0x%lx\n", hr
);
205 memset(buffer
, 0x55, sizeof(buffer
));
206 hr
= psl
->GetDescription(buffer
, RTL_NUMBER_OF(buffer
));
207 ok(hr
== S_OK
, "IShellLink::GetDescription returned hr = 0x%lx\n", hr
);
208 ok(buffer
[wcslen(testDescription
)] == 0, "buffer[n] = %x\n", buffer
[wcslen(testDescription
)]);
209 ok(buffer
[wcslen(testDescription
) + 1] == 0x5555, "buffer[n+1] = %x\n", buffer
[wcslen(testDescription
) + 1]);
210 ok(!wcscmp(buffer
, testDescription
), "buffer = '%ls'\n", buffer
);
212 hr
= psl
->SetDescription(NULL
);
213 ok(hr
== S_OK
, "IShellLink::SetDescription returned hr = 0x%lx\n", hr
);
215 memset(buffer
, 0x55, sizeof(buffer
));
216 hr
= psl
->GetDescription(buffer
, RTL_NUMBER_OF(buffer
));
217 ok(hr
== S_OK
, "IShellLink::GetDescription returned hr = 0x%lx\n", hr
);
218 ok(buffer
[0] == 0, "buffer[0] = %x\n", buffer
[0]);
219 ok(buffer
[1] == 0x5555, "buffer[1] = %x\n", buffer
[1]);
223 /* Test IShellLink::Get/SetIconLocation and IExtractIcon::GetIconLocation */
228 /* Expected results */
229 HRESULT hrDefIcon
; // Return value for GIL_DEFAULTICON
230 HRESULT hrForShrt
; // Return value for GIL_FORSHORTCUT
231 /* Return values for GIL_FORSHELL */
237 static TEST_SHELL_ICON ShIconTests
[] =
239 /* Executable with icons */
240 {L
"%SystemRoot%\\system32\\cmd.exe", S_FALSE
, E_INVALIDARG
,
241 S_OK
, L
"%SystemRoot%\\system32\\cmd.exe", GIL_NOTFILENAME
| GIL_PERINSTANCE
},
243 /* Executable without icon */
244 {L
"%SystemRoot%\\system32\\autochk.exe", S_FALSE
, E_INVALIDARG
,
245 S_OK
, L
"%SystemRoot%\\system32\\autochk.exe", GIL_NOTFILENAME
| GIL_PERINSTANCE
},
248 {L
"%SystemRoot%\\system32\\shell32.dll", S_FALSE
, E_INVALIDARG
,
249 S_OK
, L
"*", GIL_NOTFILENAME
| GIL_PERCLASS
},
251 /* Non-existing files */
252 {L
"%SystemRoot%\\non-existent-file.sdf", S_FALSE
, E_INVALIDARG
,
253 S_OK
, L
"*", GIL_NOTFILENAME
| GIL_PERCLASS
},
254 {L
"c:\\non-existent-path\\non-existent-file.sdf", S_FALSE
, E_INVALIDARG
,
255 S_OK
, L
"*", GIL_NOTFILENAME
| GIL_PERCLASS
},
260 test_iconlocation(UINT i
, TEST_SHELL_ICON
* testDef
)
263 CComPtr
<IShellLinkW
> psl
;
264 CComPtr
<IExtractIconW
> pei
;
267 PCWSTR pszExplorer
= L
"%SystemRoot%\\explorer.exe";
268 WCHAR szPath
[MAX_PATH
];
269 WCHAR szPath2
[MAX_PATH
];
271 hr
= CoCreateInstance(CLSID_ShellLink
,
273 CLSCTX_INPROC_SERVER
,
274 IID_PPV_ARG(IShellLinkW
, &psl
));
275 ok(hr
== S_OK
, "CoCreateInstance, hr = 0x%lx\n", hr
);
278 skip("Could not instantiate CShellLink\n");
282 /* Set the path to a file */
283 ExpandEnvironmentStringsW(testDef
->FilePath
, szPath
, _countof(szPath
));
284 hr
= psl
->SetPath(szPath
);
285 ok(hr
== S_OK
, "IShellLink::SetPath failed, hr = 0x%lx\n", hr
);
288 * This test shows that this does not imply that the icon is automatically
289 * set and be retrieved naively by a call to IShellLink::GetIconLocation.
292 wcscpy(szPath
, L
"garbage");
293 hr
= psl
->GetIconLocation(szPath
, _countof(szPath
), &iIcon
);
294 ok(hr
== S_OK
, "IShellLink::GetIconLocation(%d) failed, hr = 0x%lx\n", i
, hr
);
295 ok(*szPath
== L
'\0', "IShellLink::GetIconLocation(%d) returned '%S'\n", i
, szPath
);
296 ok(iIcon
== 0, "IShellLink::GetIconLocation(%d) returned %d, expected %d\n", i
, iIcon
, 0);
298 /* Try to grab the IExtractIconW interface */
299 hr
= psl
->QueryInterface(IID_PPV_ARG(IExtractIconW
, &pei
));
300 ok(hr
== S_OK
, "IShellLink::QueryInterface(IExtractIconW)(%d) failed, hr = 0x%lx\n", i
, hr
);
303 win_skip("No IExtractIconW interface\n");
307 iIcon
= wFlags
= 0xdeadbeef;
308 wcscpy(szPath
, L
"garbage");
309 hr
= pei
->GetIconLocation(GIL_DEFAULTICON
, szPath
, _countof(szPath
), &iIcon
, &wFlags
);
310 ok(hr
== testDef
->hrDefIcon
, "IExtractIcon::GetIconLocation(%d) returned hr = 0x%lx, expected 0x%lx\n", i
, hr
, testDef
->hrDefIcon
);
311 ok(*szPath
== L
'\0', "IExtractIcon::GetIconLocation(%d) returned '%S'\n", i
, szPath
);
312 // ok(iIcon == 0, "IExtractIcon::GetIconLocation(%d) returned %d\n", i, iIcon);
314 iIcon
= wFlags
= 0xdeadbeef;
315 wcscpy(szPath
, L
"garbage");
316 hr
= pei
->GetIconLocation(GIL_FORSHORTCUT
, szPath
, _countof(szPath
), &iIcon
, &wFlags
);
317 ok(hr
== testDef
->hrForShrt
, "IExtractIcon::GetIconLocation(%d) returned hr = 0x%lx, expected 0x%lx\n", i
, hr
, testDef
->hrForShrt
);
318 // Here, both szPath and iIcon are untouched...
320 iIcon
= wFlags
= 0xdeadbeef;
321 wcscpy(szPath
, L
"garbage");
322 hr
= pei
->GetIconLocation(GIL_FORSHELL
, szPath
, _countof(szPath
), &iIcon
, &wFlags
);
323 ok(hr
== testDef
->hrForShell
, "IExtractIcon::GetIconLocation(%d) returned hr = 0x%lx, expected 0x%lx\n", i
, hr
, testDef
->hrForShell
);
324 ok(wFlags
== testDef
->Flags
, "IExtractIcon::GetIconLocation(%d) returned wFlags = 0x%x, expected 0x%x\n", i
, wFlags
, testDef
->Flags
);
326 * Actually, even if wFlags specifies GIL_NOTFILENAME, a correct file name is returned
327 * for executables only (at least...), otherwise we can get an asterix '*'.
329 ExpandEnvironmentStringsW(testDef
->IconPath
, szPath2
, _countof(szPath2
));
330 ok(_wcsicmp(szPath2
, szPath
) == 0, "IExtractIcon::GetIconLocation(%d) returned '%S', expected '%S'\n", i
, szPath
, szPath2
);
332 // ok(*szPath == L'\0', "IExtractIcon::GetIconLocation returned '%S'\n", szPath);
333 // ok(iIcon == 0, "IExtractIcon::GetIconLocation returned %d\n", iIcon);
334 // ok(FALSE, "hr = 0x%lx, szPath = '%S', iIcon = %d, wFlags = %d\n", hr, szPath, iIcon, wFlags);
338 * Now we test what happens when we explicitly set an icon to the shortcut.
339 * Note that actually, SetIconLocation() does not verify whether the file
342 hr
= psl
->SetIconLocation(pszExplorer
, 1);
343 ok(hr
== S_OK
, "IShellLink::SetIconLocation(%d) failed, hr = 0x%lx\n", i
, hr
);
346 * First, we call IShellLink::GetIconLocation. We retrieve
347 * exactly what we specified with SetIconLocation.
350 wcscpy(szPath
, L
"garbage");
351 hr
= psl
->GetIconLocation(szPath
, _countof(szPath
), &iIcon
);
352 ok(hr
== S_OK
, "IShellLink::GetIconLocation(%d) failed, hr = 0x%lx\n", i
, hr
);
353 ok(wcscmp(szPath
, pszExplorer
) == 0, "IShellLink::GetIconLocation(%d) returned '%S', expected '%S'\n", i
, szPath
, pszExplorer
);
354 ok(iIcon
== 1, "IShellLink::GetIconLocation(%d) returned %d, expected %d\n", i
, iIcon
, 1);
357 * Now we test what happens with IExtractIcon::GetIconLocation.
358 * We see that it retrieves the icon of the shortcut's underlying file.
360 iIcon
= wFlags
= 0xdeadbeef;
361 wcscpy(szPath
, L
"garbage");
362 hr
= pei
->GetIconLocation(GIL_DEFAULTICON
, szPath
, _countof(szPath
), &iIcon
, &wFlags
);
363 ok(hr
== testDef
->hrDefIcon
, "IExtractIcon::GetIconLocation(%d) returned hr = 0x%lx, expected 0x%lx\n", i
, hr
, testDef
->hrDefIcon
);
364 ok(*szPath
== L
'\0', "IExtractIcon::GetIconLocation(%d) returned '%S'\n", i
, szPath
);
365 // ok(iIcon == 0, "IExtractIcon::GetIconLocation(%d) returned %d\n", i, iIcon);
367 iIcon
= wFlags
= 0xdeadbeef;
368 wcscpy(szPath
, L
"garbage");
369 hr
= pei
->GetIconLocation(GIL_FORSHORTCUT
, szPath
, _countof(szPath
), &iIcon
, &wFlags
);
370 ok(hr
== testDef
->hrForShrt
, "IExtractIcon::GetIconLocation(%d) returned hr = 0x%lx, expected 0x%lx\n", i
, hr
, testDef
->hrForShrt
);
371 // Here, both szPath and iIcon are untouched...
373 iIcon
= wFlags
= 0xdeadbeef;
374 wcscpy(szPath
, L
"garbage");
375 hr
= pei
->GetIconLocation(GIL_FORSHELL
, szPath
, _countof(szPath
), &iIcon
, &wFlags
);
376 ok(hr
== testDef
->hrForShell
, "IExtractIcon::GetIconLocation(%d) returned hr = 0x%lx, expected 0x%lx\n", i
, hr
, testDef
->hrForShell
);
377 ok(wFlags
== testDef
->Flags
, "IExtractIcon::GetIconLocation(%d) returned wFlags = 0x%x, expected 0x%x\n", i
, wFlags
, testDef
->Flags
);
379 * Actually, even if wFlags specifies GIL_NOTFILENAME, a correct file name is returned
380 * for executables only (at least...), otherwise we can get an asterix '*'.
382 ExpandEnvironmentStringsW(testDef
->IconPath
, szPath2
, _countof(szPath2
));
383 ok(_wcsicmp(szPath2
, szPath
) == 0, "IExtractIcon::GetIconLocation(%d) returned '%S', expected '%S'\n", i
, szPath
, szPath2
);
385 // ok(*szPath == L'\0', "IExtractIcon::GetIconLocation returned '%S'\n", szPath);
386 // ok(iIcon == 0, "IExtractIcon::GetIconLocation returned %d\n", iIcon);
387 // ok(FALSE, "hr = 0x%lx, szPath = '%S', iIcon = %d, wFlags = %d\n", hr, szPath, iIcon, wFlags);
392 TestIconLocation(void)
396 for (i
= 0; i
< _countof(ShIconTests
); ++i
)
398 test_iconlocation(i
, &ShIconTests
[i
]);
403 START_TEST(CShellLink
)
405 CoInitializeEx(NULL
, COINIT_APARTMENTTHREADED
);