script.c 11.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
/*
 * 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);

39 40 41 42 43 44 45 46 47 48 49 50 51 52
#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

53 54 55 56 57 58 59 60 61 62
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;
63
    IDispatch *pInstaller;
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
    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;

79
    object = msi_alloc_zero( sizeof(MsiActiveScriptSite) );
80 81 82

    object->lpVtbl.lpVtbl = &ASS_Vtbl;
    object->ref = 1;
83
    object->pInstaller = NULL;
84 85 86 87 88 89 90 91 92 93 94 95 96 97
    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;
98
    IActiveScriptParse *pActiveScriptParse = NULL;
99 100 101 102 103 104
    MsiActiveScriptSite *pActiveScriptSite = NULL;
    IDispatch *pDispatch = NULL;
    DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
    DISPID dispid;
    CLSID clsid;
    VARIANT var;
105
    DWORD ret = ERROR_INSTALL_FAILURE;
106 107 108 109 110 111 112

    CoInitialize(NULL);

    /* Create MsiActiveScriptSite object */
    hr = create_ActiveScriptSite(NULL, (void **)&pActiveScriptSite);
    if (hr != S_OK) goto done;

113 114 115 116
    /* Create an installer object */
    hr = create_msiserver(NULL, (LPVOID *)&pActiveScriptSite->pInstaller);
    if (hr != S_OK) goto done;

117
    /* Create a session object */
118
    hr = create_session(hPackage, pActiveScriptSite->pInstaller, &pActiveScriptSite->pSession);
119 120 121
    if (hr != S_OK) goto done;

    /* Create the scripting engine */
122
    if ((type & 7) == msidbCustomActionTypeJScript)
123
        hr = CLSIDFromProgID(szJScript, &clsid);
124
    else if ((type & 7) == msidbCustomActionTypeVBScript)
125
        hr = CLSIDFromProgID(szVBScript, &clsid);
126
    else {
127 128
        ERR("Unknown script type %d\n", type);
        goto done;
129 130
    }
    if (FAILED(hr)) {
131 132
        ERR("Could not find CLSID for Windows Script\n");
        goto done;
133 134 135
    }
    hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IActiveScript, (void **)&pActiveScript);
    if (FAILED(hr)) {
136 137
        ERR("Could not instantiate class for Windows Script\n");
        goto done;
138 139
    }

140 141
    hr = IActiveScript_QueryInterface(pActiveScript, &IID_IActiveScriptParse, (void **)&pActiveScriptParse);
    if (FAILED(hr)) goto done;
142

143 144
    hr = IActiveScript_SetScriptSite(pActiveScript, (IActiveScriptSite *)pActiveScriptSite);
    if (FAILED(hr)) goto done;
145

146 147
    hr = IActiveScriptParse_InitNew(pActiveScriptParse);
    if (FAILED(hr)) goto done;
148

149
    hr = IActiveScript_AddNamedItem(pActiveScript, szSession, SCRIPTITEM_GLOBALMEMBERS|SCRIPTITEM_ISVISIBLE);
150
    if (FAILED(hr)) goto done;
151

152 153
    hr = IActiveScriptParse_ParseScriptText(pActiveScriptParse, script, NULL, NULL, NULL, 0, 0, 0L, NULL, NULL);
    if (FAILED(hr)) goto done;
154 155 156 157 158 159

    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) {
160
        TRACE("Calling function %s\n", debugstr_w(function));
161

162 163
        hr = IActiveScript_GetScriptDispatch(pActiveScript, NULL, &pDispatch);
        if (FAILED(hr)) goto done;
164

165 166
        hr = IDispatch_GetIDsOfNames(pDispatch, &IID_NULL, (WCHAR **)&function, 1,LOCALE_USER_DEFAULT, &dispid);
        if (FAILED(hr)) goto done;
167

168 169
        hr = IDispatch_Invoke(pDispatch, dispid, &IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparamsNoArgs, &var, NULL, NULL);
        if (FAILED(hr)) goto done;
170

171 172 173
        /* Check return value, if it's not IDOK we failed */
        hr = VariantChangeType(&var, &var, 0, VT_I4);
        if (FAILED(hr)) goto done;
174

175 176 177
        if (V_I4(&var) == IDOK)
            ret = ERROR_SUCCESS;
        else ret = ERROR_INSTALL_FAILURE;
178

179
        VariantClear(&var);
180
    } else {
181 182
        /* If no function to be called, MSI behavior is to succeed */
        ret = ERROR_SUCCESS;
183 184 185 186 187
    }

done:

    if (pDispatch) IDispatch_Release(pDispatch);
188
    if (pActiveScript) IActiveScript_Release(pActiveScript);
189
    if (pActiveScriptParse) IActiveScriptParse_Release(pActiveScriptParse);
190 191 192 193 194 195
    if (pActiveScriptSite)
    {
        if (pActiveScriptSite->pSession) IDispatch_Release(pActiveScriptSite->pSession);
        if (pActiveScriptSite->pInstaller) IDispatch_Release(pActiveScriptSite->pInstaller);
        IActiveScriptSite_Release((IActiveScriptSite *)pActiveScriptSite);
    }
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
    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))
    {
214
        IActiveScriptSite_AddRef(iface);
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
        *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)
241
        msi_free(This);
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260

    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) {
261 262
        if (!ppti) return E_INVALIDARG;
        *ppti = NULL;
263 264
    }
    if (dwReturnMask & SCRIPTINFO_IUNKNOWN) {
265 266
        if (!ppiunkItem) return E_INVALIDARG;
        *ppiunkItem = NULL;
267 268 269 270
    }

    /* Are we looking for the session object? */
    if (!strcmpW(szSession, pstrName)) {
271 272 273 274 275
        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;
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
        }
    }

    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) {
299 300 301
        case SCRIPTSTATE_UNINITIALIZED:
              TRACE("State: Uninitialized.\n");
              break;
302

303 304 305
        case SCRIPTSTATE_INITIALIZED:
              TRACE("State: Initialized.\n");
              break;
306

307 308 309
        case SCRIPTSTATE_STARTED:
              TRACE("State: Started.\n");
              break;
310

311 312 313
        case SCRIPTSTATE_CONNECTED:
              TRACE("State: Connected.\n");
              break;
314

315 316 317
        case SCRIPTSTATE_DISCONNECTED:
              TRACE("State: Disconnected.\n");
              break;
318

319 320 321
        case SCRIPTSTATE_CLOSED:
              TRACE("State: Closed.\n");
              break;
322

323 324 325
        default:
              ERR("Unknown State: %d\n", ssScriptState);
              break;
326 327 328 329 330 331 332 333 334 335 336 337 338
    }

    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);

339
    memset(&exception, 0, sizeof(EXCEPINFO));
340 341
    hr = IActiveScriptError_GetExceptionInfo(pscripterror, &exception);
    if (SUCCEEDED(hr))
342
    {
343
        ERR("script error: %s\n", debugstr_w(exception.bstrDescription));
344 345 346 347
        SysFreeString(exception.bstrSource);
        SysFreeString(exception.bstrDescription);
        SysFreeString(exception.bstrHelpFile);
    }
348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379

    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
};