[4/4 revised] msi: Add full JScript/VBScript support.

Misha Koshelev mk144210 at bcm.tmc.edu
Sun Feb 25 22:47:48 CST 2007


Implements the IActiveScriptSite interface which links with the session
object implemented in patch #3 and then adds a call to the script
handler from the common script handling function implemented in patch
#1. This fixes bug #7357 and possibly others.

Changelog:

	* msi: Add full JScript/VBScript support.
-------------- next part --------------
From bea150c6a681acd029ee2c95faab9b77d7e613c6 Mon Sep 17 00:00:00 2001
From: Misha Koshelev <mk144210 at bcm.tmc.edu>
Date: Sun, 25 Feb 2007 22:24:06 -0600
Subject: msi: Add full JScript/VBScript support.
---
 dlls/msi/Makefile.in |    1 
 dlls/msi/custom.c    |    4 -
 dlls/msi/msipriv.h   |    3 
 dlls/msi/script.c    |  369 ++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 375 insertions(+), 2 deletions(-)

diff --git a/dlls/msi/Makefile.in b/dlls/msi/Makefile.in
index 3418fb5..5b7a991 100644
--- a/dlls/msi/Makefile.in
+++ b/dlls/msi/Makefile.in
@@ -38,6 +38,7 @@ C_SRCS = \
 	record.c \
 	registry.c \
 	regsvr.c \
+        script.c \
 	select.c \
 	source.c \
 	string.c \
diff --git a/dlls/msi/custom.c b/dlls/msi/custom.c
index 7cbbf40..bdffe8b 100644
--- a/dlls/msi/custom.c
+++ b/dlls/msi/custom.c
@@ -892,12 +892,12 @@ static DWORD WINAPI ACTION_CallScript( c
         return r;
     }
 
-    FIXME("function %s, script %s\n", debugstr_w( info->function ), debugstr_w( info->dllname ) );
+    TRACE("function %s, script %s\n", debugstr_w( info->function ), debugstr_w( info->dllname ) );
 
     hPackage = alloc_msihandle( &info->package->hdr );
     if (hPackage)
     {
-	r = S_OK;
+        r = call_script( hPackage, info->type, info->dllname, info->function, info->action );
         MsiCloseHandle( hPackage );
     }
     else
diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h
index 23768c0..57f2531 100644
--- a/dlls/msi/msipriv.h
+++ b/dlls/msi/msipriv.h
@@ -792,6 +792,9 @@ extern VOID ControlEvent_UnSubscribeToEv
 extern HRESULT create_session(MSIHANDLE msiHandle, IDispatch **pDispatch);
 extern HRESULT WINAPI LoadTypeInfo(IDispatch *iface, ITypeInfo **pptinfo, REFIID clsid, LCID lcid);
 
+/* Scripting */
+extern DWORD call_script(MSIHANDLE hPackage, INT type, LPCWSTR script, LPCWSTR function, LPCWSTR action);
+
 /* User Interface messages from the actions */
 extern void ui_progress(MSIPACKAGE *, int, int, int, int);
 extern void ui_actiondata(MSIPACKAGE *, LPCWSTR, MSIRECORD *);
diff --git a/dlls/msi/script.c b/dlls/msi/script.c
new file mode 100644
index 0000000..65a937d
--- /dev/null
+++ b/dlls/msi/script.c
@@ -0,0 +1,369 @@
+/*
+ * Implementation of scripting for Microsoft Installer (msi.dll)
+ *
+ * Copyright 2007 Misha Koshelev
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define COBJMACROS
+
+#include <stdarg.h>
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "winuser.h"
+#include "msidefs.h"
+#include "msipriv.h"
+#include "activscp.h"
+#include "oleauto.h"
+#include "wine/debug.h"
+#include "wine/unicode.h"
+
+#include "msiserver.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+const WCHAR szJScript[] = { 'J','S','c','r','i','p','t',0};
+const WCHAR szVBScript[] = { 'V','B','S','c','r','i','p','t',0};
+const WCHAR szSession[] = {'S','e','s','s','i','o','n',0};
+
+/*
+ * MsiActiveScriptSite - Our IActiveScriptSite implementation.
+ */
+
+typedef struct {
+    IActiveScriptSite lpVtbl;
+    IDispatch *pSession;
+    LONG ref;
+} MsiActiveScriptSite;
+
+static const struct IActiveScriptSiteVtbl ASS_Vtbl;
+
+static HRESULT ASS_create(IUnknown *pUnkOuter, LPVOID *ppObj)
+{
+    MsiActiveScriptSite* object; 
+
+    TRACE("(%p,%p)\n", pUnkOuter, ppObj);
+
+    if( pUnkOuter )
+        return CLASS_E_NOAGGREGATION;
+
+    object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MsiActiveScriptSite));
+
+    object->lpVtbl.lpVtbl = &ASS_Vtbl;
+    object->ref = 1;
+    object->pSession = NULL;
+
+    *ppObj = object;
+
+    return S_OK;
+}
+
+/*
+ * Call a script. This is our meat and potatoes. 
+ *     - Currently, since the function is relatively new, it will always end up returning S_OK.
+ *       Think of it like a bonus feature, we can run the script - great. If we have a problem,
+ *       we are no worse off than if this function had not been called.
+ */
+DWORD call_script(MSIHANDLE hPackage, INT type, LPCWSTR script, LPCWSTR function, LPCWSTR action)
+{
+    HRESULT hr;
+    IActiveScript *pActiveScript = NULL;
+    IActiveScriptParse *pActiveScriptParse = NULL;
+    MsiActiveScriptSite *pActiveScriptSite = NULL;
+    IDispatch *pDispatch = NULL;
+    DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
+    DISPID dispid;
+    CLSID clsid;
+    VARIANT var;
+
+    /* Return success by default (if Windows Script not installed) - not native behavior. This
+     * should be here until we implement wine scripting. */
+    DWORD ret = ERROR_SUCCESS;    
+  
+    CoInitialize(NULL);
+
+    /* Create MsiActiveScriptSite object */
+    hr = ASS_create(NULL, (void **)&pActiveScriptSite);
+    if (hr != S_OK) goto done;
+
+    /* Create a session object */
+    hr = create_session(hPackage, &pActiveScriptSite->pSession);
+    if (hr != S_OK) goto done;
+    IUnknown_AddRef((IUnknown *)pActiveScriptSite->pSession);
+
+    /* Create the scripting engine */
+    if (type & msidbCustomActionTypeJScript)
+	hr = CLSIDFromProgID(szJScript, &clsid);
+    else if (type & msidbCustomActionTypeVBScript)
+	hr = CLSIDFromProgID(szVBScript, &clsid);
+    else {
+	ERR("Unknown script type %d\n", type);
+	goto done;
+    }
+    if (FAILED(hr)) {
+	ERR("Could not find CLSID for Windows Script\n");
+	goto done;
+    }
+    hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IActiveScript, (void **)&pActiveScript);
+    if (FAILED(hr)) {
+	ERR("Could not instantiate class for Windows Script\n");
+	goto done;
+    }
+
+    /* If we got this far, Windows Script is installed, so don't return success by default anymore */
+    ret = ERROR_INSTALL_FAILURE; 
+
+    /* Get the IActiveScriptParse engine interface */
+    hr = IActiveScript_QueryInterface(pActiveScript, &IID_IActiveScriptParse, (void **)&pActiveScriptParse);
+    if (FAILED(hr)) goto done;
+
+    /* Give our host to the engine */
+    hr = IActiveScript_SetScriptSite(pActiveScript, (IActiveScriptSite *)pActiveScriptSite);
+    if (FAILED(hr)) goto done;
+
+    /* Initialize the script engine */
+    hr = IActiveScriptParse_InitNew(pActiveScriptParse);
+    if (FAILED(hr)) goto done;
+
+    /* Add the session object */
+    hr = IActiveScript_AddNamedItem(pActiveScript, szSession, SCRIPTITEM_ISVISIBLE);
+
+    /* Pass the script to the engine */
+    hr = IActiveScriptParse_ParseScriptText(pActiveScriptParse, script, NULL, NULL, NULL, 0, 0, 0L, NULL, NULL);
+    if (FAILED(hr)) goto done;
+
+    /* Start processing the script */
+    hr = IActiveScript_SetScriptState(pActiveScript, SCRIPTSTATE_CONNECTED);
+    if (FAILED(hr)) goto done;
+
+    /* Call a function if necessary through the IDispatch interface */
+    if (function != NULL && strlenW(function) > 0) {
+	TRACE("Calling function %s\n", debugstr_w(function));
+
+	hr = IActiveScript_GetScriptDispatch(pActiveScript, NULL, &pDispatch);
+	if (FAILED(hr)) goto done; 
+
+	hr = IDispatch_GetIDsOfNames(pDispatch, &IID_NULL, (WCHAR **)&function, 1,LOCALE_USER_DEFAULT, &dispid);
+	if (FAILED(hr)) goto done;
+  
+	hr = IDispatch_Invoke(pDispatch, dispid, &IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparamsNoArgs, &var, NULL, NULL);
+	if (FAILED(hr)) goto done;
+
+	/* Check return value, if it's not IDOK we failed */
+	hr = VariantChangeType(&var, &var, 0, VT_I4);
+	if (FAILED(hr)) goto done;
+	
+	if (V_I4(&var) == IDOK) 
+	    ret = ERROR_SUCCESS;
+	else ret = ERROR_INSTALL_FAILURE;
+
+	VariantClear(&var);
+    } else {
+	/* If no function to be called, MSI behavior is to succeed */
+	ret = ERROR_SUCCESS;
+    }
+
+done:
+
+    /* Free everything that needs to be freed */
+    if (pDispatch) IDispatch_Release(pDispatch);
+    if (pActiveScript) IActiveScriptSite_Release(pActiveScript);
+    if (pActiveScriptSite &&
+	pActiveScriptSite->pSession) IUnknown_Release((IUnknown *)pActiveScriptSite->pSession);
+    if (pActiveScriptSite) IUnknown_Release((IUnknown *)pActiveScriptSite);
+
+    CoUninitialize();    /* must call even if CoInitialize failed */
+
+/*    return ret;  */
+    return ERROR_SUCCESS;       /* FIXME: Until thoroughly tested, always return success */
+}
+
+/*
+ * MsiActiveScriptSite
+ */
+
+/*** IUnknown methods ***/
+static HRESULT WINAPI MsiActiveScriptSite_QueryInterface(IActiveScriptSite* iface, REFIID riid, void** ppvObject)
+{
+    MsiActiveScriptSite *This = (MsiActiveScriptSite *)iface;
+
+    TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
+
+    if (IsEqualGUID(riid, &IID_IUnknown) ||
+        IsEqualGUID(riid, &IID_IActiveScriptSite))
+    {
+        IClassFactory_AddRef(iface);
+        *ppvObject = This;
+        return S_OK;
+    }
+
+    TRACE("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
+
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI MsiActiveScriptSite_AddRef(IActiveScriptSite* iface)
+{
+    MsiActiveScriptSite *This = (MsiActiveScriptSite *)iface;
+
+    TRACE("(%p/%p)\n", iface, This);
+
+    return InterlockedIncrement(&This->ref);
+}
+
+static ULONG WINAPI MsiActiveScriptSite_Release(IActiveScriptSite* iface)
+{
+    MsiActiveScriptSite *This = (MsiActiveScriptSite *)iface;
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p/%p)\n", iface, This);
+
+    if (!ref)
+        HeapFree(GetProcessHeap(), 0, This);
+
+    return ref;
+}
+
+/*** IActiveScriptSite methods **/
+static HRESULT WINAPI MsiActiveScriptSite_GetLCID(IActiveScriptSite* iface, LCID* plcid)
+{
+    MsiActiveScriptSite *This = (MsiActiveScriptSite *)iface;   
+    TRACE("(%p/%p)->(%p) stub!\n", This, iface, plcid);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI MsiActiveScriptSite_GetItemInfo(IActiveScriptSite* iface, LPCOLESTR pstrName, DWORD dwReturnMask, IUnknown** ppiunkItem, ITypeInfo** ppti)
+{
+    MsiActiveScriptSite *This = (MsiActiveScriptSite *)iface;
+    TRACE("(%p/%p)->(%p,%d,%p,%p)!\n", This, iface, pstrName, dwReturnMask, ppiunkItem, ppti);
+
+    /* Determine the kind of pointer that is requested, and make sure placeholder is valid */
+    if (dwReturnMask & SCRIPTINFO_ITYPEINFO) {
+	if (!ppti) return E_INVALIDARG;
+	*ppti = NULL;
+    }
+    if (dwReturnMask & SCRIPTINFO_IUNKNOWN) {
+	if (!ppiunkItem) return E_INVALIDARG;
+	*ppiunkItem = NULL;
+    }
+
+    /* Are we looking for the session object? */
+    if (!strcmpW(szSession, pstrName)) {
+	if (dwReturnMask & SCRIPTINFO_ITYPEINFO)                
+	    return LoadTypeInfo(This->pSession, ppti, &DIID_Session, 0); 
+	else if (dwReturnMask & SCRIPTINFO_IUNKNOWN) {
+	    IDispatch_QueryInterface(This->pSession, &IID_IUnknown, (void **)ppiunkItem);
+	    return S_OK;
+        }
+    }
+  
+    return TYPE_E_ELEMENTNOTFOUND;
+}
+
+static HRESULT WINAPI MsiActiveScriptSite_GetDocVersionString(IActiveScriptSite* iface, BSTR* pbstrVersion)
+{
+    MsiActiveScriptSite *This = (MsiActiveScriptSite *)iface;
+    TRACE("(%p/%p)->(%p) stub\n", This, iface, pbstrVersion);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI MsiActiveScriptSite_OnScriptTerminate(IActiveScriptSite* iface, const VARIANT* pvarResult, const EXCEPINFO* pexcepinfo)
+{
+    MsiActiveScriptSite *This = (MsiActiveScriptSite *)iface;
+    TRACE("(%p/%p)->(%p,%p) stub\n", This, iface, pvarResult, pexcepinfo);
+    return S_OK;
+}
+
+static HRESULT WINAPI MsiActiveScriptSite_OnStateChange(IActiveScriptSite* iface, SCRIPTSTATE ssScriptState)
+{
+    switch (ssScriptState) {
+	case SCRIPTSTATE_UNINITIALIZED:
+	      TRACE("State: Uninitialized.\n");
+	      break;
+
+	case SCRIPTSTATE_INITIALIZED:
+	      TRACE("State: Initialized.\n");
+	      break;
+
+	case SCRIPTSTATE_STARTED:
+	      TRACE("State: Started.\n");
+	      break;
+
+	case SCRIPTSTATE_CONNECTED:
+	      TRACE("State: Connected.\n");
+	      break;
+
+	case SCRIPTSTATE_DISCONNECTED:
+	      TRACE("State: Disconnected.\n");
+	      break;
+
+	case SCRIPTSTATE_CLOSED:
+	      TRACE("State: Closed.\n");
+	      break;
+
+	default:
+	      ERR("Unknown State: %d\n", ssScriptState);
+	      break;
+    }
+  
+    return S_OK;
+}
+
+static HRESULT WINAPI MsiActiveScriptSite_OnScriptError(IActiveScriptSite* iface, IActiveScriptError* pscripterror)
+{
+    MsiActiveScriptSite *This = (MsiActiveScriptSite *)iface;
+    EXCEPINFO exception;
+    HRESULT hr;
+
+    TRACE("(%p/%p)->(%p)\n", This, iface, pscripterror);
+
+    hr = IActiveScriptError_GetExceptionInfo(pscripterror, &exception);
+    if (SUCCEEDED(hr))
+	ERR("script error: %s\n", debugstr_w(exception.bstrDescription));
+
+    return S_OK;
+}
+
+static HRESULT WINAPI MsiActiveScriptSite_OnEnterScript(IActiveScriptSite* iface)
+{
+    MsiActiveScriptSite *This = (MsiActiveScriptSite *)iface;
+    TRACE("(%p/%p) stub\n", This, iface);
+    return S_OK;
+}
+
+static HRESULT WINAPI MsiActiveScriptSite_OnLeaveScript(IActiveScriptSite* iface)
+{
+    MsiActiveScriptSite *This = (MsiActiveScriptSite *)iface;
+    TRACE("(%p/%p) stub\n", This, iface);
+    return S_OK;
+}
+
+static const struct IActiveScriptSiteVtbl ASS_Vtbl = 
+{
+    MsiActiveScriptSite_QueryInterface,
+    MsiActiveScriptSite_AddRef,
+    MsiActiveScriptSite_Release,
+    MsiActiveScriptSite_GetLCID,
+    MsiActiveScriptSite_GetItemInfo,
+    MsiActiveScriptSite_GetDocVersionString,
+    MsiActiveScriptSite_OnScriptTerminate,
+    MsiActiveScriptSite_OnStateChange,
+    MsiActiveScriptSite_OnScriptError,
+    MsiActiveScriptSite_OnEnterScript,
+    MsiActiveScriptSite_OnLeaveScript    
+};
+
-- 
1.4.1



More information about the wine-patches mailing list