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