📄 shelllink.c
字号:
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 =
{
IPersistStream_fnQueryInterface,
IPersistStream_fnAddRef,
IPersistStream_fnRelease,
IPersistStream_fnGetClassID,
IPersistStream_fnIsDirty,
IPersistStream_fnLoad,
IPersistStream_fnSave,
IPersistStream_fnGetSizeMax
};
/**************************************************************************
* IShellLink_Constructor
*/
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 = LocalAlloc(LMEM_ZEROINIT,sizeof(IShellLinkImpl));
if (!sl)
return E_OUTOFMEMORY;
sl->ref = 1;
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);
r = ShellLink_QueryInterface( sl, riid, ppv );
ShellLink_Release( sl );
return r;
}
static BOOL SHELL_ExistsFileW(LPCWSTR path)
{
if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW(path))
return FALSE;
return TRUE;
}
/**************************************************************************
* ShellLink_UpdatePath
* update absolute path in sPath using relative path in sPathRel
*/
static HRESULT ShellLink_UpdatePath(LPWSTR sPathRel, LPCWSTR path, LPCWSTR sWorkDir, LPWSTR* psPath)
{
if (!path || !psPath)
return E_INVALIDARG;
if (!*psPath && sPathRel) {
WCHAR buffer[2*MAX_PATH], abs_path[2*MAX_PATH];
LPWSTR final = NULL;
/* first try if [directory of link file] + [relative path] finds an existing file */
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);
}
}
/* 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);
}
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)
{
IShellLinkImpl *This = (IShellLinkImpl *)iface;
return ShellLink_AddRef( This );
}
/******************************************************************************
* IShellLinkA_Release
*/
static ULONG WINAPI IShellLinkA_fnRelease(IShellLinkA * 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=%lu)(%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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -