summaryrefslogtreecommitdiffstats
path: root/libmsi/script.c
diff options
context:
space:
mode:
Diffstat (limited to 'libmsi/script.c')
-rw-r--r--libmsi/script.c379
1 files changed, 379 insertions, 0 deletions
diff --git a/libmsi/script.c b/libmsi/script.c
new file mode 100644
index 0000000..392c5ac
--- /dev/null
+++ b/libmsi/script.c
@@ -0,0 +1,379 @@
+/*
+ * 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);
+
+#ifdef _WIN64
+
+#define IActiveScriptParse_Release IActiveScriptParse64_Release
+#define IActiveScriptParse_InitNew IActiveScriptParse64_InitNew
+#define IActiveScriptParse_ParseScriptText IActiveScriptParse64_ParseScriptText
+
+#else
+
+#define IActiveScriptParse_Release IActiveScriptParse32_Release
+#define IActiveScriptParse_InitNew IActiveScriptParse32_InitNew
+#define IActiveScriptParse_ParseScriptText IActiveScriptParse32_ParseScriptText
+
+#endif
+
+static const WCHAR szJScript[] = { 'J','S','c','r','i','p','t',0};
+static const WCHAR szVBScript[] = { 'V','B','S','c','r','i','p','t',0};
+static const WCHAR szSession[] = {'S','e','s','s','i','o','n',0};
+
+/*
+ * MsiActiveScriptSite - Our IActiveScriptSite implementation.
+ */
+
+typedef struct {
+ IActiveScriptSite lpVtbl;
+ IDispatch *pInstaller;
+ 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 = msi_alloc_zero( sizeof(MsiActiveScriptSite) );
+
+ object->lpVtbl.lpVtbl = &ASS_Vtbl;
+ object->ref = 1;
+ object->pInstaller = NULL;
+ 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;
+ DWORD ret = ERROR_INSTALL_FAILURE;
+
+ CoInitialize(NULL);
+
+ /* Create MsiActiveScriptSite object */
+ hr = create_ActiveScriptSite(NULL, (void **)&pActiveScriptSite);
+ if (hr != S_OK) goto done;
+
+ /* Create an installer object */
+ hr = create_msiserver(NULL, (LPVOID *)&pActiveScriptSite->pInstaller);
+ if (hr != S_OK) goto done;
+
+ /* Create a session object */
+ hr = create_session(hPackage, pActiveScriptSite->pInstaller, &pActiveScriptSite->pSession);
+ if (hr != S_OK) goto done;
+
+ /* Create the scripting engine */
+ if ((type & 7) == msidbCustomActionTypeJScript)
+ hr = CLSIDFromProgID(szJScript, &clsid);
+ else if ((type & 7) == 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;
+ }
+
+ hr = IActiveScript_QueryInterface(pActiveScript, &IID_IActiveScriptParse, (void **)&pActiveScriptParse);
+ if (FAILED(hr)) goto done;
+
+ hr = IActiveScript_SetScriptSite(pActiveScript, (IActiveScriptSite *)pActiveScriptSite);
+ if (FAILED(hr)) goto done;
+
+ hr = IActiveScriptParse_InitNew(pActiveScriptParse);
+ if (FAILED(hr)) goto done;
+
+ hr = IActiveScript_AddNamedItem(pActiveScript, szSession, SCRIPTITEM_GLOBALMEMBERS|SCRIPTITEM_ISVISIBLE);
+ if (FAILED(hr)) goto done;
+
+ hr = IActiveScriptParse_ParseScriptText(pActiveScriptParse, script, NULL, NULL, NULL, 0, 0, 0L, NULL, NULL);
+ if (FAILED(hr)) goto done;
+
+ 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:
+
+ if (pDispatch) IDispatch_Release(pDispatch);
+ if (pActiveScript) IActiveScript_Release(pActiveScript);
+ if (pActiveScriptParse) IActiveScriptParse_Release(pActiveScriptParse);
+ if (pActiveScriptSite)
+ {
+ if (pActiveScriptSite->pSession) IDispatch_Release(pActiveScriptSite->pSession);
+ if (pActiveScriptSite->pInstaller) IDispatch_Release(pActiveScriptSite->pInstaller);
+ IActiveScriptSite_Release((IActiveScriptSite *)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))
+ {
+ IActiveScriptSite_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)
+ msi_free(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 load_type_info(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);
+
+ memset(&exception, 0, sizeof(EXCEPINFO));
+ hr = IActiveScriptError_GetExceptionInfo(pscripterror, &exception);
+ if (SUCCEEDED(hr))
+ {
+ ERR("script error: %s\n", debugstr_w(exception.bstrDescription));
+ SysFreeString(exception.bstrSource);
+ SysFreeString(exception.bstrDescription);
+ SysFreeString(exception.bstrHelpFile);
+ }
+
+ 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
+};