/*
*
- * Copyright 1997 Marcus Meissner
- * Copyright 1998 Juergen Schmied
+ * Copyright 1997 Marcus Meissner
+ * Copyright 1998 Juergen Schmied
+ * Copyright 2005 Mike McCormack
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * NOTES
+ * Nearly complete information about the binary formats
+ * of .lnk files available at http://www.wotsit.org
+ *
+ * You can use winedump to examine the contents of a link file:
+ * winedump lnk sc.lnk
+ *
+ * MSI advertised shortcuts are totally undocumented. They provide an
+ * icon for a program that is not yet installed, and invoke MSI to
+ * install the program when the shortcut is clicked on. They are
+ * created by passing a special string to SetPath, and the information
+ * in that string is parsed an stored.
*/
-#include "config.h"
-
-#include <string.h>
-#include <stdio.h>
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-#include <errno.h>
-#ifdef HAVE_SYS_WAIT_H
-# include <sys/wait.h>
-#endif
+#define COBJMACROS
+#define NONAMELESSUNION
+
#include "wine/debug.h"
-#include "wine/port.h"
#include "winerror.h"
+#include "windef.h"
#include "winbase.h"
#include "winnls.h"
#include "winreg.h"
+#include "winuser.h"
+#include "wingdi.h"
#include "shlobj.h"
#include "undocshell.h"
-#include "bitmaps/wine.xpm"
-#include "heap.h"
#include "pidl.h"
#include "shell32_main.h"
#include "shlguid.h"
+#include "shlwapi.h"
+#include "msi.h"
+#include "appmgmt.h"
+
+#include "initguid.h"
WINE_DEFAULT_DEBUG_CHANNEL(shell);
+DEFINE_GUID( SHELL32_AdvtShortcutProduct,
+ 0x9db1186f,0x40df,0x11d1,0xaa,0x8c,0x00,0xc0,0x4f,0xb6,0x78,0x63);
+DEFINE_GUID( SHELL32_AdvtShortcutComponent,
+ 0x9db1186e,0x40df,0x11d1,0xaa,0x8c,0x00,0xc0,0x4f,0xb6,0x78,0x63);
+
/* link file formats */
#include "pshpack1.h"
-/* flag1: lnk elements: simple link has 0x0B */
-#define WORKDIR 0x10
-#define ARGUMENT 0x20
-#define ICON 0x40
-#define UNC 0x80
-
-/* fStartup */
-#define NORMAL 0x01
-#define MAXIMIZED 0x03
-#define MINIMIZED 0x07
-
typedef struct _LINK_HEADER
-{ DWORD MagicStr; /* 0x00 'L','\0','\0','\0' */
- GUID MagicGuid; /* 0x04 is CLSID_ShellLink */
- DWORD Flag1; /* 0x14 describes elements following */
- DWORD Flag2; /* 0x18 */
+{
+ DWORD dwSize; /* 0x00 size of the header - 0x4c */
+ GUID MagicGuid; /* 0x04 is CLSID_ShellLink */
+ DWORD dwFlags; /* 0x14 describes elements following */
+ DWORD dwFileAttr; /* 0x18 attributes of the target file */
FILETIME Time1; /* 0x1c */
FILETIME Time2; /* 0x24 */
FILETIME Time3; /* 0x2c */
- DWORD Unknown1; /* 0x34 */
- DWORD Unknown2; /* 0x38 icon number */
+ DWORD dwFileLength; /* 0x34 File length */
+ DWORD nIcon; /* 0x38 icon number */
DWORD fStartup; /* 0x3c startup type */
DWORD wHotKey; /* 0x40 hotkey */
DWORD Unknown5; /* 0x44 */
DWORD Unknown6; /* 0x48 */
- USHORT PidlSize; /* 0x4c */
- ITEMIDLIST Pidl; /* 0x4e */
} LINK_HEADER, * PLINK_HEADER;
-#define LINK_HEADER_SIZE (sizeof(LINK_HEADER)-sizeof(ITEMIDLIST))
-
-typedef struct
-{
- BYTE bWidth;
- BYTE bHeight;
- BYTE bColorCount;
- BYTE bReserved;
- WORD wPlanes;
- WORD wBitCount;
- DWORD dwBytesInRes;
- WORD nID;
-} GRPICONDIRENTRY;
+#define SHLINK_LOCAL 0
+#define SHLINK_REMOTE 1
-typedef struct
+typedef struct _LOCATION_INFO
{
- WORD idReserved;
- WORD idType;
- WORD idCount;
- GRPICONDIRENTRY idEntries[1];
-} GRPICONDIR;
+ DWORD dwTotalSize;
+ DWORD dwHeaderSize;
+ DWORD dwFlags;
+ DWORD dwVolTableOfs;
+ DWORD dwLocalPathOfs;
+ DWORD dwNetworkVolTableOfs;
+ DWORD dwFinalPathOfs;
+} LOCATION_INFO;
-typedef struct
+typedef struct _LOCAL_VOLUME_INFO
{
- BYTE bWidth;
- BYTE bHeight;
- BYTE bColorCount;
- BYTE bReserved;
- WORD wPlanes;
- WORD wBitCount;
- DWORD dwBytesInRes;
- DWORD dwImageOffset;
-} ICONDIRENTRY;
+ DWORD dwSize;
+ DWORD dwType;
+ DWORD dwVolSerial;
+ DWORD dwVolLabelOfs;
+} LOCAL_VOLUME_INFO;
-typedef struct
+typedef struct volume_info_t
{
- WORD idReserved;
- WORD idType;
- WORD idCount;
-} ICONDIR;
-
+ DWORD type;
+ DWORD serial;
+ WCHAR label[12]; /* assume 8.3 */
+} volume_info;
#include "poppack.h"
-typedef struct
-{
- HRSRC *pResInfo;
- int nIndex;
-} ENUMRESSTRUCT;
-
-static ICOM_VTABLE(IShellLinkA) slvt;
-static ICOM_VTABLE(IShellLinkW) slvtw;
-static ICOM_VTABLE(IPersistFile) pfvt;
-static ICOM_VTABLE(IPersistStream) psvt;
+static const IShellLinkAVtbl slvt;
+static const IShellLinkWVtbl slvtw;
+static const IPersistFileVtbl pfvt;
+static const IPersistStreamVtbl psvt;
+static const IShellLinkDataListVtbl dlvt;
+static const IShellExtInitVtbl eivt;
+static const IContextMenuVtbl cmvt;
+static const IObjectWithSiteVtbl owsvt;
/* IShellLink Implementation */
typedef struct
{
- ICOM_VFIELD(IShellLinkA);
- DWORD ref;
-
- ICOM_VTABLE(IShellLinkW)* lpvtblw;
- ICOM_VTABLE(IPersistFile)* lpvtblPersistFile;
- ICOM_VTABLE(IPersistStream)* lpvtblPersistStream;
+ const IShellLinkAVtbl *lpVtbl;
+ const IShellLinkWVtbl *lpvtblw;
+ const IPersistFileVtbl *lpvtblPersistFile;
+ const IPersistStreamVtbl *lpvtblPersistStream;
+ const IShellLinkDataListVtbl *lpvtblShellLinkDataList;
+ const IShellExtInitVtbl *lpvtblShellExtInit;
+ const IContextMenuVtbl *lpvtblContextMenu;
+ const IObjectWithSiteVtbl *lpvtblObjectWithSite;
- /* internal stream of the IPersistFile interface */
- IStream* lpFileStream;
+ LONG ref;
- /* data structures according to the informations in the lnk */
- LPSTR sPath;
+ /* data structures according to the information in the link */
LPITEMIDLIST pPidl;
WORD wHotKey;
SYSTEMTIME time1;
SYSTEMTIME time2;
SYSTEMTIME time3;
- LPSTR sIcoPath;
- INT iIcoNdx;
- LPSTR sArgs;
- LPSTR sWorkDir;
- LPSTR sDescription;
+ DWORD iShowCmd;
+ LPWSTR sIcoPath;
+ INT iIcoNdx;
+ LPWSTR sPath;
+ LPWSTR sArgs;
+ LPWSTR sWorkDir;
+ LPWSTR sDescription;
+ LPWSTR sPathRel;
+ LPWSTR sProduct;
+ LPWSTR sComponent;
+ volume_info volume;
+
+ BOOL bDirty;
+ INT iIdOpen; /* id of the "Open" entry in the context menu */
+ IUnknown *site;
} IShellLinkImpl;
-#define _IShellLinkW_Offset ((int)(&(((IShellLinkImpl*)0)->lpvtblw)))
-#define _ICOM_THIS_From_IShellLinkW(class, name) class* This = (class*)(((char*)name)-_IShellLinkW_Offset);
-
-#define _IPersistFile_Offset ((int)(&(((IShellLinkImpl*)0)->lpvtblPersistFile)))
-#define _ICOM_THIS_From_IPersistFile(class, name) class* This = (class*)(((char*)name)-_IPersistFile_Offset);
-
-#define _IPersistStream_Offset ((int)(&(((IShellLinkImpl*)0)->lpvtblPersistStream)))
-#define _ICOM_THIS_From_IPersistStream(class, name) class* This = (class*)(((char*)name)-_IPersistStream_Offset);
-#define _IPersistStream_From_ICOM_THIS(class, name) class* StreamThis = (class*)(((char*)name)+_IPersistStream_Offset);
-
-
-/* strdup on the process heap */
-inline static LPSTR heap_strdup( LPCSTR str )
+static inline IShellLinkImpl *impl_from_IShellLinkW( IShellLinkW *iface )
{
- INT len = strlen(str) + 1;
- LPSTR p = HeapAlloc( GetProcessHeap(), 0, len );
- if (p) memcpy( p, str, len );
- return p;
+ return (IShellLinkImpl *)((char*)iface - FIELD_OFFSET(IShellLinkImpl, lpvtblw));
}
-
-/**************************************************************************
- * IPersistFile_QueryInterface
- */
-static HRESULT WINAPI IPersistFile_fnQueryInterface(
- IPersistFile* iface,
- REFIID riid,
- LPVOID *ppvObj)
+static inline IShellLinkImpl *impl_from_IPersistFile( IPersistFile *iface )
{
- _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface)
-
- TRACE("(%p)\n",This);
-
- return IShellLinkA_QueryInterface((IShellLinkA*)This, riid, ppvObj);
+ return (IShellLinkImpl *)((char*)iface - FIELD_OFFSET(IShellLinkImpl, lpvtblPersistFile));
}
-/******************************************************************************
- * IPersistFile_AddRef
- */
-static ULONG WINAPI IPersistFile_fnAddRef(IPersistFile* iface)
+static inline IShellLinkImpl *impl_from_IPersistStream( IPersistStream *iface )
{
- _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface)
-
- TRACE("(%p)->(count=%lu)\n",This,This->ref);
-
- return IShellLinkA_AddRef((IShellLinkA*)This);
+ return (IShellLinkImpl *)((char*)iface - FIELD_OFFSET(IShellLinkImpl, lpvtblPersistStream));
}
-/******************************************************************************
- * IPersistFile_Release
- */
-static ULONG WINAPI IPersistFile_fnRelease(IPersistFile* iface)
-{
- _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface)
- TRACE("(%p)->(count=%lu)\n",This,This->ref);
-
- return IShellLinkA_Release((IShellLinkA*)This);
+static inline IShellLinkImpl *impl_from_IShellLinkDataList( IShellLinkDataList *iface )
+{
+ return (IShellLinkImpl *)((char*)iface - FIELD_OFFSET(IShellLinkImpl, lpvtblShellLinkDataList));
}
-static HRESULT WINAPI IPersistFile_fnGetClassID(IPersistFile* iface, CLSID *pClassID)
+static inline IShellLinkImpl *impl_from_IShellExtInit( IShellExtInit *iface )
{
- _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface)
- FIXME("(%p)\n",This);
- return NOERROR;
+ return (IShellLinkImpl *)((char*)iface - FIELD_OFFSET(IShellLinkImpl, lpvtblShellExtInit));
}
-static HRESULT WINAPI IPersistFile_fnIsDirty(IPersistFile* iface)
+
+static inline IShellLinkImpl *impl_from_IContextMenu( IContextMenu *iface )
{
- _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface)
- FIXME("(%p)\n",This);
- return NOERROR;
+ return (IShellLinkImpl *)((char*)iface - FIELD_OFFSET(IShellLinkImpl, lpvtblContextMenu));
}
-static HRESULT WINAPI IPersistFile_fnLoad(IPersistFile* iface, LPCOLESTR pszFileName, DWORD dwMode)
-{
- _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface)
- _IPersistStream_From_ICOM_THIS(IPersistStream, This)
-
- LPSTR sFile = HEAP_strdupWtoA ( GetProcessHeap(), 0, pszFileName);
- HRESULT hRet = E_FAIL;
-
- TRACE("(%p, %s)\n",This, sFile);
-
-
- if (This->lpFileStream)
- IStream_Release(This->lpFileStream);
-
- if SUCCEEDED(CreateStreamOnFile(sFile, &(This->lpFileStream)))
- {
- if SUCCEEDED (IPersistStream_Load(StreamThis, This->lpFileStream))
- {
- return NOERROR;
- }
- }
- return hRet;
+static inline IShellLinkImpl *impl_from_IObjectWithSite( IObjectWithSite *iface )
+{
+ return (IShellLinkImpl *)((char*)iface - FIELD_OFFSET(IShellLinkImpl, lpvtblObjectWithSite));
}
+static HRESULT ShellLink_UpdatePath(LPWSTR sPathRel, LPCWSTR path, LPCWSTR sWorkDir, LPWSTR* psPath);
-/* Icon extraction routines
- *
- * FIXME: should use PrivateExtractIcons and friends
- * FIXME: should not use stdio
- */
-
-static BOOL SaveIconResAsXPM(const BITMAPINFO *pIcon, const char *szXPMFileName)
-{
- FILE *fXPMFile;
- int nHeight;
- int nXORWidthBytes;
- int nANDWidthBytes;
- BOOL b8BitColors;
- int nColors;
- BYTE *pXOR;
- BYTE *pAND;
- BOOL aColorUsed[256] = {0};
- int nColorsUsed = 0;
- int i,j;
-
- if (!((pIcon->bmiHeader.biBitCount == 4) || (pIcon->bmiHeader.biBitCount == 8)))
- return 0;
-
- if (!(fXPMFile = fopen(szXPMFileName, "w")))
- return 0;
-
- nHeight = pIcon->bmiHeader.biHeight / 2;
- nXORWidthBytes = 4 * ((pIcon->bmiHeader.biWidth * pIcon->bmiHeader.biBitCount / 32)
- + ((pIcon->bmiHeader.biWidth * pIcon->bmiHeader.biBitCount % 32) > 0));
- nANDWidthBytes = 4 * ((pIcon->bmiHeader.biWidth / 32)
- + ((pIcon->bmiHeader.biWidth % 32) > 0));
- b8BitColors = pIcon->bmiHeader.biBitCount == 8;
- nColors = pIcon->bmiHeader.biClrUsed ? pIcon->bmiHeader.biClrUsed
- : 1 << pIcon->bmiHeader.biBitCount;
- pXOR = (BYTE*) pIcon + sizeof (BITMAPINFOHEADER) + (nColors * sizeof (RGBQUAD));
- pAND = pXOR + nHeight * nXORWidthBytes;
-
-#define MASK(x,y) (pAND[(x) / 8 + (nHeight - (y) - 1) * nANDWidthBytes] & (1 << (7 - (x) % 8)))
-#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)
-
- for (i = 0; i < nHeight; i++)
- for (j = 0; j < pIcon->bmiHeader.biWidth; j++)
- if (!aColorUsed[COLOR(j,i)] && !MASK(j,i))
- {
- aColorUsed[COLOR(j,i)] = TRUE;
- nColorsUsed++;
- }
-
- if (fprintf(fXPMFile, "/* XPM */\nstatic char *icon[] = {\n") <= 0)
- goto error;
- if (fprintf(fXPMFile, "\"%d %d %d %d\",\n",
- (int) pIcon->bmiHeader.biWidth, nHeight, nColorsUsed + 1, 2) <=0)
- goto error;
-
- for (i = 0; i < nColors; i++)
- if (aColorUsed[i])
- if (fprintf(fXPMFile, "\"%.2X c #%.2X%.2X%.2X\",\n", i, pIcon->bmiColors[i].rgbRed,
- pIcon->bmiColors[i].rgbGreen, pIcon->bmiColors[i].rgbBlue) <= 0)
- goto error;
- if (fprintf(fXPMFile, "\" c None\"") <= 0)
- goto error;
-
- for (i = 0; i < nHeight; i++)
- {
- if (fprintf(fXPMFile, ",\n\"") <= 0)
- goto error;
- for (j = 0; j < pIcon->bmiHeader.biWidth; j++)
- {
- if MASK(j,i)
- {
- if (fprintf(fXPMFile, " ") <= 0)
- goto error;
- }
- else
- if (fprintf(fXPMFile, "%.2X", COLOR(j,i)) <= 0)
- goto error;
- }
- if (fprintf(fXPMFile, "\"") <= 0)
- goto error;
- }
- if (fprintf(fXPMFile, "};\n") <= 0)
- goto error;
-
-#undef MASK
-#undef COLOR
-
- fclose(fXPMFile);
- return 1;
-
- error:
- fclose(fXPMFile);
- unlink( szXPMFileName );
- return 0;
+/* strdup on the process heap */
+static inline LPWSTR HEAP_strdupAtoW( HANDLE heap, DWORD flags, LPCSTR str)
+{
+ INT len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
+ LPWSTR p = HeapAlloc( heap, flags, len*sizeof (WCHAR) );
+ if( !p )
+ return p;
+ MultiByteToWideChar( CP_ACP, 0, str, -1, p, len );
+ return p;
}
-static BOOL CALLBACK EnumResNameProc(HANDLE hModule, const char *lpszType, char *lpszName, LONG lParam)
+static inline LPWSTR strdupW( LPCWSTR src )
{
- ENUMRESSTRUCT *sEnumRes = (ENUMRESSTRUCT *) lParam;
-
- if (!sEnumRes->nIndex--)
- {
- *sEnumRes->pResInfo = FindResourceA(hModule, lpszName, RT_GROUP_ICONA);
- return FALSE;
- }
- else
- return TRUE;
+ LPWSTR dest;
+ if (!src) return NULL;
+ dest = HeapAlloc( GetProcessHeap(), 0, (lstrlenW(src)+1)*sizeof(WCHAR) );
+ if (dest)
+ lstrcpyW(dest, src);
+ return dest;
}
-static int ExtractFromEXEDLL(const char *szFileName, int nIndex, const char *szXPMFileName)
+/**************************************************************************
+ * ShellLink::QueryInterface implementation
+ */
+static HRESULT ShellLink_QueryInterface( IShellLinkImpl *This, REFIID riid, LPVOID *ppvObj)
{
- HMODULE hModule;
- HRSRC hResInfo;
- char *lpName = NULL;
- HGLOBAL hResData;
- GRPICONDIR *pIconDir;
- BITMAPINFO *pIcon;
- ENUMRESSTRUCT sEnumRes;
- int nMax = 0;
- int nMaxBits = 0;
- int i;
+ TRACE("(%p)->(\n\tIID:\t%s)\n",This,debugstr_guid(riid));
- if (!(hModule = LoadLibraryExA(szFileName, 0, LOAD_LIBRARY_AS_DATAFILE)))
- {
- TRACE("LoadLibraryExA (%s) failed, error %ld\n", szFileName, GetLastError());
- goto error1;
- }
+ *ppvObj = NULL;
- if (nIndex < 0)
+ if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IShellLinkA))
{
- hResInfo = FindResourceA(hModule, MAKEINTRESOURCEA(-nIndex), RT_GROUP_ICONA);
- TRACE("FindResourceA (%s) called, return 0x%x, error %ld\n", szFileName, hResInfo, GetLastError());
+ *ppvObj = This;
}
- else
+ else if(IsEqualIID(riid, &IID_IShellLinkW))
{
- sEnumRes.pResInfo = &hResInfo;
- sEnumRes.nIndex = nIndex;
- if (EnumResourceNamesA(hModule, RT_GROUP_ICONA, &EnumResNameProc, (LONG) &sEnumRes))
- {
- TRACE("EnumResourceNamesA failed, error %ld\n", GetLastError());
- goto error2;
- }
+ *ppvObj = &(This->lpvtblw);
}
-
- if (!hResInfo)
+ else if(IsEqualIID(riid, &IID_IPersistFile))
{
- TRACE("ExtractFromEXEDLL failed, error %ld\n", GetLastError());
- goto error2;
+ *ppvObj = &(This->lpvtblPersistFile);
}
-
- if (!(hResData = LoadResource(hModule, hResInfo)))
+ else if(IsEqualIID(riid, &IID_IPersistStream))
{
- TRACE("LoadResource failed, error %ld\n", GetLastError());
- goto error2;
+ *ppvObj = &(This->lpvtblPersistStream);
}
- if (!(pIconDir = LockResource(hResData)))
+ else if(IsEqualIID(riid, &IID_IShellLinkDataList))
{
- TRACE("LockResource failed, error %ld\n", GetLastError());
- goto error3;
+ *ppvObj = &(This->lpvtblShellLinkDataList);
}
-
- for (i = 0; i < pIconDir->idCount; i++)
- if ((pIconDir->idEntries[i].wBitCount >= nMaxBits) && (pIconDir->idEntries[i].wBitCount <= 8))
- {
- if (pIconDir->idEntries[i].wBitCount > nMaxBits)
- {
- nMaxBits = pIconDir->idEntries[i].wBitCount;
- nMax = 0;
- }
- if ((pIconDir->idEntries[i].bHeight * pIconDir->idEntries[i].bWidth) > nMax)
- {
- lpName = MAKEINTRESOURCEA(pIconDir->idEntries[i].nID);
- nMax = pIconDir->idEntries[i].bHeight * pIconDir->idEntries[i].bWidth;
- }
- }
-
- FreeResource(hResData);
-
- if (!(hResInfo = FindResourceA(hModule, lpName, RT_ICONA)))
+ else if(IsEqualIID(riid, &IID_IShellExtInit))
{
- TRACE("Second FindResourceA failed, error %ld\n", GetLastError());
- goto error2;
+ *ppvObj = &(This->lpvtblShellExtInit);
}
- if (!(hResData = LoadResource(hModule, hResInfo)))
+ else if(IsEqualIID(riid, &IID_IContextMenu))
{
- TRACE("Second LoadResource failed, error %ld\n", GetLastError());
- goto error2;
+ *ppvObj = &(This->lpvtblContextMenu);
}
- if (!(pIcon = LockResource(hResData)))
+ else if(IsEqualIID(riid, &IID_IObjectWithSite))
{
- TRACE("Second LockResource failed, error %ld\n", GetLastError());
- goto error3;
+ *ppvObj = &(This->lpvtblObjectWithSite);
}
- if(!SaveIconResAsXPM(pIcon, szXPMFileName))
+ if(*ppvObj)
{
- TRACE("Failed saving icon as XPM, error %ld\n", GetLastError());
- goto error3;
+ IUnknown_AddRef((IUnknown*)(*ppvObj));
+ TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
+ return S_OK;
}
+ ERR("-- Interface: E_NOINTERFACE\n");
+ return E_NOINTERFACE;
+}
- FreeResource(hResData);
- FreeLibrary(hModule);
+/**************************************************************************
+ * ShellLink::AddRef implementation
+ */
+static ULONG ShellLink_AddRef( IShellLinkImpl *This )
+{
+ ULONG refCount = InterlockedIncrement(&This->ref);
- return 1;
+ TRACE("(%p)->(count=%u)\n", This, refCount - 1);
- error3:
- FreeResource(hResData);
- error2:
- FreeLibrary(hModule);
- error1:
- return 0;
+ return refCount;
}
-static int ExtractFromICO(const char *szFileName, const char *szXPMFileName)
+/**************************************************************************
+ * ShellLink::Release implementation
+ */
+static ULONG ShellLink_Release( IShellLinkImpl *This )
{
- FILE *fICOFile;
- ICONDIR iconDir;
- ICONDIRENTRY *pIconDirEntry;
- int nMax = 0;
- int nIndex = 0;
- void *pIcon;
- int i;
+ ULONG refCount = InterlockedDecrement(&This->ref);
- if (!(fICOFile = fopen(szFileName, "r")))
- goto error1;
+ TRACE("(%p)->(count=%u)\n", This, refCount + 1);
- if (fread(&iconDir, sizeof (ICONDIR), 1, fICOFile) != 1)
- goto error2;
- if ((iconDir.idReserved != 0) || (iconDir.idType != 1))
- goto error2;
+ if (refCount)
+ return refCount;
- if ((pIconDirEntry = malloc(iconDir.idCount * sizeof (ICONDIRENTRY))) == NULL)
- goto error2;
- if (fread(pIconDirEntry, sizeof (ICONDIRENTRY), iconDir.idCount, fICOFile) != iconDir.idCount)
- goto error3;
+ TRACE("-- destroying IShellLink(%p)\n",This);
+
+ HeapFree(GetProcessHeap(), 0, This->sIcoPath);
+ HeapFree(GetProcessHeap(), 0, This->sArgs);
+ HeapFree(GetProcessHeap(), 0, This->sWorkDir);
+ HeapFree(GetProcessHeap(), 0, This->sDescription);
+ HeapFree(GetProcessHeap(),0,This->sPath);
+
+ if (This->site)
+ IUnknown_Release( This->site );
+
+ if (This->pPidl)
+ ILFree(This->pPidl);
+
+ LocalFree((HANDLE)This);
- for (i = 0; i < iconDir.idCount; i++)
- if ((pIconDirEntry[i].bHeight * pIconDirEntry[i].bWidth) > nMax)
- {
- nIndex = i;
- nMax = pIconDirEntry[i].bHeight * pIconDirEntry[i].bWidth;
- }
- if ((pIcon = malloc(pIconDirEntry[nIndex].dwBytesInRes)) == NULL)
- goto error3;
- if (fseek(fICOFile, pIconDirEntry[nIndex].dwImageOffset, SEEK_SET))
- goto error4;
- if (fread(pIcon, pIconDirEntry[nIndex].dwBytesInRes, 1, fICOFile) != 1)
- goto error4;
-
- if(!SaveIconResAsXPM(pIcon, szXPMFileName))
- goto error4;
-
- free(pIcon);
- free(pIconDirEntry);
- fclose(fICOFile);
-
- return 1;
-
- error4:
- free(pIcon);
- error3:
- free(pIconDirEntry);
- error2:
- fclose(fICOFile);
- error1:
return 0;
}
-/* get the Unix file name for a given path, allocating the string */
-inline static char *get_unix_file_name( const char *dos )
+static HRESULT ShellLink_GetClassID( IShellLinkImpl *This, CLSID *pclsid )
{
- char buffer[MAX_PATH];
+ TRACE("%p %p\n", This, pclsid);
- if (!wine_get_unix_file_name( dos, buffer, sizeof(buffer) )) return NULL;
- return heap_strdup( buffer );
+ memcpy( pclsid, &CLSID_ShellLink, sizeof (CLSID) );
+ return S_OK;
}
-static BOOL create_default_icon( const char *filename )
+/**************************************************************************
+ * IPersistFile_QueryInterface
+ */
+static HRESULT WINAPI IPersistFile_fnQueryInterface(
+ IPersistFile* iface,
+ REFIID riid,
+ LPVOID *ppvObj)
{
- FILE *fXPM;
- int i;
+ IShellLinkImpl *This = impl_from_IPersistFile(iface);
+ return ShellLink_QueryInterface( This, riid, ppvObj );
+}
- if (!(fXPM = fopen(filename, "w"))) return FALSE;
- fprintf(fXPM, "/* XPM */\nstatic char * icon[] = {");
- for (i = 0; i < sizeof(wine_xpm)/sizeof(wine_xpm[0]); i++)
- fprintf( fXPM, "\n\"%s\",", wine_xpm[i]);
- fprintf( fXPM, "};\n" );
- fclose( fXPM );
- return TRUE;
+/******************************************************************************
+ * IPersistFile_AddRef
+ */
+static ULONG WINAPI IPersistFile_fnAddRef(IPersistFile* iface)
+{
+ IShellLinkImpl *This = impl_from_IPersistFile(iface);
+ return ShellLink_AddRef( This );
}
-/* extract an icon from an exe or icon file; helper for IPersistFile_fnSave */
-static char *extract_icon( const char *path, int index)
+/******************************************************************************
+ * IPersistFile_Release
+ */
+static ULONG WINAPI IPersistFile_fnRelease(IPersistFile* iface)
{
- int fd, nodefault = 1;
- char *filename, tmpfn[25];
+ IShellLinkImpl *This = impl_from_IPersistFile(iface);
+ return IShellLinkA_Release((IShellLinkA*)This);
+}
- strcpy(tmpfn,"/tmp/icon.XXXXXX");
- fd = mkstemp( tmpfn );
- if (fd == -1)
- return NULL;
- filename = heap_strdup( tmpfn );
- close(fd); /* not needed */
+static HRESULT WINAPI IPersistFile_fnGetClassID(IPersistFile* iface, CLSID *pClassID)
+{
+ IShellLinkImpl *This = impl_from_IPersistFile(iface);
+ return ShellLink_GetClassID( This, pClassID );
+}
- /* If icon path begins with a '*' then this is a deferred call */
- if (path[0] == '*')
- {
- path++;
- nodefault = 0;
- }
- if (ExtractFromEXEDLL( path, index, filename )) return filename;
- if (ExtractFromICO( path, filename )) return filename;
- if (!nodefault)
- if (create_default_icon( filename )) return filename;
- HeapFree( GetProcessHeap(), 0, filename );
- return NULL;
+static HRESULT WINAPI IPersistFile_fnIsDirty(IPersistFile* iface)
+{
+ IShellLinkImpl *This = impl_from_IPersistFile(iface);
+
+ TRACE("(%p)\n",This);
+
+ if (This->bDirty)
+ return S_OK;
+
+ return S_FALSE;
}
+static HRESULT WINAPI IPersistFile_fnLoad(IPersistFile* iface, LPCOLESTR pszFileName, DWORD dwMode)
+{
+ IShellLinkImpl *This = impl_from_IPersistFile(iface);
+ IPersistStream *StreamThis = (IPersistStream *)&This->lpvtblPersistStream;
+ HRESULT r;
+ IStream *stm;
+
+ TRACE("(%p, %s, %x)\n",This, debugstr_w(pszFileName), dwMode);
-static HRESULT WINAPI IPersistFile_fnSave(IPersistFile* iface, LPCOLESTR pszFileName, BOOL fRemember)
+ if( dwMode == 0 )
+ dwMode = STGM_READ | STGM_SHARE_DENY_WRITE;
+ r = SHCreateStreamOnFileW(pszFileName, dwMode, &stm);
+ if( SUCCEEDED( r ) )
+ {
+ r = IPersistStream_Load(StreamThis, stm);
+ ShellLink_UpdatePath(This->sPathRel, pszFileName, This->sWorkDir, &This->sPath);
+ IStream_Release( stm );
+ This->bDirty = FALSE;
+ }
+ TRACE("-- returning hr %08x\n", r);
+ return r;
+}
+
+static BOOL StartLinkProcessor( LPCOLESTR szLink )
{
- HRESULT ret = NOERROR;
- int pid, status;
- char buffer[MAX_PATH], buff2[MAX_PATH], ascii_filename[MAX_PATH];
- char *filename, *link_name, *p;
- char *shell_link_app = NULL;
- char *icon_name = NULL;
- char *work_dir = NULL;
- BOOL bDesktop;
- HKEY hkey;
+ static const WCHAR szFormat[] = {
+ 'w','i','n','e','m','e','n','u','b','u','i','l','d','e','r','.','e','x','e',
+ ' ','-','r',' ','"','%','s','"',0 };
+ LONG len;
+ LPWSTR buffer;
+ STARTUPINFOW si;
+ PROCESS_INFORMATION pi;
- _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface);
+ len = sizeof(szFormat) + lstrlenW( szLink ) * sizeof(WCHAR);
+ buffer = HeapAlloc( GetProcessHeap(), 0, len );
+ if( !buffer )
+ return FALSE;
- TRACE("(%p)->(%s)\n",This,debugstr_w(pszFileName));
+ wsprintfW( buffer, szFormat, szLink );
- if (!pszFileName || !This->sPath)
- return ERROR_UNKNOWN;
+ TRACE("starting %s\n",debugstr_w(buffer));
- /* check for .exe extension */
- if (!(p = strrchr( This->sPath, '.' ))) return NOERROR;
- if (strchr( p, '\\' ) || strchr( p, '/' )) return NOERROR;
- if (strcasecmp( p, ".exe" )) return NOERROR;
+ memset(&si, 0, sizeof(si));
+ si.cb = sizeof(si);
+ if (!CreateProcessW( NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) return FALSE;
- /* check if ShellLinker configured */
- buffer[0] = 0;
- if (!RegOpenKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\Wine",
- 0, KEY_ALL_ACCESS, &hkey ))
- {
- DWORD type, count = sizeof(buffer);
- if (RegQueryValueExA( hkey, "ShellLinker", 0, &type, buffer, &count )) buffer[0] = 0;
- RegCloseKey( hkey );
- }
- if (!*buffer) return NOERROR;
- shell_link_app = heap_strdup( buffer );
+ /* wait for a while to throttle the creation of linker processes */
+ if( WAIT_OBJECT_0 != WaitForSingleObject( pi.hProcess, 10000 ) )
+ WARN("Timed out waiting for shell linker\n");
- if (!WideCharToMultiByte( CP_ACP, 0, pszFileName, -1, ascii_filename, sizeof(ascii_filename), NULL, NULL))
- return ERROR_UNKNOWN;
- GetFullPathNameA( ascii_filename, sizeof(buff2), buff2, NULL );
- filename = heap_strdup( buff2 );
+ CloseHandle( pi.hProcess );
+ CloseHandle( pi.hThread );
- if (SHGetSpecialFolderPathA( 0, buffer, CSIDL_STARTUP, FALSE ))
- {
- /* ignore startup for now */
- if (!strncasecmp( filename, buffer, strlen(buffer) )) goto done;
- }
- if (SHGetSpecialFolderPathA( 0, buffer, CSIDL_DESKTOPDIRECTORY, FALSE ))
- {
- if (!strncasecmp( filename, buffer, strlen(buffer) ))
- {
- link_name = filename + strlen(buffer);
- bDesktop = TRUE;
- goto found;
- }
- }
- if (SHGetSpecialFolderPathA( 0, buffer, CSIDL_STARTMENU, FALSE ))
- {
- if (!strncasecmp( filename, buffer, strlen(buffer) ))
- {
- link_name = filename + strlen(buffer);
- bDesktop = FALSE;
- goto found;
- }
- }
- goto done;
-
- found:
- /* make link name a Unix name */
- for (p = link_name; *p; p++) if (*p == '\\') *p = '/';
- /* strip leading slashes */
- while (*link_name == '/') link_name++;
- /* remove extension */
- if ((p = strrchr( link_name, '.' ))) *p = 0;
-
- /* convert app working dir */
- if (This->sWorkDir) work_dir = get_unix_file_name( This->sWorkDir );
-
- /* extract the icon */
- if (!(icon_name = extract_icon( This->sIcoPath && strlen(This->sIcoPath) ?
- This->sIcoPath : This->sPath,
- This->iIcoNdx )))
- {
- /* Couldn't extract icon -- defer this menu entry to runonce. */
- HKEY hRunOnce;
- char* buffer = NULL;
+ return TRUE;
+}
- TRACE("Deferring icon creation to reboot.\n");
- if (RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce", 0,
- NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hRunOnce, NULL) != ERROR_SUCCESS)
- {
- ret = ERROR_UNKNOWN;
- goto done;
- }
- buffer = HeapAlloc(GetProcessHeap(), 0, MAX_PATH * 3 + (This->sArgs ? strlen(This->sArgs) : 0) +
- (This->sDescription ? strlen(This->sDescription) : 0) + 200);
- sprintf(buffer, "link:%s\xff*%s\xff%d\xff%s\xff%s\xff%s", This->sPath, This->sIcoPath, This->iIcoNdx,
- This->sArgs ? This->sArgs : "", This->sDescription ? This->sDescription : "",
- This->sWorkDir ? This->sWorkDir : "");
- if (RegSetValueExA(hRunOnce, ascii_filename, 0, REG_SZ, buffer, strlen(buffer) + 1) != ERROR_SUCCESS)
- {
- HeapFree(GetProcessHeap(), 0, buffer);
- RegCloseKey(hRunOnce);
- ret = ERROR_UNKNOWN;
- goto done;
- }
- HeapFree(GetProcessHeap(), 0, buffer);
- RegCloseKey(hRunOnce);
- goto done;
- }
+static HRESULT WINAPI IPersistFile_fnSave(IPersistFile* iface, LPCOLESTR pszFileName, BOOL fRemember)
+{
+ IShellLinkImpl *This = impl_from_IPersistFile(iface);
+ IPersistStream *StreamThis = (IPersistStream *)&This->lpvtblPersistStream;
+ HRESULT r;
+ IStream *stm;
+
+ TRACE("(%p)->(%s)\n",This,debugstr_w(pszFileName));
- TRACE("linker app='%s' link='%s' mode=%s path='%s' args='%s' icon='%s' workdir='%s' descr='%s'\n",
- shell_link_app, link_name, bDesktop ? "desktop" : "menu", This->sPath,
- This->sArgs ? This->sArgs : "", icon_name, work_dir ? work_dir : "",
- This->sDescription ? This->sDescription : "" );
+ if (!pszFileName)
+ return E_FAIL;
- if ((pid = fork()) == -1) goto done;
- if (!pid)
+ r = SHCreateStreamOnFileW( pszFileName, STGM_READWRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE, &stm );
+ if( SUCCEEDED( r ) )
{
- int pos = 0;
- char *argv[20];
- argv[pos++] = shell_link_app;
- argv[pos++] = "--link";
- argv[pos++] = link_name;
- argv[pos++] = "--path";
- argv[pos++] = This->sPath;
- argv[pos++] = bDesktop ? "--desktop" : "--menu";
- if (This->sArgs && strlen(This->sArgs))
- {
- argv[pos++] = "--args";
- argv[pos++] = This->sArgs;
- }
- if (icon_name)
- {
- argv[pos++] = "--icon";
- argv[pos++] = icon_name;
- }
- if (This->sWorkDir && strlen(This->sWorkDir))
- {
- argv[pos++] = "--workdir";
- argv[pos++] = This->sWorkDir;
+ r = IPersistStream_Save(StreamThis, stm, FALSE);
+ IStream_Release( stm );
+
+ if( SUCCEEDED( r ) )
+ {
+ StartLinkProcessor( pszFileName );
+
+ This->bDirty = FALSE;
}
- if (This->sDescription && strlen(This->sDescription))
+ else
{
- argv[pos++] = "--descr";
- argv[pos++] = This->sDescription;
+ DeleteFileW( pszFileName );
+ WARN("Failed to create shortcut %s\n", debugstr_w(pszFileName) );
}
- argv[pos] = NULL;
- execvp( shell_link_app, argv );
- _exit(1);
}
- while (waitpid( pid, &status, 0 ) == -1)
- {
- if (errno != EINTR)
- {
- ret = ERROR_UNKNOWN;
- goto done;
- }
- }
- if (status) ret = E_ACCESSDENIED;
-
- done:
- if (icon_name) unlink( icon_name );
- HeapFree( GetProcessHeap(), 0, shell_link_app );
- HeapFree( GetProcessHeap(), 0, filename );
- HeapFree( GetProcessHeap(), 0, icon_name );
- HeapFree( GetProcessHeap(), 0, work_dir );
- return ret;
+ return r;
}
static HRESULT WINAPI IPersistFile_fnSaveCompleted(IPersistFile* iface, LPCOLESTR pszFileName)
{
- _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface);
+ IShellLinkImpl *This = impl_from_IPersistFile(iface);
FIXME("(%p)->(%s)\n",This,debugstr_w(pszFileName));
return NOERROR;
}
+
static HRESULT WINAPI IPersistFile_fnGetCurFile(IPersistFile* iface, LPOLESTR *ppszFileName)
{
- _ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface);
+ IShellLinkImpl *This = impl_from_IPersistFile(iface);
FIXME("(%p)\n",This);
return NOERROR;
}
-static ICOM_VTABLE(IPersistFile) pfvt =
+static const IPersistFileVtbl pfvt =
{
- ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
IPersistFile_fnQueryInterface,
IPersistFile_fnAddRef,
IPersistFile_fnRelease,
static HRESULT WINAPI IPersistStream_fnQueryInterface(
IPersistStream* iface,
REFIID riid,
- VOID** ppvoid)
+ VOID** ppvObj)
{
- _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
-
- TRACE("(%p)\n",This);
-
- return IShellLinkA_QueryInterface((IShellLinkA*)This, riid, ppvoid);
+ IShellLinkImpl *This = impl_from_IPersistStream(iface);
+ return ShellLink_QueryInterface( This, riid, ppvObj );
}
/************************************************************************
static ULONG WINAPI IPersistStream_fnRelease(
IPersistStream* iface)
{
- _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
-
- TRACE("(%p)\n",This);
-
- return IShellLinkA_Release((IShellLinkA*)This);
+ IShellLinkImpl *This = impl_from_IPersistStream(iface);
+ return IShellLinkA_Release((IShellLinkA*)This);
}
/************************************************************************
static ULONG WINAPI IPersistStream_fnAddRef(
IPersistStream* iface)
{
- _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
-
- TRACE("(%p)\n",This);
-
- return IShellLinkA_AddRef((IShellLinkA*)This);
+ IShellLinkImpl *This = impl_from_IPersistStream(iface);
+ return ShellLink_AddRef( This );
}
/************************************************************************
IPersistStream* iface,
CLSID* pClassID)
{
- _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
-
- TRACE("(%p)\n", This);
-
- if (pClassID==0)
- return E_POINTER;
-
-/* memcpy(pClassID, &CLSID_???, sizeof(CLSID_???)); */
-
- return S_OK;
+ IShellLinkImpl *This = impl_from_IPersistStream(iface);
+ return ShellLink_GetClassID( This, pClassID );
}
/************************************************************************
static HRESULT WINAPI IPersistStream_fnIsDirty(
IPersistStream* iface)
{
- _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
+ IShellLinkImpl *This = impl_from_IPersistStream(iface);
TRACE("(%p)\n", This);
return S_OK;
}
-/************************************************************************
- * IPersistStream_Load (IPersistStream)
- */
-static HRESULT WINAPI IPersistStream_fnLoad(
- IPersistStream* iface,
- IStream* pLoadStream)
+
+static HRESULT Stream_LoadString( IStream* stm, BOOL unicode, LPWSTR *pstr )
{
- PLINK_HEADER lpLinkHeader = HeapAlloc(GetProcessHeap(), 0, LINK_HEADER_SIZE);
- ULONG dwBytesRead;
- DWORD ret = E_FAIL;
- char sTemp[MAX_PATH];
+ DWORD count;
+ USHORT len;
+ LPVOID temp;
+ LPWSTR str;
+ HRESULT r;
- _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
+ TRACE("%p\n", stm);
- TRACE("(%p)(%p)\n", This, pLoadStream);
+ count = 0;
+ r = IStream_Read(stm, &len, sizeof(len), &count);
+ if ( FAILED (r) || ( count != sizeof(len) ) )
+ return E_FAIL;
- if ( ! pLoadStream)
- {
- return STG_E_INVALIDPOINTER;
- }
+ if( unicode )
+ len *= sizeof (WCHAR);
+
+ TRACE("reading %d\n", len);
+ temp = HeapAlloc(GetProcessHeap(), 0, len+sizeof(WCHAR));
+ if( !temp )
+ return E_OUTOFMEMORY;
+ count = 0;
+ r = IStream_Read(stm, temp, len, &count);
+ if( FAILED (r) || ( count != len ) )
+ {
+ HeapFree( GetProcessHeap(), 0, temp );
+ return E_FAIL;
+ }
+
+ TRACE("read %s\n", debugstr_an(temp,len));
+
+ /* convert to unicode if necessary */
+ if( !unicode )
+ {
+ count = MultiByteToWideChar( CP_ACP, 0, (LPSTR) temp, len, NULL, 0 );
+ str = HeapAlloc( GetProcessHeap(), 0, (count+1)*sizeof (WCHAR) );
+ if( !str )
+ {
+ HeapFree( GetProcessHeap(), 0, temp );
+ return E_OUTOFMEMORY;
+ }
+ MultiByteToWideChar( CP_ACP, 0, (LPSTR) temp, len, str, count );
+ HeapFree( GetProcessHeap(), 0, temp );
+ }
+ else
+ {
+ count /= 2;
+ str = (LPWSTR) temp;
+ }
+ str[count] = 0;
- IStream_AddRef (pLoadStream);
- if(!lpLinkHeader)
- goto end;
+ *pstr = str;
- dwBytesRead = 0;
- if (!(SUCCEEDED(IStream_Read(pLoadStream, lpLinkHeader, LINK_HEADER_SIZE, &dwBytesRead))))
- goto end;
+ return S_OK;
+}
- if (dwBytesRead != LINK_HEADER_SIZE)
- goto end;
+static HRESULT Stream_ReadChunk( IStream* stm, LPVOID *data )
+{
+ DWORD size;
+ ULONG count;
+ HRESULT r;
+ struct sized_chunk {
+ DWORD size;
+ unsigned char data[1];
+ } *chunk;
- if ( (lpLinkHeader->MagicStr != 0x0000004CL) || !IsEqualIID(&lpLinkHeader->MagicGuid, &CLSID_ShellLink) )
- goto end;
+ TRACE("%p\n",stm);
- if(lpLinkHeader->PidlSize)
- {
- lpLinkHeader = HeapReAlloc(GetProcessHeap(), 0, lpLinkHeader, LINK_HEADER_SIZE+lpLinkHeader->PidlSize);
- if (!lpLinkHeader)
- goto end;
- dwBytesRead = 0;
- if (!(SUCCEEDED(IStream_Read(pLoadStream, &(lpLinkHeader->Pidl), lpLinkHeader->PidlSize, &dwBytesRead))))
- goto end;
- if(dwBytesRead != lpLinkHeader->PidlSize)
- goto end;
-
- if (pcheck (&lpLinkHeader->Pidl))
- {
- This->pPidl = ILClone (&lpLinkHeader->Pidl);
-
- SHGetPathFromIDListA(&lpLinkHeader->Pidl, sTemp);
- This->sPath = heap_strdup( sTemp );
- }
- }
- This->wHotKey = lpLinkHeader->wHotKey;
- FileTimeToSystemTime (&lpLinkHeader->Time1, &This->time1);
- FileTimeToSystemTime (&lpLinkHeader->Time2, &This->time2);
- FileTimeToSystemTime (&lpLinkHeader->Time3, &This->time3);
-#if 1
- GetDateFormatA(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&This->time1, NULL, sTemp, 256);
- TRACE("-- time1: %s\n", sTemp);
- GetDateFormatA(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&This->time2, NULL, sTemp, 256);
- TRACE("-- time1: %s\n", sTemp);
- GetDateFormatA(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&This->time3, NULL, sTemp, 256);
- TRACE("-- time1: %s\n", sTemp);
- pdump (This->pPidl);
-#endif
- ret = S_OK;
+ r = IStream_Read( stm, &size, sizeof(size), &count );
+ if( FAILED( r ) || count != sizeof(size) )
+ return E_FAIL;
-end:
- IStream_Release (pLoadStream);
+ chunk = HeapAlloc( GetProcessHeap(), 0, size );
+ if( !chunk )
+ return E_OUTOFMEMORY;
+
+ chunk->size = size;
+ r = IStream_Read( stm, chunk->data, size - sizeof(size), &count );
+ if( FAILED( r ) || count != (size - sizeof(size)) )
+ {
+ HeapFree( GetProcessHeap(), 0, chunk );
+ return E_FAIL;
+ }
- pdump(This->pPidl);
+ TRACE("Read %d bytes\n",chunk->size);
- HeapFree(GetProcessHeap(), 0, lpLinkHeader);
+ *data = (LPVOID) chunk;
- return ret;
+ return S_OK;
}
-/************************************************************************
- * IPersistStream_Save (IPersistStream)
- */
-static HRESULT WINAPI IPersistStream_fnSave(
- IPersistStream* iface,
- IStream* pOutStream,
- BOOL fClearDirty)
+static BOOL Stream_LoadVolume( LOCAL_VOLUME_INFO *vol, volume_info *volume )
{
- _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
+ const int label_sz = sizeof volume->label/sizeof volume->label[0];
+ LPSTR label;
+ int len;
- TRACE("(%p) %p %x\n", This, pOutStream, fClearDirty);
+ volume->serial = vol->dwVolSerial;
+ volume->type = vol->dwType;
- return E_NOTIMPL;
+ if( !vol->dwVolLabelOfs )
+ return FALSE;
+ if( vol->dwSize <= vol->dwVolLabelOfs )
+ return FALSE;
+ len = vol->dwSize - vol->dwVolLabelOfs;
+
+ label = (LPSTR) vol;
+ label += vol->dwVolLabelOfs;
+ MultiByteToWideChar( CP_ACP, 0, label, len, volume->label, label_sz-1);
+
+ return TRUE;
}
-/************************************************************************
- * IPersistStream_GetSizeMax (IPersistStream)
- */
-static HRESULT WINAPI IPersistStream_fnGetSizeMax(
- IPersistStream* iface,
- ULARGE_INTEGER* pcbSize)
+static LPWSTR Stream_LoadPath( LPSTR p, DWORD maxlen )
{
- _ICOM_THIS_From_IPersistStream(IShellLinkImpl, iface);
+ int len = 0, wlen;
+ LPWSTR path;
- TRACE("(%p)\n", This);
+ while( p[len] && (len < maxlen) )
+ len++;
- return E_NOTIMPL;
+ wlen = MultiByteToWideChar(CP_ACP, 0, p, len, NULL, 0);
+ path = HeapAlloc(GetProcessHeap(), 0, (wlen+1)*sizeof(WCHAR));
+ MultiByteToWideChar(CP_ACP, 0, p, len, path, wlen);
+ path[wlen] = 0;
+
+ return path;
}
-static ICOM_VTABLE(IPersistStream) psvt =
+static HRESULT Stream_LoadLocation( IStream *stm,
+ volume_info *volume, LPWSTR *path )
+{
+ char *p = NULL;
+ LOCATION_INFO *loc;
+ HRESULT r;
+ int n;
+
+ r = Stream_ReadChunk( stm, (LPVOID*) &p );
+ if( FAILED(r) )
+ return r;
+
+ loc = (LOCATION_INFO*) p;
+ if (loc->dwTotalSize < sizeof(LOCATION_INFO))
+ {
+ HeapFree( GetProcessHeap(), 0, p );
+ return E_FAIL;
+ }
+
+ /* if there's valid local volume information, load it */
+ if( loc->dwVolTableOfs &&
+ ((loc->dwVolTableOfs + sizeof(LOCAL_VOLUME_INFO)) <= loc->dwTotalSize) )
+ {
+ LOCAL_VOLUME_INFO *volume_info;
+
+ volume_info = (LOCAL_VOLUME_INFO*) &p[loc->dwVolTableOfs];
+ Stream_LoadVolume( volume_info, volume );
+ }
+
+ /* if there's a local path, load it */
+ n = loc->dwLocalPathOfs;
+ if( n && (n < loc->dwTotalSize) )
+ *path = Stream_LoadPath( &p[n], loc->dwTotalSize - n );
+
+ TRACE("type %d serial %08x name %s path %s\n", volume->type,
+ volume->serial, debugstr_w(volume->label), debugstr_w(*path));
+
+ HeapFree( GetProcessHeap(), 0, p );
+ return S_OK;
+}
+
+/*
+ * The format of the advertised shortcut info seems to be:
+ *
+ * Offset Description
+ * ------ -----------
+ *
+ * 0 Length of the block (4 bytes, usually 0x314)
+ * 4 tag (dword)
+ * 8 string data in ASCII
+ * 8+0x104 string data in UNICODE
+ *
+ * In the original Win32 implementation the buffers are not initialized
+ * to zero, so data trailing the string is random garbage.
+ */
+static HRESULT Stream_LoadAdvertiseInfo( IStream* stm, LPWSTR *str )
+{
+ DWORD size;
+ ULONG count;
+ HRESULT r;
+ EXP_DARWIN_LINK buffer;
+
+ TRACE("%p\n",stm);
+
+ r = IStream_Read( stm, &buffer.dbh.cbSize, sizeof (DWORD), &count );
+ if( FAILED( r ) )
+ return r;
+
+ /* make sure that we read the size of the structure even on error */
+ size = sizeof buffer - sizeof (DWORD);
+ if( buffer.dbh.cbSize != sizeof buffer )
+ {
+ ERR("Ooops. This structure is not as expected...\n");
+ return E_FAIL;
+ }
+
+ r = IStream_Read( stm, &buffer.dbh.dwSignature, size, &count );
+ if( FAILED( r ) )
+ return r;
+
+ if( count != size )
+ return E_FAIL;
+
+ TRACE("magic %08x string = %s\n", buffer.dbh.dwSignature, debugstr_w(buffer.szwDarwinID));
+
+ if( (buffer.dbh.dwSignature&0xffff0000) != 0xa0000000 )
+ {
+ ERR("Unknown magic number %08x in advertised shortcut\n", buffer.dbh.dwSignature);
+ return E_FAIL;
+ }
+
+ *str = HeapAlloc( GetProcessHeap(), 0,
+ (lstrlenW(buffer.szwDarwinID)+1) * sizeof(WCHAR) );
+ lstrcpyW( *str, buffer.szwDarwinID );
+
+ return S_OK;
+}
+
+/************************************************************************
+ * IPersistStream_Load (IPersistStream)
+ */
+static HRESULT WINAPI IPersistStream_fnLoad(
+ IPersistStream* iface,
+ IStream* stm)
+{
+ LINK_HEADER hdr;
+ ULONG dwBytesRead;
+ BOOL unicode;
+ HRESULT r;
+ DWORD zero;
+
+ IShellLinkImpl *This = impl_from_IPersistStream(iface);
+
+ TRACE("%p %p\n", This, stm);
+
+ if( !stm )
+ return STG_E_INVALIDPOINTER;
+
+ dwBytesRead = 0;
+ r = IStream_Read(stm, &hdr, sizeof(hdr), &dwBytesRead);
+ if( FAILED( r ) )
+ return r;
+
+ if( dwBytesRead != sizeof(hdr))
+ return E_FAIL;
+ if( hdr.dwSize != sizeof(hdr))
+ return E_FAIL;
+ if( !IsEqualIID(&hdr.MagicGuid, &CLSID_ShellLink) )
+ return E_FAIL;
+
+ /* free all the old stuff */
+ ILFree(This->pPidl);
+ This->pPidl = NULL;
+ memset( &This->volume, 0, sizeof This->volume );
+ HeapFree(GetProcessHeap(), 0, This->sPath);
+ This->sPath = NULL;
+ HeapFree(GetProcessHeap(), 0, This->sDescription);
+ This->sDescription = NULL;
+ HeapFree(GetProcessHeap(), 0, This->sPathRel);
+ This->sPathRel = NULL;
+ HeapFree(GetProcessHeap(), 0, This->sWorkDir);
+ This->sWorkDir = NULL;
+ HeapFree(GetProcessHeap(), 0, This->sArgs);
+ This->sArgs = NULL;
+ HeapFree(GetProcessHeap(), 0, This->sIcoPath);
+ This->sIcoPath = NULL;
+ HeapFree(GetProcessHeap(), 0, This->sProduct);
+ This->sProduct = NULL;
+ HeapFree(GetProcessHeap(), 0, This->sComponent);
+ This->sComponent = NULL;
+
+ This->wHotKey = (WORD)hdr.wHotKey;
+ This->iIcoNdx = hdr.nIcon;
+ FileTimeToSystemTime (&hdr.Time1, &This->time1);
+ FileTimeToSystemTime (&hdr.Time2, &This->time2);
+ FileTimeToSystemTime (&hdr.Time3, &This->time3);
+ if (TRACE_ON(shell))
+ {
+ WCHAR sTemp[MAX_PATH];
+ GetDateFormatW(LOCALE_USER_DEFAULT,DATE_SHORTDATE, &This->time1,
+ NULL, sTemp, sizeof(sTemp)/sizeof(*sTemp));
+ TRACE("-- time1: %s\n", debugstr_w(sTemp) );
+ GetDateFormatW(LOCALE_USER_DEFAULT,DATE_SHORTDATE, &This->time2,
+ NULL, sTemp, sizeof(sTemp)/sizeof(*sTemp));
+ TRACE("-- time2: %s\n", debugstr_w(sTemp) );
+ GetDateFormatW(LOCALE_USER_DEFAULT,DATE_SHORTDATE, &This->time3,
+ NULL, sTemp, sizeof(sTemp)/sizeof(*sTemp));
+ TRACE("-- time3: %s\n", debugstr_w(sTemp) );
+ }
+
+ /* load all the new stuff */
+ if( hdr.dwFlags & SLDF_HAS_ID_LIST )
+ {
+ r = ILLoadFromStream( stm, &This->pPidl );
+ if( FAILED( r ) )
+ return r;
+ }
+ pdump(This->pPidl);
+
+ /* load the location information */
+ if( hdr.dwFlags & SLDF_HAS_LINK_INFO )
+ r = Stream_LoadLocation( stm, &This->volume, &This->sPath );
+ if( FAILED( r ) )
+ goto end;
+
+ unicode = hdr.dwFlags & SLDF_UNICODE;
+ if( hdr.dwFlags & SLDF_HAS_NAME )
+ {
+ r = Stream_LoadString( stm, unicode, &This->sDescription );
+ TRACE("Description -> %s\n",debugstr_w(This->sDescription));
+ }
+ if( FAILED( r ) )
+ goto end;
+
+ if( hdr.dwFlags & SLDF_HAS_RELPATH )
+ {
+ r = Stream_LoadString( stm, unicode, &This->sPathRel );
+ TRACE("Relative Path-> %s\n",debugstr_w(This->sPathRel));
+ }
+ if( FAILED( r ) )
+ goto end;
+
+ if( hdr.dwFlags & SLDF_HAS_WORKINGDIR )
+ {
+ r = Stream_LoadString( stm, unicode, &This->sWorkDir );
+ TRACE("Working Dir -> %s\n",debugstr_w(This->sWorkDir));
+ }
+ if( FAILED( r ) )
+ goto end;
+
+ if( hdr.dwFlags & SLDF_HAS_ARGS )
+ {
+ r = Stream_LoadString( stm, unicode, &This->sArgs );
+ TRACE("Working Dir -> %s\n",debugstr_w(This->sArgs));
+ }
+ if( FAILED( r ) )
+ goto end;
+
+ if( hdr.dwFlags & SLDF_HAS_ICONLOCATION )
+ {
+ r = Stream_LoadString( stm, unicode, &This->sIcoPath );
+ TRACE("Icon file -> %s\n",debugstr_w(This->sIcoPath));
+ }
+ if( FAILED( r ) )
+ goto end;
+
+ if( hdr.dwFlags & SLDF_HAS_LOGO3ID )
+ {
+ r = Stream_LoadAdvertiseInfo( stm, &This->sProduct );
+ TRACE("Product -> %s\n",debugstr_w(This->sProduct));
+ }
+ if( FAILED( r ) )
+ goto end;
+
+ if( hdr.dwFlags & SLDF_HAS_DARWINID )
+ {
+ r = Stream_LoadAdvertiseInfo( stm, &This->sComponent );
+ TRACE("Component -> %s\n",debugstr_w(This->sComponent));
+ }
+ if( FAILED( r ) )
+ goto end;
+
+ r = IStream_Read(stm, &zero, sizeof zero, &dwBytesRead);
+ if( FAILED( r ) || zero || dwBytesRead != sizeof zero )
+ ERR("Last word was not zero\n");
+
+ TRACE("OK\n");
+
+ pdump (This->pPidl);
+
+ return S_OK;
+end:
+ return r;
+}
+
+/************************************************************************
+ * Stream_WriteString
+ *
+ * Helper function for IPersistStream_Save. Writes a unicode string
+ * with terminating nul byte to a stream, preceded by the its length.
+ */
+static HRESULT Stream_WriteString( IStream* stm, LPCWSTR str )
+{
+ USHORT len = lstrlenW( str ) + 1;
+ DWORD count;
+ HRESULT r;
+
+ r = IStream_Write( stm, &len, sizeof(len), &count );
+ if( FAILED( r ) )
+ return r;
+
+ len *= sizeof(WCHAR);
+
+ r = IStream_Write( stm, str, len, &count );
+ if( FAILED( r ) )
+ return r;
+
+ return S_OK;
+}
+
+/************************************************************************
+ * Stream_WriteLocationInfo
+ *
+ * Writes the location info to a stream
+ *
+ * FIXME: One day we might want to write the network volume information
+ * and the final path.
+ * Figure out how Windows deals with unicode paths here.
+ */
+static HRESULT Stream_WriteLocationInfo( IStream* stm, LPCWSTR path,
+ volume_info *volume )
+{
+ DWORD total_size, path_size, volume_info_size, label_size, final_path_size;
+ LOCAL_VOLUME_INFO *vol;
+ LOCATION_INFO *loc;
+ LPSTR szLabel, szPath, szFinalPath;
+ ULONG count = 0;
+
+ TRACE("%p %s %p\n", stm, debugstr_w(path), volume);
+
+ /* figure out the size of everything */
+ label_size = WideCharToMultiByte( CP_ACP, 0, volume->label, -1,
+ NULL, 0, NULL, NULL );
+ path_size = WideCharToMultiByte( CP_ACP, 0, path, -1,
+ NULL, 0, NULL, NULL );
+ volume_info_size = sizeof *vol + label_size;
+ final_path_size = 1;
+ total_size = sizeof *loc + volume_info_size + path_size + final_path_size;
+
+ /* create pointers to everything */
+ loc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, total_size);
+ vol = (LOCAL_VOLUME_INFO*) &loc[1];
+ szLabel = (LPSTR) &vol[1];
+ szPath = &szLabel[label_size];
+ szFinalPath = &szPath[path_size];
+
+ /* fill in the location information header */
+ loc->dwTotalSize = total_size;
+ loc->dwHeaderSize = sizeof (*loc);
+ loc->dwFlags = 1;
+ loc->dwVolTableOfs = sizeof (*loc);
+ loc->dwLocalPathOfs = sizeof (*loc) + volume_info_size;
+ loc->dwNetworkVolTableOfs = 0;
+ loc->dwFinalPathOfs = sizeof (*loc) + volume_info_size + path_size;
+
+ /* fill in the volume information */
+ vol->dwSize = volume_info_size;
+ vol->dwType = volume->type;
+ vol->dwVolSerial = volume->serial;
+ vol->dwVolLabelOfs = sizeof (*vol);
+
+ /* copy in the strings */
+ WideCharToMultiByte( CP_ACP, 0, volume->label, -1,
+ szLabel, label_size, NULL, NULL );
+ WideCharToMultiByte( CP_ACP, 0, path, -1,
+ szPath, path_size, NULL, NULL );
+ szFinalPath[0] = 0;
+
+ return IStream_Write( stm, loc, total_size, &count );
+}
+
+static EXP_DARWIN_LINK* shelllink_build_darwinid( LPCWSTR string, DWORD magic )
+{
+ EXP_DARWIN_LINK *buffer;
+
+ buffer = LocalAlloc( LMEM_ZEROINIT, sizeof *buffer );
+ buffer->dbh.cbSize = sizeof *buffer;
+ buffer->dbh.dwSignature = magic;
+ lstrcpynW( buffer->szwDarwinID, string, MAX_PATH );
+ WideCharToMultiByte(CP_ACP, 0, string, -1, buffer->szDarwinID, MAX_PATH, NULL, NULL );
+
+ return buffer;
+}
+
+static HRESULT Stream_WriteAdvertiseInfo( IStream* stm, LPCWSTR string, DWORD magic )
+{
+ EXP_DARWIN_LINK *buffer;
+ ULONG count;
+
+ TRACE("%p\n",stm);
+
+ buffer = shelllink_build_darwinid( string, magic );
+
+ return IStream_Write( stm, buffer, buffer->dbh.cbSize, &count );
+}
+
+/************************************************************************
+ * IPersistStream_Save (IPersistStream)
+ *
+ * FIXME: makes assumptions about byte order
+ */
+static HRESULT WINAPI IPersistStream_fnSave(
+ IPersistStream* iface,
+ IStream* stm,
+ BOOL fClearDirty)
+{
+ static const WCHAR wOpen[] = {'o','p','e','n',0};
+
+ LINK_HEADER header;
+ WCHAR exePath[MAX_PATH];
+ ULONG count;
+ DWORD zero;
+ HRESULT r;
+
+ IShellLinkImpl *This = impl_from_IPersistStream(iface);
+
+ TRACE("%p %p %x\n", This, stm, fClearDirty);
+
+ *exePath = '\0';
+
+ if (This->sPath)
+ {
+ SHELL_FindExecutable(NULL, This->sPath, wOpen, exePath, MAX_PATH,
+ NULL, NULL, NULL, NULL);
+ /*
+ * windows can create lnk files to executables that do not exist yet
+ * so if the executable does not exist the just trust the path they
+ * gave us
+ */
+ if (!*exePath) lstrcpyW(exePath,This->sPath);
+ }
+
+ memset(&header, 0, sizeof(header));
+ header.dwSize = sizeof(header);
+ header.fStartup = This->iShowCmd;
+ memcpy(&header.MagicGuid, &CLSID_ShellLink, sizeof(header.MagicGuid) );
+
+ header.wHotKey = This->wHotKey;
+ header.nIcon = This->iIcoNdx;
+ header.dwFlags = SLDF_UNICODE; /* strings are in unicode */
+ if( This->pPidl )
+ header.dwFlags |= SLDF_HAS_ID_LIST;
+ if( This->sPath )
+ header.dwFlags |= SLDF_HAS_LINK_INFO;
+ if( This->sDescription )
+ header.dwFlags |= SLDF_HAS_NAME;
+ if( This->sWorkDir )
+ header.dwFlags |= SLDF_HAS_WORKINGDIR;
+ if( This->sArgs )
+ header.dwFlags |= SLDF_HAS_ARGS;
+ if( This->sIcoPath )
+ header.dwFlags |= SLDF_HAS_ICONLOCATION;
+ if( This->sProduct )
+ header.dwFlags |= SLDF_HAS_LOGO3ID;
+ if( This->sComponent )
+ header.dwFlags |= SLDF_HAS_DARWINID;
+
+ SystemTimeToFileTime ( &This->time1, &header.Time1 );
+ SystemTimeToFileTime ( &This->time2, &header.Time2 );
+ SystemTimeToFileTime ( &This->time3, &header.Time3 );
+
+ /* write the Shortcut header */
+ r = IStream_Write( stm, &header, sizeof(header), &count );
+ if( FAILED( r ) )
+ {
+ ERR("Write failed at %d\n",__LINE__);
+ return r;
+ }
+
+ TRACE("Writing pidl\n");
+
+ /* write the PIDL to the shortcut */
+ if( This->pPidl )
+ {
+ r = ILSaveToStream( stm, This->pPidl );
+ if( FAILED( r ) )
+ {
+ ERR("Failed to write PIDL at %d\n",__LINE__);
+ return r;
+ }
+ }
+
+ if( This->sPath )
+ Stream_WriteLocationInfo( stm, exePath, &This->volume );
+
+ if( This->sDescription )
+ r = Stream_WriteString( stm, This->sDescription );
+
+ if( This->sPathRel )
+ r = Stream_WriteString( stm, This->sPathRel );
+
+ if( This->sWorkDir )
+ r = Stream_WriteString( stm, This->sWorkDir );
+
+ if( This->sArgs )
+ r = Stream_WriteString( stm, This->sArgs );
+
+ if( This->sIcoPath )
+ r = Stream_WriteString( stm, This->sIcoPath );
+
+ if( This->sProduct )
+ r = Stream_WriteAdvertiseInfo( stm, This->sProduct, EXP_SZ_ICON_SIG );
+
+ if( This->sComponent )
+ r = Stream_WriteAdvertiseInfo( stm, This->sComponent, EXP_DARWIN_ID_SIG );
+
+ /* the last field is a single zero dword */
+ zero = 0;
+ r = IStream_Write( stm, &zero, sizeof zero, &count );
+
+ return S_OK;
+}
+
+/************************************************************************
+ * IPersistStream_GetSizeMax (IPersistStream)
+ */
+static HRESULT WINAPI IPersistStream_fnGetSizeMax(
+ IPersistStream* iface,
+ ULARGE_INTEGER* pcbSize)
+{
+ IShellLinkImpl *This = impl_from_IPersistStream(iface);
+
+ TRACE("(%p)\n", This);
+
+ return E_NOTIMPL;
+}
+
+static const IPersistStreamVtbl psvt =
{
- ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
IPersistStream_fnQueryInterface,
IPersistStream_fnAddRef,
IPersistStream_fnRelease,
/**************************************************************************
* IShellLink_Constructor
*/
-HRESULT WINAPI IShellLink_Constructor (
- IUnknown * pUnkOuter,
- REFIID riid,
- LPVOID * ppv)
+HRESULT WINAPI IShellLink_Constructor( IUnknown *pUnkOuter,
+ REFIID riid, LPVOID *ppv )
{
IShellLinkImpl * sl;
+ HRESULT r;
TRACE("unkOut=%p riid=%s\n",pUnkOuter, debugstr_guid(riid));
*ppv = NULL;
- if(pUnkOuter) return CLASS_E_NOAGGREGATION;
- sl = (IShellLinkImpl *) LocalAlloc(GMEM_ZEROINIT,sizeof(IShellLinkImpl));
- if (!sl) return E_OUTOFMEMORY;
+ if (pUnkOuter)
+ return CLASS_E_NOAGGREGATION;
+ sl = LocalAlloc(LMEM_ZEROINIT,sizeof(IShellLinkImpl));
+ if (!sl)
+ return E_OUTOFMEMORY;
sl->ref = 1;
- ICOM_VTBL(sl) = &slvt;
+ sl->lpVtbl = &slvt;
sl->lpvtblw = &slvtw;
sl->lpvtblPersistFile = &pfvt;
sl->lpvtblPersistStream = &psvt;
+ sl->lpvtblShellLinkDataList = &dlvt;
+ sl->lpvtblShellExtInit = &eivt;
+ sl->lpvtblContextMenu = &cmvt;
+ sl->lpvtblObjectWithSite = &owsvt;
+ sl->iShowCmd = SW_SHOWNORMAL;
+ sl->bDirty = FALSE;
+ sl->iIdOpen = -1;
+ sl->site = NULL;
TRACE("(%p)->()\n",sl);
- if (IsEqualIID(riid, &IID_IShellLinkA))
- *ppv = sl;
- else if (IsEqualIID(riid, &IID_IShellLinkW))
- *ppv = &(sl->lpvtblw);
- else {
- LocalFree((HLOCAL)sl);
- ERR("E_NOINTERFACE\n");
- return E_NOINTERFACE;
- }
+ r = ShellLink_QueryInterface( sl, riid, ppv );
+ ShellLink_Release( sl );
+ return r;
+}
- return S_OK;
+
+static BOOL SHELL_ExistsFileW(LPCWSTR path)
+{
+ if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW(path))
+ return FALSE;
+ return TRUE;
}
/**************************************************************************
- * IShellLinkA_QueryInterface
+ * ShellLink_UpdatePath
+ * update absolute path in sPath using relative path in sPathRel
*/
-static HRESULT WINAPI IShellLinkA_fnQueryInterface( IShellLinkA * iface, REFIID riid, LPVOID *ppvObj)
+static HRESULT ShellLink_UpdatePath(LPWSTR sPathRel, LPCWSTR path, LPCWSTR sWorkDir, LPWSTR* psPath)
{
- ICOM_THIS(IShellLinkImpl, iface);
+ if (!path || !psPath)
+ return E_INVALIDARG;
- TRACE("(%p)->(\n\tIID:\t%s)\n",This,debugstr_guid(riid));
+ if (!*psPath && sPathRel) {
+ WCHAR buffer[2*MAX_PATH], abs_path[2*MAX_PATH];
+ LPWSTR final = NULL;
- *ppvObj = NULL;
+ /* first try if [directory of link file] + [relative path] finds an existing file */
- if(IsEqualIID(riid, &IID_IUnknown) ||
- IsEqualIID(riid, &IID_IShellLinkA))
- {
- *ppvObj = This;
- }
- else if(IsEqualIID(riid, &IID_IShellLinkW))
- {
- *ppvObj = (IShellLinkW *)&(This->lpvtblw);
- }
- else if(IsEqualIID(riid, &IID_IPersistFile))
- {
- *ppvObj = (IPersistFile *)&(This->lpvtblPersistFile);
- }
- else if(IsEqualIID(riid, &IID_IPersistStream))
- {
- *ppvObj = (IPersistStream *)&(This->lpvtblPersistStream);
+ GetFullPathNameW( path, MAX_PATH*2, buffer, &final );
+ if( !final )
+ final = buffer;
+ lstrcpyW(final, sPathRel);
+
+ *abs_path = '\0';
+
+ if (SHELL_ExistsFileW(buffer)) {
+ if (!GetFullPathNameW(buffer, MAX_PATH, abs_path, &final))
+ lstrcpyW(abs_path, buffer);
+ } else {
+ /* try if [working directory] + [relative path] finds an existing file */
+ if (sWorkDir) {
+ lstrcpyW(buffer, sWorkDir);
+ lstrcpyW(PathAddBackslashW(buffer), sPathRel);
+
+ if (SHELL_ExistsFileW(buffer))
+ if (!GetFullPathNameW(buffer, MAX_PATH, abs_path, &final))
+ lstrcpyW(abs_path, buffer);
+ }
}
- if(*ppvObj)
- {
- IUnknown_AddRef((IUnknown*)(*ppvObj));
- TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
- return S_OK;
+ /* FIXME: This is even not enough - not all shell links can be resolved using this algorithm. */
+ if (!*abs_path)
+ lstrcpyW(abs_path, sPathRel);
+
+ *psPath = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(abs_path)+1)*sizeof(WCHAR));
+ if (!*psPath)
+ return E_OUTOFMEMORY;
+
+ lstrcpyW(*psPath, abs_path);
+ }
+
+ return S_OK;
+}
+
+/**************************************************************************
+ * IShellLink_ConstructFromFile
+ */
+HRESULT WINAPI IShellLink_ConstructFromFile( IUnknown* pUnkOuter, REFIID riid,
+ LPCITEMIDLIST pidl, LPVOID* ppv)
+{
+ IShellLinkW* psl;
+
+ HRESULT hr = IShellLink_Constructor(NULL, riid, (LPVOID*)&psl);
+
+ if (SUCCEEDED(hr)) {
+ IPersistFile* ppf;
+
+ *ppv = NULL;
+
+ hr = IShellLinkW_QueryInterface(psl, &IID_IPersistFile, (LPVOID*)&ppf);
+
+ if (SUCCEEDED(hr)) {
+ WCHAR path[MAX_PATH];
+
+ if (SHGetPathFromIDListW(pidl, path))
+ hr = IPersistFile_Load(ppf, path, 0);
+ else
+ hr = E_FAIL;
+
+ if (SUCCEEDED(hr))
+ *ppv = (IUnknown*) psl;
+
+ IPersistFile_Release(ppf);
}
- TRACE("-- Interface: E_NOINTERFACE\n");
- return E_NOINTERFACE;
+
+ if (!*ppv)
+ IShellLinkW_Release(psl);
+ }
+
+ return hr;
+}
+
+/**************************************************************************
+ * IShellLinkA_QueryInterface
+ */
+static HRESULT WINAPI IShellLinkA_fnQueryInterface( IShellLinkA * iface, REFIID riid, LPVOID *ppvObj)
+{
+ IShellLinkImpl *This = (IShellLinkImpl *)iface;
+ return ShellLink_QueryInterface( This, riid, ppvObj );
}
+
/******************************************************************************
* IShellLinkA_AddRef
*/
static ULONG WINAPI IShellLinkA_fnAddRef(IShellLinkA * iface)
{
- ICOM_THIS(IShellLinkImpl, iface);
-
- TRACE("(%p)->(count=%lu)\n",This,This->ref);
-
- return ++(This->ref);
+ IShellLinkImpl *This = (IShellLinkImpl *)iface;
+ return ShellLink_AddRef( This );
}
+
/******************************************************************************
* IShellLinkA_Release
*/
static ULONG WINAPI IShellLinkA_fnRelease(IShellLinkA * iface)
{
- ICOM_THIS(IShellLinkImpl, iface);
+ IShellLinkImpl *This = (IShellLinkImpl *)iface;
+ return ShellLink_Release( This );
+}
+
+static HRESULT WINAPI IShellLinkA_fnGetPath(IShellLinkA * iface, LPSTR pszFile,
+ INT cchMaxPath, WIN32_FIND_DATAA *pfd, DWORD fFlags)
+{
+ IShellLinkImpl *This = (IShellLinkImpl *)iface;
+
+ TRACE("(%p)->(pfile=%p len=%u find_data=%p flags=%u)(%s)\n",
+ This, pszFile, cchMaxPath, pfd, fFlags, debugstr_w(This->sPath));
+
+ if (This->sComponent || This->sProduct)
+ return S_FALSE;
+
+ if (cchMaxPath)
+ pszFile[0] = 0;
+ if (This->sPath)
+ WideCharToMultiByte( CP_ACP, 0, This->sPath, -1,
+ pszFile, cchMaxPath, NULL, NULL);
+
+ if (pfd) FIXME("(%p): WIN32_FIND_DATA is not yet filled.\n", This);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI IShellLinkA_fnGetIDList(IShellLinkA * iface, LPITEMIDLIST * ppidl)
+{
+ IShellLinkImpl *This = (IShellLinkImpl *)iface;
+
+ TRACE("(%p)->(ppidl=%p)\n",This, ppidl);
+
+ return IShellLinkW_GetIDList((IShellLinkW*)&(This->lpvtblw), ppidl);
+}
+
+static HRESULT WINAPI IShellLinkA_fnSetIDList(IShellLinkA * iface, LPCITEMIDLIST pidl)
+{
+ IShellLinkImpl *This = (IShellLinkImpl *)iface;
+
+ TRACE("(%p)->(pidl=%p)\n",This, pidl);
+
+ if (This->pPidl)
+ ILFree(This->pPidl);
+ This->pPidl = ILClone (pidl);
+ This->bDirty = TRUE;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI IShellLinkA_fnGetDescription(IShellLinkA * iface, LPSTR pszName,INT cchMaxName)
+{
+ IShellLinkImpl *This = (IShellLinkImpl *)iface;
+
+ TRACE("(%p)->(%p len=%u)\n",This, pszName, cchMaxName);
+
+ if( cchMaxName )
+ pszName[0] = 0;
+ if( This->sDescription )
+ WideCharToMultiByte( CP_ACP, 0, This->sDescription, -1,
+ pszName, cchMaxName, NULL, NULL);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI IShellLinkA_fnSetDescription(IShellLinkA * iface, LPCSTR pszName)
+{
+ IShellLinkImpl *This = (IShellLinkImpl *)iface;
+
+ TRACE("(%p)->(pName=%s)\n", This, pszName);
+
+ HeapFree(GetProcessHeap(), 0, This->sDescription);
+ This->sDescription = HEAP_strdupAtoW( GetProcessHeap(), 0, pszName);
+ if ( !This->sDescription )
+ return E_OUTOFMEMORY;
+
+ This->bDirty = TRUE;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI IShellLinkA_fnGetWorkingDirectory(IShellLinkA * iface, LPSTR pszDir,INT cchMaxPath)
+{
+ IShellLinkImpl *This = (IShellLinkImpl *)iface;
+
+ TRACE("(%p)->(%p len=%u)\n", This, pszDir, cchMaxPath);
+
+ if( cchMaxPath )
+ pszDir[0] = 0;
+ if( This->sWorkDir )
+ WideCharToMultiByte( CP_ACP, 0, This->sWorkDir, -1,
+ pszDir, cchMaxPath, NULL, NULL);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI IShellLinkA_fnSetWorkingDirectory(IShellLinkA * iface, LPCSTR pszDir)
+{
+ IShellLinkImpl *This = (IShellLinkImpl *)iface;
+
+ TRACE("(%p)->(dir=%s)\n",This, pszDir);
+
+ HeapFree(GetProcessHeap(), 0, This->sWorkDir);
+ This->sWorkDir = HEAP_strdupAtoW( GetProcessHeap(), 0, pszDir);
+ if ( !This->sWorkDir )
+ return E_OUTOFMEMORY;
+
+ This->bDirty = TRUE;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI IShellLinkA_fnGetArguments(IShellLinkA * iface, LPSTR pszArgs,INT cchMaxPath)
+{
+ IShellLinkImpl *This = (IShellLinkImpl *)iface;
+
+ TRACE("(%p)->(%p len=%u)\n", This, pszArgs, cchMaxPath);
+
+ if( cchMaxPath )
+ pszArgs[0] = 0;
+ if( This->sArgs )
+ WideCharToMultiByte( CP_ACP, 0, This->sArgs, -1,
+ pszArgs, cchMaxPath, NULL, NULL);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI IShellLinkA_fnSetArguments(IShellLinkA * iface, LPCSTR pszArgs)
+{
+ IShellLinkImpl *This = (IShellLinkImpl *)iface;
+
+ TRACE("(%p)->(args=%s)\n",This, pszArgs);
+
+ HeapFree(GetProcessHeap(), 0, This->sArgs);
+ This->sArgs = HEAP_strdupAtoW( GetProcessHeap(), 0, pszArgs);
+ if( !This->sArgs )
+ return E_OUTOFMEMORY;
+
+ This->bDirty = TRUE;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI IShellLinkA_fnGetHotkey(IShellLinkA * iface, WORD *pwHotkey)
+{
+ IShellLinkImpl *This = (IShellLinkImpl *)iface;
+
+ TRACE("(%p)->(%p)(0x%08x)\n",This, pwHotkey, This->wHotKey);
+
+ *pwHotkey = This->wHotKey;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI IShellLinkA_fnSetHotkey(IShellLinkA * iface, WORD wHotkey)
+{
+ IShellLinkImpl *This = (IShellLinkImpl *)iface;
+
+ TRACE("(%p)->(hotkey=%x)\n",This, wHotkey);
+
+ This->wHotKey = wHotkey;
+ This->bDirty = TRUE;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI IShellLinkA_fnGetShowCmd(IShellLinkA * iface, INT *piShowCmd)
+{
+ IShellLinkImpl *This = (IShellLinkImpl *)iface;
+
+ TRACE("(%p)->(%p)\n",This, piShowCmd);
+ *piShowCmd = This->iShowCmd;
+ return S_OK;
+}
+
+static HRESULT WINAPI IShellLinkA_fnSetShowCmd(IShellLinkA * iface, INT iShowCmd)
+{
+ IShellLinkImpl *This = (IShellLinkImpl *)iface;
+
+ TRACE("(%p) %d\n",This, iShowCmd);
+
+ This->iShowCmd = iShowCmd;
+ This->bDirty = TRUE;
+
+ return NOERROR;
+}
+
+static HRESULT SHELL_PidlGeticonLocationA(IShellFolder* psf, LPITEMIDLIST pidl, LPSTR pszIconPath, int cchIconPath, int* piIcon)
+{
+ LPCITEMIDLIST pidlLast;
+
+ HRESULT hr = SHBindToParent(pidl, &IID_IShellFolder, (LPVOID*)&psf, &pidlLast);
+
+ if (SUCCEEDED(hr)) {
+ IExtractIconA* pei;
+
+ hr = IShellFolder_GetUIObjectOf(psf, 0, 1, (LPCITEMIDLIST*)&pidlLast, &IID_IExtractIconA, NULL, (LPVOID*)&pei);
+
+ if (SUCCEEDED(hr)) {
+ hr = IExtractIconA_GetIconLocation(pei, 0, pszIconPath, MAX_PATH, piIcon, NULL);
+
+ IExtractIconA_Release(pei);
+ }
+
+ IShellFolder_Release(psf);
+ }
+
+ return hr;
+}
+
+static HRESULT WINAPI IShellLinkA_fnGetIconLocation(IShellLinkA * iface, LPSTR pszIconPath,INT cchIconPath,INT *piIcon)
+{
+ IShellLinkImpl *This = (IShellLinkImpl *)iface;
+
+ TRACE("(%p)->(%p len=%u iicon=%p)\n", This, pszIconPath, cchIconPath, piIcon);
+
+ pszIconPath[0] = 0;
+ *piIcon = This->iIcoNdx;
+
+ if (This->sIcoPath)
+ {
+ WideCharToMultiByte(CP_ACP, 0, This->sIcoPath, -1, pszIconPath, cchIconPath, NULL, NULL);
+ return S_OK;
+ }
+
+ if (This->pPidl || This->sPath)
+ {
+ IShellFolder* pdsk;
+
+ HRESULT hr = SHGetDesktopFolder(&pdsk);
+
+ if (SUCCEEDED(hr))
+ {
+ /* first look for an icon using the PIDL (if present) */
+ if (This->pPidl)
+ hr = SHELL_PidlGeticonLocationA(pdsk, This->pPidl, pszIconPath, cchIconPath, piIcon);
+ else
+ hr = E_FAIL;
+
+ /* if we couldn't find an icon yet, look for it using the file system path */
+ if (FAILED(hr) && This->sPath)
+ {
+ LPITEMIDLIST pidl;
+
+ hr = IShellFolder_ParseDisplayName(pdsk, 0, NULL, This->sPath, NULL, &pidl, NULL);
+
+ if (SUCCEEDED(hr)) {
+ hr = SHELL_PidlGeticonLocationA(pdsk, pidl, pszIconPath, cchIconPath, piIcon);
+
+ SHFree(pidl);
+ }
+ }
+
+ IShellFolder_Release(pdsk);
+ }
+
+ return hr;
+ }
+ return S_OK;
+}
+
+static HRESULT WINAPI IShellLinkA_fnSetIconLocation(IShellLinkA * iface, LPCSTR pszIconPath,INT iIcon)
+{
+ IShellLinkImpl *This = (IShellLinkImpl *)iface;
+
+ TRACE("(%p)->(path=%s iicon=%u)\n",This, pszIconPath, iIcon);
+
+ HeapFree(GetProcessHeap(), 0, This->sIcoPath);
+ This->sIcoPath = HEAP_strdupAtoW(GetProcessHeap(), 0, pszIconPath);
+ if ( !This->sIcoPath )
+ return E_OUTOFMEMORY;
+
+ This->iIcoNdx = iIcon;
+ This->bDirty = TRUE;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI IShellLinkA_fnSetRelativePath(IShellLinkA * iface, LPCSTR pszPathRel, DWORD dwReserved)
+{
+ IShellLinkImpl *This = (IShellLinkImpl *)iface;
+
+ TRACE("(%p)->(path=%s %x)\n",This, pszPathRel, dwReserved);
+
+ HeapFree(GetProcessHeap(), 0, This->sPathRel);
+ This->sPathRel = HEAP_strdupAtoW(GetProcessHeap(), 0, pszPathRel);
+ This->bDirty = TRUE;
+
+ return ShellLink_UpdatePath(This->sPathRel, This->sPath, This->sWorkDir, &This->sPath);
+}
+
+static HRESULT WINAPI IShellLinkA_fnResolve(IShellLinkA * iface, HWND hwnd, DWORD fFlags)
+{
+ IShellLinkImpl *This = (IShellLinkImpl *)iface;
+
+ TRACE("(%p)->(hwnd=%p flags=%x)\n",This, hwnd, fFlags);
+
+ return IShellLinkW_Resolve( (IShellLinkW*)&(This->lpvtblw), hwnd, fFlags );
+}
+
+static HRESULT WINAPI IShellLinkA_fnSetPath(IShellLinkA * iface, LPCSTR pszFile)
+{
+ HRESULT r;
+ LPWSTR str;
+ IShellLinkImpl *This = (IShellLinkImpl *)iface;
+
+ TRACE("(%p)->(path=%s)\n",This, pszFile);
+
+ str = HEAP_strdupAtoW(GetProcessHeap(), 0, pszFile);
+ if( !str )
+ return E_OUTOFMEMORY;
+
+ r = IShellLinkW_SetPath((IShellLinkW*)&(This->lpvtblw), str);
+ HeapFree( GetProcessHeap(), 0, str );
+
+ return r;
+}
+
+/**************************************************************************
+* IShellLink Implementation
+*/
+
+static const IShellLinkAVtbl slvt =
+{
+ IShellLinkA_fnQueryInterface,
+ IShellLinkA_fnAddRef,
+ IShellLinkA_fnRelease,
+ IShellLinkA_fnGetPath,
+ IShellLinkA_fnGetIDList,
+ IShellLinkA_fnSetIDList,
+ IShellLinkA_fnGetDescription,
+ IShellLinkA_fnSetDescription,
+ IShellLinkA_fnGetWorkingDirectory,
+ IShellLinkA_fnSetWorkingDirectory,
+ IShellLinkA_fnGetArguments,
+ IShellLinkA_fnSetArguments,
+ IShellLinkA_fnGetHotkey,
+ IShellLinkA_fnSetHotkey,
+ IShellLinkA_fnGetShowCmd,
+ IShellLinkA_fnSetShowCmd,
+ IShellLinkA_fnGetIconLocation,
+ IShellLinkA_fnSetIconLocation,
+ IShellLinkA_fnSetRelativePath,
+ IShellLinkA_fnResolve,
+ IShellLinkA_fnSetPath
+};
+
+
+/**************************************************************************
+ * IShellLinkW_fnQueryInterface
+ */
+static HRESULT WINAPI IShellLinkW_fnQueryInterface(
+ IShellLinkW * iface, REFIID riid, LPVOID *ppvObj)
+{
+ IShellLinkImpl *This = impl_from_IShellLinkW(iface);
+ return ShellLink_QueryInterface( This, riid, ppvObj );
+}
+
+/******************************************************************************
+ * IShellLinkW_fnAddRef
+ */
+static ULONG WINAPI IShellLinkW_fnAddRef(IShellLinkW * iface)
+{
+ IShellLinkImpl *This = impl_from_IShellLinkW(iface);
+ return ShellLink_AddRef( This );
+}
+
+/******************************************************************************
+ * IShellLinkW_fnRelease
+ */
+static ULONG WINAPI IShellLinkW_fnRelease(IShellLinkW * iface)
+{
+ IShellLinkImpl *This = impl_from_IShellLinkW(iface);
+ return ShellLink_Release( This );
+}
+
+static HRESULT WINAPI IShellLinkW_fnGetPath(IShellLinkW * iface, LPWSTR pszFile,INT cchMaxPath, WIN32_FIND_DATAW *pfd, DWORD fFlags)
+{
+ IShellLinkImpl *This = impl_from_IShellLinkW(iface);
+
+ TRACE("(%p)->(pfile=%p len=%u find_data=%p flags=%u)(%s)\n",
+ This, pszFile, cchMaxPath, pfd, fFlags, debugstr_w(This->sPath));
+
+ if (This->sComponent || This->sProduct)
+ return S_FALSE;
+
+ if (cchMaxPath)
+ pszFile[0] = 0;
+ if (This->sPath)
+ lstrcpynW( pszFile, This->sPath, cchMaxPath );
+
+ if (pfd) FIXME("(%p): WIN32_FIND_DATA is not yet filled.\n", This);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI IShellLinkW_fnGetIDList(IShellLinkW * iface, LPITEMIDLIST * ppidl)
+{
+ IShellLinkImpl *This = impl_from_IShellLinkW(iface);
+
+ TRACE("(%p)->(ppidl=%p)\n",This, ppidl);
+
+ if (!This->pPidl)
+ {
+ *ppidl = NULL;
+ return S_FALSE;
+ }
+ *ppidl = ILClone(This->pPidl);
+ return S_OK;
+}
+
+static HRESULT WINAPI IShellLinkW_fnSetIDList(IShellLinkW * iface, LPCITEMIDLIST pidl)
+{
+ IShellLinkImpl *This = impl_from_IShellLinkW(iface);
+
+ TRACE("(%p)->(pidl=%p)\n",This, pidl);
+
+ if( This->pPidl )
+ ILFree( This->pPidl );
+ This->pPidl = ILClone( pidl );
+ if( !This->pPidl )
+ return E_FAIL;
+
+ This->bDirty = TRUE;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI IShellLinkW_fnGetDescription(IShellLinkW * iface, LPWSTR pszName,INT cchMaxName)
+{
+ IShellLinkImpl *This = impl_from_IShellLinkW(iface);
+
+ TRACE("(%p)->(%p len=%u)\n",This, pszName, cchMaxName);
+
+ pszName[0] = 0;
+ if( This->sDescription )
+ lstrcpynW( pszName, This->sDescription, cchMaxName );
+
+ return S_OK;
+}
+
+static HRESULT WINAPI IShellLinkW_fnSetDescription(IShellLinkW * iface, LPCWSTR pszName)
+{
+ IShellLinkImpl *This = impl_from_IShellLinkW(iface);
+
+ TRACE("(%p)->(desc=%s)\n",This, debugstr_w(pszName));
+
+ HeapFree(GetProcessHeap(), 0, This->sDescription);
+ This->sDescription = HeapAlloc( GetProcessHeap(), 0,
+ (lstrlenW( pszName )+1)*sizeof(WCHAR) );
+ if ( !This->sDescription )
+ return E_OUTOFMEMORY;
+
+ lstrcpyW( This->sDescription, pszName );
+ This->bDirty = TRUE;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI IShellLinkW_fnGetWorkingDirectory(IShellLinkW * iface, LPWSTR pszDir,INT cchMaxPath)
+{
+ IShellLinkImpl *This = impl_from_IShellLinkW(iface);
+
+ TRACE("(%p)->(%p len %u)\n", This, pszDir, cchMaxPath);
+
+ if( cchMaxPath )
+ pszDir[0] = 0;
+ if( This->sWorkDir )
+ lstrcpynW( pszDir, This->sWorkDir, cchMaxPath );
+
+ return S_OK;
+}
+
+static HRESULT WINAPI IShellLinkW_fnSetWorkingDirectory(IShellLinkW * iface, LPCWSTR pszDir)
+{
+ IShellLinkImpl *This = impl_from_IShellLinkW(iface);
- TRACE("(%p)->(count=%lu)\n",This,This->ref);
+ TRACE("(%p)->(dir=%s)\n",This, debugstr_w(pszDir));
- if (!--(This->ref))
- { TRACE("-- destroying IShellLink(%p)\n",This);
+ HeapFree(GetProcessHeap(), 0, This->sWorkDir);
+ This->sWorkDir = HeapAlloc( GetProcessHeap(), 0,
+ (lstrlenW( pszDir )+1)*sizeof (WCHAR) );
+ if ( !This->sWorkDir )
+ return E_OUTOFMEMORY;
+ lstrcpyW( This->sWorkDir, pszDir );
+ This->bDirty = TRUE;
- if (This->sIcoPath)
- HeapFree(GetProcessHeap(), 0, This->sIcoPath);
+ return S_OK;
+}
- if (This->sArgs)
- HeapFree(GetProcessHeap(), 0, This->sArgs);
+static HRESULT WINAPI IShellLinkW_fnGetArguments(IShellLinkW * iface, LPWSTR pszArgs,INT cchMaxPath)
+{
+ IShellLinkImpl *This = impl_from_IShellLinkW(iface);
- if (This->sWorkDir)
- HeapFree(GetProcessHeap(), 0, This->sWorkDir);
+ TRACE("(%p)->(%p len=%u)\n", This, pszArgs, cchMaxPath);
- if (This->sDescription)
- HeapFree(GetProcessHeap(), 0, This->sDescription);
+ if( cchMaxPath )
+ pszArgs[0] = 0;
+ if( This->sArgs )
+ lstrcpynW( pszArgs, This->sArgs, cchMaxPath );
- if (This->sPath)
- HeapFree(GetProcessHeap(),0,This->sPath);
+ return NOERROR;
+}
- if (This->pPidl)
- SHFree(This->pPidl);
+static HRESULT WINAPI IShellLinkW_fnSetArguments(IShellLinkW * iface, LPCWSTR pszArgs)
+{
+ IShellLinkImpl *This = impl_from_IShellLinkW(iface);
- if (This->lpFileStream)
- IStream_Release(This->lpFileStream);
+ TRACE("(%p)->(args=%s)\n",This, debugstr_w(pszArgs));
- This->iIcoNdx = 0;
+ HeapFree(GetProcessHeap(), 0, This->sArgs);
+ This->sArgs = HeapAlloc( GetProcessHeap(), 0,
+ (lstrlenW( pszArgs )+1)*sizeof (WCHAR) );
+ if ( !This->sArgs )
+ return E_OUTOFMEMORY;
+ lstrcpyW( This->sArgs, pszArgs );
+ This->bDirty = TRUE;
- LocalFree((HANDLE)This);
- return 0;
- }
- return This->ref;
+ return S_OK;
}
-static HRESULT WINAPI IShellLinkA_fnGetPath(IShellLinkA * iface, LPSTR pszFile,INT cchMaxPath, WIN32_FIND_DATAA *pfd, DWORD fFlags)
+static HRESULT WINAPI IShellLinkW_fnGetHotkey(IShellLinkW * iface, WORD *pwHotkey)
{
- ICOM_THIS(IShellLinkImpl, iface);
+ IShellLinkImpl *This = impl_from_IShellLinkW(iface);
- TRACE("(%p)->(pfile=%p len=%u find_data=%p flags=%lu)(%s)\n",This, pszFile, cchMaxPath, pfd, fFlags, debugstr_a(This->sPath));
+ TRACE("(%p)->(%p)\n",This, pwHotkey);
- if (This->sPath)
- lstrcpynA(pszFile,This->sPath, cchMaxPath);
- else
- return E_FAIL;
+ *pwHotkey=This->wHotKey;
- return NOERROR;
+ return S_OK;
}
-static HRESULT WINAPI IShellLinkA_fnGetIDList(IShellLinkA * iface, LPITEMIDLIST * ppidl)
+
+static HRESULT WINAPI IShellLinkW_fnSetHotkey(IShellLinkW * iface, WORD wHotkey)
{
- ICOM_THIS(IShellLinkImpl, iface);
+ IShellLinkImpl *This = impl_from_IShellLinkW(iface);
- TRACE("(%p)->(ppidl=%p)\n",This, ppidl);
+ TRACE("(%p)->(hotkey=%x)\n",This, wHotkey);
- *ppidl = ILClone(This->pPidl);
- return NOERROR;
+ This->wHotKey = wHotkey;
+ This->bDirty = TRUE;
+
+ return S_OK;
}
-static HRESULT WINAPI IShellLinkA_fnSetIDList(IShellLinkA * iface, LPCITEMIDLIST pidl)
+
+static HRESULT WINAPI IShellLinkW_fnGetShowCmd(IShellLinkW * iface, INT *piShowCmd)
{
- ICOM_THIS(IShellLinkImpl, iface);
+ IShellLinkImpl *This = impl_from_IShellLinkW(iface);
- TRACE("(%p)->(pidl=%p)\n",This, pidl);
+ TRACE("(%p)->(%p)\n",This, piShowCmd);
- if (This->pPidl)
- SHFree(This->pPidl);
- This->pPidl = ILClone (pidl);
- return NOERROR;
+ *piShowCmd = This->iShowCmd;
+
+ return S_OK;
}
-static HRESULT WINAPI IShellLinkA_fnGetDescription(IShellLinkA * iface, LPSTR pszName,INT cchMaxName)
+
+static HRESULT WINAPI IShellLinkW_fnSetShowCmd(IShellLinkW * iface, INT iShowCmd)
{
- ICOM_THIS(IShellLinkImpl, iface);
+ IShellLinkImpl *This = impl_from_IShellLinkW(iface);
- FIXME("(%p)->(%p len=%u)\n",This, pszName, cchMaxName);
- lstrcpynA(pszName,"Description, FIXME",cchMaxName);
- return NOERROR;
+ This->iShowCmd = iShowCmd;
+ This->bDirty = TRUE;
+
+ return S_OK;
}
-static HRESULT WINAPI IShellLinkA_fnSetDescription(IShellLinkA * iface, LPCSTR pszName)
+
+static HRESULT SHELL_PidlGeticonLocationW(IShellFolder* psf, LPITEMIDLIST pidl, LPWSTR pszIconPath, int cchIconPath, int* piIcon)
{
- ICOM_THIS(IShellLinkImpl, iface);
+ LPCITEMIDLIST pidlLast;
- TRACE("(%p)->(pName=%s)\n", This, pszName);
+ HRESULT hr = SHBindToParent(pidl, &IID_IShellFolder, (LPVOID*)&psf, &pidlLast);
- if (This->sDescription)
- HeapFree(GetProcessHeap(), 0, This->sDescription);
- if (!(This->sDescription = heap_strdup(pszName)))
- return E_OUTOFMEMORY;
+ if (SUCCEEDED(hr)) {
+ IExtractIconW* pei;
- return NOERROR;
-}
-static HRESULT WINAPI IShellLinkA_fnGetWorkingDirectory(IShellLinkA * iface, LPSTR pszDir,INT cchMaxPath)
-{
- ICOM_THIS(IShellLinkImpl, iface);
+ hr = IShellFolder_GetUIObjectOf(psf, 0, 1, (LPCITEMIDLIST*)&pidlLast, &IID_IExtractIconW, NULL, (LPVOID*)&pei);
- TRACE("(%p)->(%p len=%u)\n", This, pszDir, cchMaxPath);
+ if (SUCCEEDED(hr)) {
+ hr = IExtractIconW_GetIconLocation(pei, 0, pszIconPath, MAX_PATH, piIcon, NULL);
- lstrcpynA( pszDir, This->sWorkDir ? This->sWorkDir : "", cchMaxPath );
+ IExtractIconW_Release(pei);
+ }
- return NOERROR;
+ IShellFolder_Release(psf);
+ }
+
+ return hr;
}
-static HRESULT WINAPI IShellLinkA_fnSetWorkingDirectory(IShellLinkA * iface, LPCSTR pszDir)
+
+static HRESULT WINAPI IShellLinkW_fnGetIconLocation(IShellLinkW * iface, LPWSTR pszIconPath,INT cchIconPath,INT *piIcon)
{
- ICOM_THIS(IShellLinkImpl, iface);
+ IShellLinkImpl *This = impl_from_IShellLinkW(iface);
- TRACE("(%p)->(dir=%s)\n",This, pszDir);
+ TRACE("(%p)->(%p len=%u iicon=%p)\n", This, pszIconPath, cchIconPath, piIcon);
- if (This->sWorkDir)
- HeapFree(GetProcessHeap(), 0, This->sWorkDir);
- if (!(This->sWorkDir = heap_strdup(pszDir)))
- return E_OUTOFMEMORY;
+ pszIconPath[0] = 0;
+ *piIcon = This->iIcoNdx;
- return NOERROR;
-}
-static HRESULT WINAPI IShellLinkA_fnGetArguments(IShellLinkA * iface, LPSTR pszArgs,INT cchMaxPath)
-{
- ICOM_THIS(IShellLinkImpl, iface);
+ if (This->sIcoPath)
+ {
+ lstrcpynW(pszIconPath, This->sIcoPath, cchIconPath);
+ return S_OK;
+ }
- TRACE("(%p)->(%p len=%u)\n", This, pszArgs, cchMaxPath);
+ if (This->pPidl || This->sPath)
+ {
+ IShellFolder* pdsk;
- lstrcpynA( pszArgs, This->sArgs ? This->sArgs : "", cchMaxPath );
+ HRESULT hr = SHGetDesktopFolder(&pdsk);
- return NOERROR;
-}
-static HRESULT WINAPI IShellLinkA_fnSetArguments(IShellLinkA * iface, LPCSTR pszArgs)
-{
- ICOM_THIS(IShellLinkImpl, iface);
+ if (SUCCEEDED(hr))
+ {
+ /* first look for an icon using the PIDL (if present) */
+ if (This->pPidl)
+ hr = SHELL_PidlGeticonLocationW(pdsk, This->pPidl, pszIconPath, cchIconPath, piIcon);
+ else
+ hr = E_FAIL;
+
+ /* if we couldn't find an icon yet, look for it using the file system path */
+ if (FAILED(hr) && This->sPath)
+ {
+ LPITEMIDLIST pidl;
- TRACE("(%p)->(args=%s)\n",This, pszArgs);
+ hr = IShellFolder_ParseDisplayName(pdsk, 0, NULL, This->sPath, NULL, &pidl, NULL);
- if (This->sArgs)
- HeapFree(GetProcessHeap(), 0, This->sArgs);
- if (!(This->sArgs = heap_strdup(pszArgs)))
- return E_OUTOFMEMORY;
+ if (SUCCEEDED(hr))
+ {
+ hr = SHELL_PidlGeticonLocationW(pdsk, pidl, pszIconPath, cchIconPath, piIcon);
- return NOERROR;
+ SHFree(pidl);
+ }
+ }
+
+ IShellFolder_Release(pdsk);
+ }
+ return hr;
+ }
+ return S_OK;
}
-static HRESULT WINAPI IShellLinkA_fnGetHotkey(IShellLinkA * iface, WORD *pwHotkey)
+
+static HRESULT WINAPI IShellLinkW_fnSetIconLocation(IShellLinkW * iface, LPCWSTR pszIconPath,INT iIcon)
{
- ICOM_THIS(IShellLinkImpl, iface);
+ IShellLinkImpl *This = impl_from_IShellLinkW(iface);
- TRACE("(%p)->(%p)(0x%08x)\n",This, pwHotkey, This->wHotKey);
+ TRACE("(%p)->(path=%s iicon=%u)\n",This, debugstr_w(pszIconPath), iIcon);
- *pwHotkey = This->wHotKey;
+ HeapFree(GetProcessHeap(), 0, This->sIcoPath);
+ This->sIcoPath = HeapAlloc( GetProcessHeap(), 0,
+ (lstrlenW( pszIconPath )+1)*sizeof (WCHAR) );
+ if ( !This->sIcoPath )
+ return E_OUTOFMEMORY;
+ lstrcpyW( This->sIcoPath, pszIconPath );
- return NOERROR;
+ This->iIcoNdx = iIcon;
+ This->bDirty = TRUE;
+
+ return S_OK;
}
-static HRESULT WINAPI IShellLinkA_fnSetHotkey(IShellLinkA * iface, WORD wHotkey)
+
+static HRESULT WINAPI IShellLinkW_fnSetRelativePath(IShellLinkW * iface, LPCWSTR pszPathRel, DWORD dwReserved)
{
- ICOM_THIS(IShellLinkImpl, iface);
+ IShellLinkImpl *This = impl_from_IShellLinkW(iface);
- TRACE("(%p)->(hotkey=%x)\n",This, wHotkey);
+ TRACE("(%p)->(path=%s %x)\n",This, debugstr_w(pszPathRel), dwReserved);
- This->wHotKey = wHotkey;
+ HeapFree(GetProcessHeap(), 0, This->sPathRel);
+ This->sPathRel = HeapAlloc( GetProcessHeap(), 0,
+ (lstrlenW( pszPathRel )+1) * sizeof (WCHAR) );
+ if ( !This->sPathRel )
+ return E_OUTOFMEMORY;
+ lstrcpyW( This->sPathRel, pszPathRel );
+ This->bDirty = TRUE;
- return NOERROR;
+ return ShellLink_UpdatePath(This->sPathRel, This->sPath, This->sWorkDir, &This->sPath);
}
-static HRESULT WINAPI IShellLinkA_fnGetShowCmd(IShellLinkA * iface, INT *piShowCmd)
-{
- ICOM_THIS(IShellLinkImpl, iface);
- FIXME("(%p)->(%p)\n",This, piShowCmd);
- *piShowCmd=0;
- return NOERROR;
-}
-static HRESULT WINAPI IShellLinkA_fnSetShowCmd(IShellLinkA * iface, INT iShowCmd)
+static HRESULT WINAPI IShellLinkW_fnResolve(IShellLinkW * iface, HWND hwnd, DWORD fFlags)
{
- ICOM_THIS(IShellLinkImpl, iface);
+ HRESULT hr = S_OK;
+ BOOL bSuccess;
- FIXME("(%p)->(showcmd=%x)\n",This, iShowCmd);
- return NOERROR;
-}
-static HRESULT WINAPI IShellLinkA_fnGetIconLocation(IShellLinkA * iface, LPSTR pszIconPath,INT cchIconPath,INT *piIcon)
-{
- ICOM_THIS(IShellLinkImpl, iface);
+ IShellLinkImpl *This = impl_from_IShellLinkW(iface);
- TRACE("(%p)->(%p len=%u iicon=%p)\n", This, pszIconPath, cchIconPath, piIcon);
+ TRACE("(%p)->(hwnd=%p flags=%x)\n",This, hwnd, fFlags);
- lstrcpynA( pszIconPath, This->sIcoPath ? This->sIcoPath : "", cchIconPath );
- *piIcon = This->iIcoNdx;
+ /*FIXME: use IResolveShellLink interface */
- return NOERROR;
-}
-static HRESULT WINAPI IShellLinkA_fnSetIconLocation(IShellLinkA * iface, LPCSTR pszIconPath,INT iIcon)
-{
- ICOM_THIS(IShellLinkImpl, iface);
+ if (!This->sPath && This->pPidl) {
+ WCHAR buffer[MAX_PATH];
+
+ bSuccess = SHGetPathFromIDListW(This->pPidl, buffer);
+
+ if (bSuccess && *buffer) {
+ This->sPath = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(buffer)+1)*sizeof(WCHAR));
+ if (!This->sPath)
+ return E_OUTOFMEMORY;
+
+ lstrcpyW(This->sPath, buffer);
- TRACE("(%p)->(path=%s iicon=%u)\n",This, pszIconPath, iIcon);
+ This->bDirty = TRUE;
+ } else
+ hr = S_OK; /* don't report an error occurred while just caching information */
+ }
- if (This->sIcoPath)
- HeapFree(GetProcessHeap(), 0, This->sIcoPath);
- if (!(This->sIcoPath = heap_strdup(pszIconPath)))
+ if (!This->sIcoPath && This->sPath) {
+ This->sIcoPath = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(This->sPath)+1)*sizeof(WCHAR));
+ if (!This->sIcoPath)
return E_OUTOFMEMORY;
- This->iIcoNdx = iIcon;
- return NOERROR;
+ lstrcpyW(This->sIcoPath, This->sPath);
+ This->iIcoNdx = 0;
+
+ This->bDirty = TRUE;
+ }
+
+ return hr;
}
-static HRESULT WINAPI IShellLinkA_fnSetRelativePath(IShellLinkA * iface, LPCSTR pszPathRel, DWORD dwReserved)
+
+static LPWSTR ShellLink_GetAdvertisedArg(LPCWSTR str)
{
- ICOM_THIS(IShellLinkImpl, iface);
+ LPWSTR ret;
+ LPCWSTR p;
+ DWORD len;
- FIXME("(%p)->(path=%s %lx)\n",This, pszPathRel, dwReserved);
- return NOERROR;
+ if( !str )
+ return NULL;
+
+ p = strchrW( str, ':' );
+ if( !p )
+ return NULL;
+ len = p - str;
+ ret = HeapAlloc( GetProcessHeap(), 0, sizeof(WCHAR)*(len+1));
+ if( !ret )
+ return ret;
+ memcpy( ret, str, sizeof(WCHAR)*len );
+ ret[len] = 0;
+ return ret;
}
-static HRESULT WINAPI IShellLinkA_fnResolve(IShellLinkA * iface, HWND hwnd, DWORD fFlags)
+
+static HRESULT ShellLink_SetAdvertiseInfo(IShellLinkImpl *This, LPCWSTR str)
{
- ICOM_THIS(IShellLinkImpl, iface);
+ LPCWSTR szComponent = NULL, szProduct = NULL, p;
+ WCHAR szGuid[39];
+ HRESULT r;
+ GUID guid;
+ int len;
- FIXME("(%p)->(hwnd=%x flags=%lx)\n",This, hwnd, fFlags);
- return NOERROR;
+ while( str[0] )
+ {
+ /* each segment must start with two colons */
+ if( str[0] != ':' || str[1] != ':' )
+ return E_FAIL;
+
+ /* the last segment is just two colons */
+ if( !str[2] )
+ break;
+ str += 2;
+
+ /* there must be a colon straight after a guid */
+ p = strchrW( str, ':' );
+ if( !p )
+ return E_FAIL;
+ len = p - str;
+ if( len != 38 )
+ return E_FAIL;
+
+ /* get the guid, and check it's validly formatted */
+ memcpy( szGuid, str, sizeof(WCHAR)*len );
+ szGuid[len] = 0;
+ r = CLSIDFromString( szGuid, &guid );
+ if( r != S_OK )
+ return r;
+ str = p + 1;
+
+ /* match it up to a guid that we care about */
+ if( IsEqualGUID( &guid, &SHELL32_AdvtShortcutComponent ) && !szComponent )
+ szComponent = str;
+ else if( IsEqualGUID( &guid, &SHELL32_AdvtShortcutProduct ) && !szProduct )
+ szProduct = str;
+ else
+ return E_FAIL;
+
+ /* skip to the next field */
+ str = strchrW( str, ':' );
+ if( !str )
+ return E_FAIL;
+ }
+
+ /* we have to have a component for an advertised shortcut */
+ if( !szComponent )
+ return E_FAIL;
+
+ This->sComponent = ShellLink_GetAdvertisedArg( szComponent );
+ This->sProduct = ShellLink_GetAdvertisedArg( szProduct );
+
+ TRACE("Component = %s\n", debugstr_w(This->sComponent));
+ TRACE("Product = %s\n", debugstr_w(This->sProduct));
+
+ return S_OK;
}
-static HRESULT WINAPI IShellLinkA_fnSetPath(IShellLinkA * iface, LPCSTR pszFile)
+
+static BOOL ShellLink_GetVolumeInfo(LPWSTR path, volume_info *volume)
+{
+ const int label_sz = sizeof volume->label/sizeof volume->label[0];
+ WCHAR drive[4] = { path[0], ':', '\\', 0 };
+ BOOL r;
+
+ volume->type = GetDriveTypeW(drive);
+ r = GetVolumeInformationW(drive, volume->label, label_sz,
+ &volume->serial, NULL, NULL, NULL, 0);
+ TRACE("r = %d type %d serial %08x name %s\n", r,
+ volume->type, volume->serial, debugstr_w(volume->label));
+ return r;
+}
+
+static HRESULT WINAPI IShellLinkW_fnSetPath(IShellLinkW * iface, LPCWSTR pszFile)
{
- ICOM_THIS(IShellLinkImpl, iface);
+ IShellLinkImpl *This = impl_from_IShellLinkW(iface);
+ WCHAR buffer[MAX_PATH];
+ LPWSTR fname, unquoted = NULL;
+ HRESULT hr = S_OK;
+ UINT len;
- TRACE("(%p)->(path=%s)\n",This, pszFile);
+ TRACE("(%p)->(path=%s)\n",This, debugstr_w(pszFile));
- if (This->sPath)
- HeapFree(GetProcessHeap(), 0, This->sPath);
- if (!(This->sPath = heap_strdup(pszFile)))
- return E_OUTOFMEMORY;
+ /* quotes at the ends of the string are stripped */
+ len = lstrlenW(pszFile);
+ if (pszFile[0] == '"' && pszFile[len-1] == '"')
+ {
+ unquoted = strdupW(pszFile);
+ PathUnquoteSpacesW(unquoted);
+ pszFile = unquoted;
+ }
- return NOERROR;
+ /* any other quote marks are invalid */
+ if (strchrW(pszFile, '"'))
+ return S_FALSE;
+
+ HeapFree(GetProcessHeap(), 0, This->sPath);
+ This->sPath = NULL;
+
+ HeapFree(GetProcessHeap(), 0, This->sComponent);
+ This->sComponent = NULL;
+
+ if (This->pPidl)
+ ILFree(This->pPidl);
+ This->pPidl = NULL;
+
+ if (S_OK != ShellLink_SetAdvertiseInfo( This, pszFile ))
+ {
+ if (*pszFile == '\0')
+ *buffer = '\0';
+ else if (!GetFullPathNameW(pszFile, MAX_PATH, buffer, &fname))
+ return E_FAIL;
+ else if(!PathFileExistsW(buffer) &&
+ !SearchPathW(NULL, pszFile, NULL, MAX_PATH, buffer, NULL))
+ hr = S_FALSE;
+
+ This->pPidl = SHSimpleIDListFromPathW(pszFile);
+ ShellLink_GetVolumeInfo(buffer, &This->volume);
+
+ This->sPath = HeapAlloc( GetProcessHeap(), 0,
+ (lstrlenW( buffer )+1) * sizeof (WCHAR) );
+ if (!This->sPath)
+ return E_OUTOFMEMORY;
+
+ lstrcpyW(This->sPath, buffer);
+ }
+ This->bDirty = TRUE;
+ HeapFree(GetProcessHeap(), 0, unquoted);
+
+ return hr;
}
/**************************************************************************
-* IShellLink Implementation
+* IShellLinkW Implementation
*/
-static ICOM_VTABLE(IShellLinkA) slvt =
-{
- ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
- IShellLinkA_fnQueryInterface,
- IShellLinkA_fnAddRef,
- IShellLinkA_fnRelease,
- IShellLinkA_fnGetPath,
- IShellLinkA_fnGetIDList,
- IShellLinkA_fnSetIDList,
- IShellLinkA_fnGetDescription,
- IShellLinkA_fnSetDescription,
- IShellLinkA_fnGetWorkingDirectory,
- IShellLinkA_fnSetWorkingDirectory,
- IShellLinkA_fnGetArguments,
- IShellLinkA_fnSetArguments,
- IShellLinkA_fnGetHotkey,
- IShellLinkA_fnSetHotkey,
- IShellLinkA_fnGetShowCmd,
- IShellLinkA_fnSetShowCmd,
- IShellLinkA_fnGetIconLocation,
- IShellLinkA_fnSetIconLocation,
- IShellLinkA_fnSetRelativePath,
- IShellLinkA_fnResolve,
- IShellLinkA_fnSetPath
+static const IShellLinkWVtbl slvtw =
+{
+ IShellLinkW_fnQueryInterface,
+ IShellLinkW_fnAddRef,
+ IShellLinkW_fnRelease,
+ IShellLinkW_fnGetPath,
+ IShellLinkW_fnGetIDList,
+ IShellLinkW_fnSetIDList,
+ IShellLinkW_fnGetDescription,
+ IShellLinkW_fnSetDescription,
+ IShellLinkW_fnGetWorkingDirectory,
+ IShellLinkW_fnSetWorkingDirectory,
+ IShellLinkW_fnGetArguments,
+ IShellLinkW_fnSetArguments,
+ IShellLinkW_fnGetHotkey,
+ IShellLinkW_fnSetHotkey,
+ IShellLinkW_fnGetShowCmd,
+ IShellLinkW_fnSetShowCmd,
+ IShellLinkW_fnGetIconLocation,
+ IShellLinkW_fnSetIconLocation,
+ IShellLinkW_fnSetRelativePath,
+ IShellLinkW_fnResolve,
+ IShellLinkW_fnSetPath
};
-
-/**************************************************************************
- * IShellLinkW_fnQueryInterface
- */
-static HRESULT WINAPI IShellLinkW_fnQueryInterface(
- IShellLinkW * iface, REFIID riid, LPVOID *ppvObj)
+static HRESULT WINAPI
+ShellLink_DataList_QueryInterface( IShellLinkDataList* iface, REFIID riid, void** ppvObject)
{
- _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
-
- return IShellLinkA_QueryInterface((IShellLinkA*)This, riid, ppvObj);
+ IShellLinkImpl *This = impl_from_IShellLinkDataList(iface);
+ return IShellLinkA_QueryInterface((IShellLinkA*)This, riid, ppvObject);
}
-/******************************************************************************
- * IShellLinkW_fnAddRef
- */
-static ULONG WINAPI IShellLinkW_fnAddRef(IShellLinkW * iface)
+static ULONG WINAPI
+ShellLink_DataList_AddRef( IShellLinkDataList* iface )
{
- _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
+ IShellLinkImpl *This = impl_from_IShellLinkDataList(iface);
+ return IShellLinkA_AddRef((IShellLinkA*)This);
+}
- TRACE("(%p)->(count=%lu)\n",This,This->ref);
+static ULONG WINAPI
+ShellLink_DataList_Release( IShellLinkDataList* iface )
+{
+ IShellLinkImpl *This = impl_from_IShellLinkDataList(iface);
+ return ShellLink_Release( This );
+}
- return IShellLinkA_AddRef((IShellLinkA*)This);
+static HRESULT WINAPI
+ShellLink_AddDataBlock( IShellLinkDataList* iface, void* pDataBlock )
+{
+ FIXME("\n");
+ return E_NOTIMPL;
}
-/******************************************************************************
- * IShellLinkW_fnRelease
- */
-static ULONG WINAPI IShellLinkW_fnRelease(IShellLinkW * iface)
+static HRESULT WINAPI
+ShellLink_CopyDataBlock( IShellLinkDataList* iface, DWORD dwSig, void** ppDataBlock )
{
- _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
+ IShellLinkImpl *This = impl_from_IShellLinkDataList(iface);
+ LPVOID block = NULL;
+ HRESULT r = E_FAIL;
- TRACE("(%p)->(count=%lu)\n",This,This->ref);
+ TRACE("%p %08x %p\n", iface, dwSig, ppDataBlock );
- return IShellLinkA_Release((IShellLinkA*)This);
+ switch (dwSig)
+ {
+ case EXP_DARWIN_ID_SIG:
+ if (!This->sComponent)
+ break;
+ block = shelllink_build_darwinid( This->sComponent, dwSig );
+ r = S_OK;
+ break;
+ case EXP_SZ_LINK_SIG:
+ case NT_CONSOLE_PROPS_SIG:
+ case NT_FE_CONSOLE_PROPS_SIG:
+ case EXP_SPECIAL_FOLDER_SIG:
+ case EXP_SZ_ICON_SIG:
+ FIXME("valid but unhandled datablock %08x\n", dwSig);
+ break;
+ default:
+ ERR("unknown datablock %08x\n", dwSig);
+ }
+ *ppDataBlock = block;
+ return r;
}
-static HRESULT WINAPI IShellLinkW_fnGetPath(IShellLinkW * iface, LPWSTR pszFile,INT cchMaxPath, WIN32_FIND_DATAA *pfd, DWORD fFlags)
+static HRESULT WINAPI
+ShellLink_RemoveDataBlock( IShellLinkDataList* iface, DWORD dwSig )
{
- _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
-
- FIXME("(%p)->(pfile=%p len=%u find_data=%p flags=%lu)\n",This, pszFile, cchMaxPath, pfd, fFlags);
- MultiByteToWideChar( CP_ACP, 0, "c:\\foo.bar", -1, pszFile, cchMaxPath );
- return NOERROR;
+ FIXME("\n");
+ return E_NOTIMPL;
}
-static HRESULT WINAPI IShellLinkW_fnGetIDList(IShellLinkW * iface, LPITEMIDLIST * ppidl)
+static HRESULT WINAPI
+ShellLink_GetFlags( IShellLinkDataList* iface, DWORD* pdwFlags )
{
- _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
+ IShellLinkImpl *This = impl_from_IShellLinkDataList(iface);
+ DWORD flags = 0;
- FIXME("(%p)->(ppidl=%p)\n",This, ppidl);
- *ppidl = _ILCreateDesktop();
- return NOERROR;
-}
+ FIXME("%p %p\n", This, pdwFlags );
-static HRESULT WINAPI IShellLinkW_fnSetIDList(IShellLinkW * iface, LPCITEMIDLIST pidl)
-{
- _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
+ /* FIXME: add more */
+ if (This->sArgs)
+ flags |= SLDF_HAS_ARGS;
+ if (This->sComponent)
+ flags |= SLDF_HAS_DARWINID;
+ if (This->sIcoPath)
+ flags |= SLDF_HAS_ICONLOCATION;
+ if (This->sProduct)
+ flags |= SLDF_HAS_LOGO3ID;
+ if (This->pPidl)
+ flags |= SLDF_HAS_ID_LIST;
- FIXME("(%p)->(pidl=%p)\n",This, pidl);
- return NOERROR;
+ *pdwFlags = flags;
+
+ return S_OK;
}
-static HRESULT WINAPI IShellLinkW_fnGetDescription(IShellLinkW * iface, LPWSTR pszName,INT cchMaxName)
+static HRESULT WINAPI
+ShellLink_SetFlags( IShellLinkDataList* iface, DWORD dwFlags )
{
- _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
-
- FIXME("(%p)->(%p len=%u)\n",This, pszName, cchMaxName);
- MultiByteToWideChar( CP_ACP, 0, "Description, FIXME", -1, pszName, cchMaxName );
- return NOERROR;
+ FIXME("\n");
+ return E_NOTIMPL;
}
-static HRESULT WINAPI IShellLinkW_fnSetDescription(IShellLinkW * iface, LPCWSTR pszName)
+static const IShellLinkDataListVtbl dlvt =
{
- _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
+ ShellLink_DataList_QueryInterface,
+ ShellLink_DataList_AddRef,
+ ShellLink_DataList_Release,
+ ShellLink_AddDataBlock,
+ ShellLink_CopyDataBlock,
+ ShellLink_RemoveDataBlock,
+ ShellLink_GetFlags,
+ ShellLink_SetFlags
+};
- TRACE("(%p)->(desc=%s)\n",This, debugstr_w(pszName));
+static HRESULT WINAPI
+ShellLink_ExtInit_QueryInterface( IShellExtInit* iface, REFIID riid, void** ppvObject )
+{
+ IShellLinkImpl *This = impl_from_IShellExtInit(iface);
+ return IShellLinkA_QueryInterface((IShellLinkA*)This, riid, ppvObject);
+}
- if (This->sDescription)
- HeapFree(GetProcessHeap(), 0, This->sDescription);
- if (!(This->sDescription = HEAP_strdupWtoA(GetProcessHeap(), 0, pszName)))
- return E_OUTOFMEMORY;
+static ULONG WINAPI
+ShellLink_ExtInit_AddRef( IShellExtInit* iface )
+{
+ IShellLinkImpl *This = impl_from_IShellExtInit(iface);
+ return IShellLinkA_AddRef((IShellLinkA*)This);
+}
- return NOERROR;
+static ULONG WINAPI
+ShellLink_ExtInit_Release( IShellExtInit* iface )
+{
+ IShellLinkImpl *This = impl_from_IShellExtInit(iface);
+ return ShellLink_Release( This );
}
-static HRESULT WINAPI IShellLinkW_fnGetWorkingDirectory(IShellLinkW * iface, LPWSTR pszDir,INT cchMaxPath)
+/**************************************************************************
+ * ShellLink implementation of IShellExtInit::Initialize()
+ *
+ * Loads the shelllink from the dataobject the shell is pointing to.
+ */
+static HRESULT WINAPI
+ShellLink_ExtInit_Initialize( IShellExtInit* iface, LPCITEMIDLIST pidlFolder,
+ IDataObject *pdtobj, HKEY hkeyProgID )
{
- _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
+ IShellLinkImpl *This = impl_from_IShellExtInit(iface);
+ FORMATETC format;
+ STGMEDIUM stgm;
+ UINT count;
+ HRESULT r = E_FAIL;
- TRACE("(%p)->(%p len %u)\n", This, pszDir, cchMaxPath);
+ TRACE("%p %p %p %p\n", This, pidlFolder, pdtobj, hkeyProgID );
- MultiByteToWideChar( CP_ACP, 0, This->sWorkDir ? This->sWorkDir : "", -1, pszDir, cchMaxPath );
+ if( !pdtobj )
+ return r;
- return NOERROR;
-}
+ format.cfFormat = CF_HDROP;
+ format.ptd = NULL;
+ format.dwAspect = DVASPECT_CONTENT;
+ format.lindex = -1;
+ format.tymed = TYMED_HGLOBAL;
-static HRESULT WINAPI IShellLinkW_fnSetWorkingDirectory(IShellLinkW * iface, LPCWSTR pszDir)
-{
- _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
+ if( FAILED( IDataObject_GetData( pdtobj, &format, &stgm ) ) )
+ return r;
- TRACE("(%p)->(dir=%s)\n",This, debugstr_w(pszDir));
+ count = DragQueryFileW( stgm.u.hGlobal, -1, NULL, 0 );
+ if( count == 1 )
+ {
+ LPWSTR path;
- if (This->sWorkDir)
- HeapFree(GetProcessHeap(), 0, This->sWorkDir);
- if (!(This->sWorkDir = HEAP_strdupWtoA(GetProcessHeap(), 0, pszDir)))
- return E_OUTOFMEMORY;
+ count = DragQueryFileW( stgm.u.hGlobal, 0, NULL, 0 );
+ count++;
+ path = HeapAlloc( GetProcessHeap(), 0, count*sizeof(WCHAR) );
+ if( path )
+ {
+ IPersistFile *pf = (IPersistFile*) &This->lpvtblPersistFile;
- return NOERROR;
+ count = DragQueryFileW( stgm.u.hGlobal, 0, path, count );
+ r = IPersistFile_Load( pf, path, 0 );
+ HeapFree( GetProcessHeap(), 0, path );
+ }
+ }
+ ReleaseStgMedium( &stgm );
+
+ return r;
}
-static HRESULT WINAPI IShellLinkW_fnGetArguments(IShellLinkW * iface, LPWSTR pszArgs,INT cchMaxPath)
+static const IShellExtInitVtbl eivt =
{
- _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
+ ShellLink_ExtInit_QueryInterface,
+ ShellLink_ExtInit_AddRef,
+ ShellLink_ExtInit_Release,
+ ShellLink_ExtInit_Initialize
+};
- TRACE("(%p)->(%p len=%u)\n", This, pszArgs, cchMaxPath);
+static HRESULT WINAPI
+ShellLink_ContextMenu_QueryInterface( IContextMenu* iface, REFIID riid, void** ppvObject )
+{
+ IShellLinkImpl *This = impl_from_IContextMenu(iface);
+ return IShellLinkA_QueryInterface((IShellLinkA*)This, riid, ppvObject);
+}
- MultiByteToWideChar( CP_ACP, 0, This->sArgs ? This->sArgs : "", -1, pszArgs, cchMaxPath );
+static ULONG WINAPI
+ShellLink_ContextMenu_AddRef( IContextMenu* iface )
+{
+ IShellLinkImpl *This = impl_from_IContextMenu(iface);
+ return IShellLinkA_AddRef((IShellLinkA*)This);
+}
- return NOERROR;
+static ULONG WINAPI
+ShellLink_ContextMenu_Release( IContextMenu* iface )
+{
+ IShellLinkImpl *This = impl_from_IContextMenu(iface);
+ return ShellLink_Release( This );
}
-static HRESULT WINAPI IShellLinkW_fnSetArguments(IShellLinkW * iface, LPCWSTR pszArgs)
+static HRESULT WINAPI
+ShellLink_QueryContextMenu( IContextMenu* iface, HMENU hmenu, UINT indexMenu,
+ UINT idCmdFirst, UINT idCmdLast, UINT uFlags )
{
- _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
+ IShellLinkImpl *This = impl_from_IContextMenu(iface);
+ static WCHAR szOpen[] = { 'O','p','e','n',0 };
+ MENUITEMINFOW mii;
+ int id = 1;
- TRACE("(%p)->(args=%s)\n",This, debugstr_w(pszArgs));
+ TRACE("%p %p %u %u %u %u\n", This,
+ hmenu, indexMenu, idCmdFirst, idCmdLast, uFlags );
- if (This->sArgs)
- HeapFree(GetProcessHeap(), 0, This->sArgs);
- if (!(This->sArgs = HEAP_strdupWtoA(GetProcessHeap(), 0, pszArgs)))
- return E_OUTOFMEMORY;
+ if ( !hmenu )
+ return E_INVALIDARG;
- return NOERROR;
+ memset( &mii, 0, sizeof mii );
+ mii.cbSize = sizeof mii;
+ mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
+ mii.dwTypeData = szOpen;
+ mii.cch = strlenW( mii.dwTypeData );
+ mii.wID = idCmdFirst + id++;
+ mii.fState = MFS_DEFAULT | MFS_ENABLED;
+ mii.fType = MFT_STRING;
+ if (!InsertMenuItemW( hmenu, indexMenu, TRUE, &mii ))
+ return E_FAIL;
+ This->iIdOpen = 0;
+
+ return MAKE_HRESULT( SEVERITY_SUCCESS, 0, id );
}
-static HRESULT WINAPI IShellLinkW_fnGetHotkey(IShellLinkW * iface, WORD *pwHotkey)
+static LPWSTR
+shelllink_get_msi_component_path( LPWSTR component )
{
- _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
+ LPWSTR path;
+ DWORD r, sz = 0;
- FIXME("(%p)->(%p)\n",This, pwHotkey);
- *pwHotkey=0x0;
- return NOERROR;
-}
+ r = CommandLineFromMsiDescriptor( component, NULL, &sz );
+ if (r != ERROR_SUCCESS)
+ return NULL;
-static HRESULT WINAPI IShellLinkW_fnSetHotkey(IShellLinkW * iface, WORD wHotkey)
-{
- _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
+ sz++;
+ path = HeapAlloc( GetProcessHeap(), 0, sz*sizeof(WCHAR) );
+ r = CommandLineFromMsiDescriptor( component, path, &sz );
+ if (r != ERROR_SUCCESS)
+ {
+ HeapFree( GetProcessHeap(), 0, path );
+ path = NULL;
+ }
- FIXME("(%p)->(hotkey=%x)\n",This, wHotkey);
- return NOERROR;
+ TRACE("returning %s\n", debugstr_w( path ) );
+
+ return path;
}
-static HRESULT WINAPI IShellLinkW_fnGetShowCmd(IShellLinkW * iface, INT *piShowCmd)
+static HRESULT WINAPI
+ShellLink_InvokeCommand( IContextMenu* iface, LPCMINVOKECOMMANDINFO lpici )
{
- _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
+ IShellLinkImpl *This = impl_from_IContextMenu(iface);
+ static const WCHAR szOpen[] = { 'O','p','e','n',0 };
+ SHELLEXECUTEINFOW sei;
+ HWND hwnd = NULL; /* FIXME: get using interface set from IObjectWithSite */
+ LPWSTR args = NULL;
+ LPWSTR path = NULL;
+ HRESULT r;
- FIXME("(%p)->(%p)\n",This, piShowCmd);
- *piShowCmd=0;
- return NOERROR;
-}
+ TRACE("%p %p\n", This, lpici );
-static HRESULT WINAPI IShellLinkW_fnSetShowCmd(IShellLinkW * iface, INT iShowCmd)
-{
- _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
+ if ( lpici->cbSize < sizeof (CMINVOKECOMMANDINFO) )
+ return E_INVALIDARG;
- FIXME("(%p)->(showcmd=%x)\n",This, iShowCmd);
- return NOERROR;
-}
+ if ( lpici->lpVerb != MAKEINTRESOURCEA(This->iIdOpen) )
+ {
+ ERR("Unknown id %d != %d\n", (INT)lpici->lpVerb, This->iIdOpen );
+ return E_INVALIDARG;
+ }
-static HRESULT WINAPI IShellLinkW_fnGetIconLocation(IShellLinkW * iface, LPWSTR pszIconPath,INT cchIconPath,INT *piIcon)
-{
- _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
+ r = IShellLinkW_Resolve( (IShellLinkW*)&(This->lpvtblw), hwnd, 0 );
+ if ( FAILED( r ) )
+ return r;
+
+ if ( This->sComponent )
+ {
+ path = shelllink_get_msi_component_path( This->sComponent );
+ if (!path)
+ return E_FAIL;
+ }
+ else
+ path = strdupW( This->sPath );
+
+ if ( lpici->cbSize == sizeof (CMINVOKECOMMANDINFOEX) &&
+ ( lpici->fMask & CMIC_MASK_UNICODE ) )
+ {
+ LPCMINVOKECOMMANDINFOEX iciex = (LPCMINVOKECOMMANDINFOEX) lpici;
+ DWORD len = 2;
+
+ if ( This->sArgs )
+ len += lstrlenW( This->sArgs );
+ if ( iciex->lpParametersW )
+ len += lstrlenW( iciex->lpParametersW );
+
+ args = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
+ args[0] = 0;
+ if ( This->sArgs )
+ lstrcatW( args, This->sArgs );
+ if ( iciex->lpParametersW )
+ {
+ static const WCHAR space[] = { ' ', 0 };
+ lstrcatW( args, space );
+ lstrcatW( args, iciex->lpParametersW );
+ }
+ }
- TRACE("(%p)->(%p len=%u iicon=%p)\n", This, pszIconPath, cchIconPath, piIcon);
+ memset( &sei, 0, sizeof sei );
+ sei.cbSize = sizeof sei;
+ sei.fMask = SEE_MASK_UNICODE | SEE_MASK_NOCLOSEPROCESS;
+ sei.lpFile = path;
+ sei.nShow = This->iShowCmd;
+ sei.lpIDList = This->pPidl;
+ sei.lpDirectory = This->sWorkDir;
+ sei.lpParameters = args;
+ sei.lpVerb = szOpen;
+
+ if( ShellExecuteExW( &sei ) )
+ {
+ if ( sei.hProcess )
+ {
+ WaitForSingleObject( sei.hProcess, 10000 );
+ CloseHandle( sei.hProcess );
+ }
+ r = S_OK;
+ }
+ else
+ r = E_FAIL;
- MultiByteToWideChar( CP_ACP, 0, This->sIcoPath ? This->sIcoPath : "", -1, pszIconPath, cchIconPath );
- *piIcon = This->iIcoNdx;
+ HeapFree( GetProcessHeap(), 0, args );
+ HeapFree( GetProcessHeap(), 0, path );
- return NOERROR;
+ return r;
}
-static HRESULT WINAPI IShellLinkW_fnSetIconLocation(IShellLinkW * iface, LPCWSTR pszIconPath,INT iIcon)
+static HRESULT WINAPI
+ShellLink_GetCommandString( IContextMenu* iface, UINT_PTR idCmd, UINT uType,
+ UINT* pwReserved, LPSTR pszName, UINT cchMax )
{
- _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
+ IShellLinkImpl *This = impl_from_IContextMenu(iface);
- TRACE("(%p)->(path=%s iicon=%u)\n",This, debugstr_w(pszIconPath), iIcon);
+ FIXME("%p %lu %u %p %p %u\n", This,
+ idCmd, uType, pwReserved, pszName, cchMax );
- if (This->sIcoPath)
- HeapFree(GetProcessHeap(), 0, This->sIcoPath);
- if (!(This->sIcoPath = HEAP_strdupWtoA(GetProcessHeap(), 0, pszIconPath)))
- return E_OUTOFMEMORY;
- This->iIcoNdx = iIcon;
+ return E_NOTIMPL;
+}
- return NOERROR;
+static const IContextMenuVtbl cmvt =
+{
+ ShellLink_ContextMenu_QueryInterface,
+ ShellLink_ContextMenu_AddRef,
+ ShellLink_ContextMenu_Release,
+ ShellLink_QueryContextMenu,
+ ShellLink_InvokeCommand,
+ ShellLink_GetCommandString
+};
+
+static HRESULT WINAPI
+ShellLink_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
+{
+ IShellLinkImpl *This = impl_from_IObjectWithSite(iface);
+ return ShellLink_QueryInterface( This, riid, ppvObject );
}
-static HRESULT WINAPI IShellLinkW_fnSetRelativePath(IShellLinkW * iface, LPCWSTR pszPathRel, DWORD dwReserved)
+static ULONG WINAPI
+ShellLink_ObjectWithSite_AddRef( IObjectWithSite* iface )
{
- _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
+ IShellLinkImpl *This = impl_from_IObjectWithSite(iface);
+ return ShellLink_AddRef( This );
+}
- FIXME("(%p)->(path=%s %lx)\n",This, debugstr_w(pszPathRel), dwReserved);
- return NOERROR;
+static ULONG WINAPI
+ShellLink_ObjectWithSite_Release( IObjectWithSite* iface )
+{
+ IShellLinkImpl *This = impl_from_IObjectWithSite(iface);
+ return ShellLink_Release( This );
}
-static HRESULT WINAPI IShellLinkW_fnResolve(IShellLinkW * iface, HWND hwnd, DWORD fFlags)
+static HRESULT WINAPI
+ShellLink_GetSite( IObjectWithSite *iface, REFIID iid, void ** ppvSite )
{
- _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
+ IShellLinkImpl *This = impl_from_IObjectWithSite(iface);
- FIXME("(%p)->(hwnd=%x flags=%lx)\n",This, hwnd, fFlags);
- return NOERROR;
+ TRACE("%p %s %p\n", This, debugstr_guid( iid ), ppvSite );
+
+ if ( !This->site )
+ return E_FAIL;
+ return IUnknown_QueryInterface( This->site, iid, ppvSite );
}
-static HRESULT WINAPI IShellLinkW_fnSetPath(IShellLinkW * iface, LPCWSTR pszFile)
+static HRESULT WINAPI
+ShellLink_SetSite( IObjectWithSite *iface, IUnknown *punk )
{
- _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
+ IShellLinkImpl *This = impl_from_IObjectWithSite(iface);
- TRACE("(%p)->(path=%s)\n",This, debugstr_w(pszFile));
+ TRACE("%p %p\n", iface, punk);
- if (This->sPath)
- HeapFree(GetProcessHeap(), 0, This->sPath);
- if (!(This->sPath = HEAP_strdupWtoA(GetProcessHeap(), 0, pszFile)))
- return E_OUTOFMEMORY;
+ if ( punk )
+ IUnknown_AddRef( punk );
+ This->site = punk;
- return NOERROR;
+ return S_OK;
}
-/**************************************************************************
-* IShellLinkW Implementation
-*/
-
-static ICOM_VTABLE(IShellLinkW) slvtw =
-{
- ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
- IShellLinkW_fnQueryInterface,
- IShellLinkW_fnAddRef,
- IShellLinkW_fnRelease,
- IShellLinkW_fnGetPath,
- IShellLinkW_fnGetIDList,
- IShellLinkW_fnSetIDList,
- IShellLinkW_fnGetDescription,
- IShellLinkW_fnSetDescription,
- IShellLinkW_fnGetWorkingDirectory,
- IShellLinkW_fnSetWorkingDirectory,
- IShellLinkW_fnGetArguments,
- IShellLinkW_fnSetArguments,
- IShellLinkW_fnGetHotkey,
- IShellLinkW_fnSetHotkey,
- IShellLinkW_fnGetShowCmd,
- IShellLinkW_fnSetShowCmd,
- IShellLinkW_fnGetIconLocation,
- IShellLinkW_fnSetIconLocation,
- IShellLinkW_fnSetRelativePath,
- IShellLinkW_fnResolve,
- IShellLinkW_fnSetPath
+static const IObjectWithSiteVtbl owsvt =
+{
+ ShellLink_ObjectWithSite_QueryInterface,
+ ShellLink_ObjectWithSite_AddRef,
+ ShellLink_ObjectWithSite_Release,
+ ShellLink_SetSite,
+ ShellLink_GetSite,
};