📄 shelllink.c
字号:
/*
*
* 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
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* 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
*
* NOTES
* Nearly complete informations 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.
*/
#define COBJMACROS
#define NONAMELESSUNION
#include "wine/debug.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 "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"
typedef struct _LINK_HEADER
{
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 dwFileLength; /* 0x34 File length */
DWORD nIcon; /* 0x38 icon number */
DWORD fStartup; /* 0x3c startup type */
DWORD wHotKey; /* 0x40 hotkey */
DWORD Unknown5; /* 0x44 */
DWORD Unknown6; /* 0x48 */
} LINK_HEADER, * PLINK_HEADER;
#define SHLINK_LOCAL 0
#define SHLINK_REMOTE 1
typedef struct _LOCATION_INFO
{
DWORD dwTotalSize;
DWORD dwHeaderSize;
DWORD dwFlags;
DWORD dwVolTableOfs;
DWORD dwLocalPathOfs;
DWORD dwNetworkVolTableOfs;
DWORD dwFinalPathOfs;
} LOCATION_INFO;
typedef struct _LOCAL_VOLUME_INFO
{
DWORD dwSize;
DWORD dwType;
DWORD dwVolSerial;
DWORD dwVolLabelOfs;
} LOCAL_VOLUME_INFO;
typedef struct volume_info_t
{
DWORD type;
DWORD serial;
WCHAR label[12]; /* assume 8.3 */
} volume_info;
#include "poppack.h"
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
{
const IShellLinkAVtbl *lpVtbl;
const IShellLinkWVtbl *lpvtblw;
const IPersistFileVtbl *lpvtblPersistFile;
const IPersistStreamVtbl *lpvtblPersistStream;
const IShellLinkDataListVtbl *lpvtblShellLinkDataList;
const IShellExtInitVtbl *lpvtblShellExtInit;
const IContextMenuVtbl *lpvtblContextMenu;
const IObjectWithSiteVtbl *lpvtblObjectWithSite;
LONG ref;
/* data structures according to the informations in the link */
LPITEMIDLIST pPidl;
WORD wHotKey;
SYSTEMTIME time1;
SYSTEMTIME time2;
SYSTEMTIME time3;
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;
static inline IShellLinkImpl *impl_from_IShellLinkW( IShellLinkW *iface )
{
return (IShellLinkImpl *)((char*)iface - FIELD_OFFSET(IShellLinkImpl, lpvtblw));
}
static inline IShellLinkImpl *impl_from_IPersistFile( IPersistFile *iface )
{
return (IShellLinkImpl *)((char*)iface - FIELD_OFFSET(IShellLinkImpl, lpvtblPersistFile));
}
static inline IShellLinkImpl *impl_from_IPersistStream( IPersistStream *iface )
{
return (IShellLinkImpl *)((char*)iface - FIELD_OFFSET(IShellLinkImpl, lpvtblPersistStream));
}
static inline IShellLinkImpl *impl_from_IShellLinkDataList( IShellLinkDataList *iface )
{
return (IShellLinkImpl *)((char*)iface - FIELD_OFFSET(IShellLinkImpl, lpvtblShellLinkDataList));
}
static inline IShellLinkImpl *impl_from_IShellExtInit( IShellExtInit *iface )
{
return (IShellLinkImpl *)((char*)iface - FIELD_OFFSET(IShellLinkImpl, lpvtblShellExtInit));
}
static inline IShellLinkImpl *impl_from_IContextMenu( IContextMenu *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 */
inline static 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;
}
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
*/
static HRESULT ShellLink_QueryInterface( IShellLinkImpl *This, REFIID riid, LPVOID *ppvObj)
{
TRACE("(%p)->(\n\tIID:\t%s)\n",This,debugstr_guid(riid));
*ppvObj = NULL;
if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IShellLinkA))
{
*ppvObj = This;
}
else if(IsEqualIID(riid, &IID_IShellLinkW))
{
*ppvObj = &(This->lpvtblw);
}
else if(IsEqualIID(riid, &IID_IPersistFile))
{
*ppvObj = &(This->lpvtblPersistFile);
}
else if(IsEqualIID(riid, &IID_IPersistStream))
{
*ppvObj = &(This->lpvtblPersistStream);
}
else if(IsEqualIID(riid, &IID_IShellLinkDataList))
{
*ppvObj = &(This->lpvtblShellLinkDataList);
}
else if(IsEqualIID(riid, &IID_IShellExtInit))
{
*ppvObj = &(This->lpvtblShellExtInit);
}
else if(IsEqualIID(riid, &IID_IContextMenu))
{
*ppvObj = &(This->lpvtblContextMenu);
}
else if(IsEqualIID(riid, &IID_IObjectWithSite))
{
*ppvObj = &(This->lpvtblObjectWithSite);
}
if(*ppvObj)
{
IUnknown_AddRef((IUnknown*)(*ppvObj));
TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
return S_OK;
}
ERR("-- Interface: E_NOINTERFACE\n");
return E_NOINTERFACE;
}
/**************************************************************************
* ShellLink::AddRef implementation
*/
static ULONG ShellLink_AddRef( IShellLinkImpl *This )
{
ULONG refCount = InterlockedIncrement(&This->ref);
TRACE("(%p)->(count=%lu)\n", This, refCount - 1);
return refCount;
}
/**************************************************************************
* ShellLink::Release implementation
*/
static ULONG ShellLink_Release( IShellLinkImpl *This )
{
ULONG refCount = InterlockedDecrement(&This->ref);
TRACE("(%p)->(count=%lu)\n", This, refCount + 1);
if (refCount)
return refCount;
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);
return 0;
}
static HRESULT ShellLink_GetClassID( IShellLinkImpl *This, CLSID *pclsid )
{
TRACE("%p %p\n", This, pclsid);
memcpy( pclsid, &CLSID_ShellLink, sizeof (CLSID) );
return S_OK;
}
/**************************************************************************
* IPersistFile_QueryInterface
*/
static HRESULT WINAPI IPersistFile_fnQueryInterface(
IPersistFile* iface,
REFIID riid,
LPVOID *ppvObj)
{
IShellLinkImpl *This = impl_from_IPersistFile(iface);
return ShellLink_QueryInterface( This, riid, ppvObj );
}
/******************************************************************************
* IPersistFile_AddRef
*/
static ULONG WINAPI IPersistFile_fnAddRef(IPersistFile* iface)
{
IShellLinkImpl *This = impl_from_IPersistFile(iface);
return ShellLink_AddRef( This );
}
/******************************************************************************
* IPersistFile_Release
*/
static ULONG WINAPI IPersistFile_fnRelease(IPersistFile* iface)
{
IShellLinkImpl *This = impl_from_IPersistFile(iface);
return IShellLinkA_Release((IShellLinkA*)This);
}
static HRESULT WINAPI IPersistFile_fnGetClassID(IPersistFile* iface, CLSID *pClassID)
{
IShellLinkImpl *This = impl_from_IPersistFile(iface);
return ShellLink_GetClassID( This, pClassID );
}
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, %lx)\n",This, debugstr_w(pszFileName), dwMode);
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 %08lx\n", r);
return r;
}
static BOOL StartLinkProcessor( LPCOLESTR szLink )
{
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;
len = sizeof(szFormat) + lstrlenW( szLink ) * sizeof(WCHAR);
buffer = HeapAlloc( GetProcessHeap(), 0, len );
if( !buffer )
return FALSE;
wsprintfW( buffer, szFormat, szLink );
TRACE("starting %s\n",debugstr_w(buffer));
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
if (!CreateProcessW( NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) return FALSE;
/* 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");
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
return TRUE;
}
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));
if (!pszFileName)
return E_FAIL;
r = SHCreateStreamOnFileW( pszFileName, STGM_READWRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE, &stm );
if( SUCCEEDED( r ) )
{
r = IPersistStream_Save(StreamThis, stm, FALSE);
IStream_Release( stm );
if( SUCCEEDED( r ) )
{
StartLinkProcessor( pszFileName );
This->bDirty = FALSE;
}
else
{
DeleteFileW( pszFileName );
WARN("Failed to create shortcut %s\n", debugstr_w(pszFileName) );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -