Documentation fixes.
[wine] / dlls / shell32 / shelllink.c
1 /*
2  *
3  *      Copyright 1997  Marcus Meissner
4  *      Copyright 1998  Juergen Schmied
5  *
6  */
7
8 #include "config.h"
9
10 #include <string.h>
11 #include <stdio.h>
12 #include <unistd.h>
13 #include <errno.h>
14 #ifdef HAVE_SYS_WAIT_H
15 # include <sys/wait.h>
16 #endif
17 #include "debugtools.h"
18 #include "winerror.h"
19 #include "winbase.h"
20 #include "winnls.h"
21 #include "winreg.h"
22
23 #include "shlobj.h"
24 #include "wine/undocshell.h"
25 #include "bitmaps/wine.xpm"
26
27 #include "heap.h"
28 #include "pidl.h"
29 #include "shell32_main.h"
30 #include "shlguid.h"
31
32 DEFAULT_DEBUG_CHANNEL(shell);
33
34 /* link file formats */
35
36 #include "pshpack1.h"
37
38 /* flag1: lnk elements: simple link has 0x0B */
39 #define WORKDIR         0x10
40 #define ARGUMENT        0x20
41 #define ICON            0x40
42 #define UNC             0x80
43
44 /* fStartup */
45 #define NORMAL          0x01
46 #define MAXIMIZED       0x03
47 #define MINIMIZED       0x07
48
49 typedef struct _LINK_HEADER     
50 {       DWORD   MagicStr;       /* 0x00 'L','\0','\0','\0' */
51         GUID    MagicGuid;      /* 0x04 is CLSID_ShellLink */
52         DWORD   Flag1;          /* 0x14 describes elements following */
53         DWORD   Flag2;          /* 0x18 */
54         FILETIME Time1;         /* 0x1c */
55         FILETIME Time2;         /* 0x24 */
56         FILETIME Time3;         /* 0x2c */
57         DWORD   Unknown1;       /* 0x34 */
58         DWORD   Unknown2;       /* 0x38 icon number */
59         DWORD   fStartup;       /* 0x3c startup type */
60         DWORD   wHotKey;        /* 0x40 hotkey */
61         DWORD   Unknown5;       /* 0x44 */
62         DWORD   Unknown6;       /* 0x48 */
63         USHORT  PidlSize;       /* 0x4c */
64         ITEMIDLIST Pidl;        /* 0x4e */
65 } LINK_HEADER, * PLINK_HEADER;
66
67 #define LINK_HEADER_SIZE (sizeof(LINK_HEADER)-sizeof(ITEMIDLIST))
68
69 typedef struct
70 {
71         BYTE bWidth;
72         BYTE bHeight;
73         BYTE bColorCount;
74         BYTE bReserved;
75         WORD wPlanes;
76         WORD wBitCount;
77         DWORD dwBytesInRes;
78         WORD nID;
79 } GRPICONDIRENTRY;
80
81 typedef struct
82 {
83         WORD idReserved;
84         WORD idType;
85         WORD idCount;
86         GRPICONDIRENTRY idEntries[1];
87 } GRPICONDIR;
88
89 typedef struct
90 {
91         BYTE bWidth;
92         BYTE bHeight;
93         BYTE bColorCount;
94         BYTE bReserved;
95         WORD wPlanes;
96         WORD wBitCount;
97         DWORD dwBytesInRes;
98         DWORD dwImageOffset;
99 } ICONDIRENTRY;
100
101 typedef struct
102 {
103         WORD idReserved;
104         WORD idType;
105         WORD idCount;
106 } ICONDIR;
107
108
109 #include "poppack.h"
110
111
112 static ICOM_VTABLE(IShellLinkA)         slvt;
113 static ICOM_VTABLE(IShellLinkW)         slvtw;
114 static ICOM_VTABLE(IPersistFile)        pfvt;
115 static ICOM_VTABLE(IPersistStream)      psvt;
116
117 /* IShellLink Implementation */
118
119 typedef struct
120 {
121         ICOM_VFIELD(IShellLinkA);
122         DWORD                           ref;
123
124         ICOM_VTABLE(IShellLinkW)*       lpvtblw;
125         ICOM_VTABLE(IPersistFile)*      lpvtblPersistFile;
126         ICOM_VTABLE(IPersistStream)*    lpvtblPersistStream;
127         
128         /* internal stream of the IPersistFile interface */
129         IStream*                        lpFileStream;
130         
131         /* data structures according to the informations in the lnk */
132         LPSTR           sPath;
133         LPITEMIDLIST    pPidl;
134         WORD            wHotKey;
135         SYSTEMTIME      time1;
136         SYSTEMTIME      time2;
137         SYSTEMTIME      time3;
138
139         LPSTR           sIcoPath;
140         INT             iIcoNdx;
141         LPSTR           sArgs;
142         LPSTR           sWorkDir;
143         LPSTR           sDescription;
144 } IShellLinkImpl;
145
146 #define _IShellLinkW_Offset ((int)(&(((IShellLinkImpl*)0)->lpvtblw)))
147 #define _ICOM_THIS_From_IShellLinkW(class, name) class* This = (class*)(((char*)name)-_IShellLinkW_Offset);
148
149 #define _IPersistFile_Offset ((int)(&(((IShellLinkImpl*)0)->lpvtblPersistFile)))
150 #define _ICOM_THIS_From_IPersistFile(class, name) class* This = (class*)(((char*)name)-_IPersistFile_Offset);
151
152 #define _IPersistStream_Offset ((int)(&(((IShellLinkImpl*)0)->lpvtblPersistStream)))
153 #define _ICOM_THIS_From_IPersistStream(class, name) class* This = (class*)(((char*)name)-_IPersistStream_Offset);
154 #define _IPersistStream_From_ICOM_THIS(class, name) class* StreamThis = (class*)(((char*)name)+_IPersistStream_Offset);
155
156 /**************************************************************************
157  *  IPersistFile_QueryInterface
158  */
159 static HRESULT WINAPI IPersistFile_fnQueryInterface(
160         IPersistFile* iface,
161         REFIID riid,
162         LPVOID *ppvObj)
163 {
164         _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface)
165
166         TRACE("(%p)\n",This);
167
168         return IShellLinkA_QueryInterface((IShellLinkA*)This, riid, ppvObj);
169 }
170
171 /******************************************************************************
172  * IPersistFile_AddRef
173  */
174 static ULONG WINAPI IPersistFile_fnAddRef(IPersistFile* iface)
175 {
176         _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface)
177
178         TRACE("(%p)->(count=%lu)\n",This,This->ref);
179
180         return IShellLinkA_AddRef((IShellLinkA*)This);
181 }
182 /******************************************************************************
183  * IPersistFile_Release
184  */
185 static ULONG WINAPI IPersistFile_fnRelease(IPersistFile* iface)
186 {
187         _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface)
188
189         TRACE("(%p)->(count=%lu)\n",This,This->ref);
190
191         return IShellLinkA_Release((IShellLinkA*)This);
192 }
193
194 static HRESULT WINAPI IPersistFile_fnGetClassID(IPersistFile* iface, CLSID *pClassID)
195 {
196         _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface)
197         FIXME("(%p)\n",This);
198         return NOERROR;
199 }
200 static HRESULT WINAPI IPersistFile_fnIsDirty(IPersistFile* iface)
201 {
202         _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface)
203         FIXME("(%p)\n",This);
204         return NOERROR;
205 }
206 static HRESULT WINAPI IPersistFile_fnLoad(IPersistFile* iface, LPCOLESTR pszFileName, DWORD dwMode)
207 {
208         _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface)
209         _IPersistStream_From_ICOM_THIS(IPersistStream, This)
210
211         LPSTR           sFile = HEAP_strdupWtoA ( GetProcessHeap(), 0, pszFileName);
212         HRESULT         hRet = E_FAIL;
213
214         TRACE("(%p, %s)\n",This, sFile);
215         
216
217         if (This->lpFileStream)
218           IStream_Release(This->lpFileStream);
219         
220         if SUCCEEDED(CreateStreamOnFile(sFile, &(This->lpFileStream)))
221         {
222           if SUCCEEDED (IPersistStream_Load(StreamThis, This->lpFileStream))
223           {
224             return NOERROR;
225           }
226         }
227         
228         return hRet;
229 }
230
231
232 /* Icon extraction routines
233  *
234  * FIXME: should use PrivateExtractIcons and friends
235  * FIXME: should not use stdio
236  */
237
238 static BOOL SaveIconResAsXPM(const BITMAPINFO *pIcon, const char *szXPMFileName)
239 {
240     FILE *fXPMFile;
241     int nHeight;
242     int nXORWidthBytes;
243     int nANDWidthBytes;
244     BOOL b8BitColors;
245     int nColors;
246     BYTE *pXOR;
247     BYTE *pAND;
248     BOOL aColorUsed[256] = {0};
249     int nColorsUsed = 0;
250     int i,j;
251
252     if (!((pIcon->bmiHeader.biBitCount == 4) || (pIcon->bmiHeader.biBitCount == 8)))
253         return 0;
254
255     if (!(fXPMFile = fopen(szXPMFileName, "w")))
256         return 0;
257
258     nHeight = pIcon->bmiHeader.biHeight / 2;
259     nXORWidthBytes = 4 * ((pIcon->bmiHeader.biWidth * pIcon->bmiHeader.biBitCount / 32)
260                           + ((pIcon->bmiHeader.biWidth * pIcon->bmiHeader.biBitCount % 32) > 0));
261     nANDWidthBytes = 4 * ((pIcon->bmiHeader.biWidth / 32)
262                           + ((pIcon->bmiHeader.biWidth % 32) > 0));
263     b8BitColors = pIcon->bmiHeader.biBitCount == 8;
264     nColors = pIcon->bmiHeader.biClrUsed ? pIcon->bmiHeader.biClrUsed
265         : 1 << pIcon->bmiHeader.biBitCount;
266     pXOR = (BYTE*) pIcon + sizeof (BITMAPINFOHEADER) + (nColors * sizeof (RGBQUAD));
267     pAND = pXOR + nHeight * nXORWidthBytes;
268
269 #define MASK(x,y) (pAND[(x) / 8 + (nHeight - (y) - 1) * nANDWidthBytes] & (1 << (7 - (x) % 8)))
270 #define COLOR(x,y) (b8BitColors ? pXOR[(x) + (nHeight - (y) - 1) * nXORWidthBytes] : (x) % 2 ? pXOR[(x) / 2 + (nHeight - (y) - 1) * nXORWidthBytes] & 0xF : (pXOR[(x) / 2 + (nHeight - (y) - 1) * nXORWidthBytes] & 0xF0) >> 4)
271
272     for (i = 0; i < nHeight; i++)
273         for (j = 0; j < pIcon->bmiHeader.biWidth; j++)
274             if (!aColorUsed[COLOR(j,i)] && !MASK(j,i))
275             {
276                 aColorUsed[COLOR(j,i)] = TRUE;
277                 nColorsUsed++;
278             }
279
280     if (fprintf(fXPMFile, "/* XPM */\nstatic char *icon[] = {\n") <= 0)
281         goto error;
282     if (fprintf(fXPMFile, "\"%d %d %d %d\",\n",
283                 (int) pIcon->bmiHeader.biWidth, nHeight, nColorsUsed + 1, 2) <=0)
284         goto error;
285
286     for (i = 0; i < nColors; i++)
287         if (aColorUsed[i])
288             if (fprintf(fXPMFile, "\"%.2X c #%.2X%.2X%.2X\",\n", i, pIcon->bmiColors[i].rgbRed,
289                         pIcon->bmiColors[i].rgbGreen, pIcon->bmiColors[i].rgbBlue) <= 0)
290                 goto error;
291     if (fprintf(fXPMFile, "\"   c None\"") <= 0)
292         goto error;
293
294     for (i = 0; i < nHeight; i++)
295     {
296         if (fprintf(fXPMFile, ",\n\"") <= 0)
297             goto error;
298         for (j = 0; j < pIcon->bmiHeader.biWidth; j++)
299         {
300             if MASK(j,i)
301                 {
302                     if (fprintf(fXPMFile, "  ") <= 0)
303                         goto error;
304                 }
305             else
306                 if (fprintf(fXPMFile, "%.2X", COLOR(j,i)) <= 0)
307                     goto error;
308         }
309         if (fprintf(fXPMFile, "\"") <= 0)
310             goto error;
311     }
312     if (fprintf(fXPMFile, "};\n") <= 0)
313         goto error;
314
315 #undef MASK
316 #undef COLOR
317
318     fclose(fXPMFile);
319     return 1;
320
321  error:
322     fclose(fXPMFile);
323     unlink( szXPMFileName );
324     return 0;
325 }
326
327 static BOOL CALLBACK EnumResNameProc(HANDLE hModule, const char *lpszType, char *lpszName, LONG lParam)
328 {
329     *(HRSRC *) lParam = FindResourceA(hModule, lpszName, RT_GROUP_ICONA);
330     return FALSE;
331 }
332
333 static int ExtractFromEXEDLL(const char *szFileName, int nIndex, const char *szXPMFileName)
334 {
335     HMODULE hModule;
336     HRSRC hResInfo;
337     char *lpName = NULL;
338     HGLOBAL hResData;
339     GRPICONDIR *pIconDir;
340     BITMAPINFO *pIcon;
341     int nMax = 0;
342     int i;
343
344     if (!(hModule = LoadLibraryExA(szFileName, 0, LOAD_LIBRARY_AS_DATAFILE)))
345     {
346         TRACE("LoadLibraryExA (%s) failed, error %ld\n", szFileName, GetLastError());
347         goto error1;
348     }
349
350     if (nIndex)
351     {
352         hResInfo = FindResourceA(hModule, MAKEINTRESOURCEA(nIndex), RT_GROUP_ICONA);
353         TRACE("FindResourceA (%s) called, return 0x%x, error %ld\n", szFileName, hResInfo, GetLastError());
354     }
355     else
356         if (EnumResourceNamesA(hModule, RT_GROUP_ICONA, &EnumResNameProc, (LONG) &hResInfo))
357         {
358             TRACE("EnumResourceNamesA failed, error %ld\n", GetLastError());
359             goto error2;
360         }
361
362     if (!hResInfo)
363     {
364         TRACE("ExtractFromEXEDLL failed, error %ld\n", GetLastError());
365         goto error2;
366     }
367
368     if (!(hResData = LoadResource(hModule, hResInfo)))
369     {
370         TRACE("LoadResource failed, error %ld\n", GetLastError());
371         goto error2;
372     }
373     if (!(pIconDir = LockResource(hResData)))
374     {
375         TRACE("LockResource failed, error %ld\n", GetLastError());
376         goto error3;
377     }
378
379     for (i = 0; i < pIconDir->idCount; i++)
380         if ((pIconDir->idEntries[i].bHeight * pIconDir->idEntries[i].bWidth) > nMax)
381         {
382             lpName = MAKEINTRESOURCEA(pIconDir->idEntries[i].nID);
383             nMax = pIconDir->idEntries[i].bHeight * pIconDir->idEntries[i].bWidth;
384         }
385
386     FreeResource(hResData);
387
388     if (!(hResInfo = FindResourceA(hModule, lpName, RT_ICONA)))
389     {
390         TRACE("Second FindResourceA failed, error %ld\n", GetLastError());
391         goto error2;
392     }
393     if (!(hResData = LoadResource(hModule, hResInfo)))
394     {
395         TRACE("Second LoadResource failed, error %ld\n", GetLastError());
396         goto error2;
397     }
398     if (!(pIcon = LockResource(hResData)))
399     {
400         TRACE("Second LockResource failed, error %ld\n", GetLastError());
401         goto error3;
402     }
403
404     if(!SaveIconResAsXPM(pIcon, szXPMFileName))
405     {
406         TRACE("Failed saving icon as XPM, error %ld\n", GetLastError());
407         goto error3;
408     }
409
410     FreeResource(hResData);
411     FreeLibrary(hModule);
412
413     return 1;
414
415  error3:
416     FreeResource(hResData);
417  error2:
418     FreeLibrary(hModule);
419  error1:
420     return 0;
421 }
422
423 static int ExtractFromICO(const char *szFileName, const char *szXPMFileName)
424 {
425     FILE *fICOFile;
426     ICONDIR iconDir;
427     ICONDIRENTRY *pIconDirEntry;
428     int nMax = 0;
429     int nIndex = 0;
430     void *pIcon;
431     int i;
432
433     if (!(fICOFile = fopen(szFileName, "r")))
434         goto error1;
435
436     if (fread(&iconDir, sizeof (ICONDIR), 1, fICOFile) != 1)
437         goto error2;
438     if ((iconDir.idReserved != 0) || (iconDir.idType != 1))
439         goto error2;
440
441     if ((pIconDirEntry = malloc(iconDir.idCount * sizeof (ICONDIRENTRY))) == NULL)
442         goto error2;
443     if (fread(pIconDirEntry, sizeof (ICONDIRENTRY), iconDir.idCount, fICOFile) != iconDir.idCount)
444         goto error3;
445
446     for (i = 0; i < iconDir.idCount; i++)
447         if ((pIconDirEntry[i].bHeight * pIconDirEntry[i].bWidth) > nMax)
448         {
449             nIndex = i;
450             nMax = pIconDirEntry[i].bHeight * pIconDirEntry[i].bWidth;
451         }
452     if ((pIcon = malloc(pIconDirEntry[nIndex].dwBytesInRes)) == NULL)
453         goto error3;
454     if (fseek(fICOFile, pIconDirEntry[nIndex].dwImageOffset, SEEK_SET))
455         goto error4;
456     if (fread(pIcon, pIconDirEntry[nIndex].dwBytesInRes, 1, fICOFile) != 1)
457         goto error4;
458
459     if(!SaveIconResAsXPM(pIcon, szXPMFileName))
460         goto error4;
461
462     free(pIcon);
463     free(pIconDirEntry);
464     fclose(fICOFile);
465
466     return 1;
467
468  error4:
469     free(pIcon);
470  error3:
471     free(pIconDirEntry);
472  error2:
473     fclose(fICOFile);
474  error1:
475     return 0;
476 }
477
478 /* get the Unix file name for a given path, allocating the string */
479 inline static char *get_unix_file_name( const char *dos )
480 {
481     char buffer[MAX_PATH];
482
483     if (!wine_get_unix_file_name( dos, buffer, sizeof(buffer) )) return NULL;
484     return HEAP_strdupA( GetProcessHeap(), 0, buffer );
485 }
486
487 static BOOL create_default_icon( const char *filename )
488 {
489     FILE *fXPM;
490     int i;
491
492     if (!(fXPM = fopen(filename, "w"))) return FALSE;
493     fprintf(fXPM, "/* XPM */\nstatic char * icon[] = {");
494     for (i = 0; i < sizeof(wine_xpm)/sizeof(wine_xpm[0]); i++)
495         fprintf( fXPM, "\n\"%s\",", wine_xpm[i]);
496     fprintf( fXPM, "};\n" );
497     fclose( fXPM );
498     return TRUE;
499 }
500
501 /* extract an icon from an exe or icon file; helper for IPersistFile_fnSave */
502 static char *extract_icon( const char *path, int index )
503 {
504     char *filename = HEAP_strdupA( GetProcessHeap(), 0, tmpnam(NULL) );
505     if (ExtractFromEXEDLL( path, index, filename )) return filename;
506     if (ExtractFromICO( path, filename )) return filename;
507     if (create_default_icon( filename )) return filename;
508     HeapFree( GetProcessHeap(), 0, filename );
509     return NULL;
510 }
511
512
513 static HRESULT WINAPI IPersistFile_fnSave(IPersistFile* iface, LPCOLESTR pszFileName, BOOL fRemember)
514 {
515     HRESULT ret = NOERROR;
516     int pid, status;
517     char buffer[MAX_PATH], buff2[MAX_PATH];
518     char *filename, *link_name, *p;
519     char *shell_link_app = NULL;
520     char *icon_name = NULL;
521     char *path_name = NULL;
522     char *work_dir = NULL;
523     BOOL bDesktop;
524     HKEY hkey;
525
526     _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface);
527
528     TRACE("(%p)->(%s)\n",This,debugstr_w(pszFileName));
529
530     if (!pszFileName || !This->sPath)
531         return ERROR_UNKNOWN;
532
533     /* check for .exe extension */
534     if (!(p = strrchr( This->sPath, '.' ))) return NOERROR;
535     if (strchr( p, '\\' ) || strchr( p, '/' )) return NOERROR;
536     if (strcasecmp( p, ".exe" )) return NOERROR;
537
538     /* check if ShellLinker configured */
539     buffer[0] = 0;
540     if (!RegOpenKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\Wine",
541                         0, KEY_ALL_ACCESS, &hkey ))
542     {
543         DWORD type, count = sizeof(buffer);
544         if (RegQueryValueExA( hkey, "ShellLinker", 0, &type, buffer, &count )) buffer[0] = 0;
545         RegCloseKey( hkey );
546     }
547     if (!*buffer) return NOERROR;
548     shell_link_app = HEAP_strdupA( GetProcessHeap(), 0, buffer );
549
550     if (!WideCharToMultiByte( CP_ACP, 0, pszFileName, -1, buffer, sizeof(buffer), NULL, NULL))
551         return ERROR_UNKNOWN;
552     GetFullPathNameA( buffer, sizeof(buff2), buff2, NULL );
553     filename = HEAP_strdupA( GetProcessHeap(), 0, buff2 );
554
555     if (SHGetSpecialFolderPathA( 0, buffer, CSIDL_STARTUP, FALSE ))
556     {
557         /* ignore startup for now */
558         if (!strncasecmp( filename, buffer, strlen(buffer) )) goto done;
559     }
560     if (SHGetSpecialFolderPathA( 0, buffer, CSIDL_DESKTOPDIRECTORY, FALSE ))
561     {
562         if (!strncasecmp( filename, buffer, strlen(buffer) ))
563         {
564             link_name = filename + strlen(buffer);
565             bDesktop = TRUE;
566             goto found;
567         }
568     }
569     if (SHGetSpecialFolderPathA( 0, buffer, CSIDL_STARTMENU, FALSE ))
570     {
571         if (!strncasecmp( filename, buffer, strlen(buffer) ))
572         {
573             link_name = filename + strlen(buffer);
574             bDesktop = FALSE;
575             goto found;
576         }
577     }
578     goto done;
579
580  found:
581     /* make link name a Unix name */
582     for (p = link_name; *p; p++) if (*p == '\\') *p = '/';
583     /* strip leading slashes */
584     while (*link_name == '/') link_name++;
585     /* remove extension */
586     if ((p = strrchr( link_name, '.' ))) *p = 0;
587
588     /* convert app path name */
589     path_name = get_unix_file_name( This->sPath );
590
591     /* convert app working dir */
592     if (This->sWorkDir) work_dir = get_unix_file_name( This->sWorkDir );
593
594     /* extract the icon */
595     if (!(icon_name = extract_icon( This->sIcoPath && strlen(This->sIcoPath) ? 
596                                       This->sIcoPath : This->sPath,
597                                       This->iIcoNdx ))) goto done;
598
599
600     TRACE("linker app='%s' link='%s' mode=%s path='%s' args='%s' icon='%s' workdir='%s' descr='%s'\n",
601         shell_link_app, link_name, bDesktop ? "desktop" : "menu", path_name,
602         This->sArgs ? This->sArgs : "", icon_name, work_dir ? work_dir : "",
603         This->sDescription ? This->sDescription : "" );
604
605     if ((pid = fork()) == -1) goto done;
606     if (!pid)
607     {
608         int pos = 0;
609         char *argv[20];
610         argv[pos++] = shell_link_app;
611         argv[pos++] = "--link";
612         argv[pos++] = link_name;
613         argv[pos++] = "--path";
614         argv[pos++] = path_name;
615         argv[pos++] = bDesktop ? "--desktop" : "--menu";
616         if (This->sArgs && strlen(This->sArgs))
617         {
618             argv[pos++] = "--args";
619             argv[pos++] = This->sArgs;
620         }
621         if (icon_name)
622         {
623             argv[pos++] = "--icon";
624             argv[pos++] = icon_name;
625         }
626         if (This->sWorkDir && strlen(This->sWorkDir))
627         {
628             argv[pos++] = "--workdir";
629             argv[pos++] = This->sWorkDir;
630         }
631         if (This->sDescription && strlen(This->sDescription))
632         {
633             argv[pos++] = "--descr";
634             argv[pos++] = This->sDescription;
635         }
636         argv[pos] = NULL;
637         execvp( shell_link_app, argv );
638         _exit(1);
639     }
640
641     while (waitpid( pid, &status, 0 ) == -1)
642     {
643         if (errno != EINTR)
644         {
645             ret = ERROR_UNKNOWN;
646             goto done;
647         }
648     }
649     if (status) ret = E_ACCESSDENIED;
650
651  done:
652     if (icon_name) unlink( icon_name );
653     HeapFree( GetProcessHeap(), 0, shell_link_app );
654     HeapFree( GetProcessHeap(), 0, filename );
655     HeapFree( GetProcessHeap(), 0, icon_name );
656     HeapFree( GetProcessHeap(), 0, path_name );
657     HeapFree( GetProcessHeap(), 0, work_dir );
658     return ret;
659 }
660
661 static HRESULT WINAPI IPersistFile_fnSaveCompleted(IPersistFile* iface, LPCOLESTR pszFileName)
662 {
663         _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface);
664         FIXME("(%p)->(%s)\n",This,debugstr_w(pszFileName));
665         return NOERROR;
666 }
667 static HRESULT WINAPI IPersistFile_fnGetCurFile(IPersistFile* iface, LPOLESTR *ppszFileName)
668 {
669         _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface);
670         FIXME("(%p)\n",This);
671         return NOERROR;
672 }
673
674 static ICOM_VTABLE(IPersistFile) pfvt = 
675 {
676         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
677         IPersistFile_fnQueryInterface,
678         IPersistFile_fnAddRef,
679         IPersistFile_fnRelease,
680         IPersistFile_fnGetClassID,
681         IPersistFile_fnIsDirty,
682         IPersistFile_fnLoad,
683         IPersistFile_fnSave,
684         IPersistFile_fnSaveCompleted,
685         IPersistFile_fnGetCurFile
686 };
687
688 /************************************************************************
689  * IPersistStream_QueryInterface
690  */
691 static HRESULT WINAPI IPersistStream_fnQueryInterface(
692         IPersistStream* iface,
693         REFIID     riid,
694         VOID**     ppvoid)
695 {
696         _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
697
698         TRACE("(%p)\n",This);
699
700         return IShellLinkA_QueryInterface((IShellLinkA*)This, riid, ppvoid);
701 }
702
703 /************************************************************************
704  * IPersistStream_Release
705  */
706 static ULONG WINAPI IPersistStream_fnRelease(
707         IPersistStream* iface)
708 {
709         _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
710
711         TRACE("(%p)\n",This);
712
713         return IShellLinkA_Release((IShellLinkA*)This);
714 }
715
716 /************************************************************************
717  * IPersistStream_AddRef
718  */
719 static ULONG WINAPI IPersistStream_fnAddRef(
720         IPersistStream* iface)
721 {
722         _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
723
724         TRACE("(%p)\n",This);
725
726         return IShellLinkA_AddRef((IShellLinkA*)This);
727
728
729 /************************************************************************
730  * IPersistStream_GetClassID
731  *
732  */
733 static HRESULT WINAPI IPersistStream_fnGetClassID(
734         IPersistStream* iface,
735         CLSID* pClassID)
736 {
737         _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
738
739         TRACE("(%p)\n", This);
740
741         if (pClassID==0)
742           return E_POINTER;
743
744 /*      memcpy(pClassID, &CLSID_???, sizeof(CLSID_???)); */
745
746         return S_OK;
747 }
748
749 /************************************************************************
750  * IPersistStream_IsDirty (IPersistStream)
751  */
752 static HRESULT WINAPI IPersistStream_fnIsDirty(
753         IPersistStream*  iface)
754 {
755         _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
756
757         TRACE("(%p)\n", This);
758
759         return S_OK;
760 }
761 /************************************************************************
762  * IPersistStream_Load (IPersistStream)
763  */
764
765 static HRESULT WINAPI IPersistStream_fnLoad(
766         IPersistStream*  iface,
767         IStream*         pLoadStream)
768 {
769         PLINK_HEADER lpLinkHeader = HeapAlloc(GetProcessHeap(), 0, LINK_HEADER_SIZE);
770         ULONG   dwBytesRead;
771         DWORD   ret = E_FAIL;
772         char    sTemp[MAX_PATH];
773         
774         _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
775
776         TRACE("(%p)(%p)\n", This, pLoadStream);
777
778         if ( ! pLoadStream)
779         {
780           return STG_E_INVALIDPOINTER;
781         }
782         
783         IStream_AddRef (pLoadStream);
784         if(lpLinkHeader)
785         {
786           if (SUCCEEDED(IStream_Read(pLoadStream, lpLinkHeader, LINK_HEADER_SIZE, &dwBytesRead)))
787           {
788             if ((lpLinkHeader->MagicStr == 0x0000004CL) && IsEqualIID(&lpLinkHeader->MagicGuid, &CLSID_ShellLink))
789             {
790               lpLinkHeader = HeapReAlloc(GetProcessHeap(), 0, lpLinkHeader, LINK_HEADER_SIZE+lpLinkHeader->PidlSize);
791               if (lpLinkHeader)
792               {
793                 if (SUCCEEDED(IStream_Read(pLoadStream, &(lpLinkHeader->Pidl), lpLinkHeader->PidlSize, &dwBytesRead)))
794                 {
795                   if (pcheck (&lpLinkHeader->Pidl))
796                   {     
797                     This->pPidl = ILClone (&lpLinkHeader->Pidl);
798
799                     SHGetPathFromIDListA(&lpLinkHeader->Pidl, sTemp);
800                     This->sPath = HEAP_strdupA ( GetProcessHeap(), 0, sTemp);
801                   }
802                   This->wHotKey = lpLinkHeader->wHotKey;
803                   FileTimeToSystemTime (&lpLinkHeader->Time1, &This->time1);
804                   FileTimeToSystemTime (&lpLinkHeader->Time2, &This->time2);
805                   FileTimeToSystemTime (&lpLinkHeader->Time3, &This->time3);
806 #if 1
807                   GetDateFormatA(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&This->time1, NULL, sTemp, 256);
808                   TRACE("-- time1: %s\n", sTemp);
809                   GetDateFormatA(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&This->time2, NULL, sTemp, 256);
810                   TRACE("-- time1: %s\n", sTemp);
811                   GetDateFormatA(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&This->time3, NULL, sTemp, 256);
812                   TRACE("-- time1: %s\n", sTemp);
813                   pdump (This->pPidl);
814 #endif            
815                   ret = S_OK;
816                 }
817               }
818             }
819             else
820             {
821               WARN("stream contains no link!\n");
822             }
823           }
824         }
825
826         IStream_Release (pLoadStream);
827
828         pdump(This->pPidl);
829         
830         HeapFree(GetProcessHeap(), 0, lpLinkHeader);
831
832         return ret;
833 }
834
835 /************************************************************************
836  * IPersistStream_Save (IPersistStream)
837  */
838 static HRESULT WINAPI IPersistStream_fnSave(
839         IPersistStream*  iface,
840         IStream*         pOutStream,
841         BOOL             fClearDirty)
842 {
843         _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
844         
845         TRACE("(%p) %p %x\n", This, pOutStream, fClearDirty);
846
847         return E_NOTIMPL;
848 }
849
850 /************************************************************************
851  * IPersistStream_GetSizeMax (IPersistStream)
852  */
853 static HRESULT WINAPI IPersistStream_fnGetSizeMax(
854         IPersistStream*  iface,
855         ULARGE_INTEGER*  pcbSize)
856 {
857         _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
858         
859         TRACE("(%p)\n", This);
860
861         return E_NOTIMPL;
862 }
863
864 static ICOM_VTABLE(IPersistStream) psvt =
865 {
866         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
867         IPersistStream_fnQueryInterface,
868         IPersistStream_fnAddRef,
869         IPersistStream_fnRelease,
870         IPersistStream_fnGetClassID,
871         IPersistStream_fnIsDirty,
872         IPersistStream_fnLoad,
873         IPersistStream_fnSave,
874         IPersistStream_fnGetSizeMax
875 };
876
877 /**************************************************************************
878  *        IShellLink_Constructor
879  */
880 IShellLinkA * IShellLink_Constructor(BOOL bUnicode) 
881 {       IShellLinkImpl * sl;
882
883         sl = (IShellLinkImpl *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IShellLinkImpl));
884         sl->ref = 1;
885         ICOM_VTBL(sl) = &slvt;
886         sl->lpvtblw = &slvtw;
887         sl->lpvtblPersistFile = &pfvt;
888         sl->lpvtblPersistStream = &psvt;
889         
890         TRACE("(%p)->()\n",sl);
891         shell32_ObjCount++;
892         return bUnicode ? (IShellLinkA *) &(sl->lpvtblw) : (IShellLinkA *)sl;
893 }
894
895 /**************************************************************************
896  *  IShellLinkA_QueryInterface
897  */
898 static HRESULT WINAPI IShellLinkA_fnQueryInterface( IShellLinkA * iface, REFIID riid,  LPVOID *ppvObj)
899 {
900         ICOM_THIS(IShellLinkImpl, iface);
901         
902         TRACE("(%p)->(\n\tIID:\t%s)\n",This,debugstr_guid(riid));
903
904         *ppvObj = NULL;
905
906         if(IsEqualIID(riid, &IID_IUnknown) ||
907            IsEqualIID(riid, &IID_IShellLinkA))
908         {
909           *ppvObj = This;
910         }   
911         else if(IsEqualIID(riid, &IID_IShellLinkW))
912         {
913           *ppvObj = (IShellLinkW *)&(This->lpvtblw);
914         }   
915         else if(IsEqualIID(riid, &IID_IPersistFile))
916         {
917           *ppvObj = (IPersistFile *)&(This->lpvtblPersistFile);
918         }
919         else if(IsEqualIID(riid, &IID_IPersistStream))
920         {
921           *ppvObj = (IPersistStream *)&(This->lpvtblPersistStream);
922         }   
923
924         if(*ppvObj)
925         {
926           IUnknown_AddRef((IUnknown*)(*ppvObj));
927           TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
928           return S_OK;
929         }
930         TRACE("-- Interface: E_NOINTERFACE\n");
931         return E_NOINTERFACE;
932 }  
933 /******************************************************************************
934  * IShellLinkA_AddRef
935  */
936 static ULONG WINAPI IShellLinkA_fnAddRef(IShellLinkA * iface)
937 {
938         ICOM_THIS(IShellLinkImpl, iface);
939         
940         TRACE("(%p)->(count=%lu)\n",This,This->ref);
941
942         shell32_ObjCount++;
943         return ++(This->ref);
944 }
945 /******************************************************************************
946  *      IShellLinkA_Release
947  */
948 static ULONG WINAPI IShellLinkA_fnRelease(IShellLinkA * iface)
949 {
950         ICOM_THIS(IShellLinkImpl, iface);
951         
952         TRACE("(%p)->(count=%lu)\n",This,This->ref);
953
954         shell32_ObjCount--;
955         if (!--(This->ref)) 
956         { TRACE("-- destroying IShellLink(%p)\n",This);
957         
958           if (This->sIcoPath)
959             HeapFree(GetProcessHeap(), 0, This->sIcoPath);
960             
961           if (This->sArgs)
962             HeapFree(GetProcessHeap(), 0, This->sArgs);
963
964           if (This->sWorkDir)
965             HeapFree(GetProcessHeap(), 0, This->sWorkDir);
966             
967           if (This->sDescription)
968             HeapFree(GetProcessHeap(), 0, This->sDescription);
969
970           if (This->sPath)
971             HeapFree(GetProcessHeap(),0,This->sPath);
972
973           if (This->pPidl)
974             SHFree(This->pPidl);
975
976           if (This->lpFileStream)
977             IStream_Release(This->lpFileStream);
978         
979           This->iIcoNdx = 0;
980
981           HeapFree(GetProcessHeap(),0,This);
982           return 0;
983         }
984         return This->ref;
985 }
986
987 static HRESULT WINAPI IShellLinkA_fnGetPath(IShellLinkA * iface, LPSTR pszFile,INT cchMaxPath, WIN32_FIND_DATAA *pfd, DWORD fFlags)
988 {
989         ICOM_THIS(IShellLinkImpl, iface);
990         
991         TRACE("(%p)->(pfile=%p len=%u find_data=%p flags=%lu)(%s)\n",This, pszFile, cchMaxPath, pfd, fFlags, debugstr_a(This->sPath));
992
993         if (This->sPath)
994           lstrcpynA(pszFile,This->sPath, cchMaxPath);
995         else
996           return E_FAIL;
997
998         return NOERROR;
999 }
1000 static HRESULT WINAPI IShellLinkA_fnGetIDList(IShellLinkA * iface, LPITEMIDLIST * ppidl)
1001 {
1002         ICOM_THIS(IShellLinkImpl, iface);
1003         
1004         TRACE("(%p)->(ppidl=%p)\n",This, ppidl);
1005
1006         *ppidl = ILClone(This->pPidl);
1007         return NOERROR;
1008 }
1009 static HRESULT WINAPI IShellLinkA_fnSetIDList(IShellLinkA * iface, LPCITEMIDLIST pidl)
1010 {
1011         ICOM_THIS(IShellLinkImpl, iface);
1012         
1013         TRACE("(%p)->(pidl=%p)\n",This, pidl);
1014
1015         if (This->pPidl)
1016             SHFree(This->pPidl);
1017         This->pPidl = ILClone (pidl);
1018         return NOERROR;
1019 }
1020 static HRESULT WINAPI IShellLinkA_fnGetDescription(IShellLinkA * iface, LPSTR pszName,INT cchMaxName)
1021 {
1022         ICOM_THIS(IShellLinkImpl, iface);
1023         
1024         FIXME("(%p)->(%p len=%u)\n",This, pszName, cchMaxName);
1025         lstrcpynA(pszName,"Description, FIXME",cchMaxName);
1026         return NOERROR;
1027 }
1028 static HRESULT WINAPI IShellLinkA_fnSetDescription(IShellLinkA * iface, LPCSTR pszName)
1029 {
1030         ICOM_THIS(IShellLinkImpl, iface);
1031         
1032         TRACE("(%p)->(pName=%s)\n", This, pszName);
1033
1034         if (This->sDescription)
1035             HeapFree(GetProcessHeap(), 0, This->sDescription);
1036         if (!(This->sDescription = HEAP_strdupA(GetProcessHeap(), 0, pszName)))
1037             return E_OUTOFMEMORY;
1038
1039         return NOERROR;
1040 }
1041 static HRESULT WINAPI IShellLinkA_fnGetWorkingDirectory(IShellLinkA * iface, LPSTR pszDir,INT cchMaxPath)
1042 {
1043         ICOM_THIS(IShellLinkImpl, iface);
1044         
1045         TRACE("(%p)->(%p len=%u)\n", This, pszDir, cchMaxPath);
1046
1047         lstrcpynA( pszDir, This->sWorkDir ? This->sWorkDir : "", cchMaxPath );
1048
1049         return NOERROR;
1050 }
1051 static HRESULT WINAPI IShellLinkA_fnSetWorkingDirectory(IShellLinkA * iface, LPCSTR pszDir)
1052 {
1053         ICOM_THIS(IShellLinkImpl, iface);
1054         
1055         TRACE("(%p)->(dir=%s)\n",This, pszDir);
1056
1057         if (This->sWorkDir)
1058             HeapFree(GetProcessHeap(), 0, This->sWorkDir);
1059         if (!(This->sWorkDir = HEAP_strdupA(GetProcessHeap(), 0, pszDir)))
1060             return E_OUTOFMEMORY;
1061
1062         return NOERROR;
1063 }
1064 static HRESULT WINAPI IShellLinkA_fnGetArguments(IShellLinkA * iface, LPSTR pszArgs,INT cchMaxPath)
1065 {
1066         ICOM_THIS(IShellLinkImpl, iface);
1067         
1068         TRACE("(%p)->(%p len=%u)\n", This, pszArgs, cchMaxPath);
1069
1070         lstrcpynA( pszArgs, This->sArgs ? This->sArgs : "", cchMaxPath );
1071
1072         return NOERROR;
1073 }
1074 static HRESULT WINAPI IShellLinkA_fnSetArguments(IShellLinkA * iface, LPCSTR pszArgs)
1075 {
1076         ICOM_THIS(IShellLinkImpl, iface);
1077         
1078         TRACE("(%p)->(args=%s)\n",This, pszArgs);
1079
1080         if (This->sArgs)
1081             HeapFree(GetProcessHeap(), 0, This->sArgs);
1082         if (!(This->sArgs = HEAP_strdupA(GetProcessHeap(), 0, pszArgs)))
1083             return E_OUTOFMEMORY;
1084
1085         return NOERROR;
1086 }
1087 static HRESULT WINAPI IShellLinkA_fnGetHotkey(IShellLinkA * iface, WORD *pwHotkey)
1088 {
1089         ICOM_THIS(IShellLinkImpl, iface);
1090         
1091         TRACE("(%p)->(%p)(0x%08x)\n",This, pwHotkey, This->wHotKey);
1092
1093         *pwHotkey = This->wHotKey;
1094
1095         return NOERROR;
1096 }
1097 static HRESULT WINAPI IShellLinkA_fnSetHotkey(IShellLinkA * iface, WORD wHotkey)
1098 {
1099         ICOM_THIS(IShellLinkImpl, iface);
1100         
1101         TRACE("(%p)->(hotkey=%x)\n",This, wHotkey);
1102         
1103         This->wHotKey = wHotkey;
1104
1105         return NOERROR;
1106 }
1107 static HRESULT WINAPI IShellLinkA_fnGetShowCmd(IShellLinkA * iface, INT *piShowCmd)
1108 {
1109         ICOM_THIS(IShellLinkImpl, iface);
1110         
1111         FIXME("(%p)->(%p)\n",This, piShowCmd);
1112         *piShowCmd=0;
1113         return NOERROR;
1114 }
1115 static HRESULT WINAPI IShellLinkA_fnSetShowCmd(IShellLinkA * iface, INT iShowCmd)
1116 {
1117         ICOM_THIS(IShellLinkImpl, iface);
1118         
1119         FIXME("(%p)->(showcmd=%x)\n",This, iShowCmd);
1120         return NOERROR;
1121 }
1122 static HRESULT WINAPI IShellLinkA_fnGetIconLocation(IShellLinkA * iface, LPSTR pszIconPath,INT cchIconPath,INT *piIcon)
1123 {
1124         ICOM_THIS(IShellLinkImpl, iface);
1125         
1126         TRACE("(%p)->(%p len=%u iicon=%p)\n", This, pszIconPath, cchIconPath, piIcon);
1127
1128         lstrcpynA( pszIconPath, This->sIcoPath ? This->sIcoPath : "", cchIconPath );
1129         *piIcon = This->iIcoNdx;
1130
1131         return NOERROR;
1132 }
1133 static HRESULT WINAPI IShellLinkA_fnSetIconLocation(IShellLinkA * iface, LPCSTR pszIconPath,INT iIcon)
1134 {
1135         ICOM_THIS(IShellLinkImpl, iface);
1136         
1137         TRACE("(%p)->(path=%s iicon=%u)\n",This, pszIconPath, iIcon);
1138         
1139         if (This->sIcoPath)
1140             HeapFree(GetProcessHeap(), 0, This->sIcoPath);
1141         if (!(This->sIcoPath = HEAP_strdupA(GetProcessHeap(), 0, pszIconPath)))
1142             return E_OUTOFMEMORY;       
1143         This->iIcoNdx = iIcon;
1144         
1145         return NOERROR;
1146 }
1147 static HRESULT WINAPI IShellLinkA_fnSetRelativePath(IShellLinkA * iface, LPCSTR pszPathRel, DWORD dwReserved)
1148 {
1149         ICOM_THIS(IShellLinkImpl, iface);
1150         
1151         FIXME("(%p)->(path=%s %lx)\n",This, pszPathRel, dwReserved);
1152         return NOERROR;
1153 }
1154 static HRESULT WINAPI IShellLinkA_fnResolve(IShellLinkA * iface, HWND hwnd, DWORD fFlags)
1155 {
1156         ICOM_THIS(IShellLinkImpl, iface);
1157         
1158         FIXME("(%p)->(hwnd=%x flags=%lx)\n",This, hwnd, fFlags);
1159         return NOERROR;
1160 }
1161 static HRESULT WINAPI IShellLinkA_fnSetPath(IShellLinkA * iface, LPCSTR pszFile)
1162 {
1163         ICOM_THIS(IShellLinkImpl, iface);
1164         
1165         TRACE("(%p)->(path=%s)\n",This, pszFile);
1166
1167         if (This->sPath)
1168             HeapFree(GetProcessHeap(), 0, This->sPath);
1169         if (!(This->sPath = HEAP_strdupA(GetProcessHeap(), 0, pszFile)))
1170             return E_OUTOFMEMORY;
1171         
1172         return NOERROR;
1173 }
1174
1175 /**************************************************************************
1176 * IShellLink Implementation
1177 */
1178
1179 static ICOM_VTABLE(IShellLinkA) slvt = 
1180 {       
1181         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1182         IShellLinkA_fnQueryInterface,
1183         IShellLinkA_fnAddRef,
1184         IShellLinkA_fnRelease,
1185         IShellLinkA_fnGetPath,
1186         IShellLinkA_fnGetIDList,
1187         IShellLinkA_fnSetIDList,
1188         IShellLinkA_fnGetDescription,
1189         IShellLinkA_fnSetDescription,
1190         IShellLinkA_fnGetWorkingDirectory,
1191         IShellLinkA_fnSetWorkingDirectory,
1192         IShellLinkA_fnGetArguments,
1193         IShellLinkA_fnSetArguments,
1194         IShellLinkA_fnGetHotkey,
1195         IShellLinkA_fnSetHotkey,
1196         IShellLinkA_fnGetShowCmd,
1197         IShellLinkA_fnSetShowCmd,
1198         IShellLinkA_fnGetIconLocation,
1199         IShellLinkA_fnSetIconLocation,
1200         IShellLinkA_fnSetRelativePath,
1201         IShellLinkA_fnResolve,
1202         IShellLinkA_fnSetPath
1203 };
1204
1205
1206 /**************************************************************************
1207  *  IShellLinkW_fnQueryInterface
1208  */
1209 static HRESULT WINAPI IShellLinkW_fnQueryInterface(
1210   IShellLinkW * iface, REFIID riid, LPVOID *ppvObj)
1211 {
1212         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1213         
1214         return IShellLinkA_QueryInterface((IShellLinkA*)This, riid, ppvObj);
1215 }
1216
1217 /******************************************************************************
1218  * IShellLinkW_fnAddRef
1219  */
1220 static ULONG WINAPI IShellLinkW_fnAddRef(IShellLinkW * iface)
1221 {
1222         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1223         
1224         TRACE("(%p)->(count=%lu)\n",This,This->ref);
1225
1226         return IShellLinkA_AddRef((IShellLinkA*)This);
1227 }
1228 /******************************************************************************
1229  * IShellLinkW_fnRelease
1230  */
1231
1232 static ULONG WINAPI IShellLinkW_fnRelease(IShellLinkW * iface)
1233 {
1234         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1235         
1236         TRACE("(%p)->(count=%lu)\n",This,This->ref);
1237
1238         return IShellLinkA_Release((IShellLinkA*)This);
1239 }
1240
1241 static HRESULT WINAPI IShellLinkW_fnGetPath(IShellLinkW * iface, LPWSTR pszFile,INT cchMaxPath, WIN32_FIND_DATAA *pfd, DWORD fFlags)
1242 {
1243         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1244         
1245         FIXME("(%p)->(pfile=%p len=%u find_data=%p flags=%lu)\n",This, pszFile, cchMaxPath, pfd, fFlags);
1246         MultiByteToWideChar( CP_ACP, 0, "c:\\foo.bar", -1, pszFile, cchMaxPath );
1247         return NOERROR;
1248 }
1249
1250 static HRESULT WINAPI IShellLinkW_fnGetIDList(IShellLinkW * iface, LPITEMIDLIST * ppidl)
1251 {
1252         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1253         
1254         FIXME("(%p)->(ppidl=%p)\n",This, ppidl);
1255         *ppidl = _ILCreateDesktop();
1256         return NOERROR;
1257 }
1258
1259 static HRESULT WINAPI IShellLinkW_fnSetIDList(IShellLinkW * iface, LPCITEMIDLIST pidl)
1260 {
1261         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1262         
1263         FIXME("(%p)->(pidl=%p)\n",This, pidl);
1264         return NOERROR;
1265 }
1266
1267 static HRESULT WINAPI IShellLinkW_fnGetDescription(IShellLinkW * iface, LPWSTR pszName,INT cchMaxName)
1268 {
1269         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1270         
1271         FIXME("(%p)->(%p len=%u)\n",This, pszName, cchMaxName);
1272         MultiByteToWideChar( CP_ACP, 0, "Description, FIXME", -1, pszName, cchMaxName );
1273         return NOERROR;
1274 }
1275
1276 static HRESULT WINAPI IShellLinkW_fnSetDescription(IShellLinkW * iface, LPCWSTR pszName)
1277 {
1278         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1279         
1280         TRACE("(%p)->(desc=%s)\n",This, debugstr_w(pszName));
1281
1282         if (This->sDescription)
1283             HeapFree(GetProcessHeap(), 0, This->sDescription);
1284         if (!(This->sDescription = HEAP_strdupWtoA(GetProcessHeap(), 0, pszName)))
1285             return E_OUTOFMEMORY;
1286                 
1287         return NOERROR;
1288 }
1289
1290 static HRESULT WINAPI IShellLinkW_fnGetWorkingDirectory(IShellLinkW * iface, LPWSTR pszDir,INT cchMaxPath)
1291 {
1292         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1293         
1294         TRACE("(%p)->(%p len %u)\n", This, pszDir, cchMaxPath);
1295
1296         MultiByteToWideChar( CP_ACP, 0, This->sWorkDir ? This->sWorkDir : "", -1, pszDir, cchMaxPath );
1297
1298         return NOERROR;
1299 }
1300
1301 static HRESULT WINAPI IShellLinkW_fnSetWorkingDirectory(IShellLinkW * iface, LPCWSTR pszDir)
1302 {
1303         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1304         
1305         TRACE("(%p)->(dir=%s)\n",This, debugstr_w(pszDir));
1306
1307         if (This->sWorkDir)
1308             HeapFree(GetProcessHeap(), 0, This->sWorkDir);
1309         if (!(This->sWorkDir = HEAP_strdupWtoA(GetProcessHeap(), 0, pszDir)))
1310             return E_OUTOFMEMORY;
1311
1312         return NOERROR;
1313 }
1314
1315 static HRESULT WINAPI IShellLinkW_fnGetArguments(IShellLinkW * iface, LPWSTR pszArgs,INT cchMaxPath)
1316 {
1317         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1318         
1319         TRACE("(%p)->(%p len=%u)\n", This, pszArgs, cchMaxPath);
1320
1321         MultiByteToWideChar( CP_ACP, 0, This->sArgs ? This->sArgs : "", -1, pszArgs, cchMaxPath );
1322
1323         return NOERROR;
1324 }
1325
1326 static HRESULT WINAPI IShellLinkW_fnSetArguments(IShellLinkW * iface, LPCWSTR pszArgs)
1327 {
1328         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1329         
1330         TRACE("(%p)->(args=%s)\n",This, debugstr_w(pszArgs));
1331         
1332         if (This->sArgs)
1333             HeapFree(GetProcessHeap(), 0, This->sArgs);
1334         if (!(This->sArgs = HEAP_strdupWtoA(GetProcessHeap(), 0, pszArgs)))
1335             return E_OUTOFMEMORY;
1336         
1337         return NOERROR;
1338 }
1339
1340 static HRESULT WINAPI IShellLinkW_fnGetHotkey(IShellLinkW * iface, WORD *pwHotkey)
1341 {
1342         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1343         
1344         FIXME("(%p)->(%p)\n",This, pwHotkey);
1345         *pwHotkey=0x0;
1346         return NOERROR;
1347 }
1348
1349 static HRESULT WINAPI IShellLinkW_fnSetHotkey(IShellLinkW * iface, WORD wHotkey)
1350 {
1351         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1352         
1353         FIXME("(%p)->(hotkey=%x)\n",This, wHotkey);
1354         return NOERROR;
1355 }
1356
1357 static HRESULT WINAPI IShellLinkW_fnGetShowCmd(IShellLinkW * iface, INT *piShowCmd)
1358 {
1359         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1360         
1361         FIXME("(%p)->(%p)\n",This, piShowCmd);
1362         *piShowCmd=0;
1363         return NOERROR;
1364 }
1365
1366 static HRESULT WINAPI IShellLinkW_fnSetShowCmd(IShellLinkW * iface, INT iShowCmd)
1367 {
1368         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1369         
1370         FIXME("(%p)->(showcmd=%x)\n",This, iShowCmd);
1371         return NOERROR;
1372 }
1373
1374 static HRESULT WINAPI IShellLinkW_fnGetIconLocation(IShellLinkW * iface, LPWSTR pszIconPath,INT cchIconPath,INT *piIcon)
1375 {
1376         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1377         
1378         TRACE("(%p)->(%p len=%u iicon=%p)\n", This, pszIconPath, cchIconPath, piIcon);
1379
1380         MultiByteToWideChar( CP_ACP, 0, This->sIcoPath ? This->sIcoPath : "", -1, pszIconPath, cchIconPath );
1381         *piIcon = This->iIcoNdx;
1382
1383         return NOERROR;
1384 }
1385
1386 static HRESULT WINAPI IShellLinkW_fnSetIconLocation(IShellLinkW * iface, LPCWSTR pszIconPath,INT iIcon)
1387 {
1388         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1389         
1390         TRACE("(%p)->(path=%s iicon=%u)\n",This, debugstr_w(pszIconPath), iIcon);
1391
1392         if (This->sIcoPath)
1393             HeapFree(GetProcessHeap(), 0, This->sIcoPath);
1394         if (!(This->sIcoPath = HEAP_strdupWtoA(GetProcessHeap(), 0, pszIconPath)))
1395             return E_OUTOFMEMORY;       
1396         This->iIcoNdx = iIcon;
1397
1398         return NOERROR;
1399 }
1400
1401 static HRESULT WINAPI IShellLinkW_fnSetRelativePath(IShellLinkW * iface, LPCWSTR pszPathRel, DWORD dwReserved)
1402 {
1403         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1404         
1405         FIXME("(%p)->(path=%s %lx)\n",This, debugstr_w(pszPathRel), dwReserved);
1406         return NOERROR;
1407 }
1408
1409 static HRESULT WINAPI IShellLinkW_fnResolve(IShellLinkW * iface, HWND hwnd, DWORD fFlags)
1410 {
1411         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1412         
1413         FIXME("(%p)->(hwnd=%x flags=%lx)\n",This, hwnd, fFlags);
1414         return NOERROR;
1415 }
1416
1417 static HRESULT WINAPI IShellLinkW_fnSetPath(IShellLinkW * iface, LPCWSTR pszFile)
1418 {
1419         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1420         
1421         TRACE("(%p)->(path=%s)\n",This, debugstr_w(pszFile));
1422         
1423         if (This->sPath)
1424             HeapFree(GetProcessHeap(), 0, This->sPath);
1425         if (!(This->sPath = HEAP_strdupWtoA(GetProcessHeap(), 0, pszFile)))
1426             return E_OUTOFMEMORY;       
1427         
1428         return NOERROR;
1429 }
1430
1431 /**************************************************************************
1432 * IShellLinkW Implementation
1433 */
1434
1435 static ICOM_VTABLE(IShellLinkW) slvtw = 
1436 {       
1437         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1438         IShellLinkW_fnQueryInterface,
1439         IShellLinkW_fnAddRef,
1440         IShellLinkW_fnRelease,
1441         IShellLinkW_fnGetPath,
1442         IShellLinkW_fnGetIDList,
1443         IShellLinkW_fnSetIDList,
1444         IShellLinkW_fnGetDescription,
1445         IShellLinkW_fnSetDescription,
1446         IShellLinkW_fnGetWorkingDirectory,
1447         IShellLinkW_fnSetWorkingDirectory,
1448         IShellLinkW_fnGetArguments,
1449         IShellLinkW_fnSetArguments,
1450         IShellLinkW_fnGetHotkey,
1451         IShellLinkW_fnSetHotkey,
1452         IShellLinkW_fnGetShowCmd,
1453         IShellLinkW_fnSetShowCmd,
1454         IShellLinkW_fnGetIconLocation,
1455         IShellLinkW_fnSetIconLocation,
1456         IShellLinkW_fnSetRelativePath,
1457         IShellLinkW_fnResolve,
1458         IShellLinkW_fnSetPath
1459 };
1460