Changelog: - fix typos in shelllink.c header comment and a struct comment - corrected SCF_UNICODE constant and use the value of SCF_UNC instead - implemented IShellLink_ConstructFromFile() to read shell links from files - call IShellLink_ConstructFromFile() in ISF_..._fnGetUIObjectOf() when being queried for IShellLink interface Index: shell32_main.h =================================================================== RCS file: /home/wine/wine/dlls/shell32/shell32_main.h,v retrieving revision 1.77 diff -u -p -d -r1.77 shell32_main.h --- shell32_main.h 16 Jan 2004 23:06:25 -0000 1.77 +++ shell32_main.h 17 Jan 2004 16:01:29 -0000 @@ -91,6 +91,7 @@ LPSHELLVIEW IShellView_Constructor(LPSHE HRESULT WINAPI IFSFolder_Constructor(IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv); HRESULT WINAPI IShellLink_Constructor(IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv); +HRESULT WINAPI IShellLink_ConstructFromFile(IUnknown * pUnkOuter, REFIID riid, LPCITEMIDLIST pidl, LPVOID * ppv); HRESULT WINAPI ISF_Desktop_Constructor(IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv); HRESULT WINAPI ISF_MyComputer_Constructor(IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv); HRESULT WINAPI IDropTargetHelper_Constructor (IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv); Index: shelllink.c =================================================================== RCS file: /home/wine/wine/dlls/shell32/shelllink.c,v retrieving revision 1.59 diff -u -p -d -r1.59 shelllink.c --- shelllink.c 17 Nov 2003 20:31:30 -0000 1.59 +++ shelllink.c 17 Jan 2004 16:01:29 -0000 @@ -19,7 +19,7 @@ * * 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 * */ @@ -53,6 +53,7 @@ #include "pidl.h" #include "shell32_main.h" #include "shlguid.h" +#include "shlwapi.h" WINE_DEFAULT_DEBUG_CHANNEL(shell); @@ -66,8 +67,7 @@ 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" @@ -128,7 +128,7 @@ typedef struct ICOM_VTABLE(IPersistFile)* lpvtblPersistFile; ICOM_VTABLE(IPersistStream)* lpvtblPersistStream; - /* data structures according to the informations in the lnk */ + /* data structures according to the informations in the link */ LPITEMIDLIST pPidl; WORD wHotKey; SYSTEMTIME time1; @@ -800,6 +800,134 @@ HRESULT WINAPI IShellLink_Constructor ( } 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; +} + +/************************************************************************** + * SHELL_ShellLink_UpdatePath + * update absolute path in sPath using relative path in sPathRel + */ +static HRESULT SHELL_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; + LPWSTR final; + + /* copy path without file name to buffer */ + while(*src) { + if (*src=='/' || *src=='\\') + last_slash = dest; + + *dest++ = *src++; + } + + lstrcpyW(last_slash? last_slash+1: buffer, 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); + + if (SUCCEEDED(hr)) { + *ppv = (IUnknown*) psl; + + /* + The following code is here, not in IPersistStream_fnLoad() because + to be able to convert the relative path into the absolute path, + we need to know the path of the shell link file. + */ + if (IsEqualIID(riid, &IID_IShellLinkW)) { + _ICOM_THIS_From_IShellLinkW(IShellLinkImpl, psl); + + hr = SHELL_ShellLink_UpdatePath(This->sPathRel, path, This->sWorkDir, &This->sPath); + } else { + ICOM_THIS(IShellLinkImpl, psl); + + hr = SHELL_ShellLink_UpdatePath(This->sPathRel, path, This->sWorkDir, &This->sPath); + } + } + } + + IPersistFile_Release(ppf); + } + + if (!*ppv) + IShellLinkW_Release(psl); + } + + return hr; } /************************************************************************** Index: shfldr_desktop.c =================================================================== RCS file: /home/wine/wine/dlls/shell32/shfldr_desktop.c,v retrieving revision 1.14 diff -u -p -d -r1.14 shfldr_desktop.c --- shfldr_desktop.c 30 Dec 2003 19:24:22 -0000 1.14 +++ shfldr_desktop.c 17 Jan 2004 16:01:29 -0000 @@ -430,6 +430,11 @@ static HRESULT WINAPI ISF_Desktop_fnGetU hr = S_OK; } else if (IsEqualIID (riid, &IID_IDropTarget) && (cidl >= 1)) { hr = IShellFolder_QueryInterface (iface, &IID_IDropTarget, (LPVOID *) & pObj); + } else if ((IsEqualIID(riid,&IID_IShellLinkW) || IsEqualIID(riid,&IID_IShellLinkA)) + && (cidl == 1)) { + pidl = ILCombine (This->pidlRoot, apidl[0]); + hr = IShellLink_ConstructFromFile(NULL, riid, pidl, (LPVOID*)&pObj); + SHFree (pidl); } else { hr = E_NOINTERFACE; } Index: shfldr_fs.c =================================================================== RCS file: /home/wine/wine/dlls/shell32/shfldr_fs.c,v retrieving revision 1.16 diff -u -p -d -r1.16 shfldr_fs.c --- shfldr_fs.c 17 Sep 2003 04:17:33 -0000 1.16 +++ shfldr_fs.c 17 Jan 2004 16:01:30 -0000 @@ -574,6 +574,11 @@ IShellFolder_fnGetUIObjectOf (IShellFold hr = S_OK; } else if (IsEqualIID (riid, &IID_IDropTarget) && (cidl >= 1)) { hr = IShellFolder_QueryInterface (iface, &IID_IDropTarget, (LPVOID *) & pObj); + } else if ((IsEqualIID(riid,&IID_IShellLinkW) || IsEqualIID(riid,&IID_IShellLinkA)) + && (cidl == 1)) { + pidl = ILCombine (This->pidlRoot, apidl[0]); + hr = IShellLink_ConstructFromFile(NULL, riid, pidl, (LPVOID*)&pObj); + SHFree (pidl); } else { hr = E_NOINTERFACE; } Index: shfldr_mycomp.c =================================================================== RCS file: /home/wine/wine/dlls/shell32/shfldr_mycomp.c,v retrieving revision 1.11 diff -u -p -d -r1.11 shfldr_mycomp.c --- shfldr_mycomp.c 30 Dec 2003 19:24:22 -0000 1.11 +++ shfldr_mycomp.c 17 Jan 2004 16:01:30 -0000 @@ -409,6 +409,11 @@ ISF_MyComputer_fnGetUIObjectOf (IShellFo hr = S_OK; } else if (IsEqualIID (riid, &IID_IDropTarget) && (cidl >= 1)) { hr = IShellFolder_QueryInterface (iface, &IID_IDropTarget, (LPVOID *) & pObj); + } else if ((IsEqualIID(riid,&IID_IShellLinkW) || IsEqualIID(riid,&IID_IShellLinkA)) + && (cidl == 1)) { + pidl = ILCombine (This->pidlRoot, apidl[0]); + hr = IShellLink_ConstructFromFile(NULL, riid, pidl, (LPVOID*)&pObj); + SHFree (pidl); } else { hr = E_NOINTERFACE; }