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