Deal with the case of loading an empty PIDL from a stream better in
[wine] / dlls / shell32 / shelllink.c
1 /*
2  *
3  *      Copyright 1997  Marcus Meissner
4  *      Copyright 1998  Juergen Schmied
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include <ctype.h>
24 #include <string.h>
25 #include <stdio.h>
26 #ifdef HAVE_UNISTD_H
27 # include <unistd.h>
28 #endif
29 #include <errno.h>
30 #include <limits.h>
31 #ifdef HAVE_SYS_WAIT_H
32 # include <sys/wait.h>
33 #endif
34 #include "wine/debug.h"
35 #include "wine/port.h"
36 #include "winerror.h"
37 #include "winbase.h"
38 #include "winnls.h"
39 #include "winreg.h"
40
41 #include "shlobj.h"
42 #include "undocshell.h"
43
44 #include "heap.h"
45 #include "pidl.h"
46 #include "shell32_main.h"
47 #include "shlguid.h"
48
49 WINE_DEFAULT_DEBUG_CHANNEL(shell);
50
51 /* link file formats */
52
53 /* flag1: lnk elements: simple link has 0x0B */
54 #define SCF_PIDL   1
55 #define SCF_NORMAL 2
56 #define SCF_DESCRIPTION 4
57 #define SCF_RELATIVE 8
58 #define SCF_WORKDIR 0x10
59 #define SCF_ARGS 0x20
60 #define SCF_CUSTOMICON 0x40
61 #define SCF_UNC 0x80
62 #define SCF_UNICODE 0x1000
63
64 #include "pshpack1.h"
65
66 typedef struct _LINK_HEADER
67 {
68         DWORD    dwSize;        /* 0x00 size of the header - 0x4c */
69         GUID     MagicGuid;     /* 0x04 is CLSID_ShellLink */
70         DWORD    dwFlags;       /* 0x14 describes elements following */
71         DWORD    dwFileAttr;    /* 0x18 attributes of the target file */
72         FILETIME Time1;         /* 0x1c */
73         FILETIME Time2;         /* 0x24 */
74         FILETIME Time3;         /* 0x2c */
75         DWORD    dwFileLength;  /* 0x34 File length */
76         DWORD    nIcon;         /* 0x38 icon number */
77         DWORD   fStartup;       /* 0x3c startup type */
78         DWORD   wHotKey;        /* 0x40 hotkey */
79         DWORD   Unknown5;       /* 0x44 */
80         DWORD   Unknown6;       /* 0x48 */
81 } LINK_HEADER, * PLINK_HEADER;
82
83 #define SHLINK_LOCAL  0
84 #define SHLINK_REMOTE 1
85
86 typedef struct _LOCATION_INFO
87 {
88     DWORD  dwTotalSize;
89     DWORD  dwHeaderSize;
90     DWORD  dwFlags;
91     DWORD  dwVolTableOfs;
92     DWORD  dwLocalPathOfs;
93     DWORD  dwNetworkVolTableOfs;
94     DWORD  dwFinalPathOfs;
95 } LOCATION_INFO;
96
97 typedef struct _LOCAL_VOLUME_INFO
98 {
99     DWORD dwSize;
100     DWORD dwType;
101     DWORD dwVolSerial;
102     DWORD dwVolLabelOfs;
103 } LOCAL_VOLUME_INFO;
104
105 #include "poppack.h"
106
107 static ICOM_VTABLE(IShellLinkA)         slvt;
108 static ICOM_VTABLE(IShellLinkW)         slvtw;
109 static ICOM_VTABLE(IPersistFile)        pfvt;
110 static ICOM_VTABLE(IPersistStream)      psvt;
111
112 /* IShellLink Implementation */
113
114 typedef struct
115 {
116         ICOM_VFIELD(IShellLinkA);
117         DWORD                           ref;
118
119         ICOM_VTABLE(IShellLinkW)*       lpvtblw;
120         ICOM_VTABLE(IPersistFile)*      lpvtblPersistFile;
121         ICOM_VTABLE(IPersistStream)*    lpvtblPersistStream;
122
123         /* data structures according to the informations in the lnk */
124         LPITEMIDLIST    pPidl;
125         WORD            wHotKey;
126         SYSTEMTIME      time1;
127         SYSTEMTIME      time2;
128         SYSTEMTIME      time3;
129
130         DWORD         iShowCmd;
131         LPWSTR        sIcoPath;
132         INT           iIcoNdx;
133         LPWSTR        sPath;
134         LPWSTR        sArgs;
135         LPWSTR        sWorkDir;
136         LPWSTR        sDescription;
137         LPWSTR        sPathRel;
138 } IShellLinkImpl;
139
140 #define _IShellLinkW_Offset ((int)(&(((IShellLinkImpl*)0)->lpvtblw)))
141 #define _ICOM_THIS_From_IShellLinkW(class, name) class* This = (class*)(((char*)name)-_IShellLinkW_Offset)
142
143 #define _IPersistFile_Offset ((int)(&(((IShellLinkImpl*)0)->lpvtblPersistFile)))
144 #define _ICOM_THIS_From_IPersistFile(class, name) class* This = (class*)(((char*)name)-_IPersistFile_Offset)
145
146 #define _IPersistStream_Offset ((int)(&(((IShellLinkImpl*)0)->lpvtblPersistStream)))
147 #define _ICOM_THIS_From_IPersistStream(class, name) class* This = (class*)(((char*)name)-_IPersistStream_Offset)
148 #define _IPersistStream_From_ICOM_THIS(class, name) class* StreamThis = (class*)(((char*)name)+_IPersistStream_Offset)
149
150
151 /* strdup on the process heap */
152 inline static LPWSTR HEAP_strdupAtoW( HANDLE heap, DWORD flags, LPCSTR str)
153 {
154     INT len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
155     LPWSTR p = HeapAlloc( heap, flags, len*sizeof (WCHAR) );
156     if( !p )
157         return p;
158     MultiByteToWideChar( CP_ACP, 0, str, -1, p, len );
159     return p;
160 }
161
162
163 /**************************************************************************
164  *  IPersistFile_QueryInterface
165  */
166 static HRESULT WINAPI IPersistFile_fnQueryInterface(
167         IPersistFile* iface,
168         REFIID riid,
169         LPVOID *ppvObj)
170 {
171         _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface);
172
173         TRACE("(%p)\n",This);
174
175         return IShellLinkA_QueryInterface((IShellLinkA*)This, riid, ppvObj);
176 }
177
178 /******************************************************************************
179  * IPersistFile_AddRef
180  */
181 static ULONG WINAPI IPersistFile_fnAddRef(IPersistFile* iface)
182 {
183         _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface);
184
185         TRACE("(%p)->(count=%lu)\n",This,This->ref);
186
187         return IShellLinkA_AddRef((IShellLinkA*)This);
188 }
189 /******************************************************************************
190  * IPersistFile_Release
191  */
192 static ULONG WINAPI IPersistFile_fnRelease(IPersistFile* iface)
193 {
194         _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface);
195
196         TRACE("(%p)->(count=%lu)\n",This,This->ref);
197
198         return IShellLinkA_Release((IShellLinkA*)This);
199 }
200
201 static HRESULT WINAPI IPersistFile_fnGetClassID(IPersistFile* iface, CLSID *pClassID)
202 {
203         _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface);
204         FIXME("(%p)\n",This);
205         return NOERROR;
206 }
207 static HRESULT WINAPI IPersistFile_fnIsDirty(IPersistFile* iface)
208 {
209         _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface);
210         FIXME("(%p)\n",This);
211         return NOERROR;
212 }
213 static HRESULT WINAPI IPersistFile_fnLoad(IPersistFile* iface, LPCOLESTR pszFileName, DWORD dwMode)
214 {
215         _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface);
216         _IPersistStream_From_ICOM_THIS(IPersistStream, This);
217         HRESULT r;
218         IStream *stm;
219
220         TRACE("(%p, %s)\n",This, debugstr_w(pszFileName));
221
222         r = CreateStreamOnFile(pszFileName, dwMode, &stm);
223         if( SUCCEEDED( r ) )
224         {
225             r = IPersistStream_Load(StreamThis, stm);
226             IStream_Release( stm );
227         }
228
229         return r;
230 }
231
232 static BOOL StartLinkProcessor( LPCOLESTR szLink )
233 {
234     const WCHAR szFormat[] = {'w','i','n','e','m','e','n','u','b','u','i','l','d','e','r','.','e','x','e',
235                               ' ','-','r',' ','"','%','s','"',0 };
236     LONG len;
237     LPWSTR buffer;
238     STARTUPINFOW si;
239     PROCESS_INFORMATION pi;
240
241     len = sizeof(szFormat) + lstrlenW( szLink ) * sizeof(WCHAR);
242     buffer = HeapAlloc( GetProcessHeap(), 0, len );
243     if( !buffer )
244         return FALSE;
245
246     wsprintfW( buffer, szFormat, szLink );
247
248     TRACE("starting %s\n",debugstr_w(buffer));
249
250     memset(&si, 0, sizeof(si));
251     si.cb = sizeof(si);
252     if (!CreateProcessW( NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) return FALSE;
253
254     /* wait for a while to throttle the creation of linker processes */
255     if( WAIT_OBJECT_0 != WaitForSingleObject( pi.hProcess, 10000 ) )
256         WARN("Timed out waiting for shell linker\n");
257
258     CloseHandle( pi.hProcess );
259     CloseHandle( pi.hThread );
260
261     return TRUE;
262 }
263
264 static HRESULT WINAPI IPersistFile_fnSave(IPersistFile* iface, LPCOLESTR pszFileName, BOOL fRemember)
265 {
266     _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface);
267     _IPersistStream_From_ICOM_THIS(IPersistStream, This);
268     HRESULT r;
269     IStream *stm;
270
271     TRACE("(%p)->(%s)\n",This,debugstr_w(pszFileName));
272
273     if (!pszFileName || !This->sPath)
274         return ERROR_UNKNOWN;
275
276     r = CreateStreamOnFile(pszFileName, STGM_READWRITE | STGM_CREATE, &stm);
277     if( SUCCEEDED( r ) )
278     {
279         r = IPersistStream_Save(StreamThis, stm, FALSE);
280         IStream_Release( stm );
281
282         if( SUCCEEDED( r ) )
283             StartLinkProcessor( pszFileName );
284         else
285         {
286             DeleteFileW( pszFileName );
287             WARN("Failed to create shortcut %s\n", debugstr_w(pszFileName) );
288         }
289     }
290
291     return r;
292 }
293
294 static HRESULT WINAPI IPersistFile_fnSaveCompleted(IPersistFile* iface, LPCOLESTR pszFileName)
295 {
296         _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface);
297         FIXME("(%p)->(%s)\n",This,debugstr_w(pszFileName));
298         return NOERROR;
299 }
300 static HRESULT WINAPI IPersistFile_fnGetCurFile(IPersistFile* iface, LPOLESTR *ppszFileName)
301 {
302         _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface);
303         FIXME("(%p)\n",This);
304         return NOERROR;
305 }
306
307 static ICOM_VTABLE(IPersistFile) pfvt =
308 {
309         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
310         IPersistFile_fnQueryInterface,
311         IPersistFile_fnAddRef,
312         IPersistFile_fnRelease,
313         IPersistFile_fnGetClassID,
314         IPersistFile_fnIsDirty,
315         IPersistFile_fnLoad,
316         IPersistFile_fnSave,
317         IPersistFile_fnSaveCompleted,
318         IPersistFile_fnGetCurFile
319 };
320
321 /************************************************************************
322  * IPersistStream_QueryInterface
323  */
324 static HRESULT WINAPI IPersistStream_fnQueryInterface(
325         IPersistStream* iface,
326         REFIID     riid,
327         VOID**     ppvoid)
328 {
329         _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
330
331         TRACE("(%p)\n",This);
332
333         return IShellLinkA_QueryInterface((IShellLinkA*)This, riid, ppvoid);
334 }
335
336 /************************************************************************
337  * IPersistStream_Release
338  */
339 static ULONG WINAPI IPersistStream_fnRelease(
340         IPersistStream* iface)
341 {
342         _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
343
344         TRACE("(%p)\n",This);
345
346         return IShellLinkA_Release((IShellLinkA*)This);
347 }
348
349 /************************************************************************
350  * IPersistStream_AddRef
351  */
352 static ULONG WINAPI IPersistStream_fnAddRef(
353         IPersistStream* iface)
354 {
355         _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
356
357         TRACE("(%p)\n",This);
358
359         return IShellLinkA_AddRef((IShellLinkA*)This);
360 }
361
362 /************************************************************************
363  * IPersistStream_GetClassID
364  *
365  */
366 static HRESULT WINAPI IPersistStream_fnGetClassID(
367         IPersistStream* iface,
368         CLSID* pClassID)
369 {
370         _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
371
372         TRACE("(%p)\n", This);
373
374         if (pClassID==0)
375           return E_POINTER;
376
377 /*      memcpy(pClassID, &CLSID_???, sizeof(CLSID_???)); */
378
379         return S_OK;
380 }
381
382 /************************************************************************
383  * IPersistStream_IsDirty (IPersistStream)
384  */
385 static HRESULT WINAPI IPersistStream_fnIsDirty(
386         IPersistStream*  iface)
387 {
388         _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
389
390         TRACE("(%p)\n", This);
391
392         return S_OK;
393 }
394
395
396 static HRESULT Stream_LoadString( IStream* stm, BOOL unicode, LPWSTR *pstr )
397 {
398     DWORD count;
399     USHORT len;
400     LPVOID temp;
401     LPWSTR str;
402     HRESULT r;
403
404     TRACE("%p\n", stm);
405
406     count = 0;
407     r = IStream_Read(stm, &len, sizeof(len), &count);
408     if ( FAILED (r) || ( count != sizeof(len) ) )
409         return E_FAIL;
410
411     if( unicode )
412         len *= sizeof (WCHAR);
413
414     TRACE("reading %d\n", len);
415     temp = HeapAlloc(GetProcessHeap(), 0, len+sizeof(WCHAR));
416     if( !temp )
417         return E_OUTOFMEMORY;
418     count = 0;
419     r = IStream_Read(stm, temp, len, &count);
420     if( FAILED (r) || ( count != len ) )
421     {
422         HeapFree( GetProcessHeap(), 0, temp );
423         return E_FAIL;
424     }
425
426     TRACE("read %s\n", debugstr_an(temp,len));
427
428     /* convert to unicode if necessary */
429     if( !unicode )
430     {
431         count = MultiByteToWideChar( CP_ACP, 0, (LPSTR) temp, len, NULL, 0 );
432         str = HeapAlloc( GetProcessHeap(), 0, (count+1)*sizeof (WCHAR) );
433         if( str )
434             MultiByteToWideChar( CP_ACP, 0, (LPSTR) temp, len, str, count );
435         HeapFree( GetProcessHeap(), 0, temp );
436     }
437     else
438     {
439         count /= 2;
440         str = (LPWSTR) temp;
441     }
442     str[count] = 0;
443
444     *pstr = str;
445
446     return S_OK;
447 }
448
449 static HRESULT Stream_LoadLocation( IStream* stm )
450 {
451     DWORD size;
452     ULONG count;
453     HRESULT r;
454     LOCATION_INFO *loc;
455
456     TRACE("%p\n",stm);
457
458     r = IStream_Read( stm, &size, sizeof(size), &count );
459     if( FAILED( r ) )
460         return r;
461     if( count != sizeof(loc->dwTotalSize) )
462         return E_FAIL;
463
464     loc = HeapAlloc( GetProcessHeap(), 0, size );
465     if( ! loc )
466         return E_OUTOFMEMORY;
467
468     r = IStream_Read( stm, &loc->dwHeaderSize, size-sizeof(size), &count );
469     if( FAILED( r ) )
470         goto end;
471     if( count != (size - sizeof(size)) )
472     {
473         r = E_FAIL;
474         goto end;
475     }
476     loc->dwTotalSize = size;
477
478     TRACE("Read %ld bytes\n",count);
479
480     /* FIXME: do something useful with it */
481     HeapFree( GetProcessHeap(), 0, loc );
482
483     return S_OK;
484 end:
485     HeapFree( GetProcessHeap(), 0, loc );
486     return r;
487 }
488
489 /************************************************************************
490  * IPersistStream_Load (IPersistStream)
491  */
492 static HRESULT WINAPI IPersistStream_fnLoad(
493         IPersistStream*  iface,
494     IStream*         stm)
495 {
496     LINK_HEADER hdr;
497     ULONG    dwBytesRead;
498     BOOL     unicode;
499     WCHAR    sTemp[MAX_PATH];
500     HRESULT  r;
501
502     _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
503
504     TRACE("(%p)(%p)\n", This, stm);
505
506     if( !stm )
507           return STG_E_INVALIDPOINTER;
508
509     dwBytesRead = 0;
510     r = IStream_Read(stm, &hdr, sizeof(hdr), &dwBytesRead);
511     if( FAILED( r ) )
512         return r;
513
514     if( dwBytesRead != sizeof(hdr))
515         return E_FAIL;
516     if( hdr.dwSize != sizeof(hdr))
517         return E_FAIL;
518     if( !IsEqualIID(&hdr.MagicGuid, &CLSID_ShellLink) )
519         return E_FAIL;
520
521     /* if( hdr.dwFlags & SCF_PIDL ) */  /* FIXME: seems to always have a PIDL */
522     {
523         r = ILLoadFromStream( stm, &This->pPidl );
524         if( FAILED( r ) )
525             return r;
526     }
527     This->wHotKey = hdr.wHotKey;
528     This->iIcoNdx = hdr.nIcon;
529     FileTimeToSystemTime (&hdr.Time1, &This->time1);
530     FileTimeToSystemTime (&hdr.Time2, &This->time2);
531     FileTimeToSystemTime (&hdr.Time3, &This->time3);
532 #if 1
533     GetDateFormatW(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&This->time1, NULL, sTemp, 256);
534     TRACE("-- time1: %s\n", debugstr_w(sTemp) );
535     GetDateFormatW(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&This->time2, NULL, sTemp, 256);
536     TRACE("-- time1: %s\n", debugstr_w(sTemp) );
537     GetDateFormatW(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&This->time3, NULL, sTemp, 256);
538     TRACE("-- time1: %s\n", debugstr_w(sTemp) );
539     pdump (This->pPidl);
540 #endif
541     if( hdr.dwFlags & SCF_NORMAL )
542         r = Stream_LoadLocation( stm );
543     if( FAILED( r ) )
544         goto end;
545     unicode = hdr.dwFlags & SCF_UNICODE;
546     if( hdr.dwFlags & SCF_DESCRIPTION )
547     {
548         r = Stream_LoadString( stm, unicode, &This->sDescription );
549         TRACE("Description  -> %s\n",debugstr_w(This->sDescription));
550     }
551     if( FAILED( r ) )
552         goto end;
553
554     if( hdr.dwFlags & SCF_RELATIVE )
555     {
556         r = Stream_LoadString( stm, unicode, &This->sPathRel );
557         TRACE("Relative Path-> %s\n",debugstr_w(This->sPathRel));
558     }
559     if( FAILED( r ) )
560         goto end;
561
562     if( hdr.dwFlags & SCF_WORKDIR )
563           {
564         r = Stream_LoadString( stm, unicode, &This->sWorkDir );
565         TRACE("Working Dir  -> %s\n",debugstr_w(This->sWorkDir));
566     }
567     if( FAILED( r ) )
568         goto end;
569
570     if( hdr.dwFlags & SCF_ARGS )
571     {
572         r = Stream_LoadString( stm, unicode, &This->sArgs );
573         TRACE("Working Dir  -> %s\n",debugstr_w(This->sArgs));
574     }
575     if( FAILED( r ) )
576         goto end;
577
578     if( hdr.dwFlags & SCF_CUSTOMICON )
579     {
580         r = Stream_LoadString( stm, unicode, &This->sIcoPath );
581         TRACE("Icon file    -> %s\n",debugstr_w(This->sIcoPath));
582     }
583     if( FAILED( r ) )
584         goto end;
585
586     TRACE("OK\n");
587
588     pdump (This->pPidl);
589
590     return S_OK;
591 end:
592     return r;
593 }
594
595 /************************************************************************
596  * Stream_WriteString
597  *
598  * Helper function for IPersistStream_Save. Writes a unicode string 
599  *  with terminating nul byte to a stream, preceded by the its length.
600  */
601 static HRESULT Stream_WriteString( IStream* stm, LPCWSTR str )
602 {
603     USHORT len = lstrlenW( str ) + 1;
604     DWORD count;
605     HRESULT r;
606
607     r = IStream_Write( stm, &len, sizeof(len), &count );
608     if( FAILED( r ) )
609         return r;
610
611     len *= sizeof(WCHAR);
612
613     r = IStream_Write( stm, str, len, &count );
614     if( FAILED( r ) )
615         return r;
616
617     return S_OK;
618 }
619
620 static HRESULT Stream_WriteLocationInfo( IStream* stm, LPCWSTR filename )
621 {
622     LOCATION_INFO loc;
623     ULONG count;
624
625     FIXME("writing empty location info\n");
626
627     memset( &loc, 0, sizeof(loc) );
628     loc.dwTotalSize = sizeof(loc) - sizeof(loc.dwTotalSize);
629
630     /* FIXME: fill this in */
631
632     return IStream_Write( stm, &loc, loc.dwTotalSize, &count );
633 }
634
635 /************************************************************************
636  * IPersistStream_Save (IPersistStream)
637  *
638  * FIXME: makes assumptions about byte order
639  */
640 static HRESULT WINAPI IPersistStream_fnSave(
641         IPersistStream*  iface,
642         IStream*         stm,
643         BOOL             fClearDirty)
644 {
645     LINK_HEADER header;
646     ULONG    count;
647     HRESULT    r;
648
649         _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
650
651     TRACE("(%p) %p %x\n", This, stm, fClearDirty);
652
653     /* if there's no PIDL, generate one */
654     if( ! This->pPidl )
655     {
656         if( ! This->sPath )
657             return E_FAIL;
658         This->pPidl = ILCreateFromPathW( This->sPath );
659     }
660
661     memset(&header, 0, sizeof(header));
662     header.dwSize = sizeof(header);
663     memcpy(&header.MagicGuid, &CLSID_ShellLink, sizeof(header.MagicGuid) );
664
665     header.wHotKey = This->wHotKey;
666     header.nIcon = This->iIcoNdx;
667     header.dwFlags = SCF_UNICODE;   /* strings are in unicode */
668     header.dwFlags |= SCF_NORMAL;   /* how do we determine this ? */
669     if( This->pPidl )
670         header.dwFlags |= SCF_PIDL;
671     if( This->sDescription )
672         header.dwFlags |= SCF_DESCRIPTION;
673     if( This->sWorkDir )
674         header.dwFlags |= SCF_WORKDIR;
675     if( This->sArgs )
676         header.dwFlags |= SCF_ARGS;
677     if( This->sIcoPath )
678         header.dwFlags |= SCF_CUSTOMICON;
679
680     SystemTimeToFileTime ( &This->time1, &header.Time1 );
681     SystemTimeToFileTime ( &This->time2, &header.Time2 );
682     SystemTimeToFileTime ( &This->time3, &header.Time3 );
683
684     /* write the Shortcut header */
685     r = IStream_Write( stm, &header, sizeof(header), &count );
686     if( FAILED( r ) )
687     {
688         ERR("Write failed at %d\n",__LINE__);
689         return r;
690     }
691
692     TRACE("Writing pidl \n");
693
694     /* write the PIDL to the shortcut */
695     if( This->pPidl )
696     {
697         r = ILSaveToStream( stm, This->pPidl );
698         if( FAILED( r ) )
699         {
700             ERR("Failed to write PIDL at %d\n",__LINE__);
701             return r;
702         }
703     }
704
705     TRACE("Path = %s\n", debugstr_w(This->sPath));
706     if( ! This->sPath )
707         return E_FAIL;
708     Stream_WriteLocationInfo( stm, This->sPath );
709
710     TRACE("Description = %s\n", debugstr_w(This->sDescription));
711     if( This->sDescription )
712         r = Stream_WriteString( stm, This->sDescription );
713
714     if( This->sPathRel )
715         r = Stream_WriteString( stm, This->sPathRel );
716
717     if( This->sWorkDir )
718         r = Stream_WriteString( stm, This->sWorkDir );
719
720     if( This->sArgs )
721         r = Stream_WriteString( stm, This->sArgs );
722
723     if( This->sIcoPath )
724         r = Stream_WriteString( stm, This->sIcoPath );
725
726     return S_OK;
727 }
728
729 /************************************************************************
730  * IPersistStream_GetSizeMax (IPersistStream)
731  */
732 static HRESULT WINAPI IPersistStream_fnGetSizeMax(
733         IPersistStream*  iface,
734         ULARGE_INTEGER*  pcbSize)
735 {
736         _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
737
738         TRACE("(%p)\n", This);
739
740         return E_NOTIMPL;
741 }
742
743 static ICOM_VTABLE(IPersistStream) psvt =
744 {
745         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
746         IPersistStream_fnQueryInterface,
747         IPersistStream_fnAddRef,
748         IPersistStream_fnRelease,
749         IPersistStream_fnGetClassID,
750         IPersistStream_fnIsDirty,
751         IPersistStream_fnLoad,
752         IPersistStream_fnSave,
753         IPersistStream_fnGetSizeMax
754 };
755
756 /**************************************************************************
757  *        IShellLink_Constructor
758  */
759 HRESULT WINAPI IShellLink_Constructor (
760         IUnknown * pUnkOuter,
761         REFIID riid,
762         LPVOID * ppv)
763 {
764         IShellLinkImpl * sl;
765
766         TRACE("unkOut=%p riid=%s\n",pUnkOuter, debugstr_guid(riid));
767
768         *ppv = NULL;
769
770         if(pUnkOuter) return CLASS_E_NOAGGREGATION;
771         sl = (IShellLinkImpl *) LocalAlloc(GMEM_ZEROINIT,sizeof(IShellLinkImpl));
772         if (!sl) return E_OUTOFMEMORY;
773
774         sl->ref = 1;
775         sl->lpVtbl = &slvt;
776         sl->lpvtblw = &slvtw;
777         sl->lpvtblPersistFile = &pfvt;
778         sl->lpvtblPersistStream = &psvt;
779         sl->iShowCmd = SW_SHOWNORMAL;
780
781         TRACE("(%p)->()\n",sl);
782
783         if (IsEqualIID(riid, &IID_IUnknown) ||
784             IsEqualIID(riid, &IID_IShellLinkA))
785             *ppv = sl;
786         else if (IsEqualIID(riid, &IID_IShellLinkW))
787             *ppv = &(sl->lpvtblw);
788         else {
789             LocalFree((HLOCAL)sl);
790             ERR("E_NOINTERFACE\n");
791             return E_NOINTERFACE;
792         }
793
794         return S_OK;
795 }
796
797 /**************************************************************************
798  *  IShellLinkA_QueryInterface
799  */
800 static HRESULT WINAPI IShellLinkA_fnQueryInterface( IShellLinkA * iface, REFIID riid,  LPVOID *ppvObj)
801 {
802         ICOM_THIS(IShellLinkImpl, iface);
803
804         TRACE("(%p)->(\n\tIID:\t%s)\n",This,debugstr_guid(riid));
805
806         *ppvObj = NULL;
807
808         if(IsEqualIID(riid, &IID_IUnknown) ||
809            IsEqualIID(riid, &IID_IShellLinkA))
810         {
811           *ppvObj = This;
812         }
813         else if(IsEqualIID(riid, &IID_IShellLinkW))
814         {
815           *ppvObj = (IShellLinkW *)&(This->lpvtblw);
816         }
817         else if(IsEqualIID(riid, &IID_IPersistFile))
818         {
819           *ppvObj = (IPersistFile *)&(This->lpvtblPersistFile);
820         }
821         else if(IsEqualIID(riid, &IID_IPersistStream))
822         {
823           *ppvObj = (IPersistStream *)&(This->lpvtblPersistStream);
824         }
825
826         if(*ppvObj)
827         {
828           IUnknown_AddRef((IUnknown*)(*ppvObj));
829           TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
830           return S_OK;
831         }
832         TRACE("-- Interface: E_NOINTERFACE\n");
833         return E_NOINTERFACE;
834 }
835 /******************************************************************************
836  * IShellLinkA_AddRef
837  */
838 static ULONG WINAPI IShellLinkA_fnAddRef(IShellLinkA * iface)
839 {
840         ICOM_THIS(IShellLinkImpl, iface);
841
842         TRACE("(%p)->(count=%lu)\n",This,This->ref);
843
844         return ++(This->ref);
845 }
846 /******************************************************************************
847  *      IShellLinkA_Release
848  */
849 static ULONG WINAPI IShellLinkA_fnRelease(IShellLinkA * iface)
850 {
851     ICOM_THIS(IShellLinkImpl, iface);
852
853     TRACE("(%p)->(count=%lu)\n",This,This->ref);
854
855     if (--(This->ref))
856         return This->ref;
857
858     TRACE("-- destroying IShellLink(%p)\n",This);
859
860     if (This->sIcoPath)
861         HeapFree(GetProcessHeap(), 0, This->sIcoPath);
862
863     if (This->sArgs)
864         HeapFree(GetProcessHeap(), 0, This->sArgs);
865
866     if (This->sWorkDir)
867         HeapFree(GetProcessHeap(), 0, This->sWorkDir);
868
869     if (This->sDescription)
870         HeapFree(GetProcessHeap(), 0, This->sDescription);
871
872     if (This->sPath)
873         HeapFree(GetProcessHeap(),0,This->sPath);
874
875     if (This->pPidl)
876         ILFree(This->pPidl);
877
878     LocalFree((HANDLE)This);
879
880     return 0;
881 }
882
883 static HRESULT WINAPI IShellLinkA_fnGetPath(IShellLinkA * iface, LPSTR pszFile,
884                   INT cchMaxPath, WIN32_FIND_DATAA *pfd, DWORD fFlags)
885 {
886     ICOM_THIS(IShellLinkImpl, iface);
887
888     TRACE("(%p)->(pfile=%p len=%u find_data=%p flags=%lu)(%s)\n",
889           This, pszFile, cchMaxPath, pfd, fFlags, debugstr_w(This->sPath));
890
891     if( cchMaxPath )
892         pszFile[0] = 0;
893     if (This->sPath)
894         WideCharToMultiByte( CP_ACP, 0, This->sPath, -1,
895                              pszFile, cchMaxPath, NULL, NULL);
896
897     return NOERROR;
898 }
899
900 static HRESULT WINAPI IShellLinkA_fnGetIDList(IShellLinkA * iface, LPITEMIDLIST * ppidl)
901 {
902         ICOM_THIS(IShellLinkImpl, iface);
903
904         TRACE("(%p)->(ppidl=%p)\n",This, ppidl);
905
906         *ppidl = ILClone(This->pPidl);
907
908         return NOERROR;
909 }
910
911 static HRESULT WINAPI IShellLinkA_fnSetIDList(IShellLinkA * iface, LPCITEMIDLIST pidl)
912 {
913         ICOM_THIS(IShellLinkImpl, iface);
914
915         TRACE("(%p)->(pidl=%p)\n",This, pidl);
916
917         if (This->pPidl)
918             ILFree(This->pPidl);
919         This->pPidl = ILClone (pidl);
920
921     return S_OK;
922 }
923
924 static HRESULT WINAPI IShellLinkA_fnGetDescription(IShellLinkA * iface, LPSTR pszName,INT cchMaxName)
925 {
926     ICOM_THIS(IShellLinkImpl, iface);
927
928     TRACE("(%p)->(%p len=%u)\n",This, pszName, cchMaxName);
929
930     if( cchMaxName )
931         pszName[0] = 0;
932     if( This->sDescription )
933         WideCharToMultiByte( CP_ACP, 0, This->sDescription, -1,
934             pszName, cchMaxName, NULL, NULL);
935
936     return S_OK;
937 }
938 static HRESULT WINAPI IShellLinkA_fnSetDescription(IShellLinkA * iface, LPCSTR pszName)
939 {
940     ICOM_THIS(IShellLinkImpl, iface);
941
942     TRACE("(%p)->(pName=%s)\n", This, pszName);
943
944     if (This->sDescription)
945         HeapFree(GetProcessHeap(), 0, This->sDescription);
946     This->sDescription = HEAP_strdupAtoW( GetProcessHeap(), 0, pszName);
947     if ( !This->sDescription )
948         return E_OUTOFMEMORY;
949
950     return S_OK;
951 }
952
953 static HRESULT WINAPI IShellLinkA_fnGetWorkingDirectory(IShellLinkA * iface, LPSTR pszDir,INT cchMaxPath)
954 {
955     ICOM_THIS(IShellLinkImpl, iface);
956
957     TRACE("(%p)->(%p len=%u)\n", This, pszDir, cchMaxPath);
958
959     if( cchMaxPath )
960         pszDir[0] = 0;
961     if( This->sWorkDir )
962         WideCharToMultiByte( CP_ACP, 0, This->sWorkDir, -1,
963                              pszDir, cchMaxPath, NULL, NULL);
964
965     return S_OK;
966 }
967
968 static HRESULT WINAPI IShellLinkA_fnSetWorkingDirectory(IShellLinkA * iface, LPCSTR pszDir)
969 {
970     ICOM_THIS(IShellLinkImpl, iface);
971
972     TRACE("(%p)->(dir=%s)\n",This, pszDir);
973
974     if (This->sWorkDir)
975         HeapFree(GetProcessHeap(), 0, This->sWorkDir);
976     This->sWorkDir = HEAP_strdupAtoW( GetProcessHeap(), 0, pszDir);
977     if ( !This->sWorkDir )
978         return E_OUTOFMEMORY;
979
980     return S_OK;
981 }
982
983 static HRESULT WINAPI IShellLinkA_fnGetArguments(IShellLinkA * iface, LPSTR pszArgs,INT cchMaxPath)
984 {
985     ICOM_THIS(IShellLinkImpl, iface);
986
987     TRACE("(%p)->(%p len=%u)\n", This, pszArgs, cchMaxPath);
988
989     if( cchMaxPath )
990         pszArgs[0] = 0;
991     if( This->sArgs )
992         WideCharToMultiByte( CP_ACP, 0, This->sArgs, -1,
993                              pszArgs, cchMaxPath, NULL, NULL);
994
995     return S_OK;
996 }
997
998 static HRESULT WINAPI IShellLinkA_fnSetArguments(IShellLinkA * iface, LPCSTR pszArgs)
999 {
1000     ICOM_THIS(IShellLinkImpl, iface);
1001
1002     TRACE("(%p)->(args=%s)\n",This, pszArgs);
1003
1004     if (This->sArgs)
1005         HeapFree(GetProcessHeap(), 0, This->sArgs);
1006     This->sArgs = HEAP_strdupAtoW( GetProcessHeap(), 0, pszArgs);
1007     if( !This->sArgs )
1008         return E_OUTOFMEMORY;
1009
1010     return S_OK;
1011 }
1012
1013 static HRESULT WINAPI IShellLinkA_fnGetHotkey(IShellLinkA * iface, WORD *pwHotkey)
1014 {
1015         ICOM_THIS(IShellLinkImpl, iface);
1016
1017         TRACE("(%p)->(%p)(0x%08x)\n",This, pwHotkey, This->wHotKey);
1018
1019         *pwHotkey = This->wHotKey;
1020
1021         return S_OK;
1022 }
1023
1024 static HRESULT WINAPI IShellLinkA_fnSetHotkey(IShellLinkA * iface, WORD wHotkey)
1025 {
1026         ICOM_THIS(IShellLinkImpl, iface);
1027
1028         TRACE("(%p)->(hotkey=%x)\n",This, wHotkey);
1029
1030         This->wHotKey = wHotkey;
1031
1032         return S_OK;
1033 }
1034
1035 static HRESULT WINAPI IShellLinkA_fnGetShowCmd(IShellLinkA * iface, INT *piShowCmd)
1036 {
1037     ICOM_THIS(IShellLinkImpl, iface);
1038
1039     TRACE("(%p)->(%p)\n",This, piShowCmd);
1040     *piShowCmd = This->iShowCmd;
1041     return S_OK;
1042 }
1043
1044 static HRESULT WINAPI IShellLinkA_fnSetShowCmd(IShellLinkA * iface, INT iShowCmd)
1045 {
1046     ICOM_THIS(IShellLinkImpl, iface);
1047
1048     TRACE("(%p) %d\n",This, iShowCmd);
1049
1050     This->iShowCmd = iShowCmd;
1051
1052     return NOERROR;
1053 }
1054
1055 static HRESULT WINAPI IShellLinkA_fnGetIconLocation(IShellLinkA * iface, LPSTR pszIconPath,INT cchIconPath,INT *piIcon)
1056 {
1057     ICOM_THIS(IShellLinkImpl, iface);
1058
1059     TRACE("(%p)->(%p len=%u iicon=%p)\n", This, pszIconPath, cchIconPath, piIcon);
1060
1061     if( cchIconPath )
1062         pszIconPath[0] = 0;
1063     if( This->sIcoPath )
1064         WideCharToMultiByte( CP_ACP, 0, This->sIcoPath, -1,
1065                              pszIconPath, cchIconPath, NULL, NULL);
1066     *piIcon = This->iIcoNdx;
1067
1068     return NOERROR;
1069 }
1070
1071 static HRESULT WINAPI IShellLinkA_fnSetIconLocation(IShellLinkA * iface, LPCSTR pszIconPath,INT iIcon)
1072 {
1073     ICOM_THIS(IShellLinkImpl, iface);
1074
1075     TRACE("(%p)->(path=%s iicon=%u)\n",This, pszIconPath, iIcon);
1076
1077     if (This->sIcoPath)
1078         HeapFree(GetProcessHeap(), 0, This->sIcoPath);
1079     This->sIcoPath = HEAP_strdupAtoW(GetProcessHeap(), 0, pszIconPath);
1080     if ( !This->sIcoPath )
1081         return E_OUTOFMEMORY;
1082     This->iIcoNdx = iIcon;
1083
1084     return S_OK;
1085 }
1086
1087 static HRESULT WINAPI IShellLinkA_fnSetRelativePath(IShellLinkA * iface, LPCSTR pszPathRel, DWORD dwReserved)
1088 {
1089     ICOM_THIS(IShellLinkImpl, iface);
1090
1091     FIXME("(%p)->(path=%s %lx)\n",This, pszPathRel, dwReserved);
1092
1093     if (This->sPathRel)
1094         HeapFree(GetProcessHeap(), 0, This->sPathRel);
1095     This->sPathRel = HEAP_strdupAtoW(GetProcessHeap(), 0, pszPathRel);
1096
1097     return S_OK;
1098 }
1099
1100 static HRESULT WINAPI IShellLinkA_fnResolve(IShellLinkA * iface, HWND hwnd, DWORD fFlags)
1101 {
1102         ICOM_THIS(IShellLinkImpl, iface);
1103
1104         FIXME("(%p)->(hwnd=%p flags=%lx)\n",This, hwnd, fFlags);
1105         return S_OK;
1106 }
1107
1108 static HRESULT WINAPI IShellLinkA_fnSetPath(IShellLinkA * iface, LPCSTR pszFile)
1109 {
1110     ICOM_THIS(IShellLinkImpl, iface);
1111
1112     TRACE("(%p)->(path=%s)\n",This, pszFile);
1113
1114     if (This->sPath)
1115         HeapFree(GetProcessHeap(), 0, This->sPath);
1116     This->sPath = HEAP_strdupAtoW(GetProcessHeap(), 0, pszFile);
1117     if( !This->sPath )
1118         return E_OUTOFMEMORY;
1119
1120     return S_OK;
1121 }
1122
1123 /**************************************************************************
1124 * IShellLink Implementation
1125 */
1126
1127 static ICOM_VTABLE(IShellLinkA) slvt =
1128 {
1129         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1130         IShellLinkA_fnQueryInterface,
1131         IShellLinkA_fnAddRef,
1132         IShellLinkA_fnRelease,
1133         IShellLinkA_fnGetPath,
1134         IShellLinkA_fnGetIDList,
1135         IShellLinkA_fnSetIDList,
1136         IShellLinkA_fnGetDescription,
1137         IShellLinkA_fnSetDescription,
1138         IShellLinkA_fnGetWorkingDirectory,
1139         IShellLinkA_fnSetWorkingDirectory,
1140         IShellLinkA_fnGetArguments,
1141         IShellLinkA_fnSetArguments,
1142         IShellLinkA_fnGetHotkey,
1143         IShellLinkA_fnSetHotkey,
1144         IShellLinkA_fnGetShowCmd,
1145         IShellLinkA_fnSetShowCmd,
1146         IShellLinkA_fnGetIconLocation,
1147         IShellLinkA_fnSetIconLocation,
1148         IShellLinkA_fnSetRelativePath,
1149         IShellLinkA_fnResolve,
1150         IShellLinkA_fnSetPath
1151 };
1152
1153
1154 /**************************************************************************
1155  *  IShellLinkW_fnQueryInterface
1156  */
1157 static HRESULT WINAPI IShellLinkW_fnQueryInterface(
1158   IShellLinkW * iface, REFIID riid, LPVOID *ppvObj)
1159 {
1160         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1161
1162         return IShellLinkA_QueryInterface((IShellLinkA*)This, riid, ppvObj);
1163 }
1164
1165 /******************************************************************************
1166  * IShellLinkW_fnAddRef
1167  */
1168 static ULONG WINAPI IShellLinkW_fnAddRef(IShellLinkW * iface)
1169 {
1170         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1171
1172         TRACE("(%p)->(count=%lu)\n",This,This->ref);
1173
1174         return IShellLinkA_AddRef((IShellLinkA*)This);
1175 }
1176 /******************************************************************************
1177  * IShellLinkW_fnRelease
1178  */
1179
1180 static ULONG WINAPI IShellLinkW_fnRelease(IShellLinkW * iface)
1181 {
1182         _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1183
1184         TRACE("(%p)->(count=%lu)\n",This,This->ref);
1185
1186         return IShellLinkA_Release((IShellLinkA*)This);
1187 }
1188
1189 static HRESULT WINAPI IShellLinkW_fnGetPath(IShellLinkW * iface, LPWSTR pszFile,INT cchMaxPath, WIN32_FIND_DATAA *pfd, DWORD fFlags)
1190 {
1191     _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1192
1193     FIXME("(%p)->(pfile=%p len=%u find_data=%p flags=%lu)\n",This, pszFile, cchMaxPath, pfd, fFlags);
1194     if( cchMaxPath )
1195         pszFile[0] = 0;
1196     if( This->sPath )
1197         lstrcpynW( pszFile, This->sPath, cchMaxPath );
1198
1199     return NOERROR;
1200 }
1201
1202 static HRESULT WINAPI IShellLinkW_fnGetIDList(IShellLinkW * iface, LPITEMIDLIST * ppidl)
1203 {
1204     _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1205
1206     TRACE("(%p)->(ppidl=%p)\n",This, ppidl);
1207
1208     if( This->pPidl)
1209         *ppidl = ILClone( This->pPidl );
1210     else
1211         *ppidl = NULL;
1212
1213     return S_OK;
1214 }
1215
1216 static HRESULT WINAPI IShellLinkW_fnSetIDList(IShellLinkW * iface, LPCITEMIDLIST pidl)
1217 {
1218     _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1219
1220     TRACE("(%p)->(pidl=%p)\n",This, pidl);
1221
1222     if( This->pPidl )
1223         ILFree( This->pPidl );
1224     This->pPidl = ILClone( pidl );
1225     if( !This->pPidl )
1226         return E_FAIL;
1227
1228     return S_OK;
1229 }
1230
1231 static HRESULT WINAPI IShellLinkW_fnGetDescription(IShellLinkW * iface, LPWSTR pszName,INT cchMaxName)
1232 {
1233     _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1234
1235     TRACE("(%p)->(%p len=%u)\n",This, pszName, cchMaxName);
1236
1237     if( cchMaxName )
1238         pszName[0] = 0;
1239     if( This->sDescription )
1240         lstrcpynW( pszName, This->sDescription, cchMaxName );
1241
1242     return S_OK;
1243 }
1244
1245 static HRESULT WINAPI IShellLinkW_fnSetDescription(IShellLinkW * iface, LPCWSTR pszName)
1246 {
1247     _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1248
1249     TRACE("(%p)->(desc=%s)\n",This, debugstr_w(pszName));
1250
1251     if (This->sDescription)
1252         HeapFree(GetProcessHeap(), 0, This->sDescription);
1253     This->sDescription = HeapAlloc( GetProcessHeap(), 0,
1254                                     (lstrlenW( pszName )+1)*sizeof(WCHAR) );
1255     if ( !This->sDescription )
1256         return E_OUTOFMEMORY;
1257     lstrcpyW( This->sDescription, pszName );
1258
1259     return S_OK;
1260 }
1261
1262 static HRESULT WINAPI IShellLinkW_fnGetWorkingDirectory(IShellLinkW * iface, LPWSTR pszDir,INT cchMaxPath)
1263 {
1264     _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1265
1266     TRACE("(%p)->(%p len %u)\n", This, pszDir, cchMaxPath);
1267
1268     if( cchMaxPath )
1269         pszDir[0] = 0;
1270     if( This->sWorkDir )
1271         lstrcpynW( pszDir, This->sWorkDir, cchMaxPath );
1272
1273     return S_OK;
1274 }
1275
1276 static HRESULT WINAPI IShellLinkW_fnSetWorkingDirectory(IShellLinkW * iface, LPCWSTR pszDir)
1277 {
1278     _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1279
1280     TRACE("(%p)->(dir=%s)\n",This, debugstr_w(pszDir));
1281
1282     if (This->sWorkDir)
1283         HeapFree(GetProcessHeap(), 0, This->sWorkDir);
1284     This->sWorkDir = HeapAlloc( GetProcessHeap(), 0,
1285                                 (lstrlenW( pszDir )+1)*sizeof (WCHAR) );
1286     if ( !This->sWorkDir )
1287         return E_OUTOFMEMORY;
1288     lstrcpyW( This->sWorkDir, pszDir );
1289
1290     return S_OK;
1291 }
1292
1293 static HRESULT WINAPI IShellLinkW_fnGetArguments(IShellLinkW * iface, LPWSTR pszArgs,INT cchMaxPath)
1294 {
1295     _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1296
1297     TRACE("(%p)->(%p len=%u)\n", This, pszArgs, cchMaxPath);
1298
1299     if( cchMaxPath )
1300         pszArgs[0] = 0;
1301     if( This->sArgs )
1302         lstrcpynW( pszArgs, This->sArgs, cchMaxPath );
1303
1304     return NOERROR;
1305 }
1306
1307 static HRESULT WINAPI IShellLinkW_fnSetArguments(IShellLinkW * iface, LPCWSTR pszArgs)
1308 {
1309     _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1310
1311     TRACE("(%p)->(args=%s)\n",This, debugstr_w(pszArgs));
1312
1313     if (This->sArgs)
1314         HeapFree(GetProcessHeap(), 0, This->sArgs);
1315     This->sArgs = HeapAlloc( GetProcessHeap(), 0,
1316                              (lstrlenW( pszArgs )+1)*sizeof (WCHAR) );
1317     if ( !This->sArgs )
1318         return E_OUTOFMEMORY;
1319     lstrcpyW( This->sArgs, pszArgs );
1320
1321     return S_OK;
1322 }
1323
1324 static HRESULT WINAPI IShellLinkW_fnGetHotkey(IShellLinkW * iface, WORD *pwHotkey)
1325 {
1326     _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1327
1328     TRACE("(%p)->(%p)\n",This, pwHotkey);
1329
1330     *pwHotkey=This->wHotKey;
1331
1332     return S_OK;
1333 }
1334
1335 static HRESULT WINAPI IShellLinkW_fnSetHotkey(IShellLinkW * iface, WORD wHotkey)
1336 {
1337     _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1338
1339     TRACE("(%p)->(hotkey=%x)\n",This, wHotkey);
1340
1341     This->wHotKey = wHotkey;
1342
1343     return S_OK;
1344 }
1345
1346 static HRESULT WINAPI IShellLinkW_fnGetShowCmd(IShellLinkW * iface, INT *piShowCmd)
1347 {
1348     _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1349
1350     TRACE("(%p)->(%p)\n",This, piShowCmd);
1351
1352     *piShowCmd = This->iShowCmd;
1353
1354     return S_OK;
1355 }
1356
1357 static HRESULT WINAPI IShellLinkW_fnSetShowCmd(IShellLinkW * iface, INT iShowCmd)
1358 {
1359     _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1360
1361     This->iShowCmd = iShowCmd;
1362
1363     return S_OK;
1364 }
1365
1366 static HRESULT WINAPI IShellLinkW_fnGetIconLocation(IShellLinkW * iface, LPWSTR pszIconPath,INT cchIconPath,INT *piIcon)
1367 {
1368     _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1369
1370     TRACE("(%p)->(%p len=%u iicon=%p)\n", This, pszIconPath, cchIconPath, piIcon);
1371
1372     if( cchIconPath )
1373         pszIconPath[0] = 0;
1374     if( This->sIcoPath )
1375         lstrcpynW( pszIconPath, This->sIcoPath, cchIconPath );
1376     *piIcon = This->iIcoNdx;
1377
1378     return S_OK;
1379 }
1380
1381 static HRESULT WINAPI IShellLinkW_fnSetIconLocation(IShellLinkW * iface, LPCWSTR pszIconPath,INT iIcon)
1382 {
1383     _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1384
1385     TRACE("(%p)->(path=%s iicon=%u)\n",This, debugstr_w(pszIconPath), iIcon);
1386
1387     if (This->sIcoPath)
1388         HeapFree(GetProcessHeap(), 0, This->sIcoPath);
1389     This->sIcoPath = HeapAlloc( GetProcessHeap(), 0,
1390                                 (lstrlenW( pszIconPath )+1)*sizeof (WCHAR) );
1391     if ( !This->sIcoPath )
1392         return E_OUTOFMEMORY;
1393     lstrcpyW( This->sIcoPath, pszIconPath );
1394
1395     This->iIcoNdx = iIcon;
1396
1397     return S_OK;
1398 }
1399
1400 static HRESULT WINAPI IShellLinkW_fnSetRelativePath(IShellLinkW * iface, LPCWSTR pszPathRel, DWORD dwReserved)
1401 {
1402     _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1403
1404     TRACE("(%p)->(path=%s %lx)\n",This, debugstr_w(pszPathRel), dwReserved);
1405
1406     if (This->sPathRel)
1407         HeapFree(GetProcessHeap(), 0, This->sPathRel);
1408     This->sPathRel = HeapAlloc( GetProcessHeap(), 0,
1409                                 (lstrlenW( pszPathRel )+1) * sizeof (WCHAR) );
1410     if ( !This->sPathRel )
1411         return E_OUTOFMEMORY;
1412     lstrcpyW( This->sPathRel, pszPathRel );
1413
1414     return S_OK;
1415 }
1416
1417 static HRESULT WINAPI IShellLinkW_fnResolve(IShellLinkW * iface, HWND hwnd, DWORD fFlags)
1418 {
1419     _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1420
1421     FIXME("(%p)->(hwnd=%p flags=%lx)\n",This, hwnd, fFlags);
1422
1423     return S_OK;
1424 }
1425
1426 static HRESULT WINAPI IShellLinkW_fnSetPath(IShellLinkW * iface, LPCWSTR pszFile)
1427 {
1428     _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1429
1430     TRACE("(%p)->(path=%s)\n",This, debugstr_w(pszFile));
1431
1432     if (This->sPath)
1433         HeapFree(GetProcessHeap(), 0, This->sPath);
1434     This->sPath = HeapAlloc( GetProcessHeap(), 0,
1435                              (lstrlenW( pszFile )+1) * sizeof (WCHAR) );
1436     if ( !This->sPath )
1437         return E_OUTOFMEMORY;
1438     lstrcpyW( This->sPath, pszFile );
1439
1440     return S_OK;
1441 }
1442
1443 /**************************************************************************
1444 * IShellLinkW Implementation
1445 */
1446
1447 static ICOM_VTABLE(IShellLinkW) slvtw =
1448 {
1449         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1450         IShellLinkW_fnQueryInterface,
1451         IShellLinkW_fnAddRef,
1452         IShellLinkW_fnRelease,
1453         IShellLinkW_fnGetPath,
1454         IShellLinkW_fnGetIDList,
1455         IShellLinkW_fnSetIDList,
1456         IShellLinkW_fnGetDescription,
1457         IShellLinkW_fnSetDescription,
1458         IShellLinkW_fnGetWorkingDirectory,
1459         IShellLinkW_fnSetWorkingDirectory,
1460         IShellLinkW_fnGetArguments,
1461         IShellLinkW_fnSetArguments,
1462         IShellLinkW_fnGetHotkey,
1463         IShellLinkW_fnSetHotkey,
1464         IShellLinkW_fnGetShowCmd,
1465         IShellLinkW_fnSetShowCmd,
1466         IShellLinkW_fnGetIconLocation,
1467         IShellLinkW_fnSetIconLocation,
1468         IShellLinkW_fnSetRelativePath,
1469         IShellLinkW_fnResolve,
1470         IShellLinkW_fnSetPath
1471 };