[SHELL32]
[reactos.git] / reactos / dll / win32 / shell32 / shelllink.c
index 1c1c37c..ae159cd 100644 (file)
  *   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 "prsht.h"
-#include "initguid.h"
-#include "shresdef.h"
+#include <precomp.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"
@@ -125,6 +97,7 @@ static const IShellLinkDataListVtbl dlvt;
 static const IShellExtInitVtbl eivt;
 static const IContextMenuVtbl cmvt;
 static const IObjectWithSiteVtbl owsvt;
+static const IShellPropSheetExtVtbl pse;
 
 /* IShellLink Implementation */
 
@@ -138,6 +111,7 @@ typedef struct
        const IShellExtInitVtbl *lpvtblShellExtInit;
        const IContextMenuVtbl *lpvtblContextMenu;
        const IObjectWithSiteVtbl *lpvtblObjectWithSite;
+       const IShellPropSheetExtVtbl * lpvtblPropSheetExt;
 
        LONG            ref;
 
@@ -163,49 +137,54 @@ typedef struct
     BOOL          bRunAs;
        BOOL          bDirty;
         INT           iIdOpen;  /* id of the "Open" entry in the context menu */
-        INT           iIdProperties; /* id of the "Properties" entry in the context menu */
        IUnknown      *site;
-} IShellLinkImpl;
+} IShellLinkImpl, *LPIShellLinkImpl;
 
-static inline IShellLinkImpl *impl_from_IShellLinkW( IShellLinkW *iface )
+static LPIShellLinkImpl __inline impl_from_IShellLinkW( IShellLinkW *iface )
 {
     return (IShellLinkImpl *)((char*)iface - FIELD_OFFSET(IShellLinkImpl, lpvtblw));
 }
 
-static inline IShellLinkImpl *impl_from_IPersistFile( IPersistFile *iface )
+static LPIShellLinkImpl __inline impl_from_IPersistFile( IPersistFile *iface )
 {
     return (IShellLinkImpl *)((char*)iface - FIELD_OFFSET(IShellLinkImpl, lpvtblPersistFile));
 }
 
-static inline IShellLinkImpl *impl_from_IPersistStream( IPersistStream *iface )
+static LPIShellLinkImpl __inline impl_from_IPersistStream( IPersistStream *iface )
 {
     return (IShellLinkImpl *)((char*)iface - FIELD_OFFSET(IShellLinkImpl, lpvtblPersistStream));
 }
 
-static inline IShellLinkImpl *impl_from_IShellLinkDataList( IShellLinkDataList *iface )
+static LPIShellLinkImpl __inline impl_from_IShellLinkDataList( IShellLinkDataList *iface )
 {
     return (IShellLinkImpl *)((char*)iface - FIELD_OFFSET(IShellLinkImpl, lpvtblShellLinkDataList));
 }
 
-static inline IShellLinkImpl *impl_from_IShellExtInit( IShellExtInit *iface )
+static LPIShellLinkImpl __inline impl_from_IShellExtInit( IShellExtInit *iface )
 {
     return (IShellLinkImpl *)((char*)iface - FIELD_OFFSET(IShellLinkImpl, lpvtblShellExtInit));
 }
 
-static inline IShellLinkImpl *impl_from_IContextMenu( IContextMenu *iface )
+static LPIShellLinkImpl __inline impl_from_IContextMenu( IContextMenu *iface )
 {
     return (IShellLinkImpl *)((char*)iface - FIELD_OFFSET(IShellLinkImpl, lpvtblContextMenu));
 }
 
-static inline IShellLinkImpl *impl_from_IObjectWithSite( IObjectWithSite *iface )
+static LPIShellLinkImpl __inline impl_from_IObjectWithSite( IObjectWithSite *iface )
 {
     return (IShellLinkImpl *)((char*)iface - FIELD_OFFSET(IShellLinkImpl, lpvtblObjectWithSite));
 }
 
+static LPIShellLinkImpl __inline impl_from_IShellPropSheetExt( IShellPropSheetExt *iface )
+{
+    return (IShellLinkImpl *)((char*)iface - FIELD_OFFSET(IShellLinkImpl, lpvtblPropSheetExt));
+}
+
+
 static HRESULT ShellLink_UpdatePath(LPCWSTR sPathRel, LPCWSTR path, LPCWSTR sWorkDir, LPWSTR* psPath);
 
 /* strdup on the process heap */
-static inline LPWSTR HEAP_strdupAtoW( HANDLE heap, DWORD flags, LPCSTR str)
+static LPWSTR __inline 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) );
@@ -215,13 +194,13 @@ static inline LPWSTR HEAP_strdupAtoW( HANDLE heap, DWORD flags, LPCSTR str)
     return p;
 }
 
-static inline LPWSTR strdupW( LPCWSTR src )
+static LPWSTR __inline strdupW( LPCWSTR src )
 {
     LPWSTR dest;
     if (!src) return NULL;
-    dest = HeapAlloc( GetProcessHeap(), 0, (lstrlenW(src)+1)*sizeof(WCHAR) );
+    dest = HeapAlloc( GetProcessHeap(), 0, (wcslen(src)+1)*sizeof(WCHAR) );
     if (dest)
-        lstrcpyW(dest, src);
+        wcscpy(dest, src);
     return dest;
 }
 
