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