3 * Copyright 1997 Marcus Meissner
4 * Copyright 1998 Juergen Schmied
15 #ifdef HAVE_SYS_WAIT_H
16 # include <sys/wait.h>
18 #include "debugtools.h"
25 #include "wine/undocshell.h"
26 #include "bitmaps/wine.xpm"
30 #include "shell32_main.h"
33 DEFAULT_DEBUG_CHANNEL(shell
);
35 /* link file formats */
39 /* flag1: lnk elements: simple link has 0x0B */
47 #define MAXIMIZED 0x03
48 #define MINIMIZED 0x07
50 typedef struct _LINK_HEADER
51 { DWORD MagicStr
; /* 0x00 'L','\0','\0','\0' */
52 GUID MagicGuid
; /* 0x04 is CLSID_ShellLink */
53 DWORD Flag1
; /* 0x14 describes elements following */
54 DWORD Flag2
; /* 0x18 */
55 FILETIME Time1
; /* 0x1c */
56 FILETIME Time2
; /* 0x24 */
57 FILETIME Time3
; /* 0x2c */
58 DWORD Unknown1
; /* 0x34 */
59 DWORD Unknown2
; /* 0x38 icon number */
60 DWORD fStartup
; /* 0x3c startup type */
61 DWORD wHotKey
; /* 0x40 hotkey */
62 DWORD Unknown5
; /* 0x44 */
63 DWORD Unknown6
; /* 0x48 */
64 USHORT PidlSize
; /* 0x4c */
65 ITEMIDLIST Pidl
; /* 0x4e */
66 } LINK_HEADER
, * PLINK_HEADER
;
68 #define LINK_HEADER_SIZE (sizeof(LINK_HEADER)-sizeof(ITEMIDLIST))
87 GRPICONDIRENTRY idEntries
[1];
113 static ICOM_VTABLE(IShellLinkA
) slvt
;
114 static ICOM_VTABLE(IShellLinkW
) slvtw
;
115 static ICOM_VTABLE(IPersistFile
) pfvt
;
116 static ICOM_VTABLE(IPersistStream
) psvt
;
118 /* IShellLink Implementation */
122 ICOM_VFIELD(IShellLinkA
);
125 ICOM_VTABLE(IShellLinkW
)* lpvtblw
;
126 ICOM_VTABLE(IPersistFile
)* lpvtblPersistFile
;
127 ICOM_VTABLE(IPersistStream
)* lpvtblPersistStream
;
129 /* internal stream of the IPersistFile interface */
130 IStream
* lpFileStream
;
132 /* data structures according to the informations in the lnk */
147 #define _IShellLinkW_Offset ((int)(&(((IShellLinkImpl*)0)->lpvtblw)))
148 #define _ICOM_THIS_From_IShellLinkW(class, name) class* This = (class*)(((char*)name)-_IShellLinkW_Offset);
150 #define _IPersistFile_Offset ((int)(&(((IShellLinkImpl*)0)->lpvtblPersistFile)))
151 #define _ICOM_THIS_From_IPersistFile(class, name) class* This = (class*)(((char*)name)-_IPersistFile_Offset);
153 #define _IPersistStream_Offset ((int)(&(((IShellLinkImpl*)0)->lpvtblPersistStream)))
154 #define _ICOM_THIS_From_IPersistStream(class, name) class* This = (class*)(((char*)name)-_IPersistStream_Offset);
155 #define _IPersistStream_From_ICOM_THIS(class, name) class* StreamThis = (class*)(((char*)name)+_IPersistStream_Offset);
157 /**************************************************************************
158 * IPersistFile_QueryInterface
160 static HRESULT WINAPI
IPersistFile_fnQueryInterface(
165 _ICOM_THIS_From_IPersistFile(IShellLinkImpl
, iface
)
167 TRACE("(%p)\n",This
);
169 return IShellLinkA_QueryInterface((IShellLinkA
*)This
, riid
, ppvObj
);
172 /******************************************************************************
173 * IPersistFile_AddRef
175 static ULONG WINAPI
IPersistFile_fnAddRef(IPersistFile
* iface
)
177 _ICOM_THIS_From_IPersistFile(IShellLinkImpl
, iface
)
179 TRACE("(%p)->(count=%lu)\n",This
,This
->ref
);
181 return IShellLinkA_AddRef((IShellLinkA
*)This
);
183 /******************************************************************************
184 * IPersistFile_Release
186 static ULONG WINAPI
IPersistFile_fnRelease(IPersistFile
* iface
)
188 _ICOM_THIS_From_IPersistFile(IShellLinkImpl
, iface
)
190 TRACE("(%p)->(count=%lu)\n",This
,This
->ref
);
192 return IShellLinkA_Release((IShellLinkA
*)This
);
195 static HRESULT WINAPI
IPersistFile_fnGetClassID(IPersistFile
* iface
, CLSID
*pClassID
)
197 _ICOM_THIS_From_IPersistFile(IShellLinkImpl
, iface
)
198 FIXME("(%p)\n",This
);
201 static HRESULT WINAPI
IPersistFile_fnIsDirty(IPersistFile
* iface
)
203 _ICOM_THIS_From_IPersistFile(IShellLinkImpl
, iface
)
204 FIXME("(%p)\n",This
);
207 static HRESULT WINAPI
IPersistFile_fnLoad(IPersistFile
* iface
, LPCOLESTR pszFileName
, DWORD dwMode
)
209 _ICOM_THIS_From_IPersistFile(IShellLinkImpl
, iface
)
210 _IPersistStream_From_ICOM_THIS(IPersistStream
, This
)
212 LPSTR sFile
= HEAP_strdupWtoA ( GetProcessHeap(), 0, pszFileName
);
213 HRESULT hRet
= E_FAIL
;
215 TRACE("(%p, %s)\n",This
, sFile
);
218 if (This
->lpFileStream
)
219 IStream_Release(This
->lpFileStream
);
221 if SUCCEEDED(CreateStreamOnFile(sFile
, &(This
->lpFileStream
)))
223 if SUCCEEDED (IPersistStream_Load(StreamThis
, This
->lpFileStream
))
233 /* Icon extraction routines
235 * FIXME: should use PrivateExtractIcons and friends
236 * FIXME: should not use stdio
239 static BOOL
SaveIconResAsXPM(const BITMAPINFO
*pIcon
, const char *szXPMFileName
)
249 BOOL aColorUsed
[256] = {0};
253 if (!((pIcon
->bmiHeader
.biBitCount
== 4) || (pIcon
->bmiHeader
.biBitCount
== 8)))
256 if (!(fXPMFile
= fopen(szXPMFileName
, "w")))
259 nHeight
= pIcon
->bmiHeader
.biHeight
/ 2;
260 nXORWidthBytes
= 4 * ((pIcon
->bmiHeader
.biWidth
* pIcon
->bmiHeader
.biBitCount
/ 32)
261 + ((pIcon
->bmiHeader
.biWidth
* pIcon
->bmiHeader
.biBitCount
% 32) > 0));
262 nANDWidthBytes
= 4 * ((pIcon
->bmiHeader
.biWidth
/ 32)
263 + ((pIcon
->bmiHeader
.biWidth
% 32) > 0));
264 b8BitColors
= pIcon
->bmiHeader
.biBitCount
== 8;
265 nColors
= pIcon
->bmiHeader
.biClrUsed
? pIcon
->bmiHeader
.biClrUsed
266 : 1 << pIcon
->bmiHeader
.biBitCount
;
267 pXOR
= (BYTE
*) pIcon
+ sizeof (BITMAPINFOHEADER
) + (nColors
* sizeof (RGBQUAD
));
268 pAND
= pXOR
+ nHeight
* nXORWidthBytes
;
270 #define MASK(x,y) (pAND[(x) / 8 + (nHeight - (y) - 1) * nANDWidthBytes] & (1 << (7 - (x) % 8)))
271 #define COLOR(x,y) (b8BitColors ? pXOR[(x) + (nHeight - (y) - 1) * nXORWidthBytes] : (x) % 2 ? pXOR[(x) / 2 + (nHeight - (y) - 1) * nXORWidthBytes] & 0xF : (pXOR[(x) / 2 + (nHeight - (y) - 1) * nXORWidthBytes] & 0xF0) >> 4)
273 for (i
= 0; i
< nHeight
; i
++)
274 for (j
= 0; j
< pIcon
->bmiHeader
.biWidth
; j
++)
275 if (!aColorUsed
[COLOR(j
,i
)] && !MASK(j
,i
))
277 aColorUsed
[COLOR(j
,i
)] = TRUE
;
281 if (fprintf(fXPMFile
, "/* XPM */\nstatic char *icon[] = {\n") <= 0)
283 if (fprintf(fXPMFile
, "\"%d %d %d %d\",\n",
284 (int) pIcon
->bmiHeader
.biWidth
, nHeight
, nColorsUsed
+ 1, 2) <=0)
287 for (i
= 0; i
< nColors
; i
++)
289 if (fprintf(fXPMFile
, "\"%.2X c #%.2X%.2X%.2X\",\n", i
, pIcon
->bmiColors
[i
].rgbRed
,
290 pIcon
->bmiColors
[i
].rgbGreen
, pIcon
->bmiColors
[i
].rgbBlue
) <= 0)
292 if (fprintf(fXPMFile
, "\" c None\"") <= 0)
295 for (i
= 0; i
< nHeight
; i
++)
297 if (fprintf(fXPMFile
, ",\n\"") <= 0)
299 for (j
= 0; j
< pIcon
->bmiHeader
.biWidth
; j
++)
303 if (fprintf(fXPMFile
, " ") <= 0)
307 if (fprintf(fXPMFile
, "%.2X", COLOR(j
,i
)) <= 0)
310 if (fprintf(fXPMFile
, "\"") <= 0)
313 if (fprintf(fXPMFile
, "};\n") <= 0)
324 unlink( szXPMFileName
);
328 static BOOL CALLBACK
EnumResNameProc(HANDLE hModule
, const char *lpszType
, char *lpszName
, LONG lParam
)
330 *(HRSRC
*) lParam
= FindResourceA(hModule
, lpszName
, RT_GROUP_ICONA
);
334 static int ExtractFromEXEDLL(const char *szFileName
, int nIndex
, const char *szXPMFileName
)
340 GRPICONDIR
*pIconDir
;
345 if (!(hModule
= LoadLibraryExA(szFileName
, 0, LOAD_LIBRARY_AS_DATAFILE
)))
349 hResInfo
= FindResourceA(hModule
, MAKEINTRESOURCEA(nIndex
), RT_GROUP_ICONA
);
351 if (EnumResourceNamesA(hModule
, RT_GROUP_ICONA
, &EnumResNameProc
, (LONG
) &hResInfo
))
357 if (!(hResData
= LoadResource(hModule
, hResInfo
)))
359 if (!(pIconDir
= LockResource(hResData
)))
362 for (i
= 0; i
< pIconDir
->idCount
; i
++)
363 if ((pIconDir
->idEntries
[i
].bHeight
* pIconDir
->idEntries
[i
].bWidth
) > nMax
)
365 lpName
= MAKEINTRESOURCEA(pIconDir
->idEntries
[i
].nID
);
366 nMax
= pIconDir
->idEntries
[i
].bHeight
* pIconDir
->idEntries
[i
].bWidth
;
369 FreeResource(hResData
);
371 if (!(hResInfo
= FindResourceA(hModule
, lpName
, RT_ICONA
)))
373 if (!(hResData
= LoadResource(hModule
, hResInfo
)))
375 if (!(pIcon
= LockResource(hResData
)))
378 if(!SaveIconResAsXPM(pIcon
, szXPMFileName
))
381 FreeResource(hResData
);
382 FreeLibrary(hModule
);
387 FreeResource(hResData
);
389 FreeLibrary(hModule
);
394 static int ExtractFromICO(const char *szFileName
, const char *szXPMFileName
)
398 ICONDIRENTRY
*pIconDirEntry
;
404 if (!(fICOFile
= fopen(szFileName
, "r")))
407 if (fread(&iconDir
, sizeof (ICONDIR
), 1, fICOFile
) != 1)
409 if ((iconDir
.idReserved
!= 0) || (iconDir
.idType
!= 1))
412 if ((pIconDirEntry
= malloc(iconDir
.idCount
* sizeof (ICONDIRENTRY
))) == NULL
)
414 if (fread(pIconDirEntry
, sizeof (ICONDIRENTRY
), iconDir
.idCount
, fICOFile
) != iconDir
.idCount
)
417 for (i
= 0; i
< iconDir
.idCount
; i
++)
418 if ((pIconDirEntry
[i
].bHeight
* pIconDirEntry
[i
].bWidth
) > nMax
)
421 nMax
= pIconDirEntry
[i
].bHeight
* pIconDirEntry
[i
].bWidth
;
423 if ((pIcon
= malloc(pIconDirEntry
[nIndex
].dwBytesInRes
)) == NULL
)
425 if (fseek(fICOFile
, pIconDirEntry
[nIndex
].dwImageOffset
, SEEK_SET
))
427 if (fread(pIcon
, pIconDirEntry
[nIndex
].dwBytesInRes
, 1, fICOFile
) != 1)
430 if(!SaveIconResAsXPM(pIcon
, szXPMFileName
))
449 /* get the Unix file name for a given path, allocating the string */
450 inline static char *get_unix_file_name( const char *dos
)
452 char buffer
[MAX_PATH
];
454 if (!wine_get_unix_file_name( dos
, buffer
, sizeof(buffer
) )) return NULL
;
455 return HEAP_strdupA( GetProcessHeap(), 0, buffer
);
458 static BOOL
create_default_icon( const char *filename
)
463 if (!(fXPM
= fopen(filename
, "w"))) return FALSE
;
464 fprintf(fXPM
, "/* XPM */\nstatic char * icon[] = {");
465 for (i
= 0; i
< sizeof(wine_xpm
)/sizeof(wine_xpm
[0]); i
++)
466 fprintf( fXPM
, "\n\"%s\",", wine_xpm
[i
]);
467 fprintf( fXPM
, "};\n" );
472 /* extract an icon from an exe or icon file; helper for IPersistFile_fnSave */
473 static char *extract_icon( const char *path
, int index
)
475 char *filename
= HEAP_strdupA( GetProcessHeap(), 0, tmpnam(NULL
) );
476 if (ExtractFromEXEDLL( path
, index
, filename
)) return filename
;
477 if (ExtractFromICO( path
, filename
)) return filename
;
478 if (create_default_icon( filename
)) return filename
;
479 HeapFree( GetProcessHeap(), 0, filename
);
484 static HRESULT WINAPI
IPersistFile_fnSave(IPersistFile
* iface
, LPCOLESTR pszFileName
, BOOL fRemember
)
486 HRESULT ret
= NOERROR
;
488 char buffer
[MAX_PATH
], buff2
[MAX_PATH
];
489 char *filename
, *link_name
, *p
;
490 char *shell_link_app
= NULL
;
491 char *icon_name
= NULL
;
492 char *path_name
= NULL
;
493 char *work_dir
= NULL
;
497 _ICOM_THIS_From_IPersistFile(IShellLinkImpl
, iface
);
499 TRACE("(%p)->(%s)\n",This
,debugstr_w(pszFileName
));
501 if (!pszFileName
|| !This
->sPath
)
502 return ERROR_UNKNOWN
;
504 /* check for .exe extension */
505 if (!(p
= strrchr( This
->sPath
, '.' ))) return NOERROR
;
506 if (strchr( p
, '\\' ) || strchr( p
, '/' )) return NOERROR
;
507 if (strcasecmp( p
, ".exe" )) return NOERROR
;
509 /* check if ShellLinker configured */
511 if (!RegOpenKeyExA( HKEY_LOCAL_MACHINE
, "Software\\Wine\\Wine\\Config\\Wine",
512 0, KEY_ALL_ACCESS
, &hkey
))
514 DWORD type
, count
= sizeof(buffer
);
515 if (RegQueryValueExA( hkey
, "ShellLinker", 0, &type
, buffer
, &count
)) buffer
[0] = 0;
518 if (!*buffer
) return NOERROR
;
519 shell_link_app
= HEAP_strdupA( GetProcessHeap(), 0, buffer
);
521 if (!WideCharToMultiByte( CP_ACP
, 0, pszFileName
, -1, buffer
, sizeof(buffer
), NULL
, NULL
))
522 return ERROR_UNKNOWN
;
523 GetFullPathNameA( buffer
, sizeof(buff2
), buff2
, NULL
);
524 filename
= HEAP_strdupA( GetProcessHeap(), 0, buff2
);
526 if (SHGetSpecialFolderPathA( 0, buffer
, CSIDL_STARTUP
, FALSE
))
528 /* ignore startup for now */
529 if (!strncasecmp( filename
, buffer
, strlen(buffer
) )) goto done
;
531 if (SHGetSpecialFolderPathA( 0, buffer
, CSIDL_DESKTOPDIRECTORY
, FALSE
))
533 if (!strncasecmp( filename
, buffer
, strlen(buffer
) ))
535 link_name
= filename
+ strlen(buffer
);
540 if (SHGetSpecialFolderPathA( 0, buffer
, CSIDL_STARTMENU
, FALSE
))
542 if (!strncasecmp( filename
, buffer
, strlen(buffer
) ))
544 link_name
= filename
+ strlen(buffer
);
552 /* make link name a Unix name */
553 for (p
= link_name
; *p
; p
++) if (*p
== '\\') *p
= '/';
554 /* strip leading slashes */
555 while (*link_name
== '/') link_name
++;
556 /* remove extension */
557 if ((p
= strrchr( link_name
, '.' ))) *p
= 0;
559 /* convert app path name */
560 path_name
= get_unix_file_name( This
->sPath
);
562 /* convert app working dir */
563 if (This
->sWorkDir
) work_dir
= get_unix_file_name( This
->sWorkDir
);
565 /* extract the icon */
566 if (!(icon_name
= extract_icon( This
->sIcoPath
? This
->sIcoPath
: This
->sPath
,
567 This
->iIcoNdx
))) goto done
;
569 TRACE("linker app='%s' link='%s' mode=%s path='%s' args='%s' icon='%s' workdir='%s' descr='%s'\n",
570 shell_link_app
, link_name
, bDesktop
? "desktop" : "menu", path_name
,
571 This
->sArgs
? This
->sArgs
: "", icon_name
, work_dir
? work_dir
: "",
572 This
->sDescription
? This
->sDescription
: "" );
574 if ((pid
= fork()) == -1) goto done
;
579 argv
[pos
++] = shell_link_app
;
580 argv
[pos
++] = "--link";
581 argv
[pos
++] = link_name
;
582 argv
[pos
++] = "--path";
583 argv
[pos
++] = path_name
;
584 argv
[pos
++] = bDesktop
? "--desktop" : "--menu";
587 argv
[pos
++] = "--args";
588 argv
[pos
++] = This
->sArgs
;
592 argv
[pos
++] = "--icon";
593 argv
[pos
++] = icon_name
;
597 argv
[pos
++] = "--workdir";
598 argv
[pos
++] = This
->sWorkDir
;
600 if (This
->sDescription
)
602 argv
[pos
++] = "--descr";
603 argv
[pos
++] = This
->sDescription
;
606 execvp( shell_link_app
, argv
);
610 while (waitpid( pid
, &status
, 0 ) == -1)
618 if (status
) ret
= E_ACCESSDENIED
;
621 if (icon_name
) unlink( icon_name
);
622 HeapFree( GetProcessHeap(), 0, shell_link_app
);
623 HeapFree( GetProcessHeap(), 0, filename
);
624 HeapFree( GetProcessHeap(), 0, icon_name
);
625 HeapFree( GetProcessHeap(), 0, path_name
);
626 HeapFree( GetProcessHeap(), 0, work_dir
);
630 static HRESULT WINAPI
IPersistFile_fnSaveCompleted(IPersistFile
* iface
, LPCOLESTR pszFileName
)
632 _ICOM_THIS_From_IPersistFile(IShellLinkImpl
, iface
);
633 FIXME("(%p)->(%s)\n",This
,debugstr_w(pszFileName
));
636 static HRESULT WINAPI
IPersistFile_fnGetCurFile(IPersistFile
* iface
, LPOLESTR
*ppszFileName
)
638 _ICOM_THIS_From_IPersistFile(IShellLinkImpl
, iface
);
639 FIXME("(%p)\n",This
);
643 static ICOM_VTABLE(IPersistFile
) pfvt
=
645 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
646 IPersistFile_fnQueryInterface
,
647 IPersistFile_fnAddRef
,
648 IPersistFile_fnRelease
,
649 IPersistFile_fnGetClassID
,
650 IPersistFile_fnIsDirty
,
653 IPersistFile_fnSaveCompleted
,
654 IPersistFile_fnGetCurFile
657 /************************************************************************
658 * IPersistStream_QueryInterface
660 static HRESULT WINAPI
IPersistStream_fnQueryInterface(
661 IPersistStream
* iface
,
665 _ICOM_THIS_From_IPersistStream(IShellLinkImpl
, iface
);
667 TRACE("(%p)\n",This
);
669 return IShellLinkA_QueryInterface((IShellLinkA
*)This
, riid
, ppvoid
);
672 /************************************************************************
673 * IPersistStream_Release
675 static ULONG WINAPI
IPersistStream_fnRelease(
676 IPersistStream
* iface
)
678 _ICOM_THIS_From_IPersistStream(IShellLinkImpl
, iface
);
680 TRACE("(%p)\n",This
);
682 return IShellLinkA_Release((IShellLinkA
*)This
);
685 /************************************************************************
686 * IPersistStream_AddRef
688 static ULONG WINAPI
IPersistStream_fnAddRef(
689 IPersistStream
* iface
)
691 _ICOM_THIS_From_IPersistStream(IShellLinkImpl
, iface
);
693 TRACE("(%p)\n",This
);
695 return IShellLinkA_AddRef((IShellLinkA
*)This
);
698 /************************************************************************
699 * IPersistStream_GetClassID
702 static HRESULT WINAPI
IPersistStream_fnGetClassID(
703 IPersistStream
* iface
,
706 _ICOM_THIS_From_IPersistStream(IShellLinkImpl
, iface
);
708 TRACE("(%p)\n", This
);
713 /* memcpy(pClassID, &CLSID_???, sizeof(CLSID_???)); */
718 /************************************************************************
719 * IPersistStream_IsDirty (IPersistStream)
721 static HRESULT WINAPI
IPersistStream_fnIsDirty(
722 IPersistStream
* iface
)
724 _ICOM_THIS_From_IPersistStream(IShellLinkImpl
, iface
);
726 TRACE("(%p)\n", This
);
730 /************************************************************************
731 * IPersistStream_Load (IPersistStream)
734 static HRESULT WINAPI
IPersistStream_fnLoad(
735 IPersistStream
* iface
,
736 IStream
* pLoadStream
)
738 PLINK_HEADER lpLinkHeader
= HeapAlloc(GetProcessHeap(), 0, LINK_HEADER_SIZE
);
741 char sTemp
[MAX_PATH
];
743 _ICOM_THIS_From_IPersistStream(IShellLinkImpl
, iface
);
745 TRACE("(%p)(%p)\n", This
, pLoadStream
);
749 return STG_E_INVALIDPOINTER
;
752 IStream_AddRef (pLoadStream
);
755 if (SUCCEEDED(IStream_Read(pLoadStream
, lpLinkHeader
, LINK_HEADER_SIZE
, &dwBytesRead
)))
757 if ((lpLinkHeader
->MagicStr
== 0x0000004CL
) && IsEqualIID(&lpLinkHeader
->MagicGuid
, &CLSID_ShellLink
))
759 lpLinkHeader
= HeapReAlloc(GetProcessHeap(), 0, lpLinkHeader
, LINK_HEADER_SIZE
+lpLinkHeader
->PidlSize
);
762 if (SUCCEEDED(IStream_Read(pLoadStream
, &(lpLinkHeader
->Pidl
), lpLinkHeader
->PidlSize
, &dwBytesRead
)))
764 if (pcheck (&lpLinkHeader
->Pidl
))
766 This
->pPidl
= ILClone (&lpLinkHeader
->Pidl
);
768 SHGetPathFromIDListA(&lpLinkHeader
->Pidl
, sTemp
);
769 This
->sPath
= HEAP_strdupA ( GetProcessHeap(), 0, sTemp
);
771 This
->wHotKey
= lpLinkHeader
->wHotKey
;
772 FileTimeToSystemTime (&lpLinkHeader
->Time1
, &This
->time1
);
773 FileTimeToSystemTime (&lpLinkHeader
->Time2
, &This
->time2
);
774 FileTimeToSystemTime (&lpLinkHeader
->Time3
, &This
->time3
);
776 GetDateFormatA(LOCALE_USER_DEFAULT
,DATE_SHORTDATE
,&This
->time1
, NULL
, sTemp
, 256);
777 TRACE("-- time1: %s\n", sTemp
);
778 GetDateFormatA(LOCALE_USER_DEFAULT
,DATE_SHORTDATE
,&This
->time2
, NULL
, sTemp
, 256);
779 TRACE("-- time1: %s\n", sTemp
);
780 GetDateFormatA(LOCALE_USER_DEFAULT
,DATE_SHORTDATE
,&This
->time3
, NULL
, sTemp
, 256);
781 TRACE("-- time1: %s\n", sTemp
);
790 WARN("stream contains no link!\n");
795 IStream_Release (pLoadStream
);
799 HeapFree(GetProcessHeap(), 0, lpLinkHeader
);
804 /************************************************************************
805 * IPersistStream_Save (IPersistStream)
807 static HRESULT WINAPI
IPersistStream_fnSave(
808 IPersistStream
* iface
,
812 _ICOM_THIS_From_IPersistStream(IShellLinkImpl
, iface
);
814 TRACE("(%p) %p %x\n", This
, pOutStream
, fClearDirty
);
819 /************************************************************************
820 * IPersistStream_GetSizeMax (IPersistStream)
822 static HRESULT WINAPI
IPersistStream_fnGetSizeMax(
823 IPersistStream
* iface
,
824 ULARGE_INTEGER
* pcbSize
)
826 _ICOM_THIS_From_IPersistStream(IShellLinkImpl
, iface
);
828 TRACE("(%p)\n", This
);
833 static ICOM_VTABLE(IPersistStream
) psvt
=
835 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
836 IPersistStream_fnQueryInterface
,
837 IPersistStream_fnAddRef
,
838 IPersistStream_fnRelease
,
839 IPersistStream_fnGetClassID
,
840 IPersistStream_fnIsDirty
,
841 IPersistStream_fnLoad
,
842 IPersistStream_fnSave
,
843 IPersistStream_fnGetSizeMax
846 /**************************************************************************
847 * IShellLink_Constructor
849 IShellLinkA
* IShellLink_Constructor(BOOL bUnicode
)
850 { IShellLinkImpl
* sl
;
852 sl
= (IShellLinkImpl
*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IShellLinkImpl
));
854 ICOM_VTBL(sl
) = &slvt
;
855 sl
->lpvtblw
= &slvtw
;
856 sl
->lpvtblPersistFile
= &pfvt
;
857 sl
->lpvtblPersistStream
= &psvt
;
859 TRACE("(%p)->()\n",sl
);
861 return bUnicode
? (IShellLinkA
*) &(sl
->lpvtblw
) : (IShellLinkA
*)sl
;
864 /**************************************************************************
865 * IShellLinkA_QueryInterface
867 static HRESULT WINAPI
IShellLinkA_fnQueryInterface( IShellLinkA
* iface
, REFIID riid
, LPVOID
*ppvObj
)
869 ICOM_THIS(IShellLinkImpl
, iface
);
871 TRACE("(%p)->(\n\tIID:\t%s)\n",This
,debugstr_guid(riid
));
875 if(IsEqualIID(riid
, &IID_IUnknown
) ||
876 IsEqualIID(riid
, &IID_IShellLinkA
))
880 else if(IsEqualIID(riid
, &IID_IShellLinkW
))
882 *ppvObj
= (IShellLinkW
*)&(This
->lpvtblw
);
884 else if(IsEqualIID(riid
, &IID_IPersistFile
))
886 *ppvObj
= (IPersistFile
*)&(This
->lpvtblPersistFile
);
888 else if(IsEqualIID(riid
, &IID_IPersistStream
))
890 *ppvObj
= (IPersistStream
*)&(This
->lpvtblPersistStream
);
895 IUnknown_AddRef((IUnknown
*)(*ppvObj
));
896 TRACE("-- Interface: (%p)->(%p)\n",ppvObj
,*ppvObj
);
899 TRACE("-- Interface: E_NOINTERFACE\n");
900 return E_NOINTERFACE
;
902 /******************************************************************************
905 static ULONG WINAPI
IShellLinkA_fnAddRef(IShellLinkA
* iface
)
907 ICOM_THIS(IShellLinkImpl
, iface
);
909 TRACE("(%p)->(count=%lu)\n",This
,This
->ref
);
912 return ++(This
->ref
);
914 /******************************************************************************
915 * IShellLinkA_Release
917 static ULONG WINAPI
IShellLinkA_fnRelease(IShellLinkA
* iface
)
919 ICOM_THIS(IShellLinkImpl
, iface
);
921 TRACE("(%p)->(count=%lu)\n",This
,This
->ref
);
925 { TRACE("-- destroying IShellLink(%p)\n",This
);
928 HeapFree(GetProcessHeap(), 0, This
->sIcoPath
);
931 HeapFree(GetProcessHeap(), 0, This
->sArgs
);
934 HeapFree(GetProcessHeap(), 0, This
->sWorkDir
);
936 if (This
->sDescription
)
937 HeapFree(GetProcessHeap(), 0, This
->sDescription
);
940 HeapFree(GetProcessHeap(),0,This
->sPath
);
945 if (This
->lpFileStream
)
946 IStream_Release(This
->lpFileStream
);
950 HeapFree(GetProcessHeap(),0,This
);
956 static HRESULT WINAPI
IShellLinkA_fnGetPath(IShellLinkA
* iface
, LPSTR pszFile
,INT cchMaxPath
, WIN32_FIND_DATAA
*pfd
, DWORD fFlags
)
958 ICOM_THIS(IShellLinkImpl
, iface
);
960 TRACE("(%p)->(pfile=%p len=%u find_data=%p flags=%lu)(%s)\n",This
, pszFile
, cchMaxPath
, pfd
, fFlags
, debugstr_a(This
->sPath
));
963 lstrcpynA(pszFile
,This
->sPath
, cchMaxPath
);
969 static HRESULT WINAPI
IShellLinkA_fnGetIDList(IShellLinkA
* iface
, LPITEMIDLIST
* ppidl
)
971 ICOM_THIS(IShellLinkImpl
, iface
);
973 TRACE("(%p)->(ppidl=%p)\n",This
, ppidl
);
975 *ppidl
= ILClone(This
->pPidl
);
978 static HRESULT WINAPI
IShellLinkA_fnSetIDList(IShellLinkA
* iface
, LPCITEMIDLIST pidl
)
980 ICOM_THIS(IShellLinkImpl
, iface
);
982 TRACE("(%p)->(pidl=%p)\n",This
, pidl
);
986 This
->pPidl
= ILClone (pidl
);
989 static HRESULT WINAPI
IShellLinkA_fnGetDescription(IShellLinkA
* iface
, LPSTR pszName
,INT cchMaxName
)
991 ICOM_THIS(IShellLinkImpl
, iface
);
993 FIXME("(%p)->(%p len=%u)\n",This
, pszName
, cchMaxName
);
994 lstrcpynA(pszName
,"Description, FIXME",cchMaxName
);
997 static HRESULT WINAPI
IShellLinkA_fnSetDescription(IShellLinkA
* iface
, LPCSTR pszName
)
999 ICOM_THIS(IShellLinkImpl
, iface
);
1001 TRACE("(%p)->(pName=%s)\n", This
, pszName
);
1003 if (This
->sDescription
)
1004 HeapFree(GetProcessHeap(), 0, This
->sDescription
);
1005 if (!(This
->sDescription
= HEAP_strdupA(GetProcessHeap(), 0, pszName
)))
1006 return E_OUTOFMEMORY
;
1010 static HRESULT WINAPI
IShellLinkA_fnGetWorkingDirectory(IShellLinkA
* iface
, LPSTR pszDir
,INT cchMaxPath
)
1012 ICOM_THIS(IShellLinkImpl
, iface
);
1014 FIXME("(%p)->()\n",This
);
1015 lstrcpynA(pszDir
,"c:\\", cchMaxPath
);
1018 static HRESULT WINAPI
IShellLinkA_fnSetWorkingDirectory(IShellLinkA
* iface
, LPCSTR pszDir
)
1020 ICOM_THIS(IShellLinkImpl
, iface
);
1022 TRACE("(%p)->(dir=%s)\n",This
, pszDir
);
1025 HeapFree(GetProcessHeap(), 0, This
->sWorkDir
);
1026 if (!(This
->sWorkDir
= HEAP_strdupA(GetProcessHeap(), 0, pszDir
)))
1027 return E_OUTOFMEMORY
;
1031 static HRESULT WINAPI
IShellLinkA_fnGetArguments(IShellLinkA
* iface
, LPSTR pszArgs
,INT cchMaxPath
)
1033 ICOM_THIS(IShellLinkImpl
, iface
);
1035 FIXME("(%p)->(%p len=%u)\n",This
, pszArgs
, cchMaxPath
);
1036 lstrcpynA(pszArgs
, "", cchMaxPath
);
1039 static HRESULT WINAPI
IShellLinkA_fnSetArguments(IShellLinkA
* iface
, LPCSTR pszArgs
)
1041 ICOM_THIS(IShellLinkImpl
, iface
);
1043 TRACE("(%p)->(args=%s)\n",This
, pszArgs
);
1046 HeapFree(GetProcessHeap(), 0, This
->sArgs
);
1047 if (!(This
->sArgs
= HEAP_strdupA(GetProcessHeap(), 0, pszArgs
)))
1048 return E_OUTOFMEMORY
;
1052 static HRESULT WINAPI
IShellLinkA_fnGetHotkey(IShellLinkA
* iface
, WORD
*pwHotkey
)
1054 ICOM_THIS(IShellLinkImpl
, iface
);
1056 TRACE("(%p)->(%p)(0x%08x)\n",This
, pwHotkey
, This
->wHotKey
);
1058 *pwHotkey
= This
->wHotKey
;
1062 static HRESULT WINAPI
IShellLinkA_fnSetHotkey(IShellLinkA
* iface
, WORD wHotkey
)
1064 ICOM_THIS(IShellLinkImpl
, iface
);
1066 TRACE("(%p)->(hotkey=%x)\n",This
, wHotkey
);
1068 This
->wHotKey
= wHotkey
;
1072 static HRESULT WINAPI
IShellLinkA_fnGetShowCmd(IShellLinkA
* iface
, INT
*piShowCmd
)
1074 ICOM_THIS(IShellLinkImpl
, iface
);
1076 FIXME("(%p)->(%p)\n",This
, piShowCmd
);
1080 static HRESULT WINAPI
IShellLinkA_fnSetShowCmd(IShellLinkA
* iface
, INT iShowCmd
)
1082 ICOM_THIS(IShellLinkImpl
, iface
);
1084 FIXME("(%p)->(showcmd=%x)\n",This
, iShowCmd
);
1087 static HRESULT WINAPI
IShellLinkA_fnGetIconLocation(IShellLinkA
* iface
, LPSTR pszIconPath
,INT cchIconPath
,INT
*piIcon
)
1089 ICOM_THIS(IShellLinkImpl
, iface
);
1091 FIXME("(%p)->(%p len=%u iicon=%p)\n",This
, pszIconPath
, cchIconPath
, piIcon
);
1092 lstrcpynA(pszIconPath
,"shell32.dll",cchIconPath
);
1096 static HRESULT WINAPI
IShellLinkA_fnSetIconLocation(IShellLinkA
* iface
, LPCSTR pszIconPath
,INT iIcon
)
1098 ICOM_THIS(IShellLinkImpl
, iface
);
1100 TRACE("(%p)->(path=%s iicon=%u)\n",This
, pszIconPath
, iIcon
);
1103 HeapFree(GetProcessHeap(), 0, This
->sIcoPath
);
1104 if (!(This
->sIcoPath
= HEAP_strdupA(GetProcessHeap(), 0, pszIconPath
)))
1105 return E_OUTOFMEMORY
;
1106 This
->iIcoNdx
= iIcon
;
1110 static HRESULT WINAPI
IShellLinkA_fnSetRelativePath(IShellLinkA
* iface
, LPCSTR pszPathRel
, DWORD dwReserved
)
1112 ICOM_THIS(IShellLinkImpl
, iface
);
1114 FIXME("(%p)->(path=%s %lx)\n",This
, pszPathRel
, dwReserved
);
1117 static HRESULT WINAPI
IShellLinkA_fnResolve(IShellLinkA
* iface
, HWND hwnd
, DWORD fFlags
)
1119 ICOM_THIS(IShellLinkImpl
, iface
);
1121 FIXME("(%p)->(hwnd=%x flags=%lx)\n",This
, hwnd
, fFlags
);
1124 static HRESULT WINAPI
IShellLinkA_fnSetPath(IShellLinkA
* iface
, LPCSTR pszFile
)
1126 ICOM_THIS(IShellLinkImpl
, iface
);
1128 TRACE("(%p)->(path=%s)\n",This
, pszFile
);
1131 HeapFree(GetProcessHeap(), 0, This
->sPath
);
1132 if (!(This
->sPath
= HEAP_strdupA(GetProcessHeap(), 0, pszFile
)))
1133 return E_OUTOFMEMORY
;
1138 /**************************************************************************
1139 * IShellLink Implementation
1142 static ICOM_VTABLE(IShellLinkA
) slvt
=
1144 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1145 IShellLinkA_fnQueryInterface
,
1146 IShellLinkA_fnAddRef
,
1147 IShellLinkA_fnRelease
,
1148 IShellLinkA_fnGetPath
,
1149 IShellLinkA_fnGetIDList
,
1150 IShellLinkA_fnSetIDList
,
1151 IShellLinkA_fnGetDescription
,
1152 IShellLinkA_fnSetDescription
,
1153 IShellLinkA_fnGetWorkingDirectory
,
1154 IShellLinkA_fnSetWorkingDirectory
,
1155 IShellLinkA_fnGetArguments
,
1156 IShellLinkA_fnSetArguments
,
1157 IShellLinkA_fnGetHotkey
,
1158 IShellLinkA_fnSetHotkey
,
1159 IShellLinkA_fnGetShowCmd
,
1160 IShellLinkA_fnSetShowCmd
,
1161 IShellLinkA_fnGetIconLocation
,
1162 IShellLinkA_fnSetIconLocation
,
1163 IShellLinkA_fnSetRelativePath
,
1164 IShellLinkA_fnResolve
,
1165 IShellLinkA_fnSetPath
1169 /**************************************************************************
1170 * IShellLinkW_fnQueryInterface
1172 static HRESULT WINAPI
IShellLinkW_fnQueryInterface(
1173 IShellLinkW
* iface
, REFIID riid
, LPVOID
*ppvObj
)
1175 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl
, iface
);
1177 return IShellLinkA_QueryInterface((IShellLinkA
*)This
, riid
, ppvObj
);
1180 /******************************************************************************
1181 * IShellLinkW_fnAddRef
1183 static ULONG WINAPI
IShellLinkW_fnAddRef(IShellLinkW
* iface
)
1185 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl
, iface
);
1187 TRACE("(%p)->(count=%lu)\n",This
,This
->ref
);
1189 return IShellLinkA_AddRef((IShellLinkA
*)This
);
1191 /******************************************************************************
1192 * IShellLinkW_fnRelease
1195 static ULONG WINAPI
IShellLinkW_fnRelease(IShellLinkW
* iface
)
1197 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl
, iface
);
1199 TRACE("(%p)->(count=%lu)\n",This
,This
->ref
);
1201 return IShellLinkA_Release((IShellLinkA
*)This
);
1204 static HRESULT WINAPI
IShellLinkW_fnGetPath(IShellLinkW
* iface
, LPWSTR pszFile
,INT cchMaxPath
, WIN32_FIND_DATAA
*pfd
, DWORD fFlags
)
1206 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl
, iface
);
1208 FIXME("(%p)->(pfile=%p len=%u find_data=%p flags=%lu)\n",This
, pszFile
, cchMaxPath
, pfd
, fFlags
);
1209 MultiByteToWideChar( CP_ACP
, 0, "c:\\foo.bar", -1, pszFile
, cchMaxPath
);
1213 static HRESULT WINAPI
IShellLinkW_fnGetIDList(IShellLinkW
* iface
, LPITEMIDLIST
* ppidl
)
1215 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl
, iface
);
1217 FIXME("(%p)->(ppidl=%p)\n",This
, ppidl
);
1218 *ppidl
= _ILCreateDesktop();
1222 static HRESULT WINAPI
IShellLinkW_fnSetIDList(IShellLinkW
* iface
, LPCITEMIDLIST pidl
)
1224 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl
, iface
);
1226 FIXME("(%p)->(pidl=%p)\n",This
, pidl
);
1230 static HRESULT WINAPI
IShellLinkW_fnGetDescription(IShellLinkW
* iface
, LPWSTR pszName
,INT cchMaxName
)
1232 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl
, iface
);
1234 FIXME("(%p)->(%p len=%u)\n",This
, pszName
, cchMaxName
);
1235 MultiByteToWideChar( CP_ACP
, 0, "Description, FIXME", -1, pszName
, cchMaxName
);
1239 static HRESULT WINAPI
IShellLinkW_fnSetDescription(IShellLinkW
* iface
, LPCWSTR pszName
)
1241 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl
, iface
);
1243 TRACE("(%p)->(desc=%s)\n",This
, debugstr_w(pszName
));
1245 if (This
->sDescription
)
1246 HeapFree(GetProcessHeap(), 0, This
->sDescription
);
1247 if (!(This
->sDescription
= HEAP_strdupWtoA(GetProcessHeap(), 0, pszName
)))
1248 return E_OUTOFMEMORY
;
1253 static HRESULT WINAPI
IShellLinkW_fnGetWorkingDirectory(IShellLinkW
* iface
, LPWSTR pszDir
,INT cchMaxPath
)
1255 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl
, iface
);
1257 FIXME("(%p)->()\n",This
);
1258 MultiByteToWideChar( CP_ACP
, 0, "c:\\", -1, pszDir
, cchMaxPath
);
1262 static HRESULT WINAPI
IShellLinkW_fnSetWorkingDirectory(IShellLinkW
* iface
, LPCWSTR pszDir
)
1264 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl
, iface
);
1266 TRACE("(%p)->(dir=%s)\n",This
, debugstr_w(pszDir
));
1269 HeapFree(GetProcessHeap(), 0, This
->sWorkDir
);
1270 if (!(This
->sWorkDir
= HEAP_strdupWtoA(GetProcessHeap(), 0, pszDir
)))
1271 return E_OUTOFMEMORY
;
1276 static HRESULT WINAPI
IShellLinkW_fnGetArguments(IShellLinkW
* iface
, LPWSTR pszArgs
,INT cchMaxPath
)
1278 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl
, iface
);
1280 FIXME("(%p)->(%p len=%u)\n",This
, pszArgs
, cchMaxPath
);
1285 static HRESULT WINAPI
IShellLinkW_fnSetArguments(IShellLinkW
* iface
, LPCWSTR pszArgs
)
1287 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl
, iface
);
1289 TRACE("(%p)->(args=%s)\n",This
, debugstr_w(pszArgs
));
1292 HeapFree(GetProcessHeap(), 0, This
->sArgs
);
1293 if (!(This
->sArgs
= HEAP_strdupWtoA(GetProcessHeap(), 0, pszArgs
)))
1294 return E_OUTOFMEMORY
;
1299 static HRESULT WINAPI
IShellLinkW_fnGetHotkey(IShellLinkW
* iface
, WORD
*pwHotkey
)
1301 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl
, iface
);
1303 FIXME("(%p)->(%p)\n",This
, pwHotkey
);
1308 static HRESULT WINAPI
IShellLinkW_fnSetHotkey(IShellLinkW
* iface
, WORD wHotkey
)
1310 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl
, iface
);
1312 FIXME("(%p)->(hotkey=%x)\n",This
, wHotkey
);
1316 static HRESULT WINAPI
IShellLinkW_fnGetShowCmd(IShellLinkW
* iface
, INT
*piShowCmd
)
1318 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl
, iface
);
1320 FIXME("(%p)->(%p)\n",This
, piShowCmd
);
1325 static HRESULT WINAPI
IShellLinkW_fnSetShowCmd(IShellLinkW
* iface
, INT iShowCmd
)
1327 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl
, iface
);
1329 FIXME("(%p)->(showcmd=%x)\n",This
, iShowCmd
);
1333 static HRESULT WINAPI
IShellLinkW_fnGetIconLocation(IShellLinkW
* iface
, LPWSTR pszIconPath
,INT cchIconPath
,INT
*piIcon
)
1335 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl
, iface
);
1337 FIXME("(%p)->(%p len=%u iicon=%p)\n",This
, pszIconPath
, cchIconPath
, piIcon
);
1338 MultiByteToWideChar( CP_ACP
, 0, "shell32.dll", -1, pszIconPath
, cchIconPath
);
1343 static HRESULT WINAPI
IShellLinkW_fnSetIconLocation(IShellLinkW
* iface
, LPCWSTR pszIconPath
,INT iIcon
)
1345 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl
, iface
);
1347 TRACE("(%p)->(path=%s iicon=%u)\n",This
, debugstr_w(pszIconPath
), iIcon
);
1350 HeapFree(GetProcessHeap(), 0, This
->sIcoPath
);
1351 if (!(This
->sIcoPath
= HEAP_strdupWtoA(GetProcessHeap(), 0, pszIconPath
)))
1352 return E_OUTOFMEMORY
;
1353 This
->iIcoNdx
= iIcon
;
1358 static HRESULT WINAPI
IShellLinkW_fnSetRelativePath(IShellLinkW
* iface
, LPCWSTR pszPathRel
, DWORD dwReserved
)
1360 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl
, iface
);
1362 FIXME("(%p)->(path=%s %lx)\n",This
, debugstr_w(pszPathRel
), dwReserved
);
1366 static HRESULT WINAPI
IShellLinkW_fnResolve(IShellLinkW
* iface
, HWND hwnd
, DWORD fFlags
)
1368 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl
, iface
);
1370 FIXME("(%p)->(hwnd=%x flags=%lx)\n",This
, hwnd
, fFlags
);
1374 static HRESULT WINAPI
IShellLinkW_fnSetPath(IShellLinkW
* iface
, LPCWSTR pszFile
)
1376 _ICOM_THIS_From_IShellLinkW(IShellLinkImpl
, iface
);
1378 TRACE("(%p)->(path=%s)\n",This
, debugstr_w(pszFile
));
1381 HeapFree(GetProcessHeap(), 0, This
->sPath
);
1382 if (!(This
->sPath
= HEAP_strdupWtoA(GetProcessHeap(), 0, pszFile
)))
1383 return E_OUTOFMEMORY
;
1388 /**************************************************************************
1389 * IShellLinkW Implementation
1392 static ICOM_VTABLE(IShellLinkW
) slvtw
=
1394 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1395 IShellLinkW_fnQueryInterface
,
1396 IShellLinkW_fnAddRef
,
1397 IShellLinkW_fnRelease
,
1398 IShellLinkW_fnGetPath
,
1399 IShellLinkW_fnGetIDList
,
1400 IShellLinkW_fnSetIDList
,
1401 IShellLinkW_fnGetDescription
,
1402 IShellLinkW_fnSetDescription
,
1403 IShellLinkW_fnGetWorkingDirectory
,
1404 IShellLinkW_fnSetWorkingDirectory
,
1405 IShellLinkW_fnGetArguments
,
1406 IShellLinkW_fnSetArguments
,
1407 IShellLinkW_fnGetHotkey
,
1408 IShellLinkW_fnSetHotkey
,
1409 IShellLinkW_fnGetShowCmd
,
1410 IShellLinkW_fnSetShowCmd
,
1411 IShellLinkW_fnGetIconLocation
,
1412 IShellLinkW_fnSetIconLocation
,
1413 IShellLinkW_fnSetRelativePath
,
1414 IShellLinkW_fnResolve
,
1415 IShellLinkW_fnSetPath