Stub implementation for MsiGetFileHashA/W.
[wine] / dlls / shell32 / tests / shelllink.c
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  * This is a test program for the SHGet{Special}Folder{Path|Location} functions
20  * of shell32, that get either a filesytem path or a LPITEMIDLIST (shell
21  * namespace) path for a given folder (CSIDL value).
22  *
23  */
24
25 #define COBJMACROS
26
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include "windef.h"
30 #include "winbase.h"
31 #include "shlguid.h"
32 #include "shobjidl.h"
33 #include "shlobj.h"
34 #include "wine/test.h"
35
36 #include "shell32_test.h"
37
38 static const WCHAR lnkfile[]= { 'C',':','\\','t','e','s','t','.','l','n','k',0 };
39 static const WCHAR notafile[]= { 'C',':','\\','n','o','n','e','x','i','s','t','e','n','t','\\','f','i','l','e',0 };
40
41
42 /* For some reason SHILCreateFromPath does not work on Win98 and
43  * SHSimpleIDListFromPathA does not work on NT4. But if we call both we
44  * get what we want on all platforms.
45  */
46 static LPITEMIDLIST (WINAPI *pSHSimpleIDListFromPathA)(LPCSTR)=NULL;
47
48 static LPITEMIDLIST path_to_pidl(const char* path)
49 {
50     LPITEMIDLIST pidl;
51
52     if (!pSHSimpleIDListFromPathA)
53     {
54         HMODULE hdll=LoadLibraryA("shell32.dll");
55         pSHSimpleIDListFromPathA=(void*)GetProcAddress(hdll, (char*)162);
56         if (!pSHSimpleIDListFromPathA)
57             trace("SHSimpleIDListFromPathA not found in shell32.dll\n");
58     }
59
60     pidl=NULL;
61     if (pSHSimpleIDListFromPathA)
62         pidl=pSHSimpleIDListFromPathA(path);
63
64     if (!pidl)
65     {
66         WCHAR* pathW;
67         HRESULT r;
68         int len;
69
70         len=MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
71         pathW=HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
72         MultiByteToWideChar(CP_ACP, 0, path, -1, pathW, len);
73
74         r=SHILCreateFromPath(pathW, &pidl, NULL);
75         todo_wine {
76         ok(SUCCEEDED(r), "SHILCreateFromPath failed (0x%08lx)\n", r);
77         }
78         HeapFree(GetProcessHeap(), 0, pathW);
79     }
80     return pidl;
81 }
82
83
84 /*
85  * Test manipulation of an IShellLink's properties.
86  */
87
88 static void test_get_set(void)
89 {
90     HRESULT r;
91     IShellLinkA *sl;
92     char mypath[MAX_PATH];
93     char buffer[INFOTIPSIZE];
94     LPITEMIDLIST pidl, tmp_pidl;
95     const char * str;
96     int i;
97     WORD w;
98
99     r = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
100                          &IID_IShellLinkA, (LPVOID*)&sl);
101     ok(SUCCEEDED(r), "no IID_IShellLinkA (0x%08lx)\n", r);
102     if (!SUCCEEDED(r))
103         return;
104
105     /* Test Getting / Setting the description */
106     strcpy(buffer,"garbage");
107     r = IShellLinkA_GetDescription(sl, buffer, sizeof(buffer));
108     ok(SUCCEEDED(r), "GetDescription failed (0x%08lx)\n", r);
109     ok(*buffer=='\0', "GetDescription returned '%s'\n", buffer);
110
111     str="Some description";
112     r = IShellLinkA_SetDescription(sl, str);
113     ok(SUCCEEDED(r), "SetDescription failed (0x%08lx)\n", r);
114
115     strcpy(buffer,"garbage");
116     r = IShellLinkA_GetDescription(sl, buffer, sizeof(buffer));
117     ok(SUCCEEDED(r), "GetDescription failed (0x%08lx)\n", r);
118     ok(lstrcmp(buffer,str)==0, "GetDescription returned '%s'\n", buffer);
119
120     /* Test Getting / Setting the work directory */
121     strcpy(buffer,"garbage");
122     r = IShellLinkA_GetWorkingDirectory(sl, buffer, sizeof(buffer));
123     ok(SUCCEEDED(r), "GetWorkingDirectory failed (0x%08lx)\n", r);
124     ok(*buffer=='\0', "GetWorkingDirectory returned '%s'\n", buffer);
125
126     str="c:\\nonexistent\\directory";
127     r = IShellLinkA_SetWorkingDirectory(sl, str);
128     ok(SUCCEEDED(r), "SetWorkingDirectory failed (0x%08lx)\n", r);
129
130     strcpy(buffer,"garbage");
131     r = IShellLinkA_GetWorkingDirectory(sl, buffer, sizeof(buffer));
132     ok(SUCCEEDED(r), "GetWorkingDirectory failed (0x%08lx)\n", r);
133     ok(lstrcmpi(buffer,str)==0, "GetWorkingDirectory returned '%s'\n", buffer);
134
135     /* Test Getting / Setting the work directory */
136     strcpy(buffer,"garbage");
137     r = IShellLinkA_GetPath(sl, buffer, sizeof(buffer), NULL, SLGP_RAWPATH);
138     ok(SUCCEEDED(r), "GetPath failed (0x%08lx)\n", r);
139     ok(*buffer=='\0', "GetPath returned '%s'\n", buffer);
140
141     r = IShellLinkA_SetPath(sl, "");
142     ok(r==S_OK, "SetPath failed (0x%08lx)\n", r);
143
144     strcpy(buffer,"garbage");
145     r = IShellLinkA_GetPath(sl, buffer, sizeof(buffer), NULL, SLGP_RAWPATH);
146     ok(SUCCEEDED(r), "GetPath failed (0x%08lx)\n", r);
147     ok(*buffer=='\0', "GetPath returned '%s'\n", buffer);
148
149     str="c:\\nonexistent\\file";
150     r = IShellLinkA_SetPath(sl, str);
151     ok(r==S_FALSE, "SetPath failed (0x%08lx)\n", r);
152
153     strcpy(buffer,"garbage");
154     r = IShellLinkA_GetPath(sl, buffer, sizeof(buffer), NULL, SLGP_RAWPATH);
155     ok(SUCCEEDED(r), "GetPath failed (0x%08lx)\n", r);
156     ok(lstrcmpi(buffer,str)==0, "GetPath returned '%s'\n", buffer);
157
158     /* Get some a real path to play with */
159     r=GetModuleFileName(NULL, mypath, sizeof(mypath));
160     ok(r>=0 && r<sizeof(mypath), "GetModuleFileName failed (%ld)\n", r);
161
162     /* Test the interaction of SetPath and SetIDList */
163     tmp_pidl=NULL;
164     r = IShellLinkA_GetIDList(sl, &tmp_pidl);
165     ok(SUCCEEDED(r), "GetIDList failed (0x%08lx)\n", r);
166     if (SUCCEEDED(r))
167     {
168         strcpy(buffer,"garbage");
169         r=SHGetPathFromIDListA(tmp_pidl, buffer);
170         todo_wine {
171         ok(r, "SHGetPathFromIDListA failed\n");
172         }
173         if (r)
174             ok(lstrcmpi(buffer,str)==0, "GetIDList returned '%s'\n", buffer);
175     }
176
177     pidl=path_to_pidl(mypath);
178     todo_wine {
179     ok(pidl!=NULL, "path_to_pidl returned a NULL pidl\n");
180     }
181
182     if (pidl)
183     {
184         r = IShellLinkA_SetIDList(sl, pidl);
185         ok(SUCCEEDED(r), "SetIDList failed (0x%08lx)\n", r);
186
187         tmp_pidl=NULL;
188         r = IShellLinkA_GetIDList(sl, &tmp_pidl);
189         ok(SUCCEEDED(r), "GetIDList failed (0x%08lx)\n", r);
190         ok(tmp_pidl && ILIsEqual(pidl, tmp_pidl),
191            "GetIDList returned an incorrect pidl\n");
192
193         /* tmp_pidl is owned by IShellLink so we don't free it */
194         ILFree(pidl);
195
196         strcpy(buffer,"garbage");
197         r = IShellLinkA_GetPath(sl, buffer, sizeof(buffer), NULL, SLGP_RAWPATH);
198         ok(SUCCEEDED(r), "GetPath failed (0x%08lx)\n", r);
199         ok(lstrcmpi(buffer, mypath)==0, "GetPath returned '%s'\n", buffer);
200     }
201
202     /* Test Getting / Setting the arguments */
203     strcpy(buffer,"garbage");
204     r = IShellLinkA_GetArguments(sl, buffer, sizeof(buffer));
205     ok(SUCCEEDED(r), "GetArguments failed (0x%08lx)\n", r);
206     ok(*buffer=='\0', "GetArguments returned '%s'\n", buffer);
207
208     str="param1 \"spaced param2\"";
209     r = IShellLinkA_SetArguments(sl, str);
210     ok(SUCCEEDED(r), "SetArguments failed (0x%08lx)\n", r);
211
212     strcpy(buffer,"garbage");
213     r = IShellLinkA_GetArguments(sl, buffer, sizeof(buffer));
214     ok(SUCCEEDED(r), "GetArguments failed (0x%08lx)\n", r);
215     ok(lstrcmp(buffer,str)==0, "GetArguments returned '%s'\n", buffer);
216
217     /* Test Getting / Setting showcmd */
218     i=0xdeadbeef;
219     r = IShellLinkA_GetShowCmd(sl, &i);
220     ok(SUCCEEDED(r), "GetShowCmd failed (0x%08lx)\n", r);
221     ok(i==SW_SHOWNORMAL, "GetShowCmd returned %d\n", i);
222
223     r = IShellLinkA_SetShowCmd(sl, SW_SHOWMAXIMIZED);
224     ok(SUCCEEDED(r), "SetShowCmd failed (0x%08lx)\n", r);
225
226     i=0xdeadbeef;
227     r = IShellLinkA_GetShowCmd(sl, &i);
228     ok(SUCCEEDED(r), "GetShowCmd failed (0x%08lx)\n", r);
229     ok(i==SW_SHOWMAXIMIZED, "GetShowCmd returned %d'\n", i);
230
231     /* Test Getting / Setting the icon */
232     i=0xdeadbeef;
233     strcpy(buffer,"garbage");
234     r = IShellLinkA_GetIconLocation(sl, buffer, sizeof(buffer), &i);
235     todo_wine {
236     ok(SUCCEEDED(r), "GetIconLocation failed (0x%08lx)\n", r);
237     }
238     ok(*buffer=='\0', "GetIconLocation returned '%s'\n", buffer);
239     ok(i==0, "GetIconLocation returned %d\n", i);
240
241     str="c:\\nonexistent\\file";
242     r = IShellLinkA_SetIconLocation(sl, str, 0xbabecafe);
243     ok(SUCCEEDED(r), "SetIconLocation failed (0x%08lx)\n", r);
244
245     i=0xdeadbeef;
246     r = IShellLinkA_GetIconLocation(sl, buffer, sizeof(buffer), &i);
247     ok(SUCCEEDED(r), "GetIconLocation failed (0x%08lx)\n", r);
248     ok(lstrcmpi(buffer,str)==0, "GetArguments returned '%s'\n", buffer);
249     ok(i==0xbabecafe, "GetIconLocation returned %d'\n", i);
250
251     /* Test Getting / Setting the hot key */
252     w=0xbeef;
253     r = IShellLinkA_GetHotkey(sl, &w);
254     ok(SUCCEEDED(r), "GetHotkey failed (0x%08lx)\n", r);
255     ok(w==0, "GetHotkey returned %d\n", w);
256
257     r = IShellLinkA_SetHotkey(sl, 0x5678);
258     ok(SUCCEEDED(r), "SetHotkey failed (0x%08lx)\n", r);
259
260     w=0xbeef;
261     r = IShellLinkA_GetHotkey(sl, &w);
262     ok(SUCCEEDED(r), "GetHotkey failed (0x%08lx)\n", r);
263     ok(w==0x5678, "GetHotkey returned %d'\n", w);
264
265     IShellLinkA_Release(sl);
266 }
267
268
269 /*
270  * Test saving and loading .lnk files
271  */
272
273 #define lok                   ok_(__FILE__, line)
274 #define check_lnk(a,b)        check_lnk_(__LINE__, (a), (b))
275
276 void create_lnk_(int line, const WCHAR* path, lnk_desc_t* desc, int save_fails)
277 {
278     HRESULT r;
279     IShellLinkA *sl;
280     IPersistFile *pf;
281
282     r = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
283                          &IID_IShellLinkA, (LPVOID*)&sl);
284     lok(SUCCEEDED(r), "no IID_IShellLinkA (0x%08lx)\n", r);
285     if (!SUCCEEDED(r))
286         return;
287
288     if (desc->description)
289     {
290         r = IShellLinkA_SetDescription(sl, desc->description);
291         lok(SUCCEEDED(r), "SetDescription failed (0x%08lx)\n", r);
292     }
293     if (desc->workdir)
294     {
295         r = IShellLinkA_SetWorkingDirectory(sl, desc->workdir);
296         lok(SUCCEEDED(r), "SetWorkingDirectory failed (0x%08lx)\n", r);
297     }
298     if (desc->path)
299     {
300         r = IShellLinkA_SetPath(sl, desc->path);
301         lok(SUCCEEDED(r), "SetPath failed (0x%08lx)\n", r);
302     }
303     if (desc->pidl)
304     {
305         r = IShellLinkA_SetIDList(sl, desc->pidl);
306         lok(SUCCEEDED(r), "SetIDList failed (0x%08lx)\n", r);
307     }
308     if (desc->arguments)
309     {
310         r = IShellLinkA_SetArguments(sl, desc->arguments);
311         lok(SUCCEEDED(r), "SetArguments failed (0x%08lx)\n", r);
312     }
313     if (desc->showcmd)
314     {
315         r = IShellLinkA_SetShowCmd(sl, desc->showcmd);
316         lok(SUCCEEDED(r), "SetShowCmd failed (0x%08lx)\n", r);
317     }
318     if (desc->icon)
319     {
320         r = IShellLinkA_SetIconLocation(sl, desc->icon, desc->icon_id);
321         lok(SUCCEEDED(r), "SetIconLocation failed (0x%08lx)\n", r);
322     }
323     if (desc->hotkey)
324     {
325         r = IShellLinkA_SetHotkey(sl, desc->hotkey);
326         lok(SUCCEEDED(r), "SetHotkey failed (0x%08lx)\n", r);
327     }
328
329     r = IShellLinkW_QueryInterface(sl, &IID_IPersistFile, (LPVOID*)&pf);
330     lok(SUCCEEDED(r), "no IID_IPersistFile (0x%08lx)\n", r);
331     if (SUCCEEDED(r))
332     {
333         r = IPersistFile_Save(pf, path, TRUE);
334         if (save_fails)
335         {
336             todo_wine {
337             lok(SUCCEEDED(r), "save failed (0x%08lx)\n", r);
338             }
339         }
340         else
341         {
342             lok(SUCCEEDED(r), "save failed (0x%08lx)\n", r);
343         }
344         IPersistFile_Release(pf);
345     }
346
347     IShellLinkA_Release(sl);
348 }
349
350 static void check_lnk_(int line, const WCHAR* path, lnk_desc_t* desc)
351 {
352     HRESULT r;
353     IShellLinkA *sl;
354     IPersistFile *pf;
355     char buffer[INFOTIPSIZE];
356
357     r = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
358                          &IID_IShellLinkA, (LPVOID*)&sl);
359     lok(SUCCEEDED(r), "no IID_IShellLinkA (0x%08lx)\n", r);
360     if (!SUCCEEDED(r))
361         return;
362
363     r = IShellLinkA_QueryInterface(sl, &IID_IPersistFile, (LPVOID*)&pf);
364     lok(SUCCEEDED(r), "no IID_IPersistFile (0x%08lx)\n", r);
365     if (!SUCCEEDED(r))
366     {
367         IShellLinkA_Release(sl);
368         return;
369     }
370
371     r = IPersistFile_Load(pf, path, STGM_READ);
372     lok(SUCCEEDED(r), "load failed (0x%08lx)\n", r);
373     IPersistFile_Release(pf);
374     if (!SUCCEEDED(r))
375     {
376         IShellLinkA_Release(sl);
377         return;
378     }
379
380     if (desc->description)
381     {
382         strcpy(buffer,"garbage");
383         r = IShellLinkA_GetDescription(sl, buffer, sizeof(buffer));
384         lok(SUCCEEDED(r), "GetDescription failed (0x%08lx)\n", r);
385         lok(lstrcmp(buffer, desc->description)==0,
386            "GetDescription returned '%s' instead of '%s'\n",
387            buffer, desc->description);
388     }
389     if (desc->workdir)
390     {
391         strcpy(buffer,"garbage");
392         r = IShellLinkA_GetWorkingDirectory(sl, buffer, sizeof(buffer));
393         lok(SUCCEEDED(r), "GetWorkingDirectory failed (0x%08lx)\n", r);
394         lok(lstrcmpi(buffer, desc->workdir)==0,
395            "GetWorkingDirectory returned '%s' instead of '%s'\n",
396            buffer, desc->workdir);
397     }
398     if (desc->path)
399     {
400         strcpy(buffer,"garbage");
401         r = IShellLinkA_GetPath(sl, buffer, sizeof(buffer), NULL, SLGP_RAWPATH);
402         lok(SUCCEEDED(r), "GetPath failed (0x%08lx)\n", r);
403         lok(lstrcmpi(buffer, desc->path)==0,
404            "GetPath returned '%s' instead of '%s'\n",
405            buffer, desc->path);
406     }
407     if (desc->pidl)
408     {
409         LPITEMIDLIST pidl=NULL;
410         r = IShellLinkA_GetIDList(sl, &pidl);
411         lok(SUCCEEDED(r), "GetIDList failed (0x%08lx)\n", r);
412         lok(ILIsEqual(pidl, desc->pidl),
413            "GetIDList returned an incorrect pidl\n");
414     }
415     if (desc->showcmd)
416     {
417         int i=0xdeadbeef;
418         r = IShellLinkA_GetShowCmd(sl, &i);
419         lok(SUCCEEDED(r), "GetShowCmd failed (0x%08lx)\n", r);
420         lok(i==desc->showcmd,
421            "GetShowCmd returned 0x%0x instead of 0x%0x\n",
422            i, desc->showcmd);
423     }
424     if (desc->icon)
425     {
426         int i=0xdeadbeef;
427         strcpy(buffer,"garbage");
428         r = IShellLinkA_GetIconLocation(sl, buffer, sizeof(buffer), &i);
429         lok(SUCCEEDED(r), "GetIconLocation failed (0x%08lx)\n", r);
430         lok(lstrcmpi(buffer, desc->icon)==0,
431            "GetIconLocation returned '%s' instead of '%s'\n",
432            buffer, desc->icon);
433         lok(i==desc->icon_id,
434            "GetIconLocation returned 0x%0x instead of 0x%0x\n",
435            i, desc->icon_id);
436     }
437     if (desc->hotkey)
438     {
439         WORD i=0xbeef;
440         r = IShellLinkA_GetHotkey(sl, &i);
441         lok(SUCCEEDED(r), "GetHotkey failed (0x%08lx)\n", r);
442         lok(i==desc->hotkey,
443            "GetHotkey returned 0x%04x instead of 0x%04x\n",
444            i, desc->hotkey);
445     }
446
447     IShellLinkA_Release(sl);
448 }
449
450 static void test_load_save(void)
451 {
452     lnk_desc_t desc;
453     char mypath[MAX_PATH];
454     char mydir[MAX_PATH];
455     char* p;
456     DWORD r;
457
458     /* Save an empty .lnk file */
459     memset(&desc, 0, sizeof(desc));
460     create_lnk(lnkfile, &desc, 0);
461
462     /* It should come back as a bunch of empty strings */
463     desc.description="";
464     desc.workdir="";
465     desc.path="";
466     desc.arguments="";
467     desc.icon="";
468     check_lnk(lnkfile, &desc);
469
470
471     /* Point a .lnk file to nonexistent files */
472     desc.description="";
473     desc.workdir="c:\\Nonexitent\\work\\directory";
474     desc.path="c:\\nonexistent\\path";
475     desc.pidl=NULL;
476     desc.arguments="";
477     desc.showcmd=0;
478     desc.icon="c:\\nonexistent\\icon\\file";
479     desc.icon_id=1234;
480     desc.hotkey=0;
481     create_lnk(lnkfile, &desc, 0);
482     check_lnk(lnkfile, &desc);
483
484     r=GetModuleFileName(NULL, mypath, sizeof(mypath));
485     ok(r>=0 && r<sizeof(mypath), "GetModuleFileName failed (%ld)\n", r);
486     strcpy(mydir, mypath);
487     p=strrchr(mydir, '\\');
488     if (p)
489         *p='\0';
490
491
492     /* Overwrite the existing lnk file and point it to existing files */
493     desc.description="test 2";
494     desc.workdir=mydir;
495     desc.path=mypath;
496     desc.pidl=NULL;
497     desc.arguments="/option1 /option2 \"Some string\"";
498     desc.showcmd=SW_SHOWNORMAL;
499     desc.icon=mypath;
500     desc.icon_id=0;
501     desc.hotkey=0x1234;
502     create_lnk(lnkfile, &desc, 0);
503     check_lnk(lnkfile, &desc);
504
505     /* FIXME: Also test saving a .lnk pointing to a pidl that cannot be
506      * represented as a path.
507      */
508
509     /* DeleteFileW is not implemented on Win9x */
510     r=DeleteFileA("c:\\test.lnk");
511     ok(r, "failed to delete link (%ld)\n", GetLastError());
512 }
513
514 START_TEST(shelllink)
515 {
516     HRESULT r;
517
518     r = CoInitialize(NULL);
519     ok(SUCCEEDED(r), "CoInitialize failed (0x%08lx)\n", r);
520     if (!SUCCEEDED(r))
521         return;
522
523     test_get_set();
524     test_load_save();
525
526     CoUninitialize();
527 }