Added/modified documentation for function arguments.
[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         goto error1;
347
348     if (nIndex)
349         hResInfo = FindResourceA(hModule, MAKEINTRESOURCEA(nIndex), RT_GROUP_ICONA);
350     else
351         if (EnumResourceNamesA(hModule, RT_GROUP_ICONA, &EnumResNameProc, (LONG) &hResInfo))
352             goto error2;
353
354     if (!hResInfo)
355         goto error2;
356
357     if (!(hResData = LoadResource(hModule, hResInfo)))
358         goto error2;
359     if (!(pIconDir = LockResource(hResData)))
360         goto error3;
361
362     for (i = 0; i < pIconDir->idCount; i++)
363         if ((pIconDir->idEntries[i].bHeight * pIconDir->idEntries[i].bWidth) > nMax)
364         {
365             lpName = MAKEINTRESOURCEA(pIconDir->idEntries[i].nID);
366             nMax = pIconDir->idEntries[i].bHeight * pIconDir->idEntries[i].bWidth;
367         }
368
369     FreeResource(hResData);
370
371     if (!(hResInfo = FindResourceA(hModule, lpName, RT_ICONA)))
372         goto error2;
373     if (!(hResData = LoadResource(hModule, hResInfo)))
374         goto error2;
375     if (!(pIcon = LockResource(hResData)))
376         goto error3;
377
378     if(!SaveIconResAsXPM(pIcon, szXPMFileName))
379         goto error3;
380
381     FreeResource(hResData);
382     FreeLibrary(hModule);
383
384     return 1;
385
386  error3:
387     FreeResource(hResData);
388  error2:
389     FreeLibrary(hModule);
390  error1:
391     return 0;
392 }
393
394 static int ExtractFromICO(const char *szFileName, const char *szXPMFileName)
395 {
396     FILE *fICOFile;
397     ICONDIR iconDir;
398     ICONDIRENTRY *pIconDirEntry;
399     int nMax = 0;
400     int nIndex = 0;
401     void *pIcon;
402     int i;
403
404     if (!(fICOFile = fopen(szFileName, "r")))
405         goto error1;
406
407     if (fread(&iconDir, sizeof (ICONDIR), 1, fICOFile) != 1)
408         goto error2;
409     if ((iconDir.idReserved != 0) || (iconDir.idType != 1))
410         goto error2;
411
412     if ((pIconDirEntry = malloc(iconDir.idCount * sizeof (ICONDIRENTRY))) == NULL)
413         goto error2;
414     if (fread(pIconDirEntry, sizeof (ICONDIRENTRY), iconDir.idCount, fICOFile) != iconDir.idCount)
415         goto error3;
416
417     for (i = 0; i < iconDir.idCount; i++)
418         if ((pIconDirEntry[i].bHeight * pIconDirEntry[i].bWidth) > nMax)
419         {
420             nIndex = i;
421             nMax = pIconDirEntry[i].bHeight * pIconDirEntry[i].bWidth;
422         }
423     if ((pIcon = malloc(pIconDirEntry[nIndex].dwBytesInRes)) == NULL)
424         goto error3;
425     if (fseek(fICOFile, pIconDirEntry[nIndex].dwImageOffset, SEEK_SET))
426         goto error4;
427     if (fread(pIcon, pIconDirEntry[nIndex].dwBytesInRes, 1, fICOFile) != 1)
428         goto error4;
429
430     if(!SaveIconResAsXPM(pIcon, szXPMFileName))
431         goto error4;
432
433     free(pIcon);
434     free(pIconDirEntry);
435     fclose(fICOFile);
436
437     return 1;
438
439  error4:
440     free(pIcon);
441  error3:
442     free(pIconDirEntry);
443  error2:
444     fclose(fICOFile);
445  error1:
446     return 0;
447 }
448
449 /* get the Unix file name for a given path, allocating the string */
450 inline static char *get_unix_file_name( const char *dos )
451 {
452     char buffer[MAX_PATH];
453
454     if (!wine_get_unix_file_name( dos, buffer, sizeof(buffer) )) return NULL;
455     return HEAP_strdupA( GetProcessHeap(), 0, buffer );
456 }
457
458 static BOOL create_default_icon( const char *filename )
459 {
460     FILE *fXPM;
461     int i;
462
463     if (!(fXPM = fopen(filename, "w"))) return FALSE;
464     fprintf(fXPM, "/* XPM */\nstatic char * icon[] = {");
465     for (i = 0; i < sizeof(wine_xpm)/sizeof(wine_xpm[0]); i++)
466         fprintf( fXPM, "\n\"%s\",", wine_xpm[i]);
467     fprintf( fXPM, "};\n" );
468     fclose( fXPM );
469     return TRUE;
470 }
471
472 /* extract an icon from an exe or icon file; helper for IPersistFile_fnSave */
473 static char *extract_icon( const char *path, int index )
474 {
475     char *filename = HEAP_strdupA( GetProcessHeap(), 0, tmpnam(NULL) );
476     if (ExtractFromEXEDLL( path, index, filename )) return filename;
477     if (ExtractFromICO( path, filename )) return filename;
478     if (create_default_icon( filename )) return filename;
479     HeapFree( GetProcessHeap(), 0, filename );
480     return NULL;
481 }
482
483
484 static HRESULT WINAPI IPersistFile_fnSave(IPersistFile* iface, LPCOLESTR pszFileName, BOOL fRemember)
485 {
486     HRESULT ret = NOERROR;
487     int pid, status;
488     char buffer[MAX_PATH], buff2[MAX_PATH];
489     char *filename, *link_name, *p;
490     char *shell_link_app = NULL;
491     char *icon_name = NULL;
492     char *path_name = NULL;
493     char *work_dir = NULL;
494     BOOL bDesktop;
495     HKEY hkey;
496
497     _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface);
498
499     TRACE("(%p)->(%s)\n",This,debugstr_w(pszFileName));
500
501     if (!pszFileName || !This->sPath)
502         return ERROR_UNKNOWN;
503
504     /* check for .exe extension */
505     if (!(p = strrchr( This->sPath, '.' ))) return NOERROR;
506     if (strchr( p, '\\' ) || strchr( p, '/' )) return NOERROR;
507     if (strcasecmp( p, ".exe" )) return NOERROR;
508
509     /* check if ShellLinker configured */
510     buffer[0] = 0;
511     if (!RegOpenKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\Wine",
512                         0, KEY_ALL_ACCESS, &hkey ))
513     {
514         DWORD type, count = sizeof(buffer);
515         if (RegQueryValueExA( hkey, "ShellLinker", 0, &type, buffer, &count )) buffer[0] = 0;
516         RegCloseKey( hkey );
517     }
518     if (!*buffer) return NOERROR;
519     shell_link_app = HEAP_strdupA( GetProcessHeap(), 0, buffer );
520
521     if (!WideCharToMultiByte( CP_ACP, 0, pszFileName, -1, buffer, sizeof(buffer), NULL, NULL))
522         return ERROR_UNKNOWN;
523     GetFullPathNameA( buffer, sizeof(buff2), buff2, NULL );
524     filename = HEAP_strdupA( GetProcessHeap(), 0, buff2 );
525
526     if (SHGetSpecialFolderPathA( 0, buffer, CSIDL_STARTUP, FALSE ))
527     {
528         /* ignore startup for now */
529         if (!strncasecmp( filename, buffer, strlen(buffer) )) goto done;
530     }
531     if (SHGetSpecialFolderPathA( 0, buffer, CSIDL_DESKTOPDIRECTORY, FALSE ))
532     {
533         if (!strncasecmp( filename, buffer, strlen(buffer) ))
534         {
535             link_name = filename + strlen(buffer);
536             bDesktop = TRUE;
537             goto found;
538         }
539     }
540     if (SHGetSpecialFolderPathA( 0, buffer, CSIDL_STARTMENU, FALSE ))
541     {
542         if (!strncasecmp( filename, buffer, strlen(buffer) ))
543         {
544             link_name = filename + strlen(buffer);
545             bDesktop = FALSE;
546             goto found;
547         }
548     }
549     goto done;
550
551  found:
552     /* make link name a Unix name */
553     for (p = link_name; *p; p++) if (*p == '\\') *p = '/';
554     /* strip leading slashes */
555     while (*link_name == '/') link_name++;
556     /* remove extension */
557     if ((p = strrchr( link_name, '.' ))) *p = 0;
558
559     /* convert app path name */
560     path_name = get_unix_file_name( This->sPath );
561
562     /* convert app working dir */
563     if (This->sWorkDir) work_dir = get_unix_file_name( This->sWorkDir );
564
565     /* extract the icon */
566     if (!(icon_name = extract_icon( This->sIcoPath ? This->sIcoPath : This->sPath,
567                                     This->iIcoNdx ))) goto done;
568
569     TRACE("linker app='%s' link='%s' mode=%s path='%s' args='%s' icon='%s' workdir='%s' descr='%s'\n",
570         shell_link_app, link_name, bDesktop ? "desktop" : "menu", path_name,
571         This->sArgs ? This->sArgs : "", icon_name, work_dir ? work_dir : "",
572         This->sDescription ? This->sDescription : "" );
573
574     if ((pid = fork()) == -1) goto done;
575     if (!pid)
576     {
577         int pos = 0;
578         char *argv[20];
579         argv[pos++] = shell_link_app;
580         argv[pos++] = "--link";
581         argv[pos++] = link_name;
582         argv[pos++] = "--path";
583         argv[pos++] = path_name;
584         argv[pos++] = bDesktop ? "--desktop" : "--menu";
585         if (This->sArgs)
586         {
587             argv[pos++] = "--args";
588             argv[pos++] = This->sArgs;
589         }
590         if (icon_name)
591         {
592             argv[pos++] = "--icon";
593             argv[pos++] = icon_name;
594         }
595         if (This->sWorkDir)
596         {
597             argv[pos++] = "--workdir";
598             argv[pos++] = This->sWorkDir;
599         }
600         if (This->sDescription)
601         {
602             argv[pos++] = "--descr";
603             argv[pos++] = This->sDescription;
604         }
605         argv[pos] = NULL;
606         execvp( shell_link_app, argv );
607         _exit(1);
608     }
609
610     while (waitpid( pid, &status, 0 ) == -1)
611     {
612         if (errno != EINTR)
613         {
614             ret = ERROR_UNKNOWN;
615             goto done;
616         }
617     }
618     if (status) ret = E_ACCESSDENIED;
619
620  done:
621     if (icon_name) unlink( icon_name );
622     HeapFree( GetProcessHeap(), 0, shell_link_app );
623     HeapFree( GetProcessHeap(), 0, filename );
624     HeapFree( GetProcessHeap(), 0, icon_name );
625     HeapFree( GetProcessHeap(), 0, path_name );
626     HeapFree( GetProcessHeap(), 0, work_dir );
627     return ret;
628 }
629
630 static HRESULT WINAPI IPersistFile_fnSaveCompleted(IPersistFile* iface, LPCOLESTR pszFileName)
631 {
632         _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface);
633         FIXME("(%p)->(%s)\n",This,debugstr_w(pszFileName));
634         return NOERROR;
635 }
636 static HRESULT WINAPI IPersistFile_fnGetCurFile(IPersistFile* iface, LPOLESTR *ppszFileName)
637 {
638         _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface);
639         FIXME("(%p)\n",This);
640         return NOERROR;
641 }
642
643 static ICOM_VTABLE(IPersistFile) pfvt = 
644 {
645         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
646         IPersistFile_fnQueryInterface,
647         IPersistFile_fnAddRef,
648         IPersistFile_fnRelease,
649         IPersistFile_fnGetClassID,
650         IPersistFile_fnIsDirty,
651         IPersistFile_fnLoad,
652         IPersistFile_fnSave,
653         IPersistFile_fnSaveCompleted,
654         IPersistFile_fnGetCurFile
655 };
656
657 /************************************************************************
658  * IPersistStream_QueryInterface
659  */
660 static HRESULT WINAPI IPersistStream_fnQueryInterface(
661         IPersistStream* iface,
662         REFIID     riid,
663         VOID**     ppvoid)
664 {
665         _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
666
667         TRACE("(%p)\n",This);
668
669         return IShellLinkA_QueryInterface((IShellLinkA*)This, riid, ppvoid);
670 }
671
672 /************************************************************************
673  * IPersistStream_Release
674  */
675 static ULONG WINAPI IPersistStream_fnRelease(
676         IPersistStream* iface)
677 {
678         _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
679
680         TRACE("(%p)\n",This);
681
682         return IShellLinkA_Release((IShellLinkA*)This);
683 }
684
685 /************************************************************************
686  * IPersistStream_AddRef
687  */
688 static ULONG WINAPI IPersistStream_fnAddRef(
689         IPersistStream* iface)
690 {
691         _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
692
693         TRACE("(%p)\n",This);
694
695         return IShellLinkA_AddRef((IShellLinkA*)This);
696
697
698 /************************************************************************
699  * IPersistStream_GetClassID
700  *
701  */
702 static HRESULT WINAPI IPersistStream_fnGetClassID(
703         IPersistStream* iface,
704         CLSID* pClassID)
705 {
706         _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
707
708         TRACE("(%p)\n", This);
709
710         if (pClassID==0)
711           return E_POINTER;
712
713 /*      memcpy(pClassID, &CLSID_???, sizeof(CLSID_???)); */
714
715         return S_OK;
716 }
717
718 /************************************************************************
719  * IPersistStream_IsDirty (IPersistStream)
720  */
721 static HRESULT WINAPI IPersistStream_fnIsDirty(
722         IPersistStream*  iface)
723 {
724         _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
725
726         TRACE("(%p)\n", This);
727
728         return S_OK;
729 }
730 /************************************************************************
731  * IPersistStream_Load (IPersistStream)
732  */
733
734 static HRESULT WINAPI IPersistStream_fnLoad(
735         IPersistStream*  iface,
736         IStream*         pLoadStream)
737 {
738         PLINK_HEADER lpLinkHeader = HeapAlloc(GetProcessHeap(), 0, LINK_HEADER_SIZE);
739         ULONG   dwBytesRead;
740         DWORD   ret = E_FAIL;
741         char    sTemp[MAX_PATH];
742         
743         _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
744
745         TRACE("(%p)(%p)\n", This, pLoadStream);
746
747         if ( ! pLoadStream)
748         {
749           return STG_E_INVALIDPOINTER;
750         }
751         
752         IStream_AddRef (pLoadStream);
753         if(lpLinkHeader)
754         {
755           if (SUCCEEDED(IStream_Read(pLoadStream, lpLinkHeader, LINK_HEADER_SIZE, &dwBytesRead)))
756           {
757             if ((lpLinkHeader->MagicStr == 0x0000004CL) && IsEqualIID(&lpLinkHeader->MagicGuid, &CLSID_ShellLink))
758             {
759               lpLinkHeader = HeapReAlloc(GetProcessHeap(), 0, lpLinkHeader, LINK_HEADER_SIZE+lpLinkHeader->PidlSize);
760               if (lpLinkHeader)
761               {
762                 if (SUCCEEDED(IStream_Read(pLoadStream, &(lpLinkHeader->Pidl), lpLinkHeader->PidlSize, &dwBytesRead)))
763                 {
764                   if (pcheck (&lpLinkHeader->Pidl))
765                   {     
766                     This->pPidl = ILClone (&lpLinkHeader->Pidl);
767
768                     SHGetPathFromIDListA(&lpLinkHeader->Pidl, sTemp);
769                     This->sPath = HEAP_strdupA ( GetProcessHeap(), 0, sTemp);
770                   }
771                   This->wHotKey = lpLinkHeader->wHotKey;
772                   FileTimeToSystemTime (&lpLinkHeader->Time1, &This->time1);
773                   FileTimeToSystemTime (&lpLinkHeader->Time2, &This->time2);
774                   FileTimeToSystemTime (&lpLinkHeader->Time3, &This->time3);
775 #if 1
776                   GetDateFormatA(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&This->time1, NULL, sTemp, 256);
777                   TRACE("-- time1: %s\n", sTemp);
778                   GetDateFormatA(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&This->time2, NULL, sTemp, 256);
779                   TRACE("-- time1: %s\n", sTemp);
780                   GetDateFormatA(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&This->time3, NULL, sTemp, 256);
781                   TRACE("-- time1: %s\n", sTemp);
782                   pdump (This->pPidl);
783 #endif            
784                   ret = S_OK;
785                 }
786               }
787             }
788             else
789             {
790               WARN("stream contains no link!\n");
791             }
792           }
793         }
794
795         IStream_Release (pLoadStream);
796
797         pdump(This->pPidl);
798         
799         HeapFree(GetProcessHeap(), 0, lpLinkHeader);
800
801         return ret;
802 }
803
804 /************************************************************************
805  * IPersistStream_Save (IPersistStream)
806  */
807 static HRESULT WINAPI IPersistStream_fnSave(
808         IPersistStream*  iface,
809         IStream*         pOutStream,
810         BOOL             fClearDirty)
811 {
812         _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
813         
814         TRACE("(%p) %p %x\n", This, pOutStream, fClearDirty);
815
816         return E_NOTIMPL;
817 }
818
819 /************************************************************************
820  * IPersistStream_GetSizeMax (IPersistStream)
821  */
822 static HRESULT WINAPI IPersistStream_fnGetSizeMax(
823         IPersistStream*  iface,
824         ULARGE_INTEGER*  pcbSize)
825 {
826         _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
827         
828         TRACE("(%p)\n", This);
829
830         return E_NOTIMPL;
831 }
832
833 static ICOM_VTABLE(IPersistStream) psvt =
834 {
835         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
836         IPersistStream_fnQueryInterface,
837         IPersistStream_fnAddRef,
838         IPersistStream_fnRelease,
839         IPersistStream_fnGetClassID,
840         IPersistStream_fnIsDirty,
841         IPersistStream_fnLoad,
842         IPersistStream_fnSave,
843         IPersistStream_fnGetSizeMax
844 };
845
846 /**************************************************************************
847  *        IShellLink_Constructor
848  */
849 IShellLinkA * IShellLink_Constructor(BOOL bUnicode) 
850 {       IShellLinkImpl * sl;
851
852         sl = (IShellLinkImpl *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IShellLinkImpl));
853         sl->ref = 1;
854         ICOM_VTBL(sl) = &slvt;
855         sl->lpvtblw = &slvtw;
856         sl->lpvtblPersistFile = &pfvt;
857         sl->lpvtblPersistStream = &psvt;
858         
859         TRACE("(%p)->()\n",sl);
860         shell32_ObjCount++;
861         return bUnicode ? (IShellLinkA *) &(sl->lpvtblw) : (IShellLinkA *)sl;
862 }
863
864 /**************************************************************************
865  *  IShellLinkA_QueryInterface
866  */
867 static HRESULT WINAPI IShellLinkA_fnQueryInterface( IShellLinkA * iface, REFIID riid,  LPVOID *ppvObj)
868 {
869         ICOM_THIS(IShellLinkImpl, iface);
870         
871         TRACE("(%p)->(\n\tIID:\t%s)\n",This,debugstr_guid(riid));
872
873         *ppvObj = NULL;
874
875         if(IsEqualIID(riid, &IID_IUnknown) ||
876            IsEqualIID(riid, &IID_IShellLinkA))
877         {
878           *ppvObj = This;
879         }   
880         else if(IsEqualIID(riid, &IID_IShellLinkW))
881         {
882           *ppvObj = (IShellLinkW *)&(This->lpvtblw);
883         }   
884         else if(IsEqualIID(riid, &IID_IPersistFile))
885         {
886           *ppvObj = (IPersistFile *)&(This->lpvtblPersistFile);
887         }
888         else if(IsEqualIID(riid, &IID_IPersistStream))
889         {
890           *ppvObj = (IPersistStream *)&(This->lpvtblPersistStream);
891         }   
892
893         if(*ppvObj)
894         {
895           IUnknown_AddRef((IUnknown*)(*ppvObj));
896           TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
897           return S_OK;
898         }
899         TRACE("-- Interface: E_NOINTERFACE\n");
900         return E_NOINTERFACE;
901 }  
902 /******************************************************************************
903  * IShellLinkA_AddRef
904  */
905 static ULONG WINAPI IShellLinkA_fnAddRef(IShellLinkA * iface)
906 {
907         ICOM_THIS(IShellLinkImpl, iface);
908         
909         TRACE("(%p)->(count=%lu)\n",This,This->ref);
910
911         shell32_ObjCount++;
912         return ++(This->ref);
913 }
914 /******************************************************************************
915  *      IShellLinkA_Release
916  */
917 static ULONG WINAPI IShellLinkA_fnRelease(IShellLinkA * iface)
918 {
919         ICOM_THIS(IShellLinkImpl, iface);
920         
921         TRACE("(%p)->(count=%lu)\n",This,This->ref);
922
923         shell32_ObjCount--;
924         if (!--(This->ref)) 
925         { TRACE("-- destroying IShellLink(%p)\n",This);
926         
927           if (This->sIcoPath)
928             HeapFree(GetProcessHeap(), 0, This->sIcoPath);
929             
930           if (This->sArgs)
931             HeapFree(GetProcessHeap(), 0, This->sArgs);
932
933           if (This->sWorkDir)
934             HeapFree(GetProcessHeap(), 0, This->sWorkDir);
935             
936           if (This->sDescription)
937             HeapFree(GetProcessHeap(), 0, This->sDescription);
938
939           if (This->sPath)
940             HeapFree(GetProcessHeap(),0,This->sPath);
941
942           if (This->pPidl)
943             SHFree(This->pPidl);
944
945           if (This->lpFileStream)
946             IStream_Release(This->lpFileStream);
947         
948           This->iIcoNdx = 0;
949
950           HeapFree(GetProcessHeap(),0,This);
951           return 0;
952         }
953         return This->ref;
954 }
955
956 static HRESULT WINAPI IShellLinkA_fnGetPath(IShellLinkA * iface, LPSTR pszFile,INT cchMaxPath, WIN32_FIND_DATAA *pfd, DWORD fFlags)
957 {
958         ICOM_THIS(IShellLinkImpl, iface);
959         
960         TRACE("(%p)->(pfile=%p len=%u find_data=%p flags=%lu)(%s)\n",This, pszFile, cchMaxPath, pfd, fFlags, debugstr_a(This->sPath));
961
962         if (This->sPath)
963           lstrcpynA(pszFile,This->sPath, cchMaxPath);
964         else
965           return E_FAIL;
966
967         return NOERROR;
968 }
969 static HRESULT WINAPI IShellLinkA_fnGetIDList(IShellLinkA * iface, LPITEMIDLIST * ppidl)
970 {
971         ICOM_THIS(IShellLinkImpl, iface);
972         
973         TRACE("(%p)->(ppidl=%p)\n",This, ppidl);
974
975         *ppidl = ILClone(This->pPidl);
976         return NOERROR;
977 }
978 static HRESULT WINAPI IShellLinkA_fnSetIDList(IShellLinkA * iface, LPCITEMIDLIST pidl)
979 {
980         ICOM_THIS(IShellLinkImpl, iface);
981         
982         TRACE("(%p)->(pidl=%p)\n",This, pidl);
983
984         if (This->pPidl)
985             SHFree(This->pPidl);
986         This->pPidl = ILClone (pidl);
987         return NOERROR;
988 }
989 static HRESULT WINAPI IShellLinkA_fnGetDescription(IShellLinkA * iface, LPSTR pszName,INT cchMaxName)
990 {
991         ICOM_THIS(IShellLinkImpl, iface);
992         
993         FIXME("(%p)->(%p len=%u)\n",This, pszName, cchMaxName);
994         lstrcpynA(pszName,"Description, FIXME",cchMaxName);
995         return NOERROR;
996 }
997 static HRESULT WINAPI IShellLinkA_fnSetDescription(IShellLinkA * iface, LPCSTR pszName)
998 {
999         ICOM_THIS(IShellLinkImpl, iface);
1000         
1001         TRACE("(%p)->(pName=%s)\n", This, pszName);
1002
1003         if (This->sDescription)
1004             HeapFree(GetProcessHeap(), 0, This->sDescription);
1005         if (!(This->sDescription = HEAP_strdupA(GetProcessHeap(), 0, pszName)))
1006             return E_OUTOFMEMORY;
1007
1008         return NOERROR;
1009 }
1010 static HRESULT WINAPI IShellLinkA_fnGetWorkingDirectory(IShellLinkA * iface, LPSTR pszDir,INT cchMaxPath)
1011 {
1012         ICOM_THIS(IShellLinkImpl, iface);
1013         
1014         FIXME("(%p)->()\n",This);
1015         lstrcpynA(pszDir,"c:\\", cchMaxPath);
1016         return NOERROR;
1017 }
1018 static HRESULT WINAPI IShellLinkA_fnSetWorkingDirectory(IShellLinkA * iface, LPCSTR pszDir)
1019 {
1020         ICOM_THIS(IShellLinkImpl, iface);
1021         
1022         TRACE("(%p)->(dir=%s)\n",This, pszDir);
1023
1024         if (This->sWorkDir)
1025             HeapFree(GetProcessHeap(), 0, This->sWorkDir);
1026         if (!(This->sWorkDir = HEAP_strdupA(GetProcessHeap(), 0, pszDir)))
1027             return E_OUTOFMEMORY;
1028
1029         return NOERROR;
1030 }
1031 static HRESULT WINAPI IShellLinkA_fnGetArguments(IShellLinkA * iface, LPSTR pszArgs,INT cchMaxPath)
1032 {
1033         ICOM_THIS(IShellLinkImpl, iface);
1034         
1035         FIXME("(%p)->(%p len=%u)\n",This, pszArgs, cchMaxPath);
1036         lstrcpynA(pszArgs, "", cchMaxPath);
1037         return NOERROR;
1038 }
1039 static HRESULT WINAPI IShellLinkA_fnSetArguments(IShellLinkA * iface, LPCSTR pszArgs)
1040 {
1041         ICOM_THIS(IShellLinkImpl, iface);
1042         
1043         TRACE("(%p)->(args=%s)\n",This, pszArgs);
1044
1045         if (This->sArgs)
1046             HeapFree(GetProcessHeap(), 0, This->sArgs);
1047         if (!(This->sArgs = HEAP_strdupA(GetProcessHeap(), 0, pszArgs)))
1048             return E_OUTOFMEMORY;
1049
1050         return NOERROR;
1051 }
1052 static HRESULT WINAPI IShellLinkA_fnGetHotkey(IShellLinkA * iface, WORD *pwHotkey)
1053 {
1054         ICOM_THIS(IShellLinkImpl, iface);
1055         
1056         TRACE("(%p)->(%p)(0x%08x)\n",This, pwHotkey, This->wHotKey);
1057
1058         *pwHotkey = This->wHotKey;
1059
1060         return NOERROR;
1061 }
1062 static HRESULT WINAPI IShellLinkA_fnSetHotkey(IShellLinkA * iface, WORD wHotkey)
1063 {
1064         ICOM_THIS(IShellLinkImpl, iface);
1065         
1066         TRACE("(%p)->(hotkey=%x)\n",This, wHotkey);
1067         
1068         This->wHotKey = wHotkey;
1069
1070         return NOERROR;
1071 }
1072 static HRESULT WINAPI IShellLinkA_fnGetShowCmd(IShellLinkA * iface, INT *piShowCmd)
1073 {
1074         ICOM_THIS(IShellLinkImpl, iface);
1075         
1076         FIXME("(%p)->(%p)\n",This, piShowCmd);
1077         *piShowCmd=0;
1078         return NOERROR;
1079 }
1080 static HRESULT WINAPI IShellLinkA_fnSetShowCmd(IShellLinkA * iface, INT iShowCmd)
1081 {
1082         ICOM_THIS(IShellLinkImpl, iface);
1083         
1084         FIXME("(%p)->(showcmd=%x)\n",This, iShowCmd);
1085         return NOERROR;
1086 }
1087 static HRESULT WINAPI IShellLinkA_fnGetIconLocation(IShellLinkA * iface, LPSTR pszIconPath,INT cchIconPath,INT *piIcon)
1088 {
1089         ICOM_THIS(IShellLinkImpl, iface);
1090         
1091         FIXME("(%p)->(%p len=%u iicon=%p)\n",This, pszIconPath, cchIconPath, piIcon);
1092         lstrcpynA(pszIconPath,"shell32.dll",cchIconPath);
1093         *piIcon=1;
1094         return NOERROR;
1095 }
1096 static HRESULT WINAPI IShellLinkA_fnSetIconLocation(IShellLinkA * iface, LPCSTR pszIconPath,INT iIcon)
1097 {
1098         ICOM_THIS(IShellLinkImpl, iface);
1099         
1100         TRACE("(%p)->(path=%s iicon=%u)\n",This, pszIconPath, iIcon);
1101         
1102         if (This->sIcoPath)
1103             HeapFree(GetProcessHeap(), 0, This->sIcoPath);
1104         if (!(This->sIcoPath = HEAP_strdupA(GetProcessHeap(), 0, pszIconPath)))
1105             return E_OUTOFMEMORY;       
1106         This->iIcoNdx = iIcon;
1107         
1108         return NOERROR;
1109 }
1110 static HRESULT WINAPI IShellLinkA_fnSetRelativePath(IShellLinkA * iface, LPCSTR pszPathRel, DWORD dwReserved)
1111 {
1112         ICOM_THIS(IShellLinkImpl, iface);
1113         
1114         FIXME("(%p)->(path=%s %lx)\n",This, pszPathRel, dwReserved);
1115         return NOERROR;
1116 }
1117 static HRESULT WINAPI IShellLinkA_fnResolve(IShellLinkA * iface, HWND hwnd, DWORD fFlags)
1118 {
1119         ICOM_THIS(IShellLinkImpl, iface);
1120         
1121         FIXME("(%p)->(hwnd=%x flags=%lx)\n",This, hwnd, fFlags);
1122         return NOERROR;
1123 }
1124 static HRESULT WINAPI IShellLinkA_fnSetPath(IShellLinkA * iface, LPCSTR pszFile)
1125 {
1126         ICOM_THIS(IShellLinkImpl, iface);
1127         
1128         TRACE("(%p)->(path=%s)\n",This, pszFile);
1129
1130         if (This->sPath)
1131             HeapFree(GetProcessHeap(), 0, This->sPath);
1132         if (!(This->sPath = HEAP_strdupA(GetProcessHeap(), 0, pszFile)))
1133             return E_OUTOFMEMORY;
1134         
1135         return NOERROR;
1136 }
1137
1138 /**************************************************************************
1139 * IShellLink Implementation
1140 */
1141
1142 static ICOM_VTABLE(IShellLinkA) slvt = 
1143 {       
1144         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1145         IShellLinkA_fnQueryInterface,
1146         IShellLinkA_fnAddRef,
1147         IShellLinkA_fnRelease,
1148         IShellLinkA_fnGetPath,
1149         IShellLinkA_fnGetIDList,
1150         IShellLinkA_fnSetIDList,
1151         IShellLinkA_fnGetDescription,
1152         IShellLinkA_fnSetDescription,
1153         IShellLinkA_fnGetWorkingDirectory,
1154         IShellLinkA_fnSetWorkingDirectory,
1155         IShellLinkA_fnGetArguments,
1156         IShellLinkA_fnSetArguments,
1157         IShellLinkA_fnGetHotkey,
1158         IShellLinkA_fnSetHotkey,
1159         IShellLinkA_fnGetShowCmd,
1160         IShellLinkA_fnSetShowCmd,
1161         IShellLinkA_fnGetIconLocation,
1162         IShellLinkA_fnSetIconLocation,
1163         IShellLinkA_fnSetRelativePath,
1164         IShellLinkA_fnResolve,
1165         IShellLinkA_fnSetPath
1166 };
1167
1168
1169 /**************************************************************************
1170  *  IShellLinkW_fnQueryInterface
1171  */
1172 static HRESULT WINAPI IShellLinkW_fnQueryInterface(
1173   IShellLinkW * iface, REFIID riid, LPVOID *ppvObj)
1174 {
1175         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1176         
1177         return IShellLinkA_QueryInterface((IShellLinkA*)This, riid, ppvObj);
1178 }
1179
1180 /******************************************************************************
1181  * IShellLinkW_fnAddRef
1182  */
1183 static ULONG WINAPI IShellLinkW_fnAddRef(IShellLinkW * iface)
1184 {
1185         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1186         
1187         TRACE("(%p)->(count=%lu)\n",This,This->ref);
1188
1189         return IShellLinkA_AddRef((IShellLinkA*)This);
1190 }
1191 /******************************************************************************
1192  * IShellLinkW_fnRelease
1193  */
1194
1195 static ULONG WINAPI IShellLinkW_fnRelease(IShellLinkW * iface)
1196 {
1197         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1198         
1199         TRACE("(%p)->(count=%lu)\n",This,This->ref);
1200
1201         return IShellLinkA_Release((IShellLinkA*)This);
1202 }
1203
1204 static HRESULT WINAPI IShellLinkW_fnGetPath(IShellLinkW * iface, LPWSTR pszFile,INT cchMaxPath, WIN32_FIND_DATAA *pfd, DWORD fFlags)
1205 {
1206         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1207         
1208         FIXME("(%p)->(pfile=%p len=%u find_data=%p flags=%lu)\n",This, pszFile, cchMaxPath, pfd, fFlags);
1209         MultiByteToWideChar( CP_ACP, 0, "c:\\foo.bar", -1, pszFile, cchMaxPath );
1210         return NOERROR;
1211 }
1212
1213 static HRESULT WINAPI IShellLinkW_fnGetIDList(IShellLinkW * iface, LPITEMIDLIST * ppidl)
1214 {
1215         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1216         
1217         FIXME("(%p)->(ppidl=%p)\n",This, ppidl);
1218         *ppidl = _ILCreateDesktop();
1219         return NOERROR;
1220 }
1221
1222 static HRESULT WINAPI IShellLinkW_fnSetIDList(IShellLinkW * iface, LPCITEMIDLIST pidl)
1223 {
1224         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1225         
1226         FIXME("(%p)->(pidl=%p)\n",This, pidl);
1227         return NOERROR;
1228 }
1229
1230 static HRESULT WINAPI IShellLinkW_fnGetDescription(IShellLinkW * iface, LPWSTR pszName,INT cchMaxName)
1231 {
1232         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1233         
1234         FIXME("(%p)->(%p len=%u)\n",This, pszName, cchMaxName);
1235         MultiByteToWideChar( CP_ACP, 0, "Description, FIXME", -1, pszName, cchMaxName );
1236         return NOERROR;
1237 }
1238
1239 static HRESULT WINAPI IShellLinkW_fnSetDescription(IShellLinkW * iface, LPCWSTR pszName)
1240 {
1241         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1242         
1243         TRACE("(%p)->(desc=%s)\n",This, debugstr_w(pszName));
1244
1245         if (This->sDescription)
1246             HeapFree(GetProcessHeap(), 0, This->sDescription);
1247         if (!(This->sDescription = HEAP_strdupWtoA(GetProcessHeap(), 0, pszName)))
1248             return E_OUTOFMEMORY;
1249                 
1250         return NOERROR;
1251 }
1252
1253 static HRESULT WINAPI IShellLinkW_fnGetWorkingDirectory(IShellLinkW * iface, LPWSTR pszDir,INT cchMaxPath)
1254 {
1255         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1256         
1257         FIXME("(%p)->()\n",This);
1258         MultiByteToWideChar( CP_ACP, 0, "c:\\", -1, pszDir, cchMaxPath );
1259         return NOERROR;
1260 }
1261
1262 static HRESULT WINAPI IShellLinkW_fnSetWorkingDirectory(IShellLinkW * iface, LPCWSTR pszDir)
1263 {
1264         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1265         
1266         TRACE("(%p)->(dir=%s)\n",This, debugstr_w(pszDir));
1267
1268         if (This->sWorkDir)
1269             HeapFree(GetProcessHeap(), 0, This->sWorkDir);
1270         if (!(This->sWorkDir = HEAP_strdupWtoA(GetProcessHeap(), 0, pszDir)))
1271             return E_OUTOFMEMORY;
1272
1273         return NOERROR;
1274 }
1275
1276 static HRESULT WINAPI IShellLinkW_fnGetArguments(IShellLinkW * iface, LPWSTR pszArgs,INT cchMaxPath)
1277 {
1278         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1279         
1280         FIXME("(%p)->(%p len=%u)\n",This, pszArgs, cchMaxPath);
1281         pszArgs[0] = 0;
1282         return NOERROR;
1283 }
1284
1285 static HRESULT WINAPI IShellLinkW_fnSetArguments(IShellLinkW * iface, LPCWSTR pszArgs)
1286 {
1287         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1288         
1289         TRACE("(%p)->(args=%s)\n",This, debugstr_w(pszArgs));
1290         
1291         if (This->sArgs)
1292             HeapFree(GetProcessHeap(), 0, This->sArgs);
1293         if (!(This->sArgs = HEAP_strdupWtoA(GetProcessHeap(), 0, pszArgs)))
1294             return E_OUTOFMEMORY;
1295         
1296         return NOERROR;
1297 }
1298
1299 static HRESULT WINAPI IShellLinkW_fnGetHotkey(IShellLinkW * iface, WORD *pwHotkey)
1300 {
1301         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1302         
1303         FIXME("(%p)->(%p)\n",This, pwHotkey);
1304         *pwHotkey=0x0;
1305         return NOERROR;
1306 }
1307
1308 static HRESULT WINAPI IShellLinkW_fnSetHotkey(IShellLinkW * iface, WORD wHotkey)
1309 {
1310         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1311         
1312         FIXME("(%p)->(hotkey=%x)\n",This, wHotkey);
1313         return NOERROR;
1314 }
1315
1316 static HRESULT WINAPI IShellLinkW_fnGetShowCmd(IShellLinkW * iface, INT *piShowCmd)
1317 {
1318         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1319         
1320         FIXME("(%p)->(%p)\n",This, piShowCmd);
1321         *piShowCmd=0;
1322         return NOERROR;
1323 }
1324
1325 static HRESULT WINAPI IShellLinkW_fnSetShowCmd(IShellLinkW * iface, INT iShowCmd)
1326 {
1327         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1328         
1329         FIXME("(%p)->(showcmd=%x)\n",This, iShowCmd);
1330         return NOERROR;
1331 }
1332
1333 static HRESULT WINAPI IShellLinkW_fnGetIconLocation(IShellLinkW * iface, LPWSTR pszIconPath,INT cchIconPath,INT *piIcon)
1334 {
1335         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1336         
1337         FIXME("(%p)->(%p len=%u iicon=%p)\n",This, pszIconPath, cchIconPath, piIcon);
1338         MultiByteToWideChar( CP_ACP, 0, "shell32.dll", -1, pszIconPath, cchIconPath );
1339         *piIcon=1;
1340         return NOERROR;
1341 }
1342
1343 static HRESULT WINAPI IShellLinkW_fnSetIconLocation(IShellLinkW * iface, LPCWSTR pszIconPath,INT iIcon)
1344 {
1345         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1346         
1347         TRACE("(%p)->(path=%s iicon=%u)\n",This, debugstr_w(pszIconPath), iIcon);
1348
1349         if (This->sIcoPath)
1350             HeapFree(GetProcessHeap(), 0, This->sIcoPath);
1351         if (!(This->sIcoPath = HEAP_strdupWtoA(GetProcessHeap(), 0, pszIconPath)))
1352             return E_OUTOFMEMORY;       
1353         This->iIcoNdx = iIcon;
1354
1355         return NOERROR;
1356 }
1357
1358 static HRESULT WINAPI IShellLinkW_fnSetRelativePath(IShellLinkW * iface, LPCWSTR pszPathRel, DWORD dwReserved)
1359 {
1360         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1361         
1362         FIXME("(%p)->(path=%s %lx)\n",This, debugstr_w(pszPathRel), dwReserved);
1363         return NOERROR;
1364 }
1365
1366 static HRESULT WINAPI IShellLinkW_fnResolve(IShellLinkW * iface, HWND hwnd, DWORD fFlags)
1367 {
1368         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1369         
1370         FIXME("(%p)->(hwnd=%x flags=%lx)\n",This, hwnd, fFlags);
1371         return NOERROR;
1372 }
1373
1374 static HRESULT WINAPI IShellLinkW_fnSetPath(IShellLinkW * iface, LPCWSTR pszFile)
1375 {
1376         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1377         
1378         TRACE("(%p)->(path=%s)\n",This, debugstr_w(pszFile));
1379         
1380         if (This->sPath)
1381             HeapFree(GetProcessHeap(), 0, This->sPath);
1382         if (!(This->sPath = HEAP_strdupWtoA(GetProcessHeap(), 0, pszFile)))
1383             return E_OUTOFMEMORY;       
1384         
1385         return NOERROR;
1386 }
1387
1388 /**************************************************************************
1389 * IShellLinkW Implementation
1390 */
1391
1392 static ICOM_VTABLE(IShellLinkW) slvtw = 
1393 {       
1394         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1395         IShellLinkW_fnQueryInterface,
1396         IShellLinkW_fnAddRef,
1397         IShellLinkW_fnRelease,
1398         IShellLinkW_fnGetPath,
1399         IShellLinkW_fnGetIDList,
1400         IShellLinkW_fnSetIDList,
1401         IShellLinkW_fnGetDescription,
1402         IShellLinkW_fnSetDescription,
1403         IShellLinkW_fnGetWorkingDirectory,
1404         IShellLinkW_fnSetWorkingDirectory,
1405         IShellLinkW_fnGetArguments,
1406         IShellLinkW_fnSetArguments,
1407         IShellLinkW_fnGetHotkey,
1408         IShellLinkW_fnSetHotkey,
1409         IShellLinkW_fnGetShowCmd,
1410         IShellLinkW_fnSetShowCmd,
1411         IShellLinkW_fnGetIconLocation,
1412         IShellLinkW_fnSetIconLocation,
1413         IShellLinkW_fnSetRelativePath,
1414         IShellLinkW_fnResolve,
1415         IShellLinkW_fnSetPath
1416 };
1417