MSI: Handle MSI advertised shortcuts in the shelllink object.

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

MSI: Handle MSI advertised shortcuts in the shelllink object.

Mike McCormack
ChangeLog:
Handle MSI advertised shortcuts in the shelllink object.

c39d35c48bec0bcbf4c95d8a2c855b4798a8d664
diff --git a/dlls/shell32/shelllink.c b/dlls/shell32/shelllink.c
--- a/dlls/shell32/shelllink.c
+++ b/dlls/shell32/shelllink.c
@@ -51,6 +51,7 @@
 #include "shell32_main.h"
 #include "shlguid.h"
 #include "shlwapi.h"
+#include "msi.h"
 
 #include "initguid.h"
 
@@ -209,6 +210,16 @@ inline static LPWSTR HEAP_strdupAtoW( HA
     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
  */
@@ -2399,6 +2410,55 @@ ShellLink_QueryContextMenu( IContextMenu
     return MAKE_HRESULT( SEVERITY_SUCCESS, 0, id );
 }
 
+static LPWSTR shelllink_get_msi_component_path( LPCWSTR component )
+{
+    UINT WINAPI (*pMsiDecomposeDescriptorW)(LPCWSTR,LPWSTR,LPWSTR,LPWSTR,DWORD*);
+    INSTALLSTATE WINAPI (*pMsiGetComponentPathW)(LPCWSTR,LPCWSTR,LPWSTR,DWORD*);
+    WCHAR szProd[MAX_FEATURE_CHARS+1], szFeat[MAX_FEATURE_CHARS+1],
+          szComp[MAX_FEATURE_CHARS+1], szCompPath[MAX_PATH];
+    INSTALLSTATE state;
+    LPWSTR path = NULL;
+    HMODULE hmsi = NULL;
+    DWORD sz = 0;
+    UINT ret;
+
+    TRACE("%s\n", debugstr_w( component ) );
+
+    hmsi = LoadLibraryA("msi");
+    if (!hmsi)
+        goto end;
+
+    pMsiDecomposeDescriptorW = (LPVOID) GetProcAddress(hmsi, "MsiDecomposeDescriptorW");
+    pMsiGetComponentPathW = (LPVOID) GetProcAddress(hmsi, "MsiGetComponentPathW");
+    if (!pMsiDecomposeDescriptorW || !pMsiGetComponentPathW)
+        goto end;
+
+    ret = pMsiDecomposeDescriptorW( component, szProd, szFeat, szComp, &sz );
+    if (ret != ERROR_SUCCESS)
+    {
+        ERR("failed to decompose descriptor %s\n", debugstr_w( component ) );
+        goto end;
+    }
+
+    sz = MAX_PATH;
+    state = pMsiGetComponentPathW( szProd, szComp, szCompPath, &sz );
+    if (state != INSTALLSTATE_LOCAL)
+    {
+        ERR("MsiGetComponentPathW failed with error %d\n", ret );
+        goto end;
+    }
+
+    path = strdupW( szCompPath );
+
+end:
+    if (hmsi)
+        FreeLibrary( hmsi );
+
+    TRACE("returning %s\n", debugstr_w( path ) );
+
+    return path;
+}
+
 static HRESULT WINAPI
 ShellLink_InvokeCommand( IContextMenu* iface, LPCMINVOKECOMMANDINFO lpici )
 {
@@ -2406,6 +2466,7 @@ ShellLink_InvokeCommand( IContextMenu* i
     SHELLEXECUTEINFOW sei;
     HWND hwnd = NULL; /* FIXME: get using interface set from IObjectWithSite */
     LPWSTR args = NULL;
+    LPWSTR path = NULL;
     HRESULT r;
 
     TRACE("%p %p\n", This, lpici );
@@ -2423,13 +2484,14 @@ ShellLink_InvokeCommand( IContextMenu* i
     if ( FAILED( r ) )
         return r;
 
-    if ( This->sProduct || This->sComponent )
+    if ( This->sComponent )
     {
-        FIXME("MSI advertised shortcut %s %s\n",
-              debugstr_w( This->sProduct ),
-              debugstr_w( This->sComponent ) );
-        return E_NOTIMPL;
+        path = shelllink_get_msi_component_path( This->sComponent );
+        if (!path)
+            return E_FAIL;
     }
+    else
+        path = strdupW( This->sPath );
 
     if ( lpici->cbSize == sizeof (CMINVOKECOMMANDINFOEX) &&
          ( lpici->fMask & CMIC_MASK_UNICODE ) )
@@ -2452,7 +2514,7 @@ ShellLink_InvokeCommand( IContextMenu* i
 
     memset( &sei, 0, sizeof sei );
     sei.cbSize = sizeof sei;
-    sei.lpFile = This->sPath;
+    sei.lpFile = path;
     sei.nShow = This->iShowCmd;
     sei.lpIDList = This->pPidl;
     sei.lpDirectory = This->sWorkDir;
@@ -2464,6 +2526,7 @@ ShellLink_InvokeCommand( IContextMenu* i
         r = E_FAIL;
 
     HeapFree( GetProcessHeap(), 0, args );
+    HeapFree( GetProcessHeap(), 0, path );
 
     return r;
 }