3 * Copyright 1997 Marcus Meissner
4 * Copyright 1998 Juergen Schmied
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.
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.
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
21 * Nearly complete informations about the binary formats
22 * of .lnk files available at http://www.wotsit.org
37 #ifdef HAVE_SYS_WAIT_H
38 # include <sys/wait.h>
40 #include "wine/debug.h"
41 #include "wine/port.h"
51 #include "undocshell.h"
54 #include "shell32_main.h"
58 WINE_DEFAULT_DEBUG_CHANNEL(shell);
60 /* link file formats */
62 /* flag1: lnk elements: simple link has 0x0B */
65 #define SCF_DESCRIPTION 4
66 #define SCF_RELATIVE 8
67 #define SCF_WORKDIR 0x10
69 #define SCF_CUSTOMICON 0x40
70 #define SCF_UNICODE 0x80
74 typedef struct _LINK_HEADER
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;
91 #define SHLINK_LOCAL 0
92 #define SHLINK_REMOTE 1
94 typedef struct _LOCATION_INFO
100 DWORD dwLocalPathOfs;
101 DWORD dwNetworkVolTableOfs;
102 DWORD dwFinalPathOfs;
105 typedef struct _LOCAL_VOLUME_INFO
115 static ICOM_VTABLE(IShellLinkA) slvt;
116 static ICOM_VTABLE(IShellLinkW) slvtw;
117 static ICOM_VTABLE(IPersistFile) pfvt;
118 static ICOM_VTABLE(IPersistStream) psvt;
120 /* IShellLink Implementation */
124 ICOM_VFIELD(IShellLinkA);
127 ICOM_VTABLE(IShellLinkW)* lpvtblw;
128 ICOM_VTABLE(IPersistFile)* lpvtblPersistFile;
129 ICOM_VTABLE(IPersistStream)* lpvtblPersistStream;
131 /* data structures according to the informations in the link */
150 #define _IShellLinkW_Offset ((int)(&(((IShellLinkImpl*)0)->lpvtblw)))
151 #define _ICOM_THIS_From_IShellLinkW(class, name) class* This = (class*)(((char*)name)-_IShellLinkW_Offset)
153 #define _IPersistFile_Offset ((int)(&(((IShellLinkImpl*)0)->lpvtblPersistFile)))
154 #define _ICOM_THIS_From_IPersistFile(class, name) class* This = (class*)(((char*)name)-_IPersistFile_Offset)
156 #define _IPersistStream_Offset ((int)(&(((IShellLinkImpl*)0)->lpvtblPersistStream)))
157 #define _ICOM_THIS_From_IPersistStream(class, name) class* This = (class*)(((char*)name)-_IPersistStream_Offset)
158 #define _IPersistStream_From_ICOM_THIS(class, name) class* StreamThis = (class*)(((char*)name)+_IPersistStream_Offset)
160 static HRESULT ShellLink_UpdatePath(LPWSTR sPathRel, LPCWSTR path, LPCWSTR sWorkDir, LPWSTR* psPath);
162 /* strdup on the process heap */
163 inline static LPWSTR HEAP_strdupAtoW( HANDLE heap, DWORD flags, LPCSTR str)
165 INT len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
166 LPWSTR p = HeapAlloc( heap, flags, len*sizeof (WCHAR) );
169 MultiByteToWideChar( CP_ACP, 0, str, -1, p, len );
174 /**************************************************************************
175 * IPersistFile_QueryInterface
177 static HRESULT WINAPI IPersistFile_fnQueryInterface(
182 _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface);
184 TRACE("(%p)\n",This);
186 return IShellLinkA_QueryInterface((IShellLinkA*)This, riid, ppvObj);
189 /******************************************************************************
190 * IPersistFile_AddRef
192 static ULONG WINAPI IPersistFile_fnAddRef(IPersistFile* iface)
194 _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface);
196 TRACE("(%p)->(count=%lu)\n",This,This->ref);
198 return IShellLinkA_AddRef((IShellLinkA*)This);
200 /******************************************************************************
201 * IPersistFile_Release
203 static ULONG WINAPI IPersistFile_fnRelease(IPersistFile* iface)
205 _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface);
207 TRACE("(%p)->(count=%lu)\n",This,This->ref);
209 return IShellLinkA_Release((IShellLinkA*)This);
212 static HRESULT WINAPI IPersistFile_fnGetClassID(IPersistFile* iface, CLSID *pClassID)
214 _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface);
215 FIXME("(%p)\n",This);
218 static HRESULT WINAPI IPersistFile_fnIsDirty(IPersistFile* iface)
220 _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface);
222 TRACE("(%p)\n",This);
229 static HRESULT WINAPI IPersistFile_fnLoad(IPersistFile* iface, LPCOLESTR pszFileName, DWORD dwMode)
231 _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface);
232 _IPersistStream_From_ICOM_THIS(IPersistStream, This);
236 TRACE("(%p, %s)\n",This, debugstr_w(pszFileName));
238 r = CreateStreamOnFile(pszFileName, dwMode, &stm);
241 r = IPersistStream_Load(StreamThis, stm);
242 ShellLink_UpdatePath(This->sPathRel, pszFileName, This->sWorkDir, &This->sPath);
243 IStream_Release( stm );
250 static BOOL StartLinkProcessor( LPCOLESTR szLink )
252 const WCHAR szFormat[] = {'w','i','n','e','m','e','n','u','b','u','i','l','d','e','r','.','e','x','e',
253 ' ','-','r',' ','"','%','s','"',0 };
257 PROCESS_INFORMATION pi;
259 len = sizeof(szFormat) + lstrlenW( szLink ) * sizeof(WCHAR);
260 buffer = HeapAlloc( GetProcessHeap(), 0, len );
264 wsprintfW( buffer, szFormat, szLink );
266 TRACE("starting %s\n",debugstr_w(buffer));
268 memset(&si, 0, sizeof(si));
270 if (!CreateProcessW( NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) return FALSE;
272 /* wait for a while to throttle the creation of linker processes */
273 if( WAIT_OBJECT_0 != WaitForSingleObject( pi.hProcess, 10000 ) )
274 WARN("Timed out waiting for shell linker\n");
276 CloseHandle( pi.hProcess );
277 CloseHandle( pi.hThread );
282 static HRESULT WINAPI IPersistFile_fnSave(IPersistFile* iface, LPCOLESTR pszFileName, BOOL fRemember)
284 _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface);
285 _IPersistStream_From_ICOM_THIS(IPersistStream, This);
289 TRACE("(%p)->(%s)\n",This,debugstr_w(pszFileName));
291 if (!pszFileName || !This->sPath)
292 return ERROR_UNKNOWN;
294 r = CreateStreamOnFile(pszFileName, STGM_READWRITE | STGM_CREATE, &stm);
297 r = IPersistStream_Save(StreamThis, stm, FALSE);
298 IStream_Release( stm );
302 StartLinkProcessor( pszFileName );
308 DeleteFileW( pszFileName );
309 WARN("Failed to create shortcut %s\n", debugstr_w(pszFileName) );
316 static HRESULT WINAPI IPersistFile_fnSaveCompleted(IPersistFile* iface, LPCOLESTR pszFileName)
318 _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface);
319 FIXME("(%p)->(%s)\n",This,debugstr_w(pszFileName));
322 static HRESULT WINAPI IPersistFile_fnGetCurFile(IPersistFile* iface, LPOLESTR *ppszFileName)
324 _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface);
325 FIXME("(%p)\n",This);
329 static ICOM_VTABLE(IPersistFile) pfvt =
331 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
332 IPersistFile_fnQueryInterface,
333 IPersistFile_fnAddRef,
334 IPersistFile_fnRelease,
335 IPersistFile_fnGetClassID,
336 IPersistFile_fnIsDirty,
339 IPersistFile_fnSaveCompleted,
340 IPersistFile_fnGetCurFile
343 /************************************************************************
344 * IPersistStream_QueryInterface
346 static HRESULT WINAPI IPersistStream_fnQueryInterface(
347 IPersistStream* iface,
351 _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
353 TRACE("(%p)\n",This);
355 return IShellLinkA_QueryInterface((IShellLinkA*)This, riid, ppvoid);
358 /************************************************************************
359 * IPersistStream_Release
361 static ULONG WINAPI IPersistStream_fnRelease(
362 IPersistStream* iface)
364 _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
366 TRACE("(%p)\n",This);
368 return IShellLinkA_Release((IShellLinkA*)This);
371 /************************************************************************
372 * IPersistStream_AddRef
374 static ULONG WINAPI IPersistStream_fnAddRef(
375 IPersistStream* iface)
377 _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
379 TRACE("(%p)\n",This);
381 return IShellLinkA_AddRef((IShellLinkA*)This);
384 /************************************************************************
385 * IPersistStream_GetClassID
388 static HRESULT WINAPI IPersistStream_fnGetClassID(
389 IPersistStream* iface,
392 _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
394 TRACE("(%p)\n", This);
399 /* memcpy(pClassID, &CLSID_???, sizeof(CLSID_???)); */
404 /************************************************************************
405 * IPersistStream_IsDirty (IPersistStream)
407 static HRESULT WINAPI IPersistStream_fnIsDirty(
408 IPersistStream* iface)
410 _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
412 TRACE("(%p)\n", This);
418 static HRESULT Stream_LoadString( IStream* stm, BOOL unicode, LPWSTR *pstr )
429 r = IStream_Read(stm, &len, sizeof(len), &count);
430 if ( FAILED (r) || ( count != sizeof(len) ) )
434 len *= sizeof (WCHAR);
436 TRACE("reading %d\n", len);
437 temp = HeapAlloc(GetProcessHeap(), 0, len+sizeof(WCHAR));
439 return E_OUTOFMEMORY;
441 r = IStream_Read(stm, temp, len, &count);
442 if( FAILED (r) || ( count != len ) )
444 HeapFree( GetProcessHeap(), 0, temp );
448 TRACE("read %s\n", debugstr_an(temp,len));
450 /* convert to unicode if necessary */
453 count = MultiByteToWideChar( CP_ACP, 0, (LPSTR) temp, len, NULL, 0 );
454 str = HeapAlloc( GetProcessHeap(), 0, (count+1)*sizeof (WCHAR) );
456 MultiByteToWideChar( CP_ACP, 0, (LPSTR) temp, len, str, count );
457 HeapFree( GetProcessHeap(), 0, temp );
471 static HRESULT Stream_LoadLocation( IStream* stm )
480 r = IStream_Read( stm, &size, sizeof(size), &count );
483 if( count != sizeof(loc->dwTotalSize) )
486 loc = HeapAlloc( GetProcessHeap(), 0, size );
488 return E_OUTOFMEMORY;
490 r = IStream_Read( stm, &loc->dwHeaderSize, size-sizeof(size), &count );
493 if( count != (size - sizeof(size)) )
498 loc->dwTotalSize = size;
500 TRACE("Read %ld bytes\n",count);
502 /* FIXME: do something useful with it */
503 HeapFree( GetProcessHeap(), 0, loc );
507 HeapFree( GetProcessHeap(), 0, loc );
511 /************************************************************************
512 * IPersistStream_Load (IPersistStream)
514 static HRESULT WINAPI IPersistStream_fnLoad(
515 IPersistStream* iface,
521 WCHAR sTemp[MAX_PATH];
524 _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
526 TRACE("(%p)(%p)\n", This, stm);
529 return STG_E_INVALIDPOINTER;
532 r = IStream_Read(stm, &hdr, sizeof(hdr), &dwBytesRead);
536 if( dwBytesRead != sizeof(hdr))
538 if( hdr.dwSize != sizeof(hdr))
540 if( !IsEqualIID(&hdr.MagicGuid, &CLSID_ShellLink) )
543 /* if( hdr.dwFlags & SCF_PIDL ) */ /* FIXME: seems to always have a PIDL */
545 r = ILLoadFromStream( stm, &This->pPidl );
549 This->wHotKey = hdr.wHotKey;
550 This->iIcoNdx = hdr.nIcon;
551 FileTimeToSystemTime (&hdr.Time1, &This->time1);
552 FileTimeToSystemTime (&hdr.Time2, &This->time2);
553 FileTimeToSystemTime (&hdr.Time3, &This->time3);
555 GetDateFormatW(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&This->time1, NULL, sTemp, 256);
556 TRACE("-- time1: %s\n", debugstr_w(sTemp) );
557 GetDateFormatW(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&This->time2, NULL, sTemp, 256);
558 TRACE("-- time1: %s\n", debugstr_w(sTemp) );
559 GetDateFormatW(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&This->time3, NULL, sTemp, 256);
560 TRACE("-- time1: %s\n", debugstr_w(sTemp) );
563 if( hdr.dwFlags & SCF_NORMAL )
564 r = Stream_LoadLocation( stm );
567 unicode = hdr.dwFlags & SCF_UNICODE;
568 if( hdr.dwFlags & SCF_DESCRIPTION )
570 r = Stream_LoadString( stm, unicode, &This->sDescription );
571 TRACE("Description -> %s\n",debugstr_w(This->sDescription));
576 if( hdr.dwFlags & SCF_RELATIVE )
578 r = Stream_LoadString( stm, unicode, &This->sPathRel );
579 TRACE("Relative Path-> %s\n",debugstr_w(This->sPathRel));
584 if( hdr.dwFlags & SCF_WORKDIR )
586 r = Stream_LoadString( stm, unicode, &This->sWorkDir );
587 TRACE("Working Dir -> %s\n",debugstr_w(This->sWorkDir));
592 if( hdr.dwFlags & SCF_ARGS )
594 r = Stream_LoadString( stm, unicode, &This->sArgs );
595 TRACE("Working Dir -> %s\n",debugstr_w(This->sArgs));
600 if( hdr.dwFlags & SCF_CUSTOMICON )
602 r = Stream_LoadString( stm, unicode, &This->sIcoPath );
603 TRACE("Icon file -> %s\n",debugstr_w(This->sIcoPath));
617 /************************************************************************
620 * Helper function for IPersistStream_Save. Writes a unicode string
621 * with terminating nul byte to a stream, preceded by the its length.
623 static HRESULT Stream_WriteString( IStream* stm, LPCWSTR str )
625 USHORT len = lstrlenW( str ) + 1;
629 r = IStream_Write( stm, &len, sizeof(len), &count );
633 len *= sizeof(WCHAR);
635 r = IStream_Write( stm, str, len, &count );
642 static HRESULT Stream_WriteLocationInfo( IStream* stm, LPCWSTR filename )
647 FIXME("writing empty location info\n");
649 memset( &loc, 0, sizeof(loc) );
650 loc.dwTotalSize = sizeof(loc) - sizeof(loc.dwTotalSize);
652 /* FIXME: fill this in */
654 return IStream_Write( stm, &loc, loc.dwTotalSize, &count );
657 /************************************************************************
658 * IPersistStream_Save (IPersistStream)
660 * FIXME: makes assumptions about byte order
662 static HRESULT WINAPI IPersistStream_fnSave(
663 IPersistStream* iface,
671 _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
673 TRACE("(%p) %p %x\n", This, stm, fClearDirty);
675 /* if there's no PIDL, generate one */
680 This->pPidl = ILCreateFromPathW( This->sPath );
683 memset(&header, 0, sizeof(header));
684 header.dwSize = sizeof(header);
685 memcpy(&header.MagicGuid, &CLSID_ShellLink, sizeof(header.MagicGuid) );
687 header.wHotKey = This->wHotKey;
688 header.nIcon = This->iIcoNdx;
689 header.dwFlags = SCF_UNICODE; /* strings are in unicode */
690 header.dwFlags |= SCF_NORMAL; /* how do we determine this ? */
692 header.dwFlags |= SCF_PIDL;
693 if( This->sDescription )
694 header.dwFlags |= SCF_DESCRIPTION;
696 header.dwFlags |= SCF_WORKDIR;
698 header.dwFlags |= SCF_ARGS;
700 header.dwFlags |= SCF_CUSTOMICON;
702 SystemTimeToFileTime ( &This->time1, &header.Time1 );
703 SystemTimeToFileTime ( &This->time2, &header.Time2 );
704 SystemTimeToFileTime ( &This->time3, &header.Time3 );
706 /* write the Shortcut header */
707 r = IStream_Write( stm, &header, sizeof(header), &count );
710 ERR("Write failed at %d\n",__LINE__);
714 TRACE("Writing pidl \n");
716 /* write the PIDL to the shortcut */
719 r = ILSaveToStream( stm, This->pPidl );
722 ERR("Failed to write PIDL at %d\n",__LINE__);
727 TRACE("Path = %s\n", debugstr_w(This->sPath));
730 Stream_WriteLocationInfo( stm, This->sPath );
732 TRACE("Description = %s\n", debugstr_w(This->sDescription));
733 if( This->sDescription )
734 r = Stream_WriteString( stm, This->sDescription );
737 r = Stream_WriteString( stm, This->sPathRel );
740 r = Stream_WriteString( stm, This->sWorkDir );
743 r = Stream_WriteString( stm, This->sArgs );
746 r = Stream_WriteString( stm, This->sIcoPath );
751 /************************************************************************
752 * IPersistStream_GetSizeMax (IPersistStream)
754 static HRESULT WINAPI IPersistStream_fnGetSizeMax(
755 IPersistStream* iface,
756 ULARGE_INTEGER* pcbSize)
758 _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
760 TRACE("(%p)\n", This);
765 static ICOM_VTABLE(IPersistStream) psvt =
767 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
768 IPersistStream_fnQueryInterface,
769 IPersistStream_fnAddRef,
770 IPersistStream_fnRelease,
771 IPersistStream_fnGetClassID,
772 IPersistStream_fnIsDirty,
773 IPersistStream_fnLoad,
774 IPersistStream_fnSave,
775 IPersistStream_fnGetSizeMax
778 /**************************************************************************
779 * IShellLink_Constructor
781 HRESULT WINAPI IShellLink_Constructor (
782 IUnknown * pUnkOuter,
788 TRACE("unkOut=%p riid=%s\n",pUnkOuter, debugstr_guid(riid));
792 if(pUnkOuter) return CLASS_E_NOAGGREGATION;
793 sl = (IShellLinkImpl *) LocalAlloc(GMEM_ZEROINIT,sizeof(IShellLinkImpl));
794 if (!sl) return E_OUTOFMEMORY;
798 sl->lpvtblw = &slvtw;
799 sl->lpvtblPersistFile = &pfvt;
800 sl->lpvtblPersistStream = &psvt;
801 sl->iShowCmd = SW_SHOWNORMAL;
804 TRACE("(%p)->()\n",sl);
806 if (IsEqualIID(riid, &IID_IUnknown) ||
807 IsEqualIID(riid, &IID_IShellLinkA))
809 else if (IsEqualIID(riid, &IID_IShellLinkW))
810 *ppv = &(sl->lpvtblw);
812 LocalFree((HLOCAL)sl);
813 ERR("E_NOINTERFACE\n");
814 return E_NOINTERFACE;
821 static BOOL SHELL_ExistsFileW(LPCWSTR path)
823 HANDLE hfile = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
825 if (hfile != INVALID_HANDLE_VALUE) {
832 /**************************************************************************
833 * ShellLink_UpdatePath
834 * update absolute path in sPath using relative path in sPathRel
836 static HRESULT ShellLink_UpdatePath(LPWSTR sPathRel, LPCWSTR path, LPCWSTR sWorkDir, LPWSTR* psPath)
838 if (!path || !psPath)
841 if (!*psPath && sPathRel) {
842 WCHAR buffer[2*MAX_PATH], abs_path[2*MAX_PATH];
845 /* first try if [directory of link file] + [relative path] finds an existing file */
847 GetFullPathNameW( path, MAX_PATH*2, buffer, &final );
850 lstrcpyW(final, sPathRel);
854 if (SHELL_ExistsFileW(buffer)) {
855 if (!GetFullPathNameW(buffer, MAX_PATH, abs_path, &final))
856 lstrcpyW(abs_path, buffer);
858 /* try if [working directory] + [relative path] finds an existing file */
860 lstrcpyW(buffer, sWorkDir);
861 lstrcpyW(PathAddBackslashW(buffer), sPathRel);
863 if (SHELL_ExistsFileW(buffer))
864 if (!GetFullPathNameW(buffer, MAX_PATH, abs_path, &final))
865 lstrcpyW(abs_path, buffer);
869 /* FIXME: This is even not enough - not all shell links can be resolved using this algorithm. */
871 lstrcpyW(abs_path, sPathRel);
873 *psPath = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(abs_path)+1)*sizeof(WCHAR));
875 return E_OUTOFMEMORY;
877 lstrcpyW(*psPath, abs_path);
883 /**************************************************************************
884 * IShellLink_ConstructFromFile
886 HRESULT WINAPI IShellLink_ConstructFromFile (
895 HRESULT hr = IShellLink_Constructor(NULL, riid, (LPVOID*)&psl);
902 hr = IShellLinkW_QueryInterface(psl, &IID_IPersistFile, (LPVOID*)&ppf);
905 WCHAR path[MAX_PATH];
907 if (SHGetPathFromIDListW(pidl, path))
908 hr = IPersistFile_Load(ppf, path, 0);
913 *ppv = (IUnknown*) psl;
915 IPersistFile_Release(ppf);
919 IShellLinkW_Release(psl);
925 /**************************************************************************
926 * IShellLinkA_QueryInterface
928 static HRESULT WINAPI IShellLinkA_fnQueryInterface( IShellLinkA * iface, REFIID riid, LPVOID *ppvObj)
930 ICOM_THIS(IShellLinkImpl, iface);
932 TRACE("(%p)->(\n\tIID:\t%s)\n",This,debugstr_guid(riid));
936 if(IsEqualIID(riid, &IID_IUnknown) ||
937 IsEqualIID(riid, &IID_IShellLinkA))
941 else if(IsEqualIID(riid, &IID_IShellLinkW))
943 *ppvObj = (IShellLinkW *)&(This->lpvtblw);
945 else if(IsEqualIID(riid, &IID_IPersistFile))
947 *ppvObj = (IPersistFile *)&(This->lpvtblPersistFile);
949 else if(IsEqualIID(riid, &IID_IPersistStream))
951 *ppvObj = (IPersistStream *)&(This->lpvtblPersistStream);
956 IUnknown_AddRef((IUnknown*)(*ppvObj));
957 TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
960 TRACE("-- Interface: E_NOINTERFACE\n");
961 return E_NOINTERFACE;
963 /******************************************************************************
966 static ULONG WINAPI IShellLinkA_fnAddRef(IShellLinkA * iface)
968 ICOM_THIS(IShellLinkImpl, iface);
970 TRACE("(%p)->(count=%lu)\n",This,This->ref);
972 return ++(This->ref);
974 /******************************************************************************
975 * IShellLinkA_Release
977 static ULONG WINAPI IShellLinkA_fnRelease(IShellLinkA * iface)
979 ICOM_THIS(IShellLinkImpl, iface);
981 TRACE("(%p)->(count=%lu)\n",This,This->ref);
986 TRACE("-- destroying IShellLink(%p)\n",This);
989 HeapFree(GetProcessHeap(), 0, This->sIcoPath);
992 HeapFree(GetProcessHeap(), 0, This->sArgs);
995 HeapFree(GetProcessHeap(), 0, This->sWorkDir);
997 if (This->sDescription)
998 HeapFree(GetProcessHeap(), 0, This->sDescription);
1001 HeapFree(GetProcessHeap(),0,This->sPath);
1004 ILFree(This->pPidl);
1006 LocalFree((HANDLE)This);
1011 static HRESULT WINAPI IShellLinkA_fnGetPath(IShellLinkA * iface, LPSTR pszFile,
1012 INT cchMaxPath, WIN32_FIND_DATAA *pfd, DWORD fFlags)
1014 ICOM_THIS(IShellLinkImpl, iface);
1016 TRACE("(%p)->(pfile=%p len=%u find_data=%p flags=%lu)(%s)\n",
1017 This, pszFile, cchMaxPath, pfd, fFlags, debugstr_w(This->sPath));
1022 WideCharToMultiByte( CP_ACP, 0, This->sPath, -1,
1023 pszFile, cchMaxPath, NULL, NULL);
1028 static HRESULT WINAPI IShellLinkA_fnGetIDList(IShellLinkA * iface, LPITEMIDLIST * ppidl)
1030 ICOM_THIS(IShellLinkImpl, iface);
1032 TRACE("(%p)->(ppidl=%p)\n",This, ppidl);
1034 *ppidl = ILClone(This->pPidl);
1039 static HRESULT WINAPI IShellLinkA_fnSetIDList(IShellLinkA * iface, LPCITEMIDLIST pidl)
1041 ICOM_THIS(IShellLinkImpl, iface);
1043 TRACE("(%p)->(pidl=%p)\n",This, pidl);
1046 ILFree(This->pPidl);
1047 This->pPidl = ILClone (pidl);
1048 This->bDirty = TRUE;
1053 static HRESULT WINAPI IShellLinkA_fnGetDescription(IShellLinkA * iface, LPSTR pszName,INT cchMaxName)
1055 ICOM_THIS(IShellLinkImpl, iface);
1057 TRACE("(%p)->(%p len=%u)\n",This, pszName, cchMaxName);
1061 if( This->sDescription )
1062 WideCharToMultiByte( CP_ACP, 0, This->sDescription, -1,
1063 pszName, cchMaxName, NULL, NULL);
1067 static HRESULT WINAPI IShellLinkA_fnSetDescription(IShellLinkA * iface, LPCSTR pszName)
1069 ICOM_THIS(IShellLinkImpl, iface);
1071 TRACE("(%p)->(pName=%s)\n", This, pszName);
1073 if (This->sDescription)
1074 HeapFree(GetProcessHeap(), 0, This->sDescription);
1075 This->sDescription = HEAP_strdupAtoW( GetProcessHeap(), 0, pszName);
1076 if ( !This->sDescription )
1077 return E_OUTOFMEMORY;
1079 This->bDirty = TRUE;
1084 static HRESULT WINAPI IShellLinkA_fnGetWorkingDirectory(IShellLinkA * iface, LPSTR pszDir,INT cchMaxPath)
1086 ICOM_THIS(IShellLinkImpl, iface);
1088 TRACE("(%p)->(%p len=%u)\n", This, pszDir, cchMaxPath);
1092 if( This->sWorkDir )
1093 WideCharToMultiByte( CP_ACP, 0, This->sWorkDir, -1,
1094 pszDir, cchMaxPath, NULL, NULL);
1099 static HRESULT WINAPI IShellLinkA_fnSetWorkingDirectory(IShellLinkA * iface, LPCSTR pszDir)
1101 ICOM_THIS(IShellLinkImpl, iface);
1103 TRACE("(%p)->(dir=%s)\n",This, pszDir);
1106 HeapFree(GetProcessHeap(), 0, This->sWorkDir);
1107 This->sWorkDir = HEAP_strdupAtoW( GetProcessHeap(), 0, pszDir);
1108 if ( !This->sWorkDir )
1109 return E_OUTOFMEMORY;
1111 This->bDirty = TRUE;
1116 static HRESULT WINAPI IShellLinkA_fnGetArguments(IShellLinkA * iface, LPSTR pszArgs,INT cchMaxPath)
1118 ICOM_THIS(IShellLinkImpl, iface);
1120 TRACE("(%p)->(%p len=%u)\n", This, pszArgs, cchMaxPath);
1125 WideCharToMultiByte( CP_ACP, 0, This->sArgs, -1,
1126 pszArgs, cchMaxPath, NULL, NULL);
1131 static HRESULT WINAPI IShellLinkA_fnSetArguments(IShellLinkA * iface, LPCSTR pszArgs)
1133 ICOM_THIS(IShellLinkImpl, iface);
1135 TRACE("(%p)->(args=%s)\n",This, pszArgs);
1138 HeapFree(GetProcessHeap(), 0, This->sArgs);
1139 This->sArgs = HEAP_strdupAtoW( GetProcessHeap(), 0, pszArgs);
1141 return E_OUTOFMEMORY;
1143 This->bDirty = TRUE;
1148 static HRESULT WINAPI IShellLinkA_fnGetHotkey(IShellLinkA * iface, WORD *pwHotkey)
1150 ICOM_THIS(IShellLinkImpl, iface);
1152 TRACE("(%p)->(%p)(0x%08x)\n",This, pwHotkey, This->wHotKey);
1154 *pwHotkey = This->wHotKey;
1159 static HRESULT WINAPI IShellLinkA_fnSetHotkey(IShellLinkA * iface, WORD wHotkey)
1161 ICOM_THIS(IShellLinkImpl, iface);
1163 TRACE("(%p)->(hotkey=%x)\n",This, wHotkey);
1165 This->wHotKey = wHotkey;
1166 This->bDirty = TRUE;
1171 static HRESULT WINAPI IShellLinkA_fnGetShowCmd(IShellLinkA * iface, INT *piShowCmd)
1173 ICOM_THIS(IShellLinkImpl, iface);
1175 TRACE("(%p)->(%p)\n",This, piShowCmd);
1176 *piShowCmd = This->iShowCmd;
1180 static HRESULT WINAPI IShellLinkA_fnSetShowCmd(IShellLinkA * iface, INT iShowCmd)
1182 ICOM_THIS(IShellLinkImpl, iface);
1184 TRACE("(%p) %d\n",This, iShowCmd);
1186 This->iShowCmd = iShowCmd;
1187 This->bDirty = TRUE;
1192 static HRESULT WINAPI IShellLinkA_fnGetIconLocation(IShellLinkA * iface, LPSTR pszIconPath,INT cchIconPath,INT *piIcon)
1194 ICOM_THIS(IShellLinkImpl, iface);
1196 TRACE("(%p)->(%p len=%u iicon=%p)\n", This, pszIconPath, cchIconPath, piIcon);
1200 if( This->sIcoPath )
1201 WideCharToMultiByte( CP_ACP, 0, This->sIcoPath, -1,
1202 pszIconPath, cchIconPath, NULL, NULL);
1203 *piIcon = This->iIcoNdx;
1208 static HRESULT WINAPI IShellLinkA_fnSetIconLocation(IShellLinkA * iface, LPCSTR pszIconPath,INT iIcon)
1210 ICOM_THIS(IShellLinkImpl, iface);
1212 TRACE("(%p)->(path=%s iicon=%u)\n",This, pszIconPath, iIcon);
1215 HeapFree(GetProcessHeap(), 0, This->sIcoPath);
1216 This->sIcoPath = HEAP_strdupAtoW(GetProcessHeap(), 0, pszIconPath);
1217 if ( !This->sIcoPath )
1218 return E_OUTOFMEMORY;
1220 This->iIcoNdx = iIcon;
1221 This->bDirty = TRUE;
1226 static HRESULT WINAPI IShellLinkA_fnSetRelativePath(IShellLinkA * iface, LPCSTR pszPathRel, DWORD dwReserved)
1228 ICOM_THIS(IShellLinkImpl, iface);
1230 FIXME("(%p)->(path=%s %lx)\n",This, pszPathRel, dwReserved);
1233 HeapFree(GetProcessHeap(), 0, This->sPathRel);
1234 This->sPathRel = HEAP_strdupAtoW(GetProcessHeap(), 0, pszPathRel);
1235 This->bDirty = TRUE;
1240 static HRESULT WINAPI IShellLinkA_fnResolve(IShellLinkA * iface, HWND hwnd, DWORD fFlags)
1242 ICOM_THIS(IShellLinkImpl, iface);
1244 FIXME("(%p)->(hwnd=%p flags=%lx)\n",This, hwnd, fFlags);
1248 static HRESULT WINAPI IShellLinkA_fnSetPath(IShellLinkA * iface, LPCSTR pszFile)
1250 ICOM_THIS(IShellLinkImpl, iface);
1252 TRACE("(%p)->(path=%s)\n",This, pszFile);
1255 HeapFree(GetProcessHeap(), 0, This->sPath);
1256 This->sPath = HEAP_strdupAtoW(GetProcessHeap(), 0, pszFile);
1258 return E_OUTOFMEMORY;
1260 This->bDirty = TRUE;
1265 /**************************************************************************
1266 * IShellLink Implementation
1269 static ICOM_VTABLE(IShellLinkA) slvt =
1271 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1272 IShellLinkA_fnQueryInterface,
1273 IShellLinkA_fnAddRef,
1274 IShellLinkA_fnRelease,
1275 IShellLinkA_fnGetPath,
1276 IShellLinkA_fnGetIDList,
1277 IShellLinkA_fnSetIDList,
1278 IShellLinkA_fnGetDescription,
1279 IShellLinkA_fnSetDescription,
1280 IShellLinkA_fnGetWorkingDirectory,
1281 IShellLinkA_fnSetWorkingDirectory,
1282 IShellLinkA_fnGetArguments,
1283 IShellLinkA_fnSetArguments,
1284 IShellLinkA_fnGetHotkey,
1285 IShellLinkA_fnSetHotkey,
1286 IShellLinkA_fnGetShowCmd,
1287 IShellLinkA_fnSetShowCmd,
1288 IShellLinkA_fnGetIconLocation,
1289 IShellLinkA_fnSetIconLocation,
1290 IShellLinkA_fnSetRelativePath,
1291 IShellLinkA_fnResolve,
1292 IShellLinkA_fnSetPath
1296 /**************************************************************************
1297 * IShellLinkW_fnQueryInterface
1299 static HRESULT WINAPI IShellLinkW_fnQueryInterface(
1300 IShellLinkW * iface, REFIID riid, LPVOID *ppvObj)
1302 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1304 return IShellLinkA_QueryInterface((IShellLinkA*)This, riid, ppvObj);
1307 /******************************************************************************
1308 * IShellLinkW_fnAddRef
1310 static ULONG WINAPI IShellLinkW_fnAddRef(IShellLinkW * iface)
1312 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1314 TRACE("(%p)->(count=%lu)\n",This,This->ref);
1316 return IShellLinkA_AddRef((IShellLinkA*)This);
1318 /******************************************************************************
1319 * IShellLinkW_fnRelease
1322 static ULONG WINAPI IShellLinkW_fnRelease(IShellLinkW * iface)
1324 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1326 TRACE("(%p)->(count=%lu)\n",This,This->ref);
1328 return IShellLinkA_Release((IShellLinkA*)This);
1331 static HRESULT WINAPI IShellLinkW_fnGetPath(IShellLinkW * iface, LPWSTR pszFile,INT cchMaxPath, WIN32_FIND_DATAW *pfd, DWORD fFlags)
1333 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1335 FIXME("(%p)->(pfile=%p len=%u find_data=%p flags=%lu)\n",This, pszFile, cchMaxPath, pfd, fFlags);
1339 lstrcpynW( pszFile, This->sPath, cchMaxPath );
1344 static HRESULT WINAPI IShellLinkW_fnGetIDList(IShellLinkW * iface, LPITEMIDLIST * ppidl)
1346 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1348 TRACE("(%p)->(ppidl=%p)\n",This, ppidl);
1351 *ppidl = ILClone( This->pPidl );
1358 static HRESULT WINAPI IShellLinkW_fnSetIDList(IShellLinkW * iface, LPCITEMIDLIST pidl)
1360 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1362 TRACE("(%p)->(pidl=%p)\n",This, pidl);
1365 ILFree( This->pPidl );
1366 This->pPidl = ILClone( pidl );
1370 This->bDirty = TRUE;
1375 static HRESULT WINAPI IShellLinkW_fnGetDescription(IShellLinkW * iface, LPWSTR pszName,INT cchMaxName)
1377 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1379 TRACE("(%p)->(%p len=%u)\n",This, pszName, cchMaxName);
1383 if( This->sDescription )
1384 lstrcpynW( pszName, This->sDescription, cchMaxName );
1389 static HRESULT WINAPI IShellLinkW_fnSetDescription(IShellLinkW * iface, LPCWSTR pszName)
1391 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1393 TRACE("(%p)->(desc=%s)\n",This, debugstr_w(pszName));
1395 if (This->sDescription)
1396 HeapFree(GetProcessHeap(), 0, This->sDescription);
1397 This->sDescription = HeapAlloc( GetProcessHeap(), 0,
1398 (lstrlenW( pszName )+1)*sizeof(WCHAR) );
1399 if ( !This->sDescription )
1400 return E_OUTOFMEMORY;
1402 lstrcpyW( This->sDescription, pszName );
1403 This->bDirty = TRUE;
1408 static HRESULT WINAPI IShellLinkW_fnGetWorkingDirectory(IShellLinkW * iface, LPWSTR pszDir,INT cchMaxPath)
1410 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1412 TRACE("(%p)->(%p len %u)\n", This, pszDir, cchMaxPath);
1416 if( This->sWorkDir )
1417 lstrcpynW( pszDir, This->sWorkDir, cchMaxPath );
1422 static HRESULT WINAPI IShellLinkW_fnSetWorkingDirectory(IShellLinkW * iface, LPCWSTR pszDir)
1424 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1426 TRACE("(%p)->(dir=%s)\n",This, debugstr_w(pszDir));
1429 HeapFree(GetProcessHeap(), 0, This->sWorkDir);
1430 This->sWorkDir = HeapAlloc( GetProcessHeap(), 0,
1431 (lstrlenW( pszDir )+1)*sizeof (WCHAR) );
1432 if ( !This->sWorkDir )
1433 return E_OUTOFMEMORY;
1434 lstrcpyW( This->sWorkDir, pszDir );
1435 This->bDirty = TRUE;
1440 static HRESULT WINAPI IShellLinkW_fnGetArguments(IShellLinkW * iface, LPWSTR pszArgs,INT cchMaxPath)
1442 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1444 TRACE("(%p)->(%p len=%u)\n", This, pszArgs, cchMaxPath);
1449 lstrcpynW( pszArgs, This->sArgs, cchMaxPath );
1454 static HRESULT WINAPI IShellLinkW_fnSetArguments(IShellLinkW * iface, LPCWSTR pszArgs)
1456 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1458 TRACE("(%p)->(args=%s)\n",This, debugstr_w(pszArgs));
1461 HeapFree(GetProcessHeap(), 0, This->sArgs);
1462 This->sArgs = HeapAlloc( GetProcessHeap(), 0,
1463 (lstrlenW( pszArgs )+1)*sizeof (WCHAR) );
1465 return E_OUTOFMEMORY;
1466 lstrcpyW( This->sArgs, pszArgs );
1467 This->bDirty = TRUE;
1472 static HRESULT WINAPI IShellLinkW_fnGetHotkey(IShellLinkW * iface, WORD *pwHotkey)
1474 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1476 TRACE("(%p)->(%p)\n",This, pwHotkey);
1478 *pwHotkey=This->wHotKey;
1483 static HRESULT WINAPI IShellLinkW_fnSetHotkey(IShellLinkW * iface, WORD wHotkey)
1485 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1487 TRACE("(%p)->(hotkey=%x)\n",This, wHotkey);
1489 This->wHotKey = wHotkey;
1490 This->bDirty = TRUE;
1495 static HRESULT WINAPI IShellLinkW_fnGetShowCmd(IShellLinkW * iface, INT *piShowCmd)
1497 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1499 TRACE("(%p)->(%p)\n",This, piShowCmd);
1501 *piShowCmd = This->iShowCmd;
1506 static HRESULT WINAPI IShellLinkW_fnSetShowCmd(IShellLinkW * iface, INT iShowCmd)
1508 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1510 This->iShowCmd = iShowCmd;
1511 This->bDirty = TRUE;
1516 static HRESULT WINAPI IShellLinkW_fnGetIconLocation(IShellLinkW * iface, LPWSTR pszIconPath,INT cchIconPath,INT *piIcon)
1518 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1520 TRACE("(%p)->(%p len=%u iicon=%p)\n", This, pszIconPath, cchIconPath, piIcon);
1524 if( This->sIcoPath )
1525 lstrcpynW( pszIconPath, This->sIcoPath, cchIconPath );
1526 *piIcon = This->iIcoNdx;
1531 static HRESULT WINAPI IShellLinkW_fnSetIconLocation(IShellLinkW * iface, LPCWSTR pszIconPath,INT iIcon)
1533 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1535 TRACE("(%p)->(path=%s iicon=%u)\n",This, debugstr_w(pszIconPath), iIcon);
1538 HeapFree(GetProcessHeap(), 0, This->sIcoPath);
1539 This->sIcoPath = HeapAlloc( GetProcessHeap(), 0,
1540 (lstrlenW( pszIconPath )+1)*sizeof (WCHAR) );
1541 if ( !This->sIcoPath )
1542 return E_OUTOFMEMORY;
1543 lstrcpyW( This->sIcoPath, pszIconPath );
1545 This->iIcoNdx = iIcon;
1546 This->bDirty = TRUE;
1551 static HRESULT WINAPI IShellLinkW_fnSetRelativePath(IShellLinkW * iface, LPCWSTR pszPathRel, DWORD dwReserved)
1553 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1555 TRACE("(%p)->(path=%s %lx)\n",This, debugstr_w(pszPathRel), dwReserved);
1558 HeapFree(GetProcessHeap(), 0, This->sPathRel);
1559 This->sPathRel = HeapAlloc( GetProcessHeap(), 0,
1560 (lstrlenW( pszPathRel )+1) * sizeof (WCHAR) );
1561 if ( !This->sPathRel )
1562 return E_OUTOFMEMORY;
1563 lstrcpyW( This->sPathRel, pszPathRel );
1564 This->bDirty = TRUE;
1569 static HRESULT WINAPI IShellLinkW_fnResolve(IShellLinkW * iface, HWND hwnd, DWORD fFlags)
1571 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1573 FIXME("(%p)->(hwnd=%p flags=%lx)\n",This, hwnd, fFlags);
1578 static HRESULT WINAPI IShellLinkW_fnSetPath(IShellLinkW * iface, LPCWSTR pszFile)
1580 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
1582 TRACE("(%p)->(path=%s)\n",This, debugstr_w(pszFile));
1585 HeapFree(GetProcessHeap(), 0, This->sPath);
1586 This->sPath = HeapAlloc( GetProcessHeap(), 0,
1587 (lstrlenW( pszFile )+1) * sizeof (WCHAR) );
1589 return E_OUTOFMEMORY;
1591 lstrcpyW( This->sPath, pszFile );
1592 This->bDirty = TRUE;
1597 /**************************************************************************
1598 * IShellLinkW Implementation
1601 static ICOM_VTABLE(IShellLinkW) slvtw =
1603 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1604 IShellLinkW_fnQueryInterface,
1605 IShellLinkW_fnAddRef,
1606 IShellLinkW_fnRelease,
1607 IShellLinkW_fnGetPath,
1608 IShellLinkW_fnGetIDList,
1609 IShellLinkW_fnSetIDList,
1610 IShellLinkW_fnGetDescription,
1611 IShellLinkW_fnSetDescription,
1612 IShellLinkW_fnGetWorkingDirectory,
1613 IShellLinkW_fnSetWorkingDirectory,
1614 IShellLinkW_fnGetArguments,
1615 IShellLinkW_fnSetArguments,
1616 IShellLinkW_fnGetHotkey,
1617 IShellLinkW_fnSetHotkey,
1618 IShellLinkW_fnGetShowCmd,
1619 IShellLinkW_fnSetShowCmd,
1620 IShellLinkW_fnGetIconLocation,
1621 IShellLinkW_fnSetIconLocation,
1622 IShellLinkW_fnSetRelativePath,
1623 IShellLinkW_fnResolve,
1624 IShellLinkW_fnSetPath