*
* NOTES
* Nearly complete informations about the binary formats
- * of .lnk files avaiable at http://www.wotsit.org
+ * of .lnk files available at http://www.wotsit.org
*
*/
#include "pidl.h"
#include "shell32_main.h"
#include "shlguid.h"
+#include "shlwapi.h"
WINE_DEFAULT_DEBUG_CHANNEL(shell);
#define SCF_WORKDIR 0x10
#define SCF_ARGS 0x20
#define SCF_CUSTOMICON 0x40
-//#define SCF_UNC 0x80
-//#define SCF_UNICODE 0x1000
#define SCF_UNICODE 0x80
#include "pshpack1.h"
#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)
+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)
{
_ICOM_THIS_From_IPersistFile(IShellLinkImpl, iface);
- FIXME("(%p)\n",This);
+ TRACE("(%p)\n",This);
if (This->bDirty)
return S_OK;
if( SUCCEEDED( r ) )
{
r = IPersistStream_Load(StreamThis, stm);
+ ShellLink_UpdatePath(This->sPathRel, pszFileName, This->sWorkDir, &This->sPath);
IStream_Release( stm );
}
return S_OK;
}
-static HRESULT Stream_WriteLocationInfo( IStream* stm, LPCSTR filename )
+static HRESULT Stream_WriteLocationInfo( IStream* stm, LPCWSTR filename )
{
LOCATION_INFO loc;
ULONG count;
return IStream_Write( stm, &loc, loc.dwTotalSize, &count );
}
-extern UINT SHELL_FindExecutable(LPCSTR lpPath, LPCSTR lpFile, LPCSTR lpOperation,
- LPSTR lpResult, LPSTR key, void **env, LPCSTR args);
-
/************************************************************************
* IPersistStream_Save (IPersistStream)
*
IStream* stm,
BOOL fClearDirty)
{
+ static const WCHAR wOpen[] = {'o','p','e','n',0};
+
LINK_HEADER header;
- char buffer[MAX_PATH];
- char exePath[MAX_PATH];
+ WCHAR exePath[MAX_PATH];
ULONG count;
HRESULT r;
*exePath = '\0';
- if (This->sPath) {
- WideCharToMultiByte(CP_ACP, 0, This->sPath, -1, buffer, MAX_PATH, 0, 0);
-
- SHELL_FindExecutable(NULL, buffer, "open", exePath, NULL, NULL, NULL);
- }
+ if (This->sPath)
+ SHELL_FindExecutable(NULL, This->sPath, wOpen, exePath, MAX_PATH, NULL, NULL, NULL, NULL);
/* if there's no PIDL, generate one */
if( ! This->pPidl )
if( !*exePath )
return E_FAIL;
- This->pPidl = ILCreateFromPathA(exePath);
+ This->pPidl = ILCreateFromPathW(exePath);
}
memset(&header, 0, sizeof(header));
return S_OK;
}
+static BOOL SHELL_ExistsFileW(LPCWSTR path)
+{
+ HANDLE hfile = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+
+ if (hfile != INVALID_HANDLE_VALUE) {
+ CloseHandle(hfile);
+ return TRUE;
+ } else
+ return FALSE;
+}
+
/**************************************************************************
- * _IShellLink_UpdatePath
+ * ShellLink_UpdatePath
* update absolute path in sPath using relative path in sPathRel
*/
-static HRESULT _IShellLink_UpdatePath(LPWSTR sPathRel, LPCWSTR path, LPWSTR* psPath)
+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];
+
+ /* first try if [directory of link file] + [relative path] finds an existing file */
LPCWSTR src = path;
LPWSTR last_slash = NULL;
LPWSTR dest = buffer;
lstrcpyW(last_slash? last_slash+1: buffer, sPathRel);
- if (!GetFullPathNameW(buffer, MAX_PATH, abs_path, &final))
- lstrcpyW(abs_path, buffer);
+ *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)
if (SUCCEEDED(hr)) {
WCHAR path[MAX_PATH];
- if (SHGetPathFromIDListW(pidl, path)) {
+ hr = SHELL_GetPathFromIDListW(pidl, path, MAX_PATH);
+
+ if (SUCCEEDED(hr)) {
hr = IPersistFile_Load(ppf, path, 0);
- if (SUCCEEDED(hr)) {
+ if (SUCCEEDED(hr))
*ppv = (IUnknown*) psl;
-
- /*
- The following code is here, not in IPersistStream_fnLoad() because
- we need to know the path of the shell link file to convert the
- relative path into the absolute path.
- */
- if (IsEqualIID(riid, &IID_IShellLinkW)) {
- _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, psl);
-
- hr = _IShellLink_UpdatePath(This->sPathRel, path, &This->sPath);
- } else {
- ICOM_THIS(IShellLinkImpl, psl);
-
- hr = _IShellLink_UpdatePath(This->sPathRel, path, &This->sPath);
- }
- }
}
IPersistFile_Release(ppf);
return NOERROR;
}
-static HRESULT _PidlGeticonLocationA(IShellFolder* psf, LPITEMIDLIST pidl, LPSTR pszIconPath, int cchIconPath, int* piIcon)
+static HRESULT SHELL_PidlGeticonLocationA(IShellFolder* psf, LPITEMIDLIST pidl, LPSTR pszIconPath, int cchIconPath, int* piIcon)
{
LPCITEMIDLIST pidlLast;
if (SUCCEEDED(hr)) {
/* first look for an icon using the PIDL (if present) */
if (This->pPidl)
- hr = _PidlGeticonLocationA(pdsk, This->pPidl, pszIconPath, cchIconPath, piIcon);
+ hr = SHELL_PidlGeticonLocationA(pdsk, This->pPidl, pszIconPath, cchIconPath, piIcon);
else
hr = E_FAIL;
hr = IShellFolder_ParseDisplayName(pdsk, 0, NULL, This->sPath, NULL, &pidl, NULL);
if (SUCCEEDED(hr)) {
- hr = _PidlGeticonLocationA(pdsk, pidl, pszIconPath, cchIconPath, piIcon);
+ hr = SHELL_PidlGeticonLocationA(pdsk, pidl, pszIconPath, cchIconPath, piIcon);
SHFree(pidl);
}
This->sPathRel = HEAP_strdupAtoW(GetProcessHeap(), 0, pszPathRel);
This->bDirty = TRUE;
- return _IShellLink_UpdatePath(This->sPathRel, This->sPath, &This->sPath);
+ return ShellLink_UpdatePath(This->sPathRel, This->sPath, This->sWorkDir, &This->sPath);
}
static HRESULT WINAPI IShellLinkA_fnResolve(IShellLinkA * iface, HWND hwnd, DWORD fFlags)
FIXME("(%p)->(hwnd=%p flags=%lx)\n",This, hwnd, fFlags);
+ /*FIXME: use IResolveShellLink interface */
+
if (!This->sPath && This->pPidl) {
WCHAR buffer[MAX_PATH];
- hr = _SHGetPathFromIDListW(This->pPidl, buffer, MAX_PATH);
+ hr = SHELL_GetPathFromIDListW(This->pPidl, buffer, MAX_PATH);
if (SUCCEEDED(hr) && *buffer) {
This->sPath = (LPWSTR) HeapAlloc(GetProcessHeap(), 0, (lstrlenW(buffer)+1)*sizeof(WCHAR));
static HRESULT WINAPI IShellLinkA_fnSetPath(IShellLinkA * iface, LPCSTR pszFile)
{
ICOM_THIS(IShellLinkImpl, iface);
+ char buffer[MAX_PATH];
+ LPSTR fname;
TRACE("(%p)->(path=%s)\n",This, pszFile);
+ if (!GetFullPathNameA(pszFile, MAX_PATH, buffer, &fname))
+ return E_FAIL;
+
if (This->sPath)
HeapFree(GetProcessHeap(), 0, This->sPath);
- This->sPath = HEAP_strdupAtoW(GetProcessHeap(), 0, pszFile);
+
+ This->sPath = HEAP_strdupAtoW(GetProcessHeap(), 0, buffer);
if( !This->sPath )
return E_OUTOFMEMORY;
return S_OK;
}
-static HRESULT _PidlGeticonLocationW(IShellFolder* psf, LPITEMIDLIST pidl, LPWSTR pszIconPath, int cchIconPath, int* piIcon)
+static HRESULT SHELL_PidlGeticonLocationW(IShellFolder* psf, LPITEMIDLIST pidl, LPWSTR pszIconPath, int cchIconPath, int* piIcon)
{
LPCITEMIDLIST pidlLast;
if (SUCCEEDED(hr)) {
/* first look for an icon using the PIDL (if present) */
if (This->pPidl)
- hr = _PidlGeticonLocationW(pdsk, This->pPidl, pszIconPath, cchIconPath, piIcon);
+ hr = SHELL_PidlGeticonLocationW(pdsk, This->pPidl, pszIconPath, cchIconPath, piIcon);
else
hr = E_FAIL;
hr = IShellFolder_ParseDisplayName(pdsk, 0, NULL, This->sPath, NULL, &pidl, NULL);
if (SUCCEEDED(hr)) {
- hr = _PidlGeticonLocationW(pdsk, pidl, pszIconPath, cchIconPath, piIcon);
+ hr = SHELL_PidlGeticonLocationW(pdsk, pidl, pszIconPath, cchIconPath, piIcon);
SHFree(pidl);
}
lstrcpyW( This->sPathRel, pszPathRel );
This->bDirty = TRUE;
- return _IShellLink_UpdatePath(This->sPathRel, This->sPath, &This->sPath);
+ return ShellLink_UpdatePath(This->sPathRel, This->sPath, This->sWorkDir, &This->sPath);
}
static HRESULT WINAPI IShellLinkW_fnResolve(IShellLinkW * iface, HWND hwnd, DWORD fFlags)
FIXME("(%p)->(hwnd=%p flags=%lx)\n",This, hwnd, fFlags);
+ /*FIXME: use IResolveShellLink interface */
+
if (!This->sPath && This->pPidl) {
WCHAR buffer[MAX_PATH];
- hr = _SHGetPathFromIDListW(This->pPidl, buffer, MAX_PATH);
+ hr = SHELL_GetPathFromIDListW(This->pPidl, buffer, MAX_PATH);
if (SUCCEEDED(hr) && *buffer) {
This->sPath = (LPWSTR) HeapAlloc(GetProcessHeap(), 0, (lstrlenW(buffer)+1)*sizeof(WCHAR));
static HRESULT WINAPI IShellLinkW_fnSetPath(IShellLinkW * iface, LPCWSTR pszFile)
{
_ICOM_THIS_From_IShellLinkW(IShellLinkImpl, iface);
+ WCHAR buffer[MAX_PATH];
+ LPWSTR fname;
TRACE("(%p)->(path=%s)\n",This, debugstr_w(pszFile));
+ if (!GetFullPathNameW(pszFile, MAX_PATH, buffer, &fname))
+ return E_FAIL;
+
if (This->sPath)
HeapFree(GetProcessHeap(), 0, This->sPath);
+
This->sPath = HeapAlloc( GetProcessHeap(), 0,
- (lstrlenW( pszFile )+1) * sizeof (WCHAR) );
+ (lstrlenW( buffer )+1) * sizeof (WCHAR) );
if ( !This->sPath )
return E_OUTOFMEMORY;
- lstrcpyW( This->sPath, pszFile );
+ lstrcpyW( This->sPath, buffer );
This->bDirty = TRUE;
return S_OK;