3 * Copyright 1997 Marcus Meissner
4 * Copyright 1998 Juergen Schmied
5 * Copyright 2005 Mike McCormack
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 * Nearly complete information about the binary formats
23 * of .lnk files available at http://www.wotsit.org
25 * You can use winedump to examine the contents of a link file:
28 * MSI advertised shortcuts are totally undocumented. They provide an
29 * icon for a program that is not yet installed, and invoke MSI to
30 * install the program when the shortcut is clicked on. They are
31 * created by passing a special string to SetPath, and the information
32 * in that string is parsed an stored.
36 #define NONAMELESSUNION
38 #include "wine/debug.h"
48 #include "undocshell.h"
51 #include "shell32_main.h"
59 WINE_DEFAULT_DEBUG_CHANNEL(shell
);
61 DEFINE_GUID( SHELL32_AdvtShortcutProduct
,
62 0x9db1186f,0x40df,0x11d1,0xaa,0x8c,0x00,0xc0,0x4f,0xb6,0x78,0x63);
63 DEFINE_GUID( SHELL32_AdvtShortcutComponent
,
64 0x9db1186e,0x40df,0x11d1,0xaa,0x8c,0x00,0xc0,0x4f,0xb6,0x78,0x63);
66 /* link file formats */
70 typedef struct _LINK_HEADER
72 DWORD dwSize
; /* 0x00 size of the header - 0x4c */
73 GUID MagicGuid
; /* 0x04 is CLSID_ShellLink */
74 DWORD dwFlags
; /* 0x14 describes elements following */
75 DWORD dwFileAttr
; /* 0x18 attributes of the target file */
76 FILETIME Time1
; /* 0x1c */
77 FILETIME Time2
; /* 0x24 */
78 FILETIME Time3
; /* 0x2c */
79 DWORD dwFileLength
; /* 0x34 File length */
80 DWORD nIcon
; /* 0x38 icon number */
81 DWORD fStartup
; /* 0x3c startup type */
82 DWORD wHotKey
; /* 0x40 hotkey */
83 DWORD Unknown5
; /* 0x44 */
84 DWORD Unknown6
; /* 0x48 */
85 } LINK_HEADER
, * PLINK_HEADER
;
87 #define SHLINK_LOCAL 0
88 #define SHLINK_REMOTE 1
90 typedef struct _LOCATION_INFO
97 DWORD dwNetworkVolTableOfs
;
101 typedef struct _LOCAL_VOLUME_INFO
109 typedef struct volume_info_t
113 WCHAR label
[12]; /* assume 8.3 */
118 /* IShellLink Implementation */
122 IShellLinkA IShellLinkA_iface
;
123 IShellLinkW IShellLinkW_iface
;
124 IPersistFile IPersistFile_iface
;
125 IPersistStream IPersistStream_iface
;
126 IShellLinkDataList IShellLinkDataList_iface
;
127 IShellExtInit IShellExtInit_iface
;
128 IContextMenu IContextMenu_iface
;
129 IObjectWithSite IObjectWithSite_iface
;
130 IPropertyStore IPropertyStore_iface
;
134 /* data structures according to the information in the link */
154 INT iIdOpen
; /* id of the "Open" entry in the context menu */
157 LPOLESTR filepath
; /* file path returned by IPersistFile::GetCurFile */
160 static inline IShellLinkImpl
*impl_from_IShellLinkA(IShellLinkA
*iface
)
162 return CONTAINING_RECORD(iface
, IShellLinkImpl
, IShellLinkA_iface
);
165 static inline IShellLinkImpl
*impl_from_IShellLinkW(IShellLinkW
*iface
)
167 return CONTAINING_RECORD(iface
, IShellLinkImpl
, IShellLinkW_iface
);
170 static inline IShellLinkImpl
*impl_from_IPersistFile(IPersistFile
*iface
)
172 return CONTAINING_RECORD(iface
, IShellLinkImpl
, IPersistFile_iface
);
175 static inline IShellLinkImpl
*impl_from_IPersistStream(IPersistStream
*iface
)
177 return CONTAINING_RECORD(iface
, IShellLinkImpl
, IPersistStream_iface
);
180 static inline IShellLinkImpl
*impl_from_IShellLinkDataList(IShellLinkDataList
*iface
)
182 return CONTAINING_RECORD(iface
, IShellLinkImpl
, IShellLinkDataList_iface
);
185 static inline IShellLinkImpl
*impl_from_IShellExtInit(IShellExtInit
*iface
)
187 return CONTAINING_RECORD(iface
, IShellLinkImpl
, IShellExtInit_iface
);
190 static inline IShellLinkImpl
*impl_from_IContextMenu(IContextMenu
*iface
)
192 return CONTAINING_RECORD(iface
, IShellLinkImpl
, IContextMenu_iface
);
195 static inline IShellLinkImpl
*impl_from_IObjectWithSite(IObjectWithSite
*iface
)
197 return CONTAINING_RECORD(iface
, IShellLinkImpl
, IObjectWithSite_iface
);
200 static inline IShellLinkImpl
*impl_from_IPropertyStore(IPropertyStore
*iface
)
202 return CONTAINING_RECORD(iface
, IShellLinkImpl
, IPropertyStore_iface
);
205 static HRESULT
ShellLink_UpdatePath(LPCWSTR sPathRel
, LPCWSTR path
, LPCWSTR sWorkDir
, LPWSTR
* psPath
);
207 /* strdup on the process heap */
208 static inline LPWSTR
heap_strdupAtoW( LPCSTR str
)
210 INT len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
211 LPWSTR p
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
214 MultiByteToWideChar( CP_ACP
, 0, str
, -1, p
, len
);
218 /**************************************************************************
219 * IPersistFile_QueryInterface
221 static HRESULT WINAPI
IPersistFile_fnQueryInterface(
226 IShellLinkImpl
*This
= impl_from_IPersistFile(iface
);
227 return IShellLinkW_QueryInterface(&This
->IShellLinkW_iface
, riid
, ppvObj
);
230 /******************************************************************************
231 * IPersistFile_AddRef
233 static ULONG WINAPI
IPersistFile_fnAddRef(IPersistFile
* iface
)
235 IShellLinkImpl
*This
= impl_from_IPersistFile(iface
);
236 return IShellLinkW_AddRef(&This
->IShellLinkW_iface
);
239 /******************************************************************************
240 * IPersistFile_Release
242 static ULONG WINAPI
IPersistFile_fnRelease(IPersistFile
* iface
)
244 IShellLinkImpl
*This
= impl_from_IPersistFile(iface
);
245 return IShellLinkW_Release(&This
->IShellLinkW_iface
);
248 static HRESULT WINAPI
IPersistFile_fnGetClassID(IPersistFile
* iface
, CLSID
*pClassID
)
250 IShellLinkImpl
*This
= impl_from_IPersistFile(iface
);
252 TRACE("(%p)->(%p)\n", This
, pClassID
);
254 *pClassID
= CLSID_ShellLink
;
259 static HRESULT WINAPI
IPersistFile_fnIsDirty(IPersistFile
* iface
)
261 IShellLinkImpl
*This
= impl_from_IPersistFile(iface
);
263 TRACE("(%p)\n",This
);
271 static HRESULT WINAPI
IPersistFile_fnLoad(IPersistFile
* iface
, LPCOLESTR pszFileName
, DWORD dwMode
)
273 IShellLinkImpl
*This
= impl_from_IPersistFile(iface
);
274 IPersistStream
*StreamThis
= &This
->IPersistStream_iface
;
278 TRACE("(%p, %s, %x)\n",This
, debugstr_w(pszFileName
), dwMode
);
281 dwMode
= STGM_READ
| STGM_SHARE_DENY_WRITE
;
282 r
= SHCreateStreamOnFileW(pszFileName
, dwMode
, &stm
);
285 r
= IPersistStream_Load(StreamThis
, stm
);
286 ShellLink_UpdatePath(This
->sPathRel
, pszFileName
, This
->sWorkDir
, &This
->sPath
);
287 IStream_Release( stm
);
289 /* update file path */
290 HeapFree(GetProcessHeap(), 0, This
->filepath
);
291 This
->filepath
= strdupW(pszFileName
);
293 This
->bDirty
= FALSE
;
295 TRACE("-- returning hr %08x\n", r
);
299 BOOL
run_winemenubuilder( const WCHAR
*args
)
301 static const WCHAR menubuilder
[] = {'\\','w','i','n','e','m','e','n','u','b','u','i','l','d','e','r','.','e','x','e',0};
305 PROCESS_INFORMATION pi
;
310 GetSystemDirectoryW( app
, MAX_PATH
- sizeof(menubuilder
)/sizeof(WCHAR
) );
311 strcatW( app
, menubuilder
);
313 len
= (strlenW( app
) + strlenW( args
) + 1) * sizeof(WCHAR
);
314 buffer
= HeapAlloc( GetProcessHeap(), 0, len
);
318 strcpyW( buffer
, app
);
319 strcatW( buffer
, args
);
321 TRACE("starting %s\n",debugstr_w(buffer
));
323 memset(&si
, 0, sizeof(si
));
326 Wow64DisableWow64FsRedirection( &redir
);
327 ret
= CreateProcessW( app
, buffer
, NULL
, NULL
, FALSE
, DETACHED_PROCESS
, NULL
, NULL
, &si
, &pi
);
328 Wow64RevertWow64FsRedirection( redir
);
330 HeapFree( GetProcessHeap(), 0, buffer
);
334 CloseHandle( pi
.hProcess
);
335 CloseHandle( pi
.hThread
);
341 static BOOL
StartLinkProcessor( LPCOLESTR szLink
)
343 static const WCHAR szFormat
[] = {' ','-','w',' ','"','%','s','"',0 };
348 len
= sizeof(szFormat
) + lstrlenW( szLink
) * sizeof(WCHAR
);
349 buffer
= HeapAlloc( GetProcessHeap(), 0, len
);
353 wsprintfW( buffer
, szFormat
, szLink
);
354 ret
= run_winemenubuilder( buffer
);
355 HeapFree( GetProcessHeap(), 0, buffer
);
359 static HRESULT WINAPI
IPersistFile_fnSave(IPersistFile
* iface
, LPCOLESTR pszFileName
, BOOL fRemember
)
361 IShellLinkImpl
*This
= impl_from_IPersistFile(iface
);
362 IPersistStream
*StreamThis
= &This
->IPersistStream_iface
;
366 TRACE("(%p)->(%s)\n",This
,debugstr_w(pszFileName
));
371 r
= SHCreateStreamOnFileW( pszFileName
, STGM_READWRITE
| STGM_CREATE
| STGM_SHARE_EXCLUSIVE
, &stm
);
374 r
= IPersistStream_Save(StreamThis
, stm
, FALSE
);
375 IStream_Release( stm
);
379 StartLinkProcessor( pszFileName
);
381 /* update file path */
382 HeapFree(GetProcessHeap(), 0, This
->filepath
);
383 This
->filepath
= strdupW(pszFileName
);
385 This
->bDirty
= FALSE
;
389 DeleteFileW( pszFileName
);
390 WARN("Failed to create shortcut %s\n", debugstr_w(pszFileName
) );
397 static HRESULT WINAPI
IPersistFile_fnSaveCompleted(IPersistFile
* iface
, LPCOLESTR filename
)
399 IShellLinkImpl
*This
= impl_from_IPersistFile(iface
);
400 FIXME("(%p)->(%s): stub\n", This
, debugstr_w(filename
));
404 static HRESULT WINAPI
IPersistFile_fnGetCurFile(IPersistFile
* iface
, LPOLESTR
*filename
)
406 IShellLinkImpl
*This
= impl_from_IPersistFile(iface
);
409 TRACE("(%p)->(%p)\n", This
, filename
);
417 SHGetMalloc(&pMalloc
);
418 *filename
= IMalloc_Alloc(pMalloc
, (strlenW(This
->filepath
)+1)*sizeof(WCHAR
));
419 if (!*filename
) return E_OUTOFMEMORY
;
421 strcpyW(*filename
, This
->filepath
);
426 static const IPersistFileVtbl pfvt
=
428 IPersistFile_fnQueryInterface
,
429 IPersistFile_fnAddRef
,
430 IPersistFile_fnRelease
,
431 IPersistFile_fnGetClassID
,
432 IPersistFile_fnIsDirty
,
435 IPersistFile_fnSaveCompleted
,
436 IPersistFile_fnGetCurFile
439 /************************************************************************
440 * IPersistStream_QueryInterface
442 static HRESULT WINAPI
IPersistStream_fnQueryInterface(
443 IPersistStream
* iface
,
447 IShellLinkImpl
*This
= impl_from_IPersistStream(iface
);
448 return IShellLinkW_QueryInterface(&This
->IShellLinkW_iface
, riid
, ppvObj
);
451 /************************************************************************
452 * IPersistStream_Release
454 static ULONG WINAPI
IPersistStream_fnRelease(
455 IPersistStream
* iface
)
457 IShellLinkImpl
*This
= impl_from_IPersistStream(iface
);
458 return IShellLinkW_Release(&This
->IShellLinkW_iface
);
461 /************************************************************************
462 * IPersistStream_AddRef
464 static ULONG WINAPI
IPersistStream_fnAddRef(
465 IPersistStream
* iface
)
467 IShellLinkImpl
*This
= impl_from_IPersistStream(iface
);
468 return IShellLinkW_AddRef(&This
->IShellLinkW_iface
);
471 /************************************************************************
472 * IPersistStream_GetClassID
475 static HRESULT WINAPI
IPersistStream_fnGetClassID(
476 IPersistStream
* iface
,
479 IShellLinkImpl
*This
= impl_from_IPersistStream(iface
);
480 return IPersistFile_GetClassID(&This
->IPersistFile_iface
, pClassID
);
483 /************************************************************************
484 * IPersistStream_IsDirty (IPersistStream)
486 static HRESULT WINAPI
IPersistStream_fnIsDirty(
487 IPersistStream
* iface
)
489 IShellLinkImpl
*This
= impl_from_IPersistStream(iface
);
491 TRACE("(%p)\n", This
);
497 static HRESULT
Stream_LoadString( IStream
* stm
, BOOL unicode
, LPWSTR
*pstr
)
508 r
= IStream_Read(stm
, &len
, sizeof(len
), &count
);
509 if ( FAILED (r
) || ( count
!= sizeof(len
) ) )
513 len
*= sizeof (WCHAR
);
515 TRACE("reading %d\n", len
);
516 temp
= HeapAlloc(GetProcessHeap(), 0, len
+sizeof(WCHAR
));
518 return E_OUTOFMEMORY
;
520 r
= IStream_Read(stm
, temp
, len
, &count
);
521 if( FAILED (r
) || ( count
!= len
) )
523 HeapFree( GetProcessHeap(), 0, temp
);
527 TRACE("read %s\n", debugstr_an(temp
,len
));
529 /* convert to unicode if necessary */
532 count
= MultiByteToWideChar( CP_ACP
, 0, temp
, len
, NULL
, 0 );
533 str
= HeapAlloc( GetProcessHeap(), 0, (count
+1)*sizeof (WCHAR
) );
536 HeapFree( GetProcessHeap(), 0, temp
);
537 return E_OUTOFMEMORY
;
539 MultiByteToWideChar( CP_ACP
, 0, temp
, len
, str
, count
);
540 HeapFree( GetProcessHeap(), 0, temp
);
554 static HRESULT
Stream_ReadChunk( IStream
* stm
, LPVOID
*data
)
561 unsigned char data
[1];
566 r
= IStream_Read( stm
, &size
, sizeof(size
), &count
);
567 if( FAILED( r
) || count
!= sizeof(size
) )
570 chunk
= HeapAlloc( GetProcessHeap(), 0, size
);
572 return E_OUTOFMEMORY
;
575 r
= IStream_Read( stm
, chunk
->data
, size
- sizeof(size
), &count
);
576 if( FAILED( r
) || count
!= (size
- sizeof(size
)) )
578 HeapFree( GetProcessHeap(), 0, chunk
);
582 TRACE("Read %d bytes\n",chunk
->size
);
589 static BOOL
Stream_LoadVolume( LOCAL_VOLUME_INFO
*vol
, volume_info
*volume
)
591 const int label_sz
= sizeof volume
->label
/sizeof volume
->label
[0];
595 volume
->serial
= vol
->dwVolSerial
;
596 volume
->type
= vol
->dwType
;
598 if( !vol
->dwVolLabelOfs
)
600 if( vol
->dwSize
<= vol
->dwVolLabelOfs
)
602 len
= vol
->dwSize
- vol
->dwVolLabelOfs
;
605 label
+= vol
->dwVolLabelOfs
;
606 MultiByteToWideChar( CP_ACP
, 0, label
, len
, volume
->label
, label_sz
-1);
611 static LPWSTR
Stream_LoadPath( LPCSTR p
, DWORD maxlen
)
616 while( p
[len
] && (len
< maxlen
) )
619 wlen
= MultiByteToWideChar(CP_ACP
, 0, p
, len
, NULL
, 0);
620 path
= HeapAlloc(GetProcessHeap(), 0, (wlen
+1)*sizeof(WCHAR
));
621 MultiByteToWideChar(CP_ACP
, 0, p
, len
, path
, wlen
);
627 static HRESULT
Stream_LoadLocation( IStream
*stm
,
628 volume_info
*volume
, LPWSTR
*path
)
635 r
= Stream_ReadChunk( stm
, (LPVOID
*) &p
);
639 loc
= (LOCATION_INFO
*) p
;
640 if (loc
->dwTotalSize
< sizeof(LOCATION_INFO
))
642 HeapFree( GetProcessHeap(), 0, p
);
646 /* if there's valid local volume information, load it */
647 if( loc
->dwVolTableOfs
&&
648 ((loc
->dwVolTableOfs
+ sizeof(LOCAL_VOLUME_INFO
)) <= loc
->dwTotalSize
) )
650 LOCAL_VOLUME_INFO
*volume_info
;
652 volume_info
= (LOCAL_VOLUME_INFO
*) &p
[loc
->dwVolTableOfs
];
653 Stream_LoadVolume( volume_info
, volume
);
656 /* if there's a local path, load it */
657 n
= loc
->dwLocalPathOfs
;
658 if( n
&& (n
< loc
->dwTotalSize
) )
659 *path
= Stream_LoadPath( &p
[n
], loc
->dwTotalSize
- n
);
661 TRACE("type %d serial %08x name %s path %s\n", volume
->type
,
662 volume
->serial
, debugstr_w(volume
->label
), debugstr_w(*path
));
664 HeapFree( GetProcessHeap(), 0, p
);
669 * The format of the advertised shortcut info seems to be:
674 * 0 Length of the block (4 bytes, usually 0x314)
676 * 8 string data in ASCII
677 * 8+0x104 string data in UNICODE
679 * In the original Win32 implementation the buffers are not initialized
680 * to zero, so data trailing the string is random garbage.
682 static HRESULT
Stream_LoadAdvertiseInfo( IStream
* stm
, LPWSTR
*str
)
687 EXP_DARWIN_LINK buffer
;
691 r
= IStream_Read( stm
, &buffer
.dbh
.cbSize
, sizeof (DWORD
), &count
);
695 /* make sure that we read the size of the structure even on error */
696 size
= sizeof buffer
- sizeof (DWORD
);
697 if( buffer
.dbh
.cbSize
!= sizeof buffer
)
699 ERR("Ooops. This structure is not as expected...\n");
703 r
= IStream_Read( stm
, &buffer
.dbh
.dwSignature
, size
, &count
);
710 TRACE("magic %08x string = %s\n", buffer
.dbh
.dwSignature
, debugstr_w(buffer
.szwDarwinID
));
712 if( (buffer
.dbh
.dwSignature
&0xffff0000) != 0xa0000000 )
714 ERR("Unknown magic number %08x in advertised shortcut\n", buffer
.dbh
.dwSignature
);
718 *str
= HeapAlloc( GetProcessHeap(), 0,
719 (lstrlenW(buffer
.szwDarwinID
)+1) * sizeof(WCHAR
) );
720 lstrcpyW( *str
, buffer
.szwDarwinID
);
725 /************************************************************************
726 * IPersistStream_Load (IPersistStream)
728 static HRESULT WINAPI
IPersistStream_fnLoad(
729 IPersistStream
* iface
,
738 IShellLinkImpl
*This
= impl_from_IPersistStream(iface
);
740 TRACE("%p %p\n", This
, stm
);
743 return STG_E_INVALIDPOINTER
;
746 r
= IStream_Read(stm
, &hdr
, sizeof(hdr
), &dwBytesRead
);
750 if( dwBytesRead
!= sizeof(hdr
))
752 if( hdr
.dwSize
!= sizeof(hdr
))
754 if( !IsEqualIID(&hdr
.MagicGuid
, &CLSID_ShellLink
) )
757 /* free all the old stuff */
760 memset( &This
->volume
, 0, sizeof This
->volume
);
761 HeapFree(GetProcessHeap(), 0, This
->sPath
);
763 HeapFree(GetProcessHeap(), 0, This
->sDescription
);
764 This
->sDescription
= NULL
;
765 HeapFree(GetProcessHeap(), 0, This
->sPathRel
);
766 This
->sPathRel
= NULL
;
767 HeapFree(GetProcessHeap(), 0, This
->sWorkDir
);
768 This
->sWorkDir
= NULL
;
769 HeapFree(GetProcessHeap(), 0, This
->sArgs
);
771 HeapFree(GetProcessHeap(), 0, This
->sIcoPath
);
772 This
->sIcoPath
= NULL
;
773 HeapFree(GetProcessHeap(), 0, This
->sProduct
);
774 This
->sProduct
= NULL
;
775 HeapFree(GetProcessHeap(), 0, This
->sComponent
);
776 This
->sComponent
= NULL
;
778 This
->wHotKey
= (WORD
)hdr
.wHotKey
;
779 This
->iIcoNdx
= hdr
.nIcon
;
780 FileTimeToSystemTime (&hdr
.Time1
, &This
->time1
);
781 FileTimeToSystemTime (&hdr
.Time2
, &This
->time2
);
782 FileTimeToSystemTime (&hdr
.Time3
, &This
->time3
);
785 WCHAR sTemp
[MAX_PATH
];
786 GetDateFormatW(LOCALE_USER_DEFAULT
,DATE_SHORTDATE
, &This
->time1
,
787 NULL
, sTemp
, sizeof(sTemp
)/sizeof(*sTemp
));
788 TRACE("-- time1: %s\n", debugstr_w(sTemp
) );
789 GetDateFormatW(LOCALE_USER_DEFAULT
,DATE_SHORTDATE
, &This
->time2
,
790 NULL
, sTemp
, sizeof(sTemp
)/sizeof(*sTemp
));
791 TRACE("-- time2: %s\n", debugstr_w(sTemp
) );
792 GetDateFormatW(LOCALE_USER_DEFAULT
,DATE_SHORTDATE
, &This
->time3
,
793 NULL
, sTemp
, sizeof(sTemp
)/sizeof(*sTemp
));
794 TRACE("-- time3: %s\n", debugstr_w(sTemp
) );
797 /* load all the new stuff */
798 if( hdr
.dwFlags
& SLDF_HAS_ID_LIST
)
800 r
= ILLoadFromStream( stm
, &This
->pPidl
);
806 /* load the location information */
807 if( hdr
.dwFlags
& SLDF_HAS_LINK_INFO
)
808 r
= Stream_LoadLocation( stm
, &This
->volume
, &This
->sPath
);
812 unicode
= hdr
.dwFlags
& SLDF_UNICODE
;
813 if( hdr
.dwFlags
& SLDF_HAS_NAME
)
815 r
= Stream_LoadString( stm
, unicode
, &This
->sDescription
);
816 TRACE("Description -> %s\n",debugstr_w(This
->sDescription
));
821 if( hdr
.dwFlags
& SLDF_HAS_RELPATH
)
823 r
= Stream_LoadString( stm
, unicode
, &This
->sPathRel
);
824 TRACE("Relative Path-> %s\n",debugstr_w(This
->sPathRel
));
829 if( hdr
.dwFlags
& SLDF_HAS_WORKINGDIR
)
831 r
= Stream_LoadString( stm
, unicode
, &This
->sWorkDir
);
832 TRACE("Working Dir -> %s\n",debugstr_w(This
->sWorkDir
));
837 if( hdr
.dwFlags
& SLDF_HAS_ARGS
)
839 r
= Stream_LoadString( stm
, unicode
, &This
->sArgs
);
840 TRACE("Working Dir -> %s\n",debugstr_w(This
->sArgs
));
845 if( hdr
.dwFlags
& SLDF_HAS_ICONLOCATION
)
847 r
= Stream_LoadString( stm
, unicode
, &This
->sIcoPath
);
848 TRACE("Icon file -> %s\n",debugstr_w(This
->sIcoPath
));
853 if( hdr
.dwFlags
& SLDF_HAS_LOGO3ID
)
855 r
= Stream_LoadAdvertiseInfo( stm
, &This
->sProduct
);
856 TRACE("Product -> %s\n",debugstr_w(This
->sProduct
));
861 if( hdr
.dwFlags
& SLDF_HAS_DARWINID
)
863 r
= Stream_LoadAdvertiseInfo( stm
, &This
->sComponent
);
864 TRACE("Component -> %s\n",debugstr_w(This
->sComponent
));
869 r
= IStream_Read(stm
, &zero
, sizeof zero
, &dwBytesRead
);
870 if( FAILED( r
) || zero
|| dwBytesRead
!= sizeof zero
)
872 /* Some lnk files have extra data blocks starting with a
873 * DATABLOCK_HEADER. For instance EXP_SPECIAL_FOLDER and an unknown
874 * one with a 0xa0000003 signature. However these don't seem to matter
877 WARN("Last word was not zero\n");
889 /************************************************************************
892 * Helper function for IPersistStream_Save. Writes a unicode string
893 * with terminating nul byte to a stream, preceded by the its length.
895 static HRESULT
Stream_WriteString( IStream
* stm
, LPCWSTR str
)
897 USHORT len
= lstrlenW( str
) + 1;
901 r
= IStream_Write( stm
, &len
, sizeof(len
), &count
);
905 len
*= sizeof(WCHAR
);
907 r
= IStream_Write( stm
, str
, len
, &count
);
914 /************************************************************************
915 * Stream_WriteLocationInfo
917 * Writes the location info to a stream
919 * FIXME: One day we might want to write the network volume information
920 * and the final path.
921 * Figure out how Windows deals with unicode paths here.
923 static HRESULT
Stream_WriteLocationInfo( IStream
* stm
, LPCWSTR path
,
924 volume_info
*volume
)
926 DWORD total_size
, path_size
, volume_info_size
, label_size
, final_path_size
;
927 LOCAL_VOLUME_INFO
*vol
;
929 LPSTR szLabel
, szPath
, szFinalPath
;
933 TRACE("%p %s %p\n", stm
, debugstr_w(path
), volume
);
935 /* figure out the size of everything */
936 label_size
= WideCharToMultiByte( CP_ACP
, 0, volume
->label
, -1,
937 NULL
, 0, NULL
, NULL
);
938 path_size
= WideCharToMultiByte( CP_ACP
, 0, path
, -1,
939 NULL
, 0, NULL
, NULL
);
940 volume_info_size
= sizeof *vol
+ label_size
;
942 total_size
= sizeof *loc
+ volume_info_size
+ path_size
+ final_path_size
;
944 /* create pointers to everything */
945 loc
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, total_size
);
946 vol
= (LOCAL_VOLUME_INFO
*) &loc
[1];
947 szLabel
= (LPSTR
) &vol
[1];
948 szPath
= &szLabel
[label_size
];
949 szFinalPath
= &szPath
[path_size
];
951 /* fill in the location information header */
952 loc
->dwTotalSize
= total_size
;
953 loc
->dwHeaderSize
= sizeof (*loc
);
955 loc
->dwVolTableOfs
= sizeof (*loc
);
956 loc
->dwLocalPathOfs
= sizeof (*loc
) + volume_info_size
;
957 loc
->dwNetworkVolTableOfs
= 0;
958 loc
->dwFinalPathOfs
= sizeof (*loc
) + volume_info_size
+ path_size
;
960 /* fill in the volume information */
961 vol
->dwSize
= volume_info_size
;
962 vol
->dwType
= volume
->type
;
963 vol
->dwVolSerial
= volume
->serial
;
964 vol
->dwVolLabelOfs
= sizeof (*vol
);
966 /* copy in the strings */
967 WideCharToMultiByte( CP_ACP
, 0, volume
->label
, -1,
968 szLabel
, label_size
, NULL
, NULL
);
969 WideCharToMultiByte( CP_ACP
, 0, path
, -1,
970 szPath
, path_size
, NULL
, NULL
);
973 hr
= IStream_Write( stm
, loc
, total_size
, &count
);
974 HeapFree(GetProcessHeap(), 0, loc
);
979 static EXP_DARWIN_LINK
* shelllink_build_darwinid( LPCWSTR string
, DWORD magic
)
981 EXP_DARWIN_LINK
*buffer
;
983 buffer
= LocalAlloc( LMEM_ZEROINIT
, sizeof *buffer
);
984 buffer
->dbh
.cbSize
= sizeof *buffer
;
985 buffer
->dbh
.dwSignature
= magic
;
986 lstrcpynW( buffer
->szwDarwinID
, string
, MAX_PATH
);
987 WideCharToMultiByte(CP_ACP
, 0, string
, -1, buffer
->szDarwinID
, MAX_PATH
, NULL
, NULL
);
992 static HRESULT
Stream_WriteAdvertiseInfo( IStream
* stm
, LPCWSTR string
, DWORD magic
)
994 EXP_DARWIN_LINK
*buffer
;
999 buffer
= shelllink_build_darwinid( string
, magic
);
1001 return IStream_Write( stm
, buffer
, buffer
->dbh
.cbSize
, &count
);
1004 /************************************************************************
1005 * IPersistStream_Save (IPersistStream)
1007 * FIXME: makes assumptions about byte order
1009 static HRESULT WINAPI
IPersistStream_fnSave(
1010 IPersistStream
* iface
,
1019 IShellLinkImpl
*This
= impl_from_IPersistStream(iface
);
1021 TRACE("%p %p %x\n", This
, stm
, fClearDirty
);
1023 memset(&header
, 0, sizeof(header
));
1024 header
.dwSize
= sizeof(header
);
1025 header
.fStartup
= This
->iShowCmd
;
1026 header
.MagicGuid
= CLSID_ShellLink
;
1028 header
.wHotKey
= This
->wHotKey
;
1029 header
.nIcon
= This
->iIcoNdx
;
1030 header
.dwFlags
= SLDF_UNICODE
; /* strings are in unicode */
1032 header
.dwFlags
|= SLDF_HAS_ID_LIST
;
1034 header
.dwFlags
|= SLDF_HAS_LINK_INFO
;
1035 if( This
->sDescription
)
1036 header
.dwFlags
|= SLDF_HAS_NAME
;
1037 if( This
->sWorkDir
)
1038 header
.dwFlags
|= SLDF_HAS_WORKINGDIR
;
1040 header
.dwFlags
|= SLDF_HAS_ARGS
;
1041 if( This
->sIcoPath
)
1042 header
.dwFlags
|= SLDF_HAS_ICONLOCATION
;
1043 if( This
->sProduct
)
1044 header
.dwFlags
|= SLDF_HAS_LOGO3ID
;
1045 if( This
->sComponent
)
1046 header
.dwFlags
|= SLDF_HAS_DARWINID
;
1048 SystemTimeToFileTime ( &This
->time1
, &header
.Time1
);
1049 SystemTimeToFileTime ( &This
->time2
, &header
.Time2
);
1050 SystemTimeToFileTime ( &This
->time3
, &header
.Time3
);
1052 /* write the Shortcut header */
1053 r
= IStream_Write( stm
, &header
, sizeof(header
), &count
);
1056 ERR("Write failed at %d\n",__LINE__
);
1060 TRACE("Writing pidl\n");
1062 /* write the PIDL to the shortcut */
1065 r
= ILSaveToStream( stm
, This
->pPidl
);
1068 ERR("Failed to write PIDL at %d\n",__LINE__
);
1074 Stream_WriteLocationInfo( stm
, This
->sPath
, &This
->volume
);
1076 if( This
->sDescription
)
1077 r
= Stream_WriteString( stm
, This
->sDescription
);
1079 if( This
->sPathRel
)
1080 r
= Stream_WriteString( stm
, This
->sPathRel
);
1082 if( This
->sWorkDir
)
1083 r
= Stream_WriteString( stm
, This
->sWorkDir
);
1086 r
= Stream_WriteString( stm
, This
->sArgs
);
1088 if( This
->sIcoPath
)
1089 r
= Stream_WriteString( stm
, This
->sIcoPath
);
1091 if( This
->sProduct
)
1092 r
= Stream_WriteAdvertiseInfo( stm
, This
->sProduct
, EXP_SZ_ICON_SIG
);
1094 if( This
->sComponent
)
1095 r
= Stream_WriteAdvertiseInfo( stm
, This
->sComponent
, EXP_DARWIN_ID_SIG
);
1097 /* the last field is a single zero dword */
1099 r
= IStream_Write( stm
, &zero
, sizeof zero
, &count
);
1104 /************************************************************************
1105 * IPersistStream_GetSizeMax (IPersistStream)
1107 static HRESULT WINAPI
IPersistStream_fnGetSizeMax(
1108 IPersistStream
* iface
,
1109 ULARGE_INTEGER
* pcbSize
)
1111 IShellLinkImpl
*This
= impl_from_IPersistStream(iface
);
1113 TRACE("(%p)\n", This
);
1118 static const IPersistStreamVtbl psvt
=
1120 IPersistStream_fnQueryInterface
,
1121 IPersistStream_fnAddRef
,
1122 IPersistStream_fnRelease
,
1123 IPersistStream_fnGetClassID
,
1124 IPersistStream_fnIsDirty
,
1125 IPersistStream_fnLoad
,
1126 IPersistStream_fnSave
,
1127 IPersistStream_fnGetSizeMax
1130 static BOOL
SHELL_ExistsFileW(LPCWSTR path
)
1132 if (INVALID_FILE_ATTRIBUTES
== GetFileAttributesW(path
))
1137 /**************************************************************************
1138 * ShellLink_UpdatePath
1139 * update absolute path in sPath using relative path in sPathRel
1141 static HRESULT
ShellLink_UpdatePath(LPCWSTR sPathRel
, LPCWSTR path
, LPCWSTR sWorkDir
, LPWSTR
* psPath
)
1143 if (!path
|| !psPath
)
1144 return E_INVALIDARG
;
1146 if (!*psPath
&& sPathRel
) {
1147 WCHAR buffer
[2*MAX_PATH
], abs_path
[2*MAX_PATH
];
1148 LPWSTR final
= NULL
;
1150 /* first try if [directory of link file] + [relative path] finds an existing file */
1152 GetFullPathNameW( path
, MAX_PATH
*2, buffer
, &final
);
1155 lstrcpyW(final
, sPathRel
);
1159 if (SHELL_ExistsFileW(buffer
)) {
1160 if (!GetFullPathNameW(buffer
, MAX_PATH
, abs_path
, &final
))
1161 lstrcpyW(abs_path
, buffer
);
1163 /* try if [working directory] + [relative path] finds an existing file */
1165 lstrcpyW(buffer
, sWorkDir
);
1166 lstrcpyW(PathAddBackslashW(buffer
), sPathRel
);
1168 if (SHELL_ExistsFileW(buffer
))
1169 if (!GetFullPathNameW(buffer
, MAX_PATH
, abs_path
, &final
))
1170 lstrcpyW(abs_path
, buffer
);
1174 /* FIXME: This is even not enough - not all shell links can be resolved using this algorithm. */
1176 lstrcpyW(abs_path
, sPathRel
);
1178 *psPath
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(abs_path
)+1)*sizeof(WCHAR
));
1180 return E_OUTOFMEMORY
;
1182 lstrcpyW(*psPath
, abs_path
);
1188 /**************************************************************************
1189 * IShellLink_ConstructFromFile
1191 HRESULT
IShellLink_ConstructFromFile( IUnknown
* pUnkOuter
, REFIID riid
,
1192 LPCITEMIDLIST pidl
, IUnknown
**ppv
)
1196 HRESULT hr
= IShellLink_Constructor(NULL
, riid
, (LPVOID
*)&psl
);
1198 if (SUCCEEDED(hr
)) {
1203 hr
= IShellLinkW_QueryInterface(psl
, &IID_IPersistFile
, (LPVOID
*)&ppf
);
1205 if (SUCCEEDED(hr
)) {
1206 WCHAR path
[MAX_PATH
];
1208 if (SHGetPathFromIDListW(pidl
, path
))
1209 hr
= IPersistFile_Load(ppf
, path
, 0);
1214 *ppv
= (IUnknown
*)psl
;
1216 IPersistFile_Release(ppf
);
1220 IShellLinkW_Release(psl
);
1226 /**************************************************************************
1227 * IShellLinkA_QueryInterface
1229 static HRESULT WINAPI
IShellLinkA_fnQueryInterface(IShellLinkA
*iface
, REFIID riid
, void **ppvObj
)
1231 IShellLinkImpl
*This
= impl_from_IShellLinkA(iface
);
1232 return IShellLinkW_QueryInterface(&This
->IShellLinkW_iface
, riid
, ppvObj
);
1235 /******************************************************************************
1236 * IShellLinkA_AddRef
1238 static ULONG WINAPI
IShellLinkA_fnAddRef(IShellLinkA
*iface
)
1240 IShellLinkImpl
*This
= impl_from_IShellLinkA(iface
);
1241 return IShellLinkW_AddRef(&This
->IShellLinkW_iface
);
1244 /******************************************************************************
1245 * IShellLinkA_Release
1247 static ULONG WINAPI
IShellLinkA_fnRelease(IShellLinkA
*iface
)
1249 IShellLinkImpl
*This
= impl_from_IShellLinkA(iface
);
1250 return IShellLinkW_Release(&This
->IShellLinkW_iface
);
1253 static HRESULT WINAPI
IShellLinkA_fnGetPath(IShellLinkA
*iface
, LPSTR pszFile
, INT cchMaxPath
,
1254 WIN32_FIND_DATAA
*pfd
, DWORD fFlags
)
1256 IShellLinkImpl
*This
= impl_from_IShellLinkA(iface
);
1259 TRACE("(%p)->(pfile=%p len=%u find_data=%p flags=%u)(%s)\n",
1260 This
, pszFile
, cchMaxPath
, pfd
, fFlags
, debugstr_w(This
->sPath
));
1262 if (This
->sComponent
|| This
->sProduct
)
1267 if (This
->sPath
&& This
->sPath
[0])
1268 WideCharToMultiByte( CP_ACP
, 0, This
->sPath
, -1,
1269 pszFile
, cchMaxPath
, NULL
, NULL
);
1275 memset(pfd
, 0, sizeof(*pfd
));
1279 char path
[MAX_PATH
];
1280 WIN32_FILE_ATTRIBUTE_DATA fad
;
1282 WideCharToMultiByte(CP_ACP
, 0, This
->sPath
, -1, path
, MAX_PATH
, NULL
, NULL
);
1284 if (GetFileAttributesExW(This
->sPath
, GetFileExInfoStandard
, &fad
))
1286 pfd
->dwFileAttributes
= fad
.dwFileAttributes
;
1287 pfd
->ftCreationTime
= fad
.ftCreationTime
;
1288 pfd
->ftLastAccessTime
= fad
.ftLastAccessTime
;
1289 pfd
->ftLastWriteTime
= fad
.ftLastWriteTime
;
1290 pfd
->nFileSizeHigh
= fad
.nFileSizeHigh
;
1291 pfd
->nFileSizeLow
= fad
.nFileSizeLow
;
1294 lstrcpyA(pfd
->cFileName
, PathFindFileNameA(path
));
1296 if (GetShortPathNameA(path
, path
, MAX_PATH
))
1298 lstrcpyA(pfd
->cAlternateFileName
, PathFindFileNameA(path
));
1302 TRACE("attr 0x%08x size 0x%08x%08x name %s shortname %s\n", pfd
->dwFileAttributes
,
1303 pfd
->nFileSizeHigh
, pfd
->nFileSizeLow
, wine_dbgstr_a(pfd
->cFileName
),
1304 wine_dbgstr_a(pfd
->cAlternateFileName
));
1310 static HRESULT WINAPI
IShellLinkA_fnGetIDList(IShellLinkA
*iface
, LPITEMIDLIST
*ppidl
)
1312 IShellLinkImpl
*This
= impl_from_IShellLinkA(iface
);
1313 return IShellLinkW_GetIDList(&This
->IShellLinkW_iface
, ppidl
);
1316 static HRESULT WINAPI
IShellLinkA_fnSetIDList(IShellLinkA
*iface
, LPCITEMIDLIST pidl
)
1318 IShellLinkImpl
*This
= impl_from_IShellLinkA(iface
);
1319 return IShellLinkW_SetIDList(&This
->IShellLinkW_iface
, pidl
);
1322 static HRESULT WINAPI
IShellLinkA_fnGetDescription(IShellLinkA
*iface
, LPSTR pszName
,
1325 IShellLinkImpl
*This
= impl_from_IShellLinkA(iface
);
1327 TRACE("(%p)->(%p len=%u)\n",This
, pszName
, cchMaxName
);
1331 if( This
->sDescription
)
1332 WideCharToMultiByte( CP_ACP
, 0, This
->sDescription
, -1,
1333 pszName
, cchMaxName
, NULL
, NULL
);
1338 static HRESULT WINAPI
IShellLinkA_fnSetDescription(IShellLinkA
*iface
, LPCSTR pszName
)
1340 IShellLinkImpl
*This
= impl_from_IShellLinkA(iface
);
1344 TRACE("(%p)->(pName=%s)\n", This
, debugstr_a(pszName
));
1348 descrW
= heap_strdupAtoW(pszName
);
1349 if (!descrW
) return E_OUTOFMEMORY
;
1354 hr
= IShellLinkW_SetDescription(&This
->IShellLinkW_iface
, descrW
);
1355 HeapFree(GetProcessHeap(), 0, descrW
);
1360 static HRESULT WINAPI
IShellLinkA_fnGetWorkingDirectory(IShellLinkA
*iface
, LPSTR pszDir
,
1363 IShellLinkImpl
*This
= impl_from_IShellLinkA(iface
);
1365 TRACE("(%p)->(%p len=%u)\n", This
, pszDir
, cchMaxPath
);
1369 if( This
->sWorkDir
)
1370 WideCharToMultiByte( CP_ACP
, 0, This
->sWorkDir
, -1,
1371 pszDir
, cchMaxPath
, NULL
, NULL
);
1376 static HRESULT WINAPI
IShellLinkA_fnSetWorkingDirectory(IShellLinkA
*iface
, LPCSTR pszDir
)
1378 IShellLinkImpl
*This
= impl_from_IShellLinkA(iface
);
1382 TRACE("(%p)->(dir=%s)\n",This
, pszDir
);
1384 dirW
= heap_strdupAtoW(pszDir
);
1385 if (!dirW
) return E_OUTOFMEMORY
;
1387 hr
= IShellLinkW_SetWorkingDirectory(&This
->IShellLinkW_iface
, dirW
);
1388 HeapFree(GetProcessHeap(), 0, dirW
);
1393 static HRESULT WINAPI
IShellLinkA_fnGetArguments(IShellLinkA
*iface
, LPSTR pszArgs
, INT cchMaxPath
)
1395 IShellLinkImpl
*This
= impl_from_IShellLinkA(iface
);
1397 TRACE("(%p)->(%p len=%u)\n", This
, pszArgs
, cchMaxPath
);
1402 WideCharToMultiByte( CP_ACP
, 0, This
->sArgs
, -1,
1403 pszArgs
, cchMaxPath
, NULL
, NULL
);
1408 static HRESULT WINAPI
IShellLinkA_fnSetArguments(IShellLinkA
*iface
, LPCSTR pszArgs
)
1410 IShellLinkImpl
*This
= impl_from_IShellLinkA(iface
);
1414 TRACE("(%p)->(args=%s)\n",This
, debugstr_a(pszArgs
));
1418 argsW
= heap_strdupAtoW(pszArgs
);
1419 if (!argsW
) return E_OUTOFMEMORY
;
1424 hr
= IShellLinkW_SetArguments(&This
->IShellLinkW_iface
, argsW
);
1425 HeapFree(GetProcessHeap(), 0, argsW
);
1430 static HRESULT WINAPI
IShellLinkA_fnGetHotkey(IShellLinkA
*iface
, WORD
*pwHotkey
)
1432 IShellLinkImpl
*This
= impl_from_IShellLinkA(iface
);
1433 return IShellLinkW_GetHotkey(&This
->IShellLinkW_iface
, pwHotkey
);
1436 static HRESULT WINAPI
IShellLinkA_fnSetHotkey(IShellLinkA
*iface
, WORD wHotkey
)
1438 IShellLinkImpl
*This
= impl_from_IShellLinkA(iface
);
1439 return IShellLinkW_SetHotkey(&This
->IShellLinkW_iface
, wHotkey
);
1442 static HRESULT WINAPI
IShellLinkA_fnGetShowCmd(IShellLinkA
*iface
, INT
*piShowCmd
)
1444 IShellLinkImpl
*This
= impl_from_IShellLinkA(iface
);
1445 return IShellLinkW_GetShowCmd(&This
->IShellLinkW_iface
, piShowCmd
);
1448 static HRESULT WINAPI
IShellLinkA_fnSetShowCmd(IShellLinkA
*iface
, INT iShowCmd
)
1450 IShellLinkImpl
*This
= impl_from_IShellLinkA(iface
);
1451 return IShellLinkW_SetShowCmd(&This
->IShellLinkW_iface
, iShowCmd
);
1454 static HRESULT WINAPI
IShellLinkA_fnGetIconLocation(IShellLinkA
*iface
, LPSTR pszIconPath
,
1455 INT cchIconPath
, INT
*piIcon
)
1457 IShellLinkImpl
*This
= impl_from_IShellLinkA(iface
);
1459 TRACE("(%p)->(%p len=%u iicon=%p)\n", This
, pszIconPath
, cchIconPath
, piIcon
);
1461 *piIcon
= This
->iIcoNdx
;
1464 WideCharToMultiByte(CP_ACP
, 0, This
->sIcoPath
, -1, pszIconPath
, cchIconPath
, NULL
, NULL
);
1471 static HRESULT WINAPI
IShellLinkA_fnSetIconLocation(IShellLinkA
*iface
, LPCSTR pszIconPath
,
1474 IShellLinkImpl
*This
= impl_from_IShellLinkA(iface
);
1478 TRACE("(%p)->(path=%s iicon=%u)\n",This
, pszIconPath
, iIcon
);
1480 pathW
= heap_strdupAtoW(pszIconPath
);
1481 if (!pathW
) return E_OUTOFMEMORY
;
1483 hr
= IShellLinkW_SetIconLocation(&This
->IShellLinkW_iface
, pathW
, iIcon
);
1484 HeapFree(GetProcessHeap(), 0, pathW
);
1489 static HRESULT WINAPI
IShellLinkA_fnSetRelativePath(IShellLinkA
*iface
, LPCSTR pszPathRel
,
1492 IShellLinkImpl
*This
= impl_from_IShellLinkA(iface
);
1496 TRACE("(%p)->(path=%s %x)\n",This
, pszPathRel
, dwReserved
);
1498 pathW
= heap_strdupAtoW(pszPathRel
);
1499 if (!pathW
) return E_OUTOFMEMORY
;
1501 hr
= IShellLinkW_SetRelativePath(&This
->IShellLinkW_iface
, pathW
, dwReserved
);
1502 HeapFree(GetProcessHeap(), 0, pathW
);
1507 static HRESULT WINAPI
IShellLinkA_fnResolve(IShellLinkA
*iface
, HWND hwnd
, DWORD fFlags
)
1509 IShellLinkImpl
*This
= impl_from_IShellLinkA(iface
);
1511 TRACE("(%p)->(hwnd=%p flags=%x)\n",This
, hwnd
, fFlags
);
1513 return IShellLinkW_Resolve(&This
->IShellLinkW_iface
, hwnd
, fFlags
);
1516 static HRESULT WINAPI
IShellLinkA_fnSetPath(IShellLinkA
*iface
, LPCSTR pszFile
)
1518 IShellLinkImpl
*This
= impl_from_IShellLinkA(iface
);
1522 TRACE("(%p)->(path=%s)\n",This
, debugstr_a(pszFile
));
1524 if (!pszFile
) return E_INVALIDARG
;
1526 str
= heap_strdupAtoW(pszFile
);
1528 return E_OUTOFMEMORY
;
1530 r
= IShellLinkW_SetPath(&This
->IShellLinkW_iface
, str
);
1531 HeapFree( GetProcessHeap(), 0, str
);
1536 /**************************************************************************
1537 * IShellLink Implementation
1540 static const IShellLinkAVtbl slvt
=
1542 IShellLinkA_fnQueryInterface
,
1543 IShellLinkA_fnAddRef
,
1544 IShellLinkA_fnRelease
,
1545 IShellLinkA_fnGetPath
,
1546 IShellLinkA_fnGetIDList
,
1547 IShellLinkA_fnSetIDList
,
1548 IShellLinkA_fnGetDescription
,
1549 IShellLinkA_fnSetDescription
,
1550 IShellLinkA_fnGetWorkingDirectory
,
1551 IShellLinkA_fnSetWorkingDirectory
,
1552 IShellLinkA_fnGetArguments
,
1553 IShellLinkA_fnSetArguments
,
1554 IShellLinkA_fnGetHotkey
,
1555 IShellLinkA_fnSetHotkey
,
1556 IShellLinkA_fnGetShowCmd
,
1557 IShellLinkA_fnSetShowCmd
,
1558 IShellLinkA_fnGetIconLocation
,
1559 IShellLinkA_fnSetIconLocation
,
1560 IShellLinkA_fnSetRelativePath
,
1561 IShellLinkA_fnResolve
,
1562 IShellLinkA_fnSetPath
1566 /**************************************************************************
1567 * IShellLinkW_fnQueryInterface
1569 static HRESULT WINAPI
IShellLinkW_fnQueryInterface(
1570 IShellLinkW
* iface
, REFIID riid
, LPVOID
*ppvObj
)
1572 IShellLinkImpl
*This
= impl_from_IShellLinkW(iface
);
1574 TRACE("(%p)->(%s)\n", This
, debugstr_guid(riid
));
1578 if(IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IShellLinkA
))
1580 *ppvObj
= &This
->IShellLinkA_iface
;
1582 else if(IsEqualIID(riid
, &IID_IShellLinkW
))
1584 *ppvObj
= &This
->IShellLinkW_iface
;
1586 else if(IsEqualIID(riid
, &IID_IPersistFile
))
1588 *ppvObj
= &This
->IPersistFile_iface
;
1590 else if(IsEqualIID(riid
, &IID_IPersistStream
))
1592 *ppvObj
= &This
->IPersistStream_iface
;
1594 else if(IsEqualIID(riid
, &IID_IShellLinkDataList
))
1596 *ppvObj
= &This
->IShellLinkDataList_iface
;
1598 else if(IsEqualIID(riid
, &IID_IShellExtInit
))
1600 *ppvObj
= &This
->IShellExtInit_iface
;
1602 else if(IsEqualIID(riid
, &IID_IContextMenu
))
1604 *ppvObj
= &This
->IContextMenu_iface
;
1606 else if(IsEqualIID(riid
, &IID_IObjectWithSite
))
1608 *ppvObj
= &This
->IObjectWithSite_iface
;
1610 else if(IsEqualIID(riid
, &IID_IPropertyStore
))
1612 *ppvObj
= &This
->IPropertyStore_iface
;
1617 IUnknown_AddRef((IUnknown
*)*ppvObj
);
1618 TRACE("-- Interface: (%p)->(%p)\n", ppvObj
, *ppvObj
);
1621 ERR("-- Interface: E_NOINTERFACE\n");
1622 return E_NOINTERFACE
;
1625 /******************************************************************************
1626 * IShellLinkW_fnAddRef
1628 static ULONG WINAPI
IShellLinkW_fnAddRef(IShellLinkW
* iface
)
1630 IShellLinkImpl
*This
= impl_from_IShellLinkW(iface
);
1631 ULONG ref
= InterlockedIncrement(&This
->ref
);
1633 TRACE("(%p)->(count=%u)\n", This
, ref
- 1);
1638 /******************************************************************************
1639 * IShellLinkW_fnRelease
1641 static ULONG WINAPI
IShellLinkW_fnRelease(IShellLinkW
* iface
)
1643 IShellLinkImpl
*This
= impl_from_IShellLinkW(iface
);
1644 ULONG refCount
= InterlockedDecrement(&This
->ref
);
1646 TRACE("(%p)->(count=%u)\n", This
, refCount
+ 1);
1651 TRACE("-- destroying IShellLink(%p)\n",This
);
1653 HeapFree(GetProcessHeap(), 0, This
->sIcoPath
);
1654 HeapFree(GetProcessHeap(), 0, This
->sArgs
);
1655 HeapFree(GetProcessHeap(), 0, This
->sWorkDir
);
1656 HeapFree(GetProcessHeap(), 0, This
->sDescription
);
1657 HeapFree(GetProcessHeap(), 0, This
->sPath
);
1658 HeapFree(GetProcessHeap(), 0, This
->sPathRel
);
1659 HeapFree(GetProcessHeap(), 0, This
->sProduct
);
1660 HeapFree(GetProcessHeap(), 0, This
->sComponent
);
1661 HeapFree(GetProcessHeap(), 0, This
->filepath
);
1664 IUnknown_Release( This
->site
);
1667 ILFree(This
->pPidl
);
1674 static HRESULT WINAPI
IShellLinkW_fnGetPath(IShellLinkW
* iface
, LPWSTR pszFile
,INT cchMaxPath
, WIN32_FIND_DATAW
*pfd
, DWORD fFlags
)
1676 IShellLinkImpl
*This
= impl_from_IShellLinkW(iface
);
1679 TRACE("(%p)->(pfile=%p len=%u find_data=%p flags=%u)(%s)\n",
1680 This
, pszFile
, cchMaxPath
, pfd
, fFlags
, debugstr_w(This
->sPath
));
1682 if (This
->sComponent
|| This
->sProduct
)
1688 lstrcpynW( pszFile
, This
->sPath
, cchMaxPath
);
1694 memset(pfd
, 0, sizeof(*pfd
));
1698 WCHAR path
[MAX_PATH
];
1699 WIN32_FILE_ATTRIBUTE_DATA fad
;
1701 if (GetFileAttributesExW(This
->sPath
, GetFileExInfoStandard
, &fad
))
1703 pfd
->dwFileAttributes
= fad
.dwFileAttributes
;
1704 pfd
->ftCreationTime
= fad
.ftCreationTime
;
1705 pfd
->ftLastAccessTime
= fad
.ftLastAccessTime
;
1706 pfd
->ftLastWriteTime
= fad
.ftLastWriteTime
;
1707 pfd
->nFileSizeHigh
= fad
.nFileSizeHigh
;
1708 pfd
->nFileSizeLow
= fad
.nFileSizeLow
;
1711 lstrcpyW(pfd
->cFileName
, PathFindFileNameW(This
->sPath
));
1713 if (GetShortPathNameW(This
->sPath
, path
, MAX_PATH
))
1715 lstrcpyW(pfd
->cAlternateFileName
, PathFindFileNameW(path
));
1719 TRACE("attr 0x%08x size 0x%08x%08x name %s shortname %s\n", pfd
->dwFileAttributes
,
1720 pfd
->nFileSizeHigh
, pfd
->nFileSizeLow
, wine_dbgstr_w(pfd
->cFileName
),
1721 wine_dbgstr_w(pfd
->cAlternateFileName
));
1727 static HRESULT WINAPI
IShellLinkW_fnGetIDList(IShellLinkW
* iface
, LPITEMIDLIST
* ppidl
)
1729 IShellLinkImpl
*This
= impl_from_IShellLinkW(iface
);
1731 TRACE("(%p)->(ppidl=%p)\n",This
, ppidl
);
1738 *ppidl
= ILClone(This
->pPidl
);
1742 static HRESULT WINAPI
IShellLinkW_fnSetIDList(IShellLinkW
* iface
, LPCITEMIDLIST pidl
)
1744 IShellLinkImpl
*This
= impl_from_IShellLinkW(iface
);
1745 WCHAR path
[MAX_PATH
];
1747 TRACE("(%p)->(pidl=%p)\n",This
, pidl
);
1750 ILFree( This
->pPidl
);
1751 This
->pPidl
= ILClone( pidl
);
1755 HeapFree( GetProcessHeap(), 0, This
->sPath
);
1758 if ( SHGetPathFromIDListW( pidl
, path
) )
1760 This
->sPath
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(path
)+1)*sizeof(WCHAR
));
1762 return E_OUTOFMEMORY
;
1764 lstrcpyW(This
->sPath
, path
);
1767 This
->bDirty
= TRUE
;
1772 static HRESULT WINAPI
IShellLinkW_fnGetDescription(IShellLinkW
* iface
, LPWSTR pszName
,INT cchMaxName
)
1774 IShellLinkImpl
*This
= impl_from_IShellLinkW(iface
);
1776 TRACE("(%p)->(%p len=%u)\n",This
, pszName
, cchMaxName
);
1779 if( This
->sDescription
)
1780 lstrcpynW( pszName
, This
->sDescription
, cchMaxName
);
1785 static HRESULT WINAPI
IShellLinkW_fnSetDescription(IShellLinkW
* iface
, LPCWSTR pszName
)
1787 IShellLinkImpl
*This
= impl_from_IShellLinkW(iface
);
1789 TRACE("(%p)->(desc=%s)\n",This
, debugstr_w(pszName
));
1791 HeapFree(GetProcessHeap(), 0, This
->sDescription
);
1794 This
->sDescription
= HeapAlloc( GetProcessHeap(), 0,
1795 (lstrlenW( pszName
)+1)*sizeof(WCHAR
) );
1796 if ( !This
->sDescription
)
1797 return E_OUTOFMEMORY
;
1799 lstrcpyW( This
->sDescription
, pszName
);
1802 This
->sDescription
= NULL
;
1803 This
->bDirty
= TRUE
;
1808 static HRESULT WINAPI
IShellLinkW_fnGetWorkingDirectory(IShellLinkW
* iface
, LPWSTR pszDir
,INT cchMaxPath
)
1810 IShellLinkImpl
*This
= impl_from_IShellLinkW(iface
);
1812 TRACE("(%p)->(%p len %u)\n", This
, pszDir
, cchMaxPath
);
1816 if( This
->sWorkDir
)
1817 lstrcpynW( pszDir
, This
->sWorkDir
, cchMaxPath
);
1822 static HRESULT WINAPI
IShellLinkW_fnSetWorkingDirectory(IShellLinkW
* iface
, LPCWSTR pszDir
)
1824 IShellLinkImpl
*This
= impl_from_IShellLinkW(iface
);
1826 TRACE("(%p)->(dir=%s)\n",This
, debugstr_w(pszDir
));
1828 HeapFree(GetProcessHeap(), 0, This
->sWorkDir
);
1829 This
->sWorkDir
= HeapAlloc( GetProcessHeap(), 0,
1830 (lstrlenW( pszDir
)+1)*sizeof (WCHAR
) );
1831 if ( !This
->sWorkDir
)
1832 return E_OUTOFMEMORY
;
1833 lstrcpyW( This
->sWorkDir
, pszDir
);
1834 This
->bDirty
= TRUE
;
1839 static HRESULT WINAPI
IShellLinkW_fnGetArguments(IShellLinkW
* iface
, LPWSTR pszArgs
,INT cchMaxPath
)
1841 IShellLinkImpl
*This
= impl_from_IShellLinkW(iface
);
1843 TRACE("(%p)->(%p len=%u)\n", This
, pszArgs
, cchMaxPath
);
1848 lstrcpynW( pszArgs
, This
->sArgs
, cchMaxPath
);
1853 static HRESULT WINAPI
IShellLinkW_fnSetArguments(IShellLinkW
* iface
, LPCWSTR pszArgs
)
1855 IShellLinkImpl
*This
= impl_from_IShellLinkW(iface
);
1857 TRACE("(%p)->(args=%s)\n",This
, debugstr_w(pszArgs
));
1859 HeapFree(GetProcessHeap(), 0, This
->sArgs
);
1862 This
->sArgs
= HeapAlloc( GetProcessHeap(), 0,
1863 (lstrlenW( pszArgs
)+1)*sizeof (WCHAR
) );
1865 return E_OUTOFMEMORY
;
1866 lstrcpyW( This
->sArgs
, pszArgs
);
1868 else This
->sArgs
= NULL
;
1870 This
->bDirty
= TRUE
;
1875 static HRESULT WINAPI
IShellLinkW_fnGetHotkey(IShellLinkW
* iface
, WORD
*pwHotkey
)
1877 IShellLinkImpl
*This
= impl_from_IShellLinkW(iface
);
1879 TRACE("(%p)->(%p)\n",This
, pwHotkey
);
1881 *pwHotkey
=This
->wHotKey
;
1886 static HRESULT WINAPI
IShellLinkW_fnSetHotkey(IShellLinkW
* iface
, WORD wHotkey
)
1888 IShellLinkImpl
*This
= impl_from_IShellLinkW(iface
);
1890 TRACE("(%p)->(hotkey=%x)\n",This
, wHotkey
);
1892 This
->wHotKey
= wHotkey
;
1893 This
->bDirty
= TRUE
;
1898 static HRESULT WINAPI
IShellLinkW_fnGetShowCmd(IShellLinkW
* iface
, INT
*piShowCmd
)
1900 IShellLinkImpl
*This
= impl_from_IShellLinkW(iface
);
1902 TRACE("(%p)->(%p)\n",This
, piShowCmd
);
1904 *piShowCmd
= This
->iShowCmd
;
1909 static HRESULT WINAPI
IShellLinkW_fnSetShowCmd(IShellLinkW
* iface
, INT iShowCmd
)
1911 IShellLinkImpl
*This
= impl_from_IShellLinkW(iface
);
1913 TRACE("(%p)->(%d)\n", This
, iShowCmd
);
1915 This
->iShowCmd
= iShowCmd
;
1916 This
->bDirty
= TRUE
;
1921 static HRESULT WINAPI
IShellLinkW_fnGetIconLocation(IShellLinkW
* iface
, LPWSTR pszIconPath
,INT cchIconPath
,INT
*piIcon
)
1923 IShellLinkImpl
*This
= impl_from_IShellLinkW(iface
);
1925 TRACE("(%p)->(%p len=%u iicon=%p)\n", This
, pszIconPath
, cchIconPath
, piIcon
);
1927 *piIcon
= This
->iIcoNdx
;
1930 lstrcpynW(pszIconPath
, This
->sIcoPath
, cchIconPath
);
1937 static HRESULT WINAPI
IShellLinkW_fnSetIconLocation(IShellLinkW
* iface
, LPCWSTR pszIconPath
,INT iIcon
)
1939 IShellLinkImpl
*This
= impl_from_IShellLinkW(iface
);
1941 TRACE("(%p)->(path=%s iicon=%u)\n",This
, debugstr_w(pszIconPath
), iIcon
);
1943 HeapFree(GetProcessHeap(), 0, This
->sIcoPath
);
1944 This
->sIcoPath
= HeapAlloc( GetProcessHeap(), 0,
1945 (lstrlenW( pszIconPath
)+1)*sizeof (WCHAR
) );
1946 if ( !This
->sIcoPath
)
1947 return E_OUTOFMEMORY
;
1948 lstrcpyW( This
->sIcoPath
, pszIconPath
);
1950 This
->iIcoNdx
= iIcon
;
1951 This
->bDirty
= TRUE
;
1956 static HRESULT WINAPI
IShellLinkW_fnSetRelativePath(IShellLinkW
* iface
, LPCWSTR pszPathRel
, DWORD dwReserved
)
1958 IShellLinkImpl
*This
= impl_from_IShellLinkW(iface
);
1960 TRACE("(%p)->(path=%s %x)\n",This
, debugstr_w(pszPathRel
), dwReserved
);
1962 HeapFree(GetProcessHeap(), 0, This
->sPathRel
);
1963 This
->sPathRel
= HeapAlloc( GetProcessHeap(), 0,
1964 (lstrlenW( pszPathRel
)+1) * sizeof (WCHAR
) );
1965 if ( !This
->sPathRel
)
1966 return E_OUTOFMEMORY
;
1967 lstrcpyW( This
->sPathRel
, pszPathRel
);
1968 This
->bDirty
= TRUE
;
1970 return ShellLink_UpdatePath(This
->sPathRel
, This
->sPath
, This
->sWorkDir
, &This
->sPath
);
1973 static HRESULT WINAPI
IShellLinkW_fnResolve(IShellLinkW
* iface
, HWND hwnd
, DWORD fFlags
)
1978 IShellLinkImpl
*This
= impl_from_IShellLinkW(iface
);
1980 TRACE("(%p)->(hwnd=%p flags=%x)\n",This
, hwnd
, fFlags
);
1982 /*FIXME: use IResolveShellLink interface */
1984 if (!This
->sPath
&& This
->pPidl
) {
1985 WCHAR buffer
[MAX_PATH
];
1987 bSuccess
= SHGetPathFromIDListW(This
->pPidl
, buffer
);
1989 if (bSuccess
&& *buffer
) {
1990 This
->sPath
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(buffer
)+1)*sizeof(WCHAR
));
1992 return E_OUTOFMEMORY
;
1994 lstrcpyW(This
->sPath
, buffer
);
1996 This
->bDirty
= TRUE
;
1998 hr
= S_OK
; /* don't report an error occurred while just caching information */
2001 if (!This
->sIcoPath
&& This
->sPath
) {
2002 This
->sIcoPath
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(This
->sPath
)+1)*sizeof(WCHAR
));
2003 if (!This
->sIcoPath
)
2004 return E_OUTOFMEMORY
;
2006 lstrcpyW(This
->sIcoPath
, This
->sPath
);
2009 This
->bDirty
= TRUE
;
2015 static LPWSTR
ShellLink_GetAdvertisedArg(LPCWSTR str
)
2024 p
= strchrW( str
, ':' );
2028 ret
= HeapAlloc( GetProcessHeap(), 0, sizeof(WCHAR
)*(len
+1));
2031 memcpy( ret
, str
, sizeof(WCHAR
)*len
);
2036 static HRESULT
ShellLink_SetAdvertiseInfo(IShellLinkImpl
*This
, LPCWSTR str
)
2038 LPCWSTR szComponent
= NULL
, szProduct
= NULL
, p
;
2046 /* each segment must start with two colons */
2047 if( str
[0] != ':' || str
[1] != ':' )
2050 /* the last segment is just two colons */
2055 /* there must be a colon straight after a guid */
2056 p
= strchrW( str
, ':' );
2063 /* get the guid, and check it's validly formatted */
2064 memcpy( szGuid
, str
, sizeof(WCHAR
)*len
);
2066 r
= CLSIDFromString( szGuid
, &guid
);
2071 /* match it up to a guid that we care about */
2072 if( IsEqualGUID( &guid
, &SHELL32_AdvtShortcutComponent
) && !szComponent
)
2074 else if( IsEqualGUID( &guid
, &SHELL32_AdvtShortcutProduct
) && !szProduct
)
2079 /* skip to the next field */
2080 str
= strchrW( str
, ':' );
2085 /* we have to have a component for an advertised shortcut */
2089 This
->sComponent
= ShellLink_GetAdvertisedArg( szComponent
);
2090 This
->sProduct
= ShellLink_GetAdvertisedArg( szProduct
);
2092 TRACE("Component = %s\n", debugstr_w(This
->sComponent
));
2093 TRACE("Product = %s\n", debugstr_w(This
->sProduct
));
2098 static BOOL
ShellLink_GetVolumeInfo(LPCWSTR path
, volume_info
*volume
)
2100 const int label_sz
= sizeof volume
->label
/sizeof volume
->label
[0];
2101 WCHAR drive
[] = { path
[0], ':', '\\', 0 };
2104 volume
->type
= GetDriveTypeW(drive
);
2105 r
= GetVolumeInformationW(drive
, volume
->label
, label_sz
,
2106 &volume
->serial
, NULL
, NULL
, NULL
, 0);
2107 TRACE("r = %d type %d serial %08x name %s\n", r
,
2108 volume
->type
, volume
->serial
, debugstr_w(volume
->label
));
2112 static HRESULT WINAPI
IShellLinkW_fnSetPath(IShellLinkW
* iface
, LPCWSTR pszFile
)
2114 IShellLinkImpl
*This
= impl_from_IShellLinkW(iface
);
2115 WCHAR buffer
[MAX_PATH
];
2116 LPWSTR fname
, unquoted
= NULL
;
2120 TRACE("(%p)->(path=%s)\n",This
, debugstr_w(pszFile
));
2122 if (!pszFile
) return E_INVALIDARG
;
2124 /* quotes at the ends of the string are stripped */
2125 len
= lstrlenW(pszFile
);
2126 if (pszFile
[0] == '"' && pszFile
[len
-1] == '"')
2128 unquoted
= strdupW(pszFile
);
2129 PathUnquoteSpacesW(unquoted
);
2133 /* any other quote marks are invalid */
2134 if (strchrW(pszFile
, '"'))
2136 HeapFree(GetProcessHeap(), 0, unquoted
);
2140 HeapFree(GetProcessHeap(), 0, This
->sPath
);
2143 HeapFree(GetProcessHeap(), 0, This
->sComponent
);
2144 This
->sComponent
= NULL
;
2147 ILFree(This
->pPidl
);
2150 if (S_OK
!= ShellLink_SetAdvertiseInfo( This
, pszFile
))
2152 if (*pszFile
== '\0')
2154 else if (!GetFullPathNameW(pszFile
, MAX_PATH
, buffer
, &fname
))
2156 else if(!PathFileExistsW(buffer
) &&
2157 !SearchPathW(NULL
, pszFile
, NULL
, MAX_PATH
, buffer
, NULL
))
2160 This
->pPidl
= SHSimpleIDListFromPathW(pszFile
);
2161 ShellLink_GetVolumeInfo(buffer
, &This
->volume
);
2163 This
->sPath
= HeapAlloc( GetProcessHeap(), 0,
2164 (lstrlenW( buffer
)+1) * sizeof (WCHAR
) );
2167 HeapFree(GetProcessHeap(), 0, unquoted
);
2168 return E_OUTOFMEMORY
;
2171 lstrcpyW(This
->sPath
, buffer
);
2173 This
->bDirty
= TRUE
;
2174 HeapFree(GetProcessHeap(), 0, unquoted
);
2179 /**************************************************************************
2180 * IShellLinkW Implementation
2183 static const IShellLinkWVtbl slvtw
=
2185 IShellLinkW_fnQueryInterface
,
2186 IShellLinkW_fnAddRef
,
2187 IShellLinkW_fnRelease
,
2188 IShellLinkW_fnGetPath
,
2189 IShellLinkW_fnGetIDList
,
2190 IShellLinkW_fnSetIDList
,
2191 IShellLinkW_fnGetDescription
,
2192 IShellLinkW_fnSetDescription
,
2193 IShellLinkW_fnGetWorkingDirectory
,
2194 IShellLinkW_fnSetWorkingDirectory
,
2195 IShellLinkW_fnGetArguments
,
2196 IShellLinkW_fnSetArguments
,
2197 IShellLinkW_fnGetHotkey
,
2198 IShellLinkW_fnSetHotkey
,
2199 IShellLinkW_fnGetShowCmd
,
2200 IShellLinkW_fnSetShowCmd
,
2201 IShellLinkW_fnGetIconLocation
,
2202 IShellLinkW_fnSetIconLocation
,
2203 IShellLinkW_fnSetRelativePath
,
2204 IShellLinkW_fnResolve
,
2205 IShellLinkW_fnSetPath
2208 static HRESULT WINAPI
2209 ShellLink_DataList_QueryInterface( IShellLinkDataList
* iface
, REFIID riid
, void** ppvObject
)
2211 IShellLinkImpl
*This
= impl_from_IShellLinkDataList(iface
);
2212 return IShellLinkW_QueryInterface(&This
->IShellLinkW_iface
, riid
, ppvObject
);
2216 ShellLink_DataList_AddRef( IShellLinkDataList
* iface
)
2218 IShellLinkImpl
*This
= impl_from_IShellLinkDataList(iface
);
2219 return IShellLinkW_AddRef(&This
->IShellLinkW_iface
);
2223 ShellLink_DataList_Release( IShellLinkDataList
* iface
)
2225 IShellLinkImpl
*This
= impl_from_IShellLinkDataList(iface
);
2226 return IShellLinkW_Release(&This
->IShellLinkW_iface
);
2229 static HRESULT WINAPI
2230 ShellLink_AddDataBlock( IShellLinkDataList
* iface
, void* pDataBlock
)
2232 FIXME("(%p)->(%p): stub\n", iface
, pDataBlock
);
2236 static HRESULT WINAPI
2237 ShellLink_CopyDataBlock( IShellLinkDataList
* iface
, DWORD dwSig
, void** ppDataBlock
)
2239 IShellLinkImpl
*This
= impl_from_IShellLinkDataList(iface
);
2240 LPVOID block
= NULL
;
2243 TRACE("%p %08x %p\n", iface
, dwSig
, ppDataBlock
);
2247 case EXP_DARWIN_ID_SIG
:
2248 if (!This
->sComponent
)
2250 block
= shelllink_build_darwinid( This
->sComponent
, dwSig
);
2253 case EXP_SZ_LINK_SIG
:
2254 case NT_CONSOLE_PROPS_SIG
:
2255 case NT_FE_CONSOLE_PROPS_SIG
:
2256 case EXP_SPECIAL_FOLDER_SIG
:
2257 case EXP_SZ_ICON_SIG
:
2258 FIXME("valid but unhandled datablock %08x\n", dwSig
);
2261 ERR("unknown datablock %08x\n", dwSig
);
2263 *ppDataBlock
= block
;
2267 static HRESULT WINAPI
2268 ShellLink_RemoveDataBlock( IShellLinkDataList
* iface
, DWORD dwSig
)
2270 FIXME("(%p)->(%u): stub\n", iface
, dwSig
);
2274 static HRESULT WINAPI
2275 ShellLink_GetFlags( IShellLinkDataList
* iface
, DWORD
* pdwFlags
)
2277 IShellLinkImpl
*This
= impl_from_IShellLinkDataList(iface
);
2280 FIXME("(%p)->(%p): partially implemented\n", This
, pdwFlags
);
2282 /* FIXME: add more */
2284 flags
|= SLDF_HAS_ARGS
;
2285 if (This
->sComponent
)
2286 flags
|= SLDF_HAS_DARWINID
;
2288 flags
|= SLDF_HAS_ICONLOCATION
;
2290 flags
|= SLDF_HAS_LOGO3ID
;
2292 flags
|= SLDF_HAS_ID_LIST
;
2299 static HRESULT WINAPI
2300 ShellLink_SetFlags( IShellLinkDataList
* iface
, DWORD dwFlags
)
2302 FIXME("(%p)->(%u): stub\n", iface
, dwFlags
);
2306 static const IShellLinkDataListVtbl dlvt
=
2308 ShellLink_DataList_QueryInterface
,
2309 ShellLink_DataList_AddRef
,
2310 ShellLink_DataList_Release
,
2311 ShellLink_AddDataBlock
,
2312 ShellLink_CopyDataBlock
,
2313 ShellLink_RemoveDataBlock
,
2318 static HRESULT WINAPI
2319 ShellLink_ExtInit_QueryInterface( IShellExtInit
* iface
, REFIID riid
, void** ppvObject
)
2321 IShellLinkImpl
*This
= impl_from_IShellExtInit(iface
);
2322 return IShellLinkW_QueryInterface(&This
->IShellLinkW_iface
, riid
, ppvObject
);
2326 ShellLink_ExtInit_AddRef( IShellExtInit
* iface
)
2328 IShellLinkImpl
*This
= impl_from_IShellExtInit(iface
);
2329 return IShellLinkW_AddRef(&This
->IShellLinkW_iface
);
2333 ShellLink_ExtInit_Release( IShellExtInit
* iface
)
2335 IShellLinkImpl
*This
= impl_from_IShellExtInit(iface
);
2336 return IShellLinkW_Release(&This
->IShellLinkW_iface
);
2339 /**************************************************************************
2340 * ShellLink implementation of IShellExtInit::Initialize()
2342 * Loads the shelllink from the dataobject the shell is pointing to.
2344 static HRESULT WINAPI
2345 ShellLink_ExtInit_Initialize( IShellExtInit
* iface
, LPCITEMIDLIST pidlFolder
,
2346 IDataObject
*pdtobj
, HKEY hkeyProgID
)
2348 IShellLinkImpl
*This
= impl_from_IShellExtInit(iface
);
2354 TRACE("%p %p %p %p\n", This
, pidlFolder
, pdtobj
, hkeyProgID
);
2359 format
.cfFormat
= CF_HDROP
;
2361 format
.dwAspect
= DVASPECT_CONTENT
;
2363 format
.tymed
= TYMED_HGLOBAL
;
2365 if( FAILED( IDataObject_GetData( pdtobj
, &format
, &stgm
) ) )
2368 count
= DragQueryFileW( stgm
.u
.hGlobal
, -1, NULL
, 0 );
2373 count
= DragQueryFileW( stgm
.u
.hGlobal
, 0, NULL
, 0 );
2375 path
= HeapAlloc( GetProcessHeap(), 0, count
*sizeof(WCHAR
) );
2378 IPersistFile
*pf
= &This
->IPersistFile_iface
;
2380 count
= DragQueryFileW( stgm
.u
.hGlobal
, 0, path
, count
);
2381 r
= IPersistFile_Load( pf
, path
, 0 );
2382 HeapFree( GetProcessHeap(), 0, path
);
2385 ReleaseStgMedium( &stgm
);
2390 static const IShellExtInitVtbl eivt
=
2392 ShellLink_ExtInit_QueryInterface
,
2393 ShellLink_ExtInit_AddRef
,
2394 ShellLink_ExtInit_Release
,
2395 ShellLink_ExtInit_Initialize
2398 static HRESULT WINAPI
2399 ShellLink_ContextMenu_QueryInterface( IContextMenu
* iface
, REFIID riid
, void** ppvObject
)
2401 IShellLinkImpl
*This
= impl_from_IContextMenu(iface
);
2402 return IShellLinkW_QueryInterface(&This
->IShellLinkW_iface
, riid
, ppvObject
);
2406 ShellLink_ContextMenu_AddRef( IContextMenu
* iface
)
2408 IShellLinkImpl
*This
= impl_from_IContextMenu(iface
);
2409 return IShellLinkW_AddRef(&This
->IShellLinkW_iface
);
2413 ShellLink_ContextMenu_Release( IContextMenu
* iface
)
2415 IShellLinkImpl
*This
= impl_from_IContextMenu(iface
);
2416 return IShellLinkW_Release(&This
->IShellLinkW_iface
);
2419 static HRESULT WINAPI
2420 ShellLink_QueryContextMenu( IContextMenu
* iface
, HMENU hmenu
, UINT indexMenu
,
2421 UINT idCmdFirst
, UINT idCmdLast
, UINT uFlags
)
2423 IShellLinkImpl
*This
= impl_from_IContextMenu(iface
);
2424 static WCHAR szOpen
[] = { 'O','p','e','n',0 };
2428 TRACE("%p %p %u %u %u %u\n", This
,
2429 hmenu
, indexMenu
, idCmdFirst
, idCmdLast
, uFlags
);
2432 return E_INVALIDARG
;
2434 memset( &mii
, 0, sizeof mii
);
2435 mii
.cbSize
= sizeof mii
;
2436 mii
.fMask
= MIIM_TYPE
| MIIM_ID
| MIIM_STATE
;
2437 mii
.dwTypeData
= szOpen
;
2438 mii
.cch
= strlenW( mii
.dwTypeData
);
2439 mii
.wID
= idCmdFirst
+ id
++;
2440 mii
.fState
= MFS_DEFAULT
| MFS_ENABLED
;
2441 mii
.fType
= MFT_STRING
;
2442 if (!InsertMenuItemW( hmenu
, indexMenu
, TRUE
, &mii
))
2446 return MAKE_HRESULT( SEVERITY_SUCCESS
, 0, id
);
2450 shelllink_get_msi_component_path( LPWSTR component
)
2455 r
= CommandLineFromMsiDescriptor( component
, NULL
, &sz
);
2456 if (r
!= ERROR_SUCCESS
)
2460 path
= HeapAlloc( GetProcessHeap(), 0, sz
*sizeof(WCHAR
) );
2461 r
= CommandLineFromMsiDescriptor( component
, path
, &sz
);
2462 if (r
!= ERROR_SUCCESS
)
2464 HeapFree( GetProcessHeap(), 0, path
);
2468 TRACE("returning %s\n", debugstr_w( path
) );
2473 static HRESULT WINAPI
2474 ShellLink_InvokeCommand( IContextMenu
* iface
, LPCMINVOKECOMMANDINFO lpici
)
2476 IShellLinkImpl
*This
= impl_from_IContextMenu(iface
);
2477 static const WCHAR szOpen
[] = { 'O','p','e','n',0 };
2478 SHELLEXECUTEINFOW sei
;
2479 HWND hwnd
= NULL
; /* FIXME: get using interface set from IObjectWithSite */
2484 TRACE("%p %p\n", This
, lpici
);
2486 if ( lpici
->cbSize
< sizeof (CMINVOKECOMMANDINFO
) )
2487 return E_INVALIDARG
;
2489 if ( lpici
->lpVerb
!= MAKEINTRESOURCEA(This
->iIdOpen
) )
2491 ERR("Unknown id %p != %d\n", lpici
->lpVerb
, This
->iIdOpen
);
2492 return E_INVALIDARG
;
2495 r
= IShellLinkW_Resolve(&This
->IShellLinkW_iface
, hwnd
, 0);
2499 if ( This
->sComponent
)
2501 path
= shelllink_get_msi_component_path( This
->sComponent
);
2506 path
= strdupW( This
->sPath
);
2508 if ( lpici
->cbSize
== sizeof (CMINVOKECOMMANDINFOEX
) &&
2509 ( lpici
->fMask
& CMIC_MASK_UNICODE
) )
2511 LPCMINVOKECOMMANDINFOEX iciex
= (LPCMINVOKECOMMANDINFOEX
) lpici
;
2515 len
+= lstrlenW( This
->sArgs
);
2516 if ( iciex
->lpParametersW
)
2517 len
+= lstrlenW( iciex
->lpParametersW
);
2519 args
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof(WCHAR
) );
2522 lstrcatW( args
, This
->sArgs
);
2523 if ( iciex
->lpParametersW
&& iciex
->lpParametersW
[0] )
2525 static const WCHAR space
[] = { ' ', 0 };
2526 lstrcatW( args
, space
);
2527 lstrcatW( args
, iciex
->lpParametersW
);
2531 memset( &sei
, 0, sizeof sei
);
2532 sei
.cbSize
= sizeof sei
;
2533 sei
.fMask
= SEE_MASK_UNICODE
| (lpici
->fMask
& (SEE_MASK_NOASYNC
|SEE_MASK_NO_CONSOLE
|SEE_MASK_ASYNCOK
|SEE_MASK_FLAG_NO_UI
));
2535 sei
.nShow
= This
->iShowCmd
;
2536 sei
.lpIDList
= This
->pPidl
;
2537 sei
.lpDirectory
= This
->sWorkDir
;
2538 sei
.lpParameters
= args
;
2539 sei
.lpVerb
= szOpen
;
2541 if( ShellExecuteExW( &sei
) )
2546 HeapFree( GetProcessHeap(), 0, args
);
2547 HeapFree( GetProcessHeap(), 0, path
);
2552 static HRESULT WINAPI
2553 ShellLink_GetCommandString( IContextMenu
* iface
, UINT_PTR idCmd
, UINT uType
,
2554 UINT
* pwReserved
, LPSTR pszName
, UINT cchMax
)
2556 IShellLinkImpl
*This
= impl_from_IContextMenu(iface
);
2558 FIXME("(%p)->(%lu %u %p %p %u): stub\n", This
,
2559 idCmd
, uType
, pwReserved
, pszName
, cchMax
);
2564 static const IContextMenuVtbl cmvt
=
2566 ShellLink_ContextMenu_QueryInterface
,
2567 ShellLink_ContextMenu_AddRef
,
2568 ShellLink_ContextMenu_Release
,
2569 ShellLink_QueryContextMenu
,
2570 ShellLink_InvokeCommand
,
2571 ShellLink_GetCommandString
2574 static HRESULT WINAPI
2575 ShellLink_ObjectWithSite_QueryInterface( IObjectWithSite
* iface
, REFIID riid
, void** ppvObject
)
2577 IShellLinkImpl
*This
= impl_from_IObjectWithSite(iface
);
2578 return IShellLinkW_QueryInterface(&This
->IShellLinkW_iface
, riid
, ppvObject
);
2582 ShellLink_ObjectWithSite_AddRef( IObjectWithSite
* iface
)
2584 IShellLinkImpl
*This
= impl_from_IObjectWithSite(iface
);
2585 return IShellLinkW_AddRef(&This
->IShellLinkW_iface
);
2589 ShellLink_ObjectWithSite_Release( IObjectWithSite
* iface
)
2591 IShellLinkImpl
*This
= impl_from_IObjectWithSite(iface
);
2592 return IShellLinkW_Release(&This
->IShellLinkW_iface
);
2595 static HRESULT WINAPI
2596 ShellLink_GetSite( IObjectWithSite
*iface
, REFIID iid
, void ** ppvSite
)
2598 IShellLinkImpl
*This
= impl_from_IObjectWithSite(iface
);
2600 TRACE("%p %s %p\n", This
, debugstr_guid( iid
), ppvSite
);
2604 return IUnknown_QueryInterface( This
->site
, iid
, ppvSite
);
2607 static HRESULT WINAPI
2608 ShellLink_SetSite( IObjectWithSite
*iface
, IUnknown
*punk
)
2610 IShellLinkImpl
*This
= impl_from_IObjectWithSite(iface
);
2612 TRACE("%p %p\n", iface
, punk
);
2615 IUnknown_AddRef( punk
);
2618 IUnknown_Release( This
->site
);
2625 static const IObjectWithSiteVtbl owsvt
=
2627 ShellLink_ObjectWithSite_QueryInterface
,
2628 ShellLink_ObjectWithSite_AddRef
,
2629 ShellLink_ObjectWithSite_Release
,
2634 static HRESULT WINAPI
propertystore_QueryInterface(IPropertyStore
*iface
, REFIID riid
, void **obj
)
2636 IShellLinkImpl
*This
= impl_from_IPropertyStore(iface
);
2637 return IShellLinkW_QueryInterface(&This
->IShellLinkW_iface
, riid
, obj
);
2640 static ULONG WINAPI
propertystore_AddRef(IPropertyStore
*iface
)
2642 IShellLinkImpl
*This
= impl_from_IPropertyStore(iface
);
2643 return IShellLinkW_AddRef(&This
->IShellLinkW_iface
);
2646 static ULONG WINAPI
propertystore_Release(IPropertyStore
*iface
)
2648 IShellLinkImpl
*This
= impl_from_IPropertyStore(iface
);
2649 return IShellLinkW_Release(&This
->IShellLinkW_iface
);
2652 static HRESULT WINAPI
propertystore_GetCount(IPropertyStore
*iface
, DWORD
*props
)
2654 IShellLinkImpl
*This
= impl_from_IPropertyStore(iface
);
2655 FIXME("(%p)->(%p): stub\n", This
, props
);
2659 static HRESULT WINAPI
propertystore_GetAt(IPropertyStore
*iface
, DWORD propid
, PROPERTYKEY
*key
)
2661 IShellLinkImpl
*This
= impl_from_IPropertyStore(iface
);
2662 FIXME("(%p)->(%d %p): stub\n", This
, propid
, key
);
2666 static HRESULT WINAPI
propertystore_GetValue(IPropertyStore
*iface
, REFPROPERTYKEY key
, PROPVARIANT
*value
)
2668 IShellLinkImpl
*This
= impl_from_IPropertyStore(iface
);
2669 FIXME("(%p)->(%p %p): stub\n", This
, key
, value
);
2673 static HRESULT WINAPI
propertystore_SetValue(IPropertyStore
*iface
, REFPROPERTYKEY key
, REFPROPVARIANT value
)
2675 IShellLinkImpl
*This
= impl_from_IPropertyStore(iface
);
2676 FIXME("(%p)->(%p %p): stub\n", This
, key
, value
);
2680 static HRESULT WINAPI
propertystore_Commit(IPropertyStore
*iface
)
2682 IShellLinkImpl
*This
= impl_from_IPropertyStore(iface
);
2683 FIXME("(%p): stub\n", This
);
2687 static const IPropertyStoreVtbl propertystorevtbl
= {
2688 propertystore_QueryInterface
,
2689 propertystore_AddRef
,
2690 propertystore_Release
,
2691 propertystore_GetCount
,
2692 propertystore_GetAt
,
2693 propertystore_GetValue
,
2694 propertystore_SetValue
,
2695 propertystore_Commit
2698 HRESULT WINAPI
IShellLink_Constructor(IUnknown
*outer
, REFIID riid
, void **obj
)
2700 IShellLinkImpl
* sl
;
2703 TRACE("outer=%p riid=%s\n", outer
, debugstr_guid(riid
));
2708 return CLASS_E_NOAGGREGATION
;
2710 sl
= LocalAlloc(LMEM_ZEROINIT
,sizeof(IShellLinkImpl
));
2712 return E_OUTOFMEMORY
;
2715 sl
->IShellLinkA_iface
.lpVtbl
= &slvt
;
2716 sl
->IShellLinkW_iface
.lpVtbl
= &slvtw
;
2717 sl
->IPersistFile_iface
.lpVtbl
= &pfvt
;
2718 sl
->IPersistStream_iface
.lpVtbl
= &psvt
;
2719 sl
->IShellLinkDataList_iface
.lpVtbl
= &dlvt
;
2720 sl
->IShellExtInit_iface
.lpVtbl
= &eivt
;
2721 sl
->IContextMenu_iface
.lpVtbl
= &cmvt
;
2722 sl
->IObjectWithSite_iface
.lpVtbl
= &owsvt
;
2723 sl
->IPropertyStore_iface
.lpVtbl
= &propertystorevtbl
;
2724 sl
->iShowCmd
= SW_SHOWNORMAL
;
2728 sl
->filepath
= NULL
;
2730 TRACE("(%p)\n", sl
);
2732 r
= IShellLinkW_QueryInterface( &sl
->IShellLinkW_iface
, riid
, obj
);
2733 IShellLinkW_Release( &sl
->IShellLinkW_iface
);