@@ -266,6 +245,10 @@ static HRESULT ShellLink_QueryInterface( IShellLinkImpl *This, REFIID riid,  LPV
     {
         *ppvObj = &(This->lpvtblObjectWithSite);
     }
+    else if(IsEqualIID(riid, &IID_IShellPropSheetExt))
+    {
+        *ppvObj = &(This->lpvtblPropSheetExt);
+    }
 
     if(*ppvObj)
     {
@@ -316,7 +299,7 @@ static ULONG ShellLink_Release( IShellLinkImpl *This )
     if (This->pPidl)
         ILFree(This->pPidl);
 
-    LocalFree((HANDLE)This);
+    LocalFree(This);
 
     return 0;
 }
@@ -325,7 +308,7 @@ static HRESULT ShellLink_GetClassID( IShellLinkImpl *This, CLSID *pclsid )
 {
     TRACE("%p %p\n", This, pclsid);
 
-    memcpy( pclsid, &CLSID_ShellLink, sizeof (CLSID) );
+    *pclsid = CLSID_ShellLink;
     return S_OK;
 }
 
@@ -392,7 +375,7 @@ static HRESULT WINAPI IPersistFile_fnLoad(IPersistFile* iface, LPCOLESTR pszFile
         if( SUCCEEDED( r ) )
         {
             HeapFree(GetProcessHeap(), 0, This->sLinkPath);
-            This->sLinkPath = _wcsdup(pszFileName);
+            This->sLinkPath = strdupW(pszFileName);
             r = IPersistStream_Load(StreamThis, stm);
             ShellLink_UpdatePath(This->sPathRel, pszFileName, This->sWorkDir, &This->sPath);
             IStream_Release( stm );
@@ -413,12 +396,12 @@ static BOOL StartLinkProcessor( LPCOLESTR szLink )
     PROCESS_INFORMATION pi;
     BOOL ret;
 
-    len = sizeof(szFormat) + lstrlenW( szLink ) * sizeof(WCHAR);
+    len = sizeof(szFormat) + wcslen( szLink ) * sizeof(WCHAR);
     buffer = HeapAlloc( GetProcessHeap(), 0, len );
     if( !buffer )
         return FALSE;
 
-    wsprintfW( buffer, szFormat, szLink );
+    swprintf( buffer, szFormat, szLink );
 
     TRACE("starting %s\n",debugstr_w(buffer));
 
@@ -592,20 +575,20 @@ static HRESULT Stream_LoadString( IStream* stm, BOOL unicode, LPWSTR *pstr )
     /* convert to unicode if necessary */
     if( !unicode )
     {
-        count = MultiByteToWideChar( CP_ACP, 0, (LPSTR) temp, len, NULL, 0 );
+        count = MultiByteToWideChar( CP_ACP, 0, temp, len, NULL, 0 );
         str = HeapAlloc( GetProcessHeap(), 0, (count+1)*sizeof (WCHAR) );
         if( !str )
         {
             HeapFree( GetProcessHeap(), 0, temp );
             return E_OUTOFMEMORY;
         }
-        MultiByteToWideChar( CP_ACP, 0, (LPSTR) temp, len, str, count );
+        MultiByteToWideChar( CP_ACP, 0, temp, len, str, count );
         HeapFree( GetProcessHeap(), 0, temp );
     }
     else
     {
         count /= 2;
-        str = (LPWSTR) temp;
+        str = temp;
     }
     str[count] = 0;
 
@@ -644,7 +627,7 @@ static HRESULT Stream_ReadChunk( IStream* stm, LPVOID *data )
 
     TRACE("Read %d bytes\n",chunk->size);
 
-    *data = (LPVOID) chunk;
+    *data = chunk;
 
     return S_OK;
 }
@@ -693,7 +676,7 @@ static HRESULT Stream_LoadLocation( IStream *stm,
     char *p = NULL;
     LOCATION_INFO *loc;
     HRESULT r;
-    int n;
+    DWORD n;
 
     r = Stream_ReadChunk( stm, (LPVOID*) &p );
     if( FAILED(r) )
@@ -707,7 +690,7 @@ static HRESULT Stream_LoadLocation( IStream *stm,
     }
 
     /* if there's valid local volume information, load it */
-    if( loc->dwVolTableOfs && 
+    if( loc->dwVolTableOfs &&
        ((loc->dwVolTableOfs + sizeof(LOCAL_VOLUME_INFO)) <= loc->dwTotalSize) )
     {
         LOCAL_VOLUME_INFO *volume_info;
@@ -748,7 +731,7 @@ static HRESULT Stream_LoadAdvertiseInfo( IStream* stm, LPWSTR *str )
     ULONG count;
     HRESULT r;
     EXP_DARWIN_LINK buffer;
-    
+
     TRACE("%p\n",stm);
 
     r = IStream_Read( stm, &buffer.dbh.cbSize, sizeof (DWORD), &count );
@@ -778,9 +761,9 @@ static HRESULT Stream_LoadAdvertiseInfo( IStream* stm, LPWSTR *str )
         return E_FAIL;
     }
 
-    *str = HeapAlloc( GetProcessHeap(), 0, 
-                     (lstrlenW(buffer.szwDarwinID)+1) * sizeof(WCHAR) );
-    lstrcpyW( *str, buffer.szwDarwinID );
+    *str = HeapAlloc( GetProcessHeap(), 0,
+                     (wcslen(buffer.szwDarwinID)+1) * sizeof(WCHAR) );
+    wcscpy( *str, buffer.szwDarwinID );
 
     return S_OK;
 }
@@ -837,7 +820,7 @@ static HRESULT WINAPI IPersistStream_fnLoad(
     This->sProduct = NULL;
     HeapFree(GetProcessHeap(), 0, This->sComponent);
     This->sComponent = NULL;
-        
+
     This->wHotKey = (WORD)hdr.wHotKey;
     This->iIcoNdx = hdr.nIcon;
     FileTimeToSystemTime (&hdr.Time1, &This->time1);
@@ -913,6 +896,7 @@ static HRESULT WINAPI IPersistStream_fnLoad(
     if( FAILED( r ) )
         goto end;
 
+#if (NTDDI_VERSION < NTDDI_LONGHORN)
     if( hdr.dwFlags & SLDF_HAS_LOGO3ID )
     {
         r = Stream_LoadAdvertiseInfo( stm, &This->sProduct );
@@ -920,6 +904,7 @@ static HRESULT WINAPI IPersistStream_fnLoad(
     }
     if( FAILED( r ) )
         goto end;
+#endif
 
     if( hdr.dwFlags & SLDF_HAS_DARWINID )
     {
@@ -954,12 +939,12 @@ end:
 /************************************************************************
  * Stream_WriteString
  *
- * Helper function for IPersistStream_Save. Writes a unicode string 
+ * 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;
+    USHORT len = wcslen( str ) + 1;
     DWORD count;
     HRESULT r;
 
@@ -993,6 +978,7 @@ static HRESULT Stream_WriteLocationInfo( IStream* stm, LPCWSTR path,
     LOCATION_INFO *loc;
     LPSTR szLabel, szPath, szFinalPath;
     ULONG count = 0;
+    HRESULT hr;
 
     TRACE("%p %s %p\n", stm, debugstr_w(path), volume);
 
@@ -1034,13 +1020,16 @@ static HRESULT Stream_WriteLocationInfo( IStream* stm, LPCWSTR path,
                          szPath, path_size, NULL, NULL );
     szFinalPath[0] = 0;
 
-    return IStream_Write( stm, loc, total_size, &count );
+    hr = IStream_Write( stm, loc, total_size, &count );
+    HeapFree(GetProcessHeap(), 0, loc);
+
+    return hr;
 }
 
 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;
@@ -1054,7 +1043,7 @@ static HRESULT Stream_WriteAdvertiseInfo( IStream* stm, LPCWSTR string, DWORD ma
 {
     EXP_DARWIN_LINK *buffer;
     ULONG count;
-    
+
     TRACE("%p\n",stm);
 
     buffer = shelllink_build_darwinid( string, magic );
@@ -1084,7 +1073,7 @@ static HRESULT WINAPI IPersistStream_fnSave(
     memset(&header, 0, sizeof(header));
     header.dwSize = sizeof(header);
     header.fStartup = This->iShowCmd;
-    memcpy(&header.MagicGuid, &CLSID_ShellLink, sizeof(header.MagicGuid) );
+    header.MagicGuid = CLSID_ShellLink;
 
     header.wHotKey = This->wHotKey;
     header.nIcon = This->iIcoNdx;
@@ -1101,8 +1090,10 @@ static HRESULT WINAPI IPersistStream_fnSave(
         header.dwFlags |= SLDF_HAS_ARGS;
     if( This->sIcoPath )
         header.dwFlags |= SLDF_HAS_ICONLOCATION;
+#if (NTDDI_VERSION < NTDDI_LONGHORN)
     if( This->sProduct )
         header.dwFlags |= SLDF_HAS_LOGO3ID;
+#endif
     if( This->sComponent )
         header.dwFlags |= SLDF_HAS_DARWINID;
     if( This->bRunAs )
@@ -1218,6 +1209,7 @@ HRESULT WINAPI IShellLink_Constructor( IUnknown *pUnkOuter,
        sl->lpvtblShellExtInit = &eivt;
        sl->lpvtblContextMenu = &cmvt;
        sl->lpvtblObjectWithSite = &owsvt;
+       sl->lpvtblPropSheetExt = &pse;
        sl->iShowCmd = SW_SHOWNORMAL;
        sl->bDirty = FALSE;
        sl->iIdOpen = -1;
@@ -1257,34 +1249,34 @@ static HRESULT ShellLink_UpdatePath(LPCWSTR sPathRel, LPCWSTR path, LPCWSTR sWor
         GetFullPathNameW( path, MAX_PATH*2, buffer, &final );
         if( !final )
             final = buffer;
-       lstrcpyW(final, sPathRel);
+       wcscpy(final, sPathRel);
 
        *abs_path = '\0';
 
        if (SHELL_ExistsFileW(buffer)) {
            if (!GetFullPathNameW(buffer, MAX_PATH, abs_path, &final))
-               lstrcpyW(abs_path, buffer);
+               wcscpy(abs_path, buffer);
        } else {
            /* try if [working directory] + [relative path] finds an existing file */
            if (sWorkDir) {
-               lstrcpyW(buffer, sWorkDir);
-               lstrcpyW(PathAddBackslashW(buffer), sPathRel);
+               wcscpy(buffer, sWorkDir);
+               wcscpy(PathAddBackslashW(buffer), sPathRel);
 
                if (SHELL_ExistsFileW(buffer))
                    if (!GetFullPathNameW(buffer, MAX_PATH, abs_path, &final))
-                       lstrcpyW(abs_path, buffer);
+                       wcscpy(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);
+           wcscpy(abs_path, sPathRel);
 
-       *psPath = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(abs_path)+1)*sizeof(WCHAR));
+       *psPath = HeapAlloc(GetProcessHeap(), 0, (wcslen(abs_path)+1)*sizeof(WCHAR));
        if (!*psPath)
            return E_OUTOFMEMORY;
 
-       lstrcpyW(*psPath, abs_path);
+       wcscpy(*psPath, abs_path);
     }
 
     return S_OK;
@@ -1310,13 +1302,13 @@ HRESULT WINAPI IShellLink_ConstructFromFile( IUnknown* pUnkOuter, REFIID riid,
        if (SUCCEEDED(hr)) {
            WCHAR path[MAX_PATH];
 
-           if (SHGetPathFromIDListW(pidl, path)) 
+           if (SHGetPathFromIDListW(pidl, path))
                hr = IPersistFile_Load(ppf, path, 0);
             else
                 hr = E_FAIL;
 
            if (SUCCEEDED(hr))
-               *ppv = (IUnknown*) psl;
+               *ppv = psl;
 
            IPersistFile_Release(ppf);
        }
@@ -1547,7 +1539,7 @@ static HRESULT SHELL_PidlGeticonLocationA(IShellFolder* psf, LPCITEMIDLIST pidl,
     if (SUCCEEDED(hr)) {
        IExtractIconA* pei;
 
-       hr = IShellFolder_GetUIObjectOf(psf, 0, 1, (LPCITEMIDLIST*)&pidlLast, &IID_IExtractIconA, NULL, (LPVOID*)&pei);
+       hr = IShellFolder_GetUIObjectOf(psf, 0, 1, &pidlLast, &IID_IExtractIconA, NULL, (LPVOID*)&pei);
 
        if (SUCCEEDED(hr)) {
            hr = IExtractIconA_GetIconLocation(pei, 0, pszIconPath, MAX_PATH, piIcon, NULL);
@@ -1659,8 +1651,10 @@ static HRESULT WINAPI IShellLinkA_fnSetPath(IShellLinkA * iface, LPCSTR pszFile)
 
     TRACE("(%p)->(path=%s)\n",This, pszFile);
 
+    if (!pszFile) return E_INVALIDARG;
+
     str = HEAP_strdupAtoW(GetProcessHeap(), 0, pszFile);
-    if( !str ) 
+    if( !str )
         return E_OUTOFMEMORY;
 
     r = IShellLinkW_SetPath((IShellLinkW*)&(This->lpvtblw), str);
@@ -1800,11 +1794,11 @@ static HRESULT WINAPI IShellLinkW_fnSetDescription(IShellLinkW * iface, LPCWSTR
 
     HeapFree(GetProcessHeap(), 0, This->sDescription);
     This->sDescription = HeapAlloc( GetProcessHeap(), 0,
-                                    (lstrlenW( pszName )+1)*sizeof(WCHAR) );
+                                    (wcslen( pszName )+1)*sizeof(WCHAR) );
     if ( !This->sDescription )
         return E_OUTOFMEMORY;
 
-    lstrcpyW( This->sDescription, pszName );
+    wcscpy( This->sDescription, pszName );
     This->bDirty = TRUE;
 
     return S_OK;
@@ -1832,10 +1826,10 @@ static HRESULT WINAPI IShellLinkW_fnSetWorkingDirectory(IShellLinkW * iface, LPC
 
     HeapFree(GetProcessHeap(), 0, This->sWorkDir);
     This->sWorkDir = HeapAlloc( GetProcessHeap(), 0,
-                                (lstrlenW( pszDir )+1)*sizeof (WCHAR) );
+                                (wcslen( pszDir )+1)*sizeof (WCHAR) );
     if ( !This->sWorkDir )
         return E_OUTOFMEMORY;
-    lstrcpyW( This->sWorkDir, pszDir );
+    wcscpy( This->sWorkDir, pszDir );
     This->bDirty = TRUE;
 
     return S_OK;
@@ -1863,10 +1857,10 @@ static HRESULT WINAPI IShellLinkW_fnSetArguments(IShellLinkW * iface, LPCWSTR ps
 
     HeapFree(GetProcessHeap(), 0, This->sArgs);
     This->sArgs = HeapAlloc( GetProcessHeap(), 0,
-                             (lstrlenW( pszArgs )+1)*sizeof (WCHAR) );
+                             (wcslen( pszArgs )+1)*sizeof (WCHAR) );
     if ( !This->sArgs )
         return E_OUTOFMEMORY;
-    lstrcpyW( This->sArgs, pszArgs );
+    wcscpy( This->sArgs, pszArgs );
     This->bDirty = TRUE;
 
     return S_OK;
@@ -1920,16 +1914,17 @@ static HRESULT SHELL_PidlGeticonLocationW(IShellFolder* psf, LPCITEMIDLIST pidl,
                                           LPWSTR pszIconPath, int cchIconPath, int* piIcon)
 {
     LPCITEMIDLIST pidlLast;
+    UINT wFlags;
 
     HRESULT hr = SHBindToParent(pidl, &IID_IShellFolder, (LPVOID*)&psf, &pidlLast);
 
     if (SUCCEEDED(hr)) {
        IExtractIconW* pei;
 
-       hr = IShellFolder_GetUIObjectOf(psf, 0, 1, (LPCITEMIDLIST*)&pidlLast, &IID_IExtractIconW, NULL, (LPVOID*)&pei);
+       hr = IShellFolder_GetUIObjectOf(psf, 0, 1, &pidlLast, &IID_IExtractIconW, NULL, (LPVOID*)&pei);
 
        if (SUCCEEDED(hr)) {
-           hr = IExtractIconW_GetIconLocation(pei, 0, pszIconPath, MAX_PATH, piIcon, NULL);
+           hr = IExtractIconW_GetIconLocation(pei, 0, pszIconPath, MAX_PATH, piIcon, &wFlags);
 
            IExtractIconW_Release(pei);
        }
@@ -1999,10 +1994,10 @@ static HRESULT WINAPI IShellLinkW_fnSetIconLocation(IShellLinkW * iface, LPCWSTR
 
     HeapFree(GetProcessHeap(), 0, This->sIcoPath);
     This->sIcoPath = HeapAlloc( GetProcessHeap(), 0,
-                                (lstrlenW( pszIconPath )+1)*sizeof (WCHAR) );
+                                (wcslen( pszIconPath )+1)*sizeof (WCHAR) );
     if ( !This->sIcoPath )
         return E_OUTOFMEMORY;
-    lstrcpyW( This->sIcoPath, pszIconPath );
+    wcscpy( This->sIcoPath, pszIconPath );
 
     This->iIcoNdx = iIcon;
     This->bDirty = TRUE;
@@ -2018,10 +2013,10 @@ static HRESULT WINAPI IShellLinkW_fnSetRelativePath(IShellLinkW * iface, LPCWSTR
 
     HeapFree(GetProcessHeap(), 0, This->sPathRel);
     This->sPathRel = HeapAlloc( GetProcessHeap(), 0,
-                                (lstrlenW( pszPathRel )+1) * sizeof (WCHAR) );
+                                (wcslen( pszPathRel )+1) * sizeof (WCHAR) );
     if ( !This->sPathRel )
         return E_OUTOFMEMORY;
-    lstrcpyW( This->sPathRel, pszPathRel );
+    wcscpy( This->sPathRel, pszPathRel );
     This->bDirty = TRUE;
 
     return ShellLink_UpdatePath(This->sPathRel, This->sPath, This->sWorkDir, &This->sPath);
@@ -2044,11 +2039,11 @@ static HRESULT WINAPI IShellLinkW_fnResolve(IShellLinkW * iface, HWND hwnd, DWOR
        bSuccess = SHGetPathFromIDListW(This->pPidl, buffer);
 
        if (bSuccess && *buffer) {
-           This->sPath = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(buffer)+1)*sizeof(WCHAR));
+           This->sPath = HeapAlloc(GetProcessHeap(), 0, (wcslen(buffer)+1)*sizeof(WCHAR));
            if (!This->sPath)
                return E_OUTOFMEMORY;
 
-           lstrcpyW(This->sPath, buffer);
+           wcscpy(This->sPath, buffer);
 
            This->bDirty = TRUE;
        } else
@@ -2056,11 +2051,11 @@ static HRESULT WINAPI IShellLinkW_fnResolve(IShellLinkW * iface, HWND hwnd, DWOR
     }
 
     if (!This->sIcoPath && This->sPath) {
-       This->sIcoPath = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(This->sPath)+1)*sizeof(WCHAR));
+       This->sIcoPath = HeapAlloc(GetProcessHeap(), 0, (wcslen(This->sPath)+1)*sizeof(WCHAR));
        if (!This->sIcoPath)
            return E_OUTOFMEMORY;
 
-       lstrcpyW(This->sIcoPath, This->sPath);
+       wcscpy(This->sIcoPath, This->sPath);
        This->iIcoNdx = 0;
 
        This->bDirty = TRUE;
@@ -2078,7 +2073,7 @@ static LPWSTR ShellLink_GetAdvertisedArg(LPCWSTR str)
     if( !str )
         return NULL;
 
-    p = strchrW( str, ':' );
+    p = wcschr( str, ':' );
     if( !p )
         return NULL;
     len = p - str;
@@ -2110,7 +2105,7 @@ static HRESULT ShellLink_SetAdvertiseInfo(IShellLinkImpl *This, LPCWSTR str)
         str += 2;
 
         /* there must be a colon straight after a guid */
-        p = strchrW( str, ':' );
+        p = wcschr( str, ':' );
         if( !p )
             return E_FAIL;
         len = p - str;
@@ -2134,7 +2129,7 @@ static HRESULT ShellLink_SetAdvertiseInfo(IShellLinkImpl *This, LPCWSTR str)
             return E_FAIL;
 
         /* skip to the next field */
-        str = strchrW( str, ':' );
+        str = wcschr( str, ':' );
         if( !str )
             return E_FAIL;
     }
@@ -2176,8 +2171,10 @@ static HRESULT WINAPI IShellLinkW_fnSetPath(IShellLinkW * iface, LPCWSTR pszFile
 
     TRACE("(%p)->(path=%s)\n",This, debugstr_w(pszFile));
 
+    if (!pszFile) return E_INVALIDARG;
+
     /* quotes at the ends of the string are stripped */
-    len = lstrlenW(pszFile);
+    len = wcslen(pszFile);
     if (pszFile[0] == '"' && pszFile[len-1] == '"')
     {
         unquoted = strdupW(pszFile);
@@ -2186,8 +2183,11 @@ static HRESULT WINAPI IShellLinkW_fnSetPath(IShellLinkW * iface, LPCWSTR pszFile
     }
 
     /* any other quote marks are invalid */
-    if (strchrW(pszFile, '"'))
+    if (wcschr(pszFile, '"'))
+    {
+        HeapFree(GetProcessHeap(), 0, unquoted);
         return S_FALSE;
+    }
 
     HeapFree(GetProcessHeap(), 0, This->sPath);
     This->sPath = NULL;
@@ -2213,11 +2213,11 @@ static HRESULT WINAPI IShellLinkW_fnSetPath(IShellLinkW * iface, LPCWSTR pszFile
         ShellLink_GetVolumeInfo(buffer, &This->volume);
 
         This->sPath = HeapAlloc( GetProcessHeap(), 0,
-                             (lstrlenW( buffer )+1) * sizeof (WCHAR) );
+                             (wcslen( buffer )+1) * sizeof (WCHAR) );
         if (!This->sPath)
             return E_OUTOFMEMORY;
 
-        lstrcpyW(This->sPath, buffer);
+        wcscpy(This->sPath, buffer);
     }
     This->bDirty = TRUE;
     HeapFree(GetProcessHeap(), 0, unquoted);
@@ -2335,8 +2335,10 @@ ShellLink_GetFlags( IShellLinkDataList* iface, DWORD* pdwFlags )
         flags |= SLDF_HAS_DARWINID;
     if (This->sIcoPath)
         flags |= SLDF_HAS_ICONLOCATION;
+#if (NTDDI_VERSION < NTDDI_LONGHORN)
     if (This->sProduct)
         flags |= SLDF_HAS_LOGO3ID;
+#endif
     if (This->pPidl)
         flags |= SLDF_HAS_ID_LIST;
 
@@ -2470,8 +2472,7 @@ ShellLink_QueryContextMenu( IContextMenu* iface, HMENU hmenu, UINT indexMenu,
                             UINT idCmdFirst, UINT idCmdLast, UINT uFlags )
 {
     IShellLinkImpl *This = impl_from_IContextMenu(iface);
-    static WCHAR szOpen[] = { 'O','p','e','n',0 };
-    static WCHAR szProperties[] = { 'P','r','o','p','e','r','t','i','e','s',0 };
+    WCHAR szOpen[20];
     MENUITEMINFOW mii;
     int id = 1;
 
@@ -2481,29 +2482,22 @@ ShellLink_QueryContextMenu( IContextMenu* iface, HMENU hmenu, UINT indexMenu,
     if ( !hmenu )
         return E_INVALIDARG;
 
+    if (!LoadStringW(shell32_hInstance, IDS_OPEN_VERB, szOpen, sizeof(szOpen)/sizeof(WCHAR)))
+        szOpen[0] = L'\0';
+    else
+        szOpen[(sizeof(szOpen)/sizeof(WCHAR))-1] = L'\0';
+
     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.cch = wcslen( 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;
-
-    mii.fState = MFS_ENABLED;
-    mii.dwTypeData = (LPWSTR)szProperties;
-    mii.cch = strlenW( mii.dwTypeData );
-    mii.wID = idCmdFirst + id++;
-    if (!InsertMenuItemW( hmenu, idCmdLast, TRUE, &mii ))
-    {
-        TRACE("ShellLink_QueryContextMenu failed to insert item properties");
-        return E_FAIL;
-    }
-    This->iIdProperties = 1;
-    id++;
+    This->iIdOpen = 1;
 
     return MAKE_HRESULT( SEVERITY_SUCCESS, 0, id );
 }
@@ -2532,7 +2526,7 @@ shelllink_get_msi_component_path( LPWSTR component )
     return path;
 }
 
-INT_PTR CALLBACK ExtendedShortcutProc(      
+INT_PTR CALLBACK ExtendedShortcutProc(
     HWND hwndDlg,
     UINT uMsg,
     WPARAM wParam,
@@ -2581,9 +2575,9 @@ INT_PTR CALLBACK ExtendedShortcutProc(
  * dialog proc of the shortcut property dialog
  */
 
-INT_PTR 
-CALLBACK 
-SH_ShellLinkDlgProc(   
+INT_PTR
+CALLBACK
+SH_ShellLinkDlgProc(
     HWND hwndDlg,
     UINT uMsg,
     WPARAM wParam,
@@ -2607,7 +2601,7 @@ SH_ShellLinkDlgProc(
         ppsp = (LPPROPSHEETPAGEW)lParam;
         if (ppsp == NULL)
             break;
-     
+
         TRACE("ShellLink_DlgProc (WM_INITDIALOG hwnd %p lParam %p ppsplParam %x)\n",hwndDlg, lParam, ppsp->lParam);
 
         This = (IShellLinkImpl *)ppsp->lParam;
@@ -2632,7 +2626,7 @@ SH_ShellLinkDlgProc(
             SendMessageW( hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)This->sDescription );
         return TRUE;
     case WM_NOTIFY:
-       lppsn = (LPPSHNOTIFY) lParam; 
+       lppsn = (LPPSHNOTIFY) lParam;
        if ( lppsn->hdr.code == PSN_APPLY )
        {
             /* set working directory */
@@ -2646,15 +2640,15 @@ SH_ShellLinkDlgProc(
             {
                 //FIXME load localized error msg
                 MessageBoxW( hwndDlg, L"file not existing", szBuffer, MB_OK );
-                SetWindowLong( hwndDlg, DWL_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE );
+                SetWindowLongPtr( hwndDlg, DWL_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE );
                 return TRUE;
             }
             ptr = wcsrchr(szBuffer, L'.');
-            if (ptr && !wcsnicmp(ptr, L".lnk", 4))
+            if (ptr && !_wcsnicmp(ptr, L".lnk", 4))
             {
                 // FIXME load localized error msg
                 MessageBoxW( hwndDlg, L"You cannot create a link to a shortcut", L"Error", MB_ICONERROR );
-                SetWindowLong( hwndDlg, DWL_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE );
+                SetWindowLongPtr( hwndDlg, DWL_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE );
                 return TRUE;
             }
 
@@ -2662,7 +2656,7 @@ SH_ShellLinkDlgProc(
 
             TRACE("This %p sLinkPath %S\n", This, This->sLinkPath);
             IPersistFile_fnSave( (IPersistFile*)&This->lpvtblPersistFile, This->sLinkPath, TRUE );
-            SetWindowLong( hwndDlg, DWL_MSGRESULT, PSNRET_NOERROR );
+            SetWindowLongPtr( hwndDlg, DWL_MSGRESULT, PSNRET_NOERROR );
             return TRUE;
        }
        break;
@@ -2670,12 +2664,18 @@ SH_ShellLinkDlgProc(
        switch(LOWORD(wParam))
        {
            case 14020:
-               /// 
+               ///
                /// FIXME
                /// open target directory
                ///
                return TRUE;
            case 14021:
+               if (This->sIcoPath)
+                    wcscpy(szBuffer, This->sIcoPath);
+               else
+                    wcscpy(szBuffer, This->sPath);
+
+               IconIndex = This->iIcoNdx;
                if (PickIconDlg(hwndDlg, szBuffer, MAX_PATH, &IconIndex))
                {
                     IShellLinkW_fnSetIconLocation((IShellLinkW*)&This->lpvtblw, szBuffer, IconIndex);
@@ -2710,60 +2710,74 @@ SH_ShellLinkDlgProc(
 }
 
 /**************************************************************************
- * ShellLink_ShortcutDialog [Internal]
- *
- * creates a shortcut property dialog
+ * ShellLink_IShellPropSheetExt interface
  */
 
 static HRESULT WINAPI
-ShellLink_ShowProperties( IShellLinkImpl *This )
+ ShellLink_IShellPropSheetExt_QueryInterface( IShellPropSheetExt* iface, REFIID riid, void** ppvObject )
 {
-    PROPSHEETHEADERW pinfo;
-    HPROPSHEETPAGE hppages[MAX_PROPERTY_SHEET_PAGE];
-    HPROPSHEETPAGE hpage;
-    UINT numpages = 0;
+    IShellLinkImpl *This = impl_from_IShellPropSheetExt(iface);
+    return ShellLink_QueryInterface( This, riid, ppvObject );
+}
 
-    TRACE("ShellLink_ShortcutDialog entered\n");
+static ULONG WINAPI
+ ShellLink_IShellPropSheetExt_AddRef( IShellPropSheetExt* iface )
+{
+    IShellLinkImpl *This = impl_from_IShellPropSheetExt(iface);
+    return ShellLink_AddRef( This );
+}
 
-    memset(hppages, 0x0, sizeof(HPROPSHEETPAGE) * MAX_PROPERTY_SHEET_PAGE);
+static ULONG WINAPI
+ ShellLink_IShellPropSheetExt_Release( IShellPropSheetExt* iface )
+{
+    IShellLinkImpl *This = impl_from_IShellPropSheetExt(iface);
+    return ShellLink_Release( This );
+}
 
-    hpage = SH_CreatePropertySheetPage("SHELL_FILE_GENERAL_DLG", SH_FileGeneralDlgProc, (LPARAM)This->sLinkPath, NULL);
-    if ( hpage == NULL )
-        return E_FAIL;
-    else
-        hppages[numpages++] = hpage;
+static HRESULT WINAPI
+ ShellLink_IShellPropSheetExt_AddPages( IShellPropSheetExt *iface, LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam)
+{
+    HPROPSHEETPAGE hPage;
+    BOOL bRet;
+    IShellLinkImpl *This = impl_from_IShellPropSheetExt(iface);
 
-       hpage = SH_CreatePropertySheetPage("SHELL_GENERAL_SHORTCUT_DLG", SH_ShellLinkDlgProc, (LPARAM)This, NULL);
-       if ( hpage == NULL )
+    hPage = SH_CreatePropertySheetPage("SHELL_GENERAL_SHORTCUT_DLG", SH_ShellLinkDlgProc, (LPARAM)This, NULL);
+    if (hPage == NULL)
     {
-        ERR("SH_CreatePropertySheetPage failed\n");
-        DestroyPropertySheetPage(hppages[0]);
-        return E_FAIL;
-       }
-    hppages[numpages++] = hpage;
-
-    ///FIXME
-    /// load extensions
+       ERR("failed to create property sheet page\n");
+       return E_FAIL;
+    }
 
-    memset(&pinfo, 0x0, sizeof(PROPSHEETHEADERW));
-    pinfo.dwSize = sizeof(PROPSHEETHEADERW);
-    pinfo.dwFlags = PSH_NOCONTEXTHELP | PSH_PROPTITLE;
-    pinfo.nPages = numpages;
-       pinfo.u3.phpage = hppages;
-    pinfo.pszCaption = This->sDescription;
-    pinfo.u2.nStartPage = 1;
+    bRet = pfnAddPage(hPage, lParam);
+    if (bRet)
+       return S_OK;
+    else
+       return E_FAIL;
+}
 
-    if ( PropertySheetW(&pinfo) < 0 )
-        return E_FAIL;
-       else
-        return S_OK;
+static HRESULT WINAPI
+ ShellLink_IShellPropSheetExt_ReplacePages( IShellPropSheetExt *iface, UINT uPageID, LPFNADDPROPSHEETPAGE pfnReplacePage, LPARAM lParam)
+{
+    IShellLinkImpl *This = impl_from_IShellPropSheetExt(iface);
+    TRACE("(%p) (uPageID %u, pfnReplacePage %p lParam %p\n", This, uPageID, pfnReplacePage, lParam);
+    return E_NOTIMPL;
 }
 
+static const IShellPropSheetExtVtbl pse =
+{
+    ShellLink_IShellPropSheetExt_QueryInterface,
+    ShellLink_IShellPropSheetExt_AddRef,
+    ShellLink_IShellPropSheetExt_Release,
+    ShellLink_IShellPropSheetExt_AddPages,
+    ShellLink_IShellPropSheetExt_ReplacePages
+};
+
 static HRESULT WINAPI
 ShellLink_InvokeCommand( IContextMenu* iface, LPCMINVOKECOMMANDINFO lpici )
 {
     IShellLinkImpl *This = impl_from_IContextMenu(iface);
-    static const WCHAR szOpen[] = { 'O','p','e','n',0 };
+    static const WCHAR szOpen[] = { 'o','p','e','n',0 };
+    static const WCHAR szCplOpen[] = { 'c','p','l','o','p','e','n',0 };
     SHELLEXECUTEINFOW sei;
     HWND hwnd = NULL; /* FIXME: get using interface set from IObjectWithSite */
     LPWSTR args = NULL;
@@ -2775,22 +2789,12 @@ ShellLink_InvokeCommand( IContextMenu* iface, LPCMINVOKECOMMANDINFO lpici )
     if ( lpici->cbSize < sizeof (CMINVOKECOMMANDINFO) )
         return E_INVALIDARG;
 
-    if ( lpici->lpVerb == MAKEINTRESOURCEA(This->iIdProperties))
-    {
-        ShellLink_ShowProperties(This);
-        return S_OK;
-    }
-
-    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 ) )
+    {
+        TRACE("failed to resolve component with error 0x%08x", r);
         return r;
-
+    }
     if ( This->sComponent )
     {
         path = shelllink_get_msi_component_path( This->sComponent );
@@ -2807,41 +2811,43 @@ ShellLink_InvokeCommand( IContextMenu* iface, LPCMINVOKECOMMANDINFO lpici )
         DWORD len = 2;
 
         if ( This->sArgs )
-            len += lstrlenW( This->sArgs );
+            len += wcslen( This->sArgs );
         if ( iciex->lpParametersW )
-            len += lstrlenW( iciex->lpParametersW );
+            len += wcslen( iciex->lpParametersW );
 
         args = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
         args[0] = 0;
         if ( This->sArgs )
-            lstrcatW( args, This->sArgs );
+            wcscat( args, This->sArgs );
         if ( iciex->lpParametersW )
         {
             static const WCHAR space[] = { ' ', 0 };
-            lstrcatW( args, space );
-            lstrcatW( args, iciex->lpParametersW );
+            wcscat( args, space );
+            wcscat( args, iciex->lpParametersW );
         }
     }
+    else if (This->sArgs != NULL)
+    {
+        args = strdupW( This->sArgs );
+    }
 
     memset( &sei, 0, sizeof sei );
     sei.cbSize = sizeof sei;
-    sei.fMask = SEE_MASK_UNICODE | SEE_MASK_NOCLOSEPROCESS;
+    sei.fMask = SEE_MASK_UNICODE | (lpici->fMask & (SEE_MASK_NOASYNC|SEE_MASK_ASYNCOK|SEE_MASK_FLAG_NO_UI));
     sei.lpFile = path;
     sei.nShow = This->iShowCmd;
-    sei.lpIDList = This->pPidl;
     sei.lpDirectory = This->sWorkDir;
     sei.lpParameters = args;
     sei.lpVerb = szOpen;
 
+    // HACK for ShellExecuteExW
+    if (!wcsstr(This->sPath, L".cpl"))
+        sei.lpVerb = szOpen;
+    else
+        sei.lpVerb = szCplOpen;
+
     if( ShellExecuteExW( &sei ) )
-    {
-        if ( sei.hProcess )
-        {
-            WaitForSingleObject( sei.hProcess, 10000 );
-            CloseHandle( sei.hProcess );
-        }
         r = S_OK;
-    }
     else
         r = E_FAIL;