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