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