[try4, 4/4] msi: Add full JScript/VBScript support.
Misha Koshelev
mk144210 at bcm.tmc.edu
Thu Mar 1 19:55:39 CST 2007
Changed ASS_create to create_ActiveScriptSite and return failure if it
is called for.
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 b4d7f1118f44a8512f859c964e5766de47db1c21 Mon Sep 17 00:00:00 2001
From: Misha Koshelev <mk144210 at bcm.tmc.edu>
Date: Thu, 1 Mar 2007 19:43:03 -0600
Subject: msi: Add full JScript/VBScript support.
---
dlls/msi/Makefile.in | 1
dlls/msi/custom.c | 12 ++
dlls/msi/msipriv.h | 3
dlls/msi/script.c | 365 ++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 380 insertions(+), 1 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 8280573..eb60d78 100644
--- a/dlls/msi/custom.c
+++ b/dlls/msi/custom.c
@@ -883,6 +883,7 @@ static UINT HANDLE_CustomType34(MSIPACKA
static DWORD WINAPI ACTION_CallScript( const LPGUID guid )
{
msi_custom_action_info *info;
+ MSIHANDLE hPackage;
UINT r = ERROR_FUNCTION_FAILED;
info = find_action_by_guid( guid );
@@ -892,7 +893,16 @@ 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 = call_script( hPackage, info->type, info->dllname, info->function, info->action );
+ MsiCloseHandle( hPackage );
+ }
+ else
+ ERR("failed to create handle for %p\n", info->package );
if (info->type & msidbCustomActionTypeAsync &&
info->type & msidbCustomActionTypeContinue)
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..6384d31
--- /dev/null
+++ b/dlls/msi/script.c
@@ -0,0 +1,365 @@
+/*
+ * 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 create_ActiveScriptSite(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.
+ */
+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 = create_ActiveScriptSite(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;
+}
+
+/*
+ * 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)\n", This, iface, plcid);
+ return E_NOTIMPL; /* Script will use system-defined locale */
+}
+
+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)\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)\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)\n", This, iface);
+ return S_OK;
+}
+
+static HRESULT WINAPI MsiActiveScriptSite_OnLeaveScript(IActiveScriptSite* iface)
+{
+ MsiActiveScriptSite *This = (MsiActiveScriptSite *)iface;
+ TRACE("(%p/%p)\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