#include "shell32_main.h"
#include "shlguid.h"
#include "shlwapi.h"
+#include "msi.h"
+#include "appmgmt.h"
#include "initguid.h"
static const IShellLinkDataListVtbl dlvt;
static const IShellExtInitVtbl eivt;
static const IContextMenuVtbl cmvt;
+static const IObjectWithSiteVtbl owsvt;
/* IShellLink Implementation */
const IShellLinkDataListVtbl *lpvtblShellLinkDataList;
const IShellExtInitVtbl *lpvtblShellExtInit;
const IContextMenuVtbl *lpvtblContextMenu;
+ const IObjectWithSiteVtbl *lpvtblObjectWithSite;
LONG ref;
LPWSTR sComponent;
volume_info volume;
- BOOL bDirty;
+ BOOL bDirty;
+ INT iIdOpen; /* id of the "Open" entry in the context menu */
+ IUnknown *site;
} IShellLinkImpl;
static inline IShellLinkImpl *impl_from_IShellLinkW( IShellLinkW *iface )
return (IShellLinkImpl *)((char*)iface - FIELD_OFFSET(IShellLinkImpl, lpvtblContextMenu));
}
+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);
/* strdup on the process heap */
return p;
}
+inline static LPWSTR strdupW( LPCWSTR src )
+{
+ LPWSTR dest;
+ if (!src) return NULL;
+ dest = HeapAlloc( GetProcessHeap(), 0, (lstrlenW(src)+1)*sizeof(WCHAR) );
+ if (dest)
+ lstrcpyW(dest, src);
+ return dest;
+}
+
/**************************************************************************
* ShellLink::QueryInterface implementation
*/
{
*ppvObj = &(This->lpvtblContextMenu);
}
+ else if(IsEqualIID(riid, &IID_IObjectWithSite))
+ {
+ *ppvObj = &(This->lpvtblObjectWithSite);
+ }
if(*ppvObj)
{
HeapFree(GetProcessHeap(), 0, This->sDescription);
HeapFree(GetProcessHeap(),0,This->sPath);
+ if (This->site)
+ IUnknown_Release( This->site );
+
if (This->pPidl)
ILFree(This->pPidl);
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;
- EXP_DARWIN_LINK buffer;
TRACE("%p\n",stm);
- memset( &buffer, 0, 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 );
+ buffer = shelllink_build_darwinid( string, magic );
- return IStream_Write( stm, &buffer, buffer.dbh.cbSize, &count );
+ return IStream_Write( stm, buffer, buffer->dbh.cbSize, &count );
}
/************************************************************************
return r;
}
- TRACE("Writing pidl \n");
+ TRACE("Writing pidl\n");
/* write the PIDL to the shortcut */
if( This->pPidl )
REFIID riid, LPVOID *ppv )
{
IShellLinkImpl * sl;
+ HRESULT r;
TRACE("unkOut=%p riid=%s\n",pUnkOuter, debugstr_guid(riid));
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_IUnknown) ||
- 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;
- }
-
- return S_OK;
+ r = ShellLink_QueryInterface( sl, riid, ppv );
+ ShellLink_Release( sl );
+ return r;
}
static HRESULT WINAPI
ShellLink_CopyDataBlock( IShellLinkDataList* iface, DWORD dwSig, void** ppDataBlock )
{
- FIXME("\n");
- return E_NOTIMPL;
+ IShellLinkImpl *This = impl_from_IShellLinkDataList(iface);
+ LPVOID block = NULL;
+ HRESULT r = E_FAIL;
+
+ TRACE("%p %08lx %p\n", iface, dwSig, ppDataBlock );
+
+ 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 %08lx\n", dwSig);
+ break;
+ default:
+ ERR("unknown datablock %08lx\n", dwSig);
+ }
+ *ppDataBlock = block;
+ return r;
}
static HRESULT WINAPI
static HRESULT WINAPI
ShellLink_GetFlags( IShellLinkDataList* iface, DWORD* pdwFlags )
{
- FIXME("\n");
- return E_NOTIMPL;
+ IShellLinkImpl *This = impl_from_IShellLinkDataList(iface);
+ DWORD flags = 0;
+
+ FIXME("%p %p\n", This, pdwFlags );
+
+ /* 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;
+
+ *pdwFlags = flags;
+
+ return S_OK;
}
static HRESULT WINAPI
UINT idCmdFirst, UINT idCmdLast, UINT uFlags )
{
IShellLinkImpl *This = impl_from_IContextMenu(iface);
+ static const WCHAR szOpen[] = { 'O','p','e','n',0 };
+ MENUITEMINFOW mii;
+ int id = 1;
- FIXME("%p %p %u %u %u %u\n", This,
+ TRACE("%p %p %u %u %u %u\n", This,
hmenu, indexMenu, idCmdFirst, idCmdLast, uFlags );
- return E_NOTIMPL;
+ if ( !hmenu )
+ return E_INVALIDARG;
+
+ memset( &mii, 0, sizeof mii );
+ mii.cbSize = sizeof mii;
+ mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
+ mii.dwTypeData = (LPWSTR)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 LPWSTR
+shelllink_get_msi_component_path( LPWSTR component )
+{
+ LPWSTR path = NULL;
+ DWORD r, sz = 0;
+
+ r = CommandLineFromMsiDescriptor( component, NULL, &sz );
+ if (r != ERROR_SUCCESS)
+ return path;
+
+ sz++;
+ path = HeapAlloc( GetProcessHeap(), 0, sz*sizeof(WCHAR) );
+ r = CommandLineFromMsiDescriptor( component, path, &sz );
+ if (r != ERROR_SUCCESS)
+ {
+ HeapFree( GetProcessHeap(), 0, path );
+ path = NULL;
+ }
+
+ TRACE("returning %s\n", debugstr_w( path ) );
+
+ return path;
}
static HRESULT WINAPI
ShellLink_InvokeCommand( IContextMenu* iface, LPCMINVOKECOMMANDINFO lpici )
{
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, lpici );
+ TRACE("%p %p\n", This, lpici );
- return E_NOTIMPL;
+ if ( lpici->cbSize < sizeof (CMINVOKECOMMANDINFO) )
+ return E_INVALIDARG;
+
+ if ( lpici->lpVerb != MAKEINTRESOURCEA(This->iIdOpen) )
+ {
+ ERR("Unknown id %d != %d\n", (INT)lpici->lpVerb, This->iIdOpen );
+ return E_INVALIDARG;
+ }
+
+ 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 );
+ }
+ }
+
+ memset( &sei, 0, sizeof sei );
+ sei.cbSize = sizeof sei;
+ sei.fMask = SEE_MASK_UNICODE;
+ sei.lpFile = path;
+ sei.nShow = This->iShowCmd;
+ sei.lpIDList = This->pPidl;
+ sei.lpDirectory = This->sWorkDir;
+ sei.lpParameters = args;
+ sei.lpVerb = szOpen;
+
+ if ( ShellExecuteExW( &sei ) && sei.hInstApp > 32 )
+ r = S_OK;
+ else
+ r = E_FAIL;
+
+ HeapFree( GetProcessHeap(), 0, args );
+ HeapFree( GetProcessHeap(), 0, path );
+
+ return r;
}
static HRESULT WINAPI
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 ULONG WINAPI
+ShellLink_ObjectWithSite_AddRef( IObjectWithSite* iface )
+{
+ IShellLinkImpl *This = impl_from_IObjectWithSite(iface);
+ return ShellLink_AddRef( This );
+}
+
+static ULONG WINAPI
+ShellLink_ObjectWithSite_Release( IObjectWithSite* iface )
+{
+ IShellLinkImpl *This = impl_from_IObjectWithSite(iface);
+ return ShellLink_Release( This );
+}
+
+static HRESULT WINAPI
+ShellLink_GetSite( IObjectWithSite *iface, REFIID iid, void ** ppvSite )
+{
+ IShellLinkImpl *This = impl_from_IObjectWithSite(iface);
+
+ 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
+ShellLink_SetSite( IObjectWithSite *iface, IUnknown *punk )
+{
+ IShellLinkImpl *This = impl_from_IObjectWithSite(iface);
+
+ TRACE("%p %p\n", iface, punk);
+
+ if ( punk )
+ IUnknown_AddRef( punk );
+ This->site = punk;
+
+ return S_OK;
+}
+
+static const IObjectWithSiteVtbl owsvt =
+{
+ ShellLink_ObjectWithSite_QueryInterface,
+ ShellLink_ObjectWithSite_AddRef,
+ ShellLink_ObjectWithSite_Release,
+ ShellLink_SetSite,
+ ShellLink_GetSite,
+};