Reactos
at master 391 lines 12 kB view raw
1/* 2 * Implementation of scripting for Microsoft Installer (msi.dll) 3 * 4 * Copyright 2007 Misha Koshelev 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21#define COBJMACROS 22 23#include <stdarg.h> 24#include "windef.h" 25#include "winbase.h" 26#include "winerror.h" 27#include "winuser.h" 28#include "msidefs.h" 29#include "msipriv.h" 30#include "activscp.h" 31#include "oleauto.h" 32#include "wine/debug.h" 33 34#include "msiserver.h" 35 36WINE_DEFAULT_DEBUG_CHANNEL(msi); 37 38#ifdef _WIN64 39 40#define IActiveScriptParse_Release IActiveScriptParse64_Release 41#define IActiveScriptParse_InitNew IActiveScriptParse64_InitNew 42#define IActiveScriptParse_ParseScriptText IActiveScriptParse64_ParseScriptText 43 44#else 45 46#define IActiveScriptParse_Release IActiveScriptParse32_Release 47#define IActiveScriptParse_InitNew IActiveScriptParse32_InitNew 48#define IActiveScriptParse_ParseScriptText IActiveScriptParse32_ParseScriptText 49 50#endif 51 52/* 53 * struct script_site - Our IActiveScriptSite implementation. 54 */ 55struct script_site 56{ 57 IActiveScriptSite IActiveScriptSite_iface; 58 IDispatch *installer; 59 IDispatch *session; 60 LONG ref; 61}; 62 63static inline struct script_site *impl_from_IActiveScriptSite( IActiveScriptSite *iface ) 64{ 65 return CONTAINING_RECORD(iface, struct script_site, IActiveScriptSite_iface); 66} 67 68/* 69 * MsiActiveScriptSite 70 */ 71static HRESULT WINAPI MsiActiveScriptSite_QueryInterface(IActiveScriptSite* iface, REFIID riid, void** obj) 72{ 73 struct script_site *This = impl_from_IActiveScriptSite(iface); 74 75 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), obj); 76 77 if (IsEqualGUID(riid, &IID_IUnknown) || 78 IsEqualGUID(riid, &IID_IActiveScriptSite)) 79 { 80 IActiveScriptSite_AddRef(iface); 81 *obj = iface; 82 return S_OK; 83 } 84 85 *obj = NULL; 86 87 return E_NOINTERFACE; 88} 89 90static ULONG WINAPI MsiActiveScriptSite_AddRef(IActiveScriptSite* iface) 91{ 92 struct script_site *This = impl_from_IActiveScriptSite(iface); 93 ULONG ref = InterlockedIncrement(&This->ref); 94 TRACE( "(%p)->(%lu)\n", This, ref ); 95 return ref; 96} 97 98static ULONG WINAPI MsiActiveScriptSite_Release(IActiveScriptSite* iface) 99{ 100 struct script_site *This = impl_from_IActiveScriptSite(iface); 101 ULONG ref = InterlockedDecrement(&This->ref); 102 103 TRACE( "(%p)->(%lu)\n", This, ref ); 104 105 if (!ref) 106 free(This); 107 108 return ref; 109} 110 111static HRESULT WINAPI MsiActiveScriptSite_GetLCID(IActiveScriptSite* iface, LCID* plcid) 112{ 113 struct script_site *This = impl_from_IActiveScriptSite(iface); 114 TRACE("(%p)->(%p)\n", This, plcid); 115 return E_NOTIMPL; /* Script will use system-defined locale */ 116} 117 118static HRESULT WINAPI MsiActiveScriptSite_GetItemInfo(IActiveScriptSite* iface, LPCOLESTR pstrName, DWORD dwReturnMask, IUnknown** ppiunkItem, ITypeInfo** ppti) 119{ 120 struct script_site *This = impl_from_IActiveScriptSite(iface); 121 122 TRACE( "(%p)->(%p, %lu, %p, %p)\n", This, pstrName, dwReturnMask, ppiunkItem, ppti ); 123 124 /* Determine the kind of pointer that is requested, and make sure placeholder is valid */ 125 if (dwReturnMask & SCRIPTINFO_ITYPEINFO) { 126 if (!ppti) return E_INVALIDARG; 127 *ppti = NULL; 128 } 129 if (dwReturnMask & SCRIPTINFO_IUNKNOWN) { 130 if (!ppiunkItem) return E_INVALIDARG; 131 *ppiunkItem = NULL; 132 } 133 134 /* Are we looking for the session object? */ 135 if (!wcscmp(L"Session", pstrName)) { 136 if (dwReturnMask & SCRIPTINFO_ITYPEINFO) { 137 HRESULT hr = get_typeinfo(Session_tid, ppti); 138 if (SUCCEEDED(hr)) 139 ITypeInfo_AddRef(*ppti); 140 return hr; 141 } 142 else if (dwReturnMask & SCRIPTINFO_IUNKNOWN) { 143 IDispatch_QueryInterface(This->session, &IID_IUnknown, (void **)ppiunkItem); 144 return S_OK; 145 } 146 } 147 148 return TYPE_E_ELEMENTNOTFOUND; 149} 150 151static HRESULT WINAPI MsiActiveScriptSite_GetDocVersionString(IActiveScriptSite* iface, BSTR* pbstrVersion) 152{ 153 struct script_site *This = impl_from_IActiveScriptSite(iface); 154 TRACE("(%p)->(%p)\n", This, pbstrVersion); 155 return E_NOTIMPL; 156} 157 158static HRESULT WINAPI MsiActiveScriptSite_OnScriptTerminate(IActiveScriptSite* iface, const VARIANT* pvarResult, const EXCEPINFO* pexcepinfo) 159{ 160 struct script_site *This = impl_from_IActiveScriptSite(iface); 161 TRACE("(%p)->(%p, %p)\n", This, pvarResult, pexcepinfo); 162 return S_OK; 163} 164 165static HRESULT WINAPI MsiActiveScriptSite_OnStateChange(IActiveScriptSite* iface, SCRIPTSTATE ssScriptState) 166{ 167 switch (ssScriptState) { 168 case SCRIPTSTATE_UNINITIALIZED: 169 TRACE("State: Uninitialized.\n"); 170 break; 171 172 case SCRIPTSTATE_INITIALIZED: 173 TRACE("State: Initialized.\n"); 174 break; 175 176 case SCRIPTSTATE_STARTED: 177 TRACE("State: Started.\n"); 178 break; 179 180 case SCRIPTSTATE_CONNECTED: 181 TRACE("State: Connected.\n"); 182 break; 183 184 case SCRIPTSTATE_DISCONNECTED: 185 TRACE("State: Disconnected.\n"); 186 break; 187 188 case SCRIPTSTATE_CLOSED: 189 TRACE("State: Closed.\n"); 190 break; 191 192 default: 193 ERR("Unknown State: %d\n", ssScriptState); 194 break; 195 } 196 197 return S_OK; 198} 199 200static HRESULT WINAPI MsiActiveScriptSite_OnScriptError(IActiveScriptSite* iface, IActiveScriptError* pscripterror) 201{ 202 struct script_site *This = impl_from_IActiveScriptSite(iface); 203 EXCEPINFO exception; 204 HRESULT hr; 205 206 TRACE("(%p)->(%p)\n", This, pscripterror); 207 208 memset(&exception, 0, sizeof(EXCEPINFO)); 209 hr = IActiveScriptError_GetExceptionInfo(pscripterror, &exception); 210 if (SUCCEEDED(hr)) 211 { 212 ERR("script error: %s\n", debugstr_w(exception.bstrDescription)); 213 SysFreeString(exception.bstrSource); 214 SysFreeString(exception.bstrDescription); 215 SysFreeString(exception.bstrHelpFile); 216 } 217 218 return S_OK; 219} 220 221static HRESULT WINAPI MsiActiveScriptSite_OnEnterScript(IActiveScriptSite* iface) 222{ 223 struct script_site *This = impl_from_IActiveScriptSite(iface); 224 TRACE("(%p)\n", This); 225 return S_OK; 226} 227 228static HRESULT WINAPI MsiActiveScriptSite_OnLeaveScript(IActiveScriptSite* iface) 229{ 230 struct script_site *This = impl_from_IActiveScriptSite(iface); 231 TRACE("(%p)\n", This); 232 return S_OK; 233} 234 235static const struct IActiveScriptSiteVtbl activescriptsitevtbl = 236{ 237 MsiActiveScriptSite_QueryInterface, 238 MsiActiveScriptSite_AddRef, 239 MsiActiveScriptSite_Release, 240 MsiActiveScriptSite_GetLCID, 241 MsiActiveScriptSite_GetItemInfo, 242 MsiActiveScriptSite_GetDocVersionString, 243 MsiActiveScriptSite_OnScriptTerminate, 244 MsiActiveScriptSite_OnStateChange, 245 MsiActiveScriptSite_OnScriptError, 246 MsiActiveScriptSite_OnEnterScript, 247 MsiActiveScriptSite_OnLeaveScript 248}; 249 250static HRESULT create_activescriptsite(struct script_site **obj) 251{ 252 struct script_site *object; 253 254 TRACE("(%p)\n", obj); 255 256 *obj = NULL; 257 258 object = malloc(sizeof(*object)); 259 if (!object) 260 return E_OUTOFMEMORY; 261 262 object->IActiveScriptSite_iface.lpVtbl = &activescriptsitevtbl; 263 object->ref = 1; 264 object->installer = NULL; 265 object->session = NULL; 266 267 *obj = object; 268 269 return S_OK; 270} 271 272static UINT map_return_value(LONG val) 273{ 274 switch (val) 275 { 276 case 0: 277 case IDOK: 278 case IDIGNORE: return ERROR_SUCCESS; 279 case IDCANCEL: return ERROR_INSTALL_USEREXIT; 280 case IDRETRY: return ERROR_INSTALL_SUSPEND; 281 case IDABORT: 282 default: return ERROR_INSTALL_FAILURE; 283 } 284} 285 286/* 287 * Call a script. 288 */ 289DWORD call_script(MSIHANDLE hPackage, INT type, LPCWSTR script, LPCWSTR function, LPCWSTR action) 290{ 291 HRESULT hr; 292 IActiveScript *pActiveScript = NULL; 293 IActiveScriptParse *pActiveScriptParse = NULL; 294 struct script_site *scriptsite; 295 IDispatch *pDispatch = NULL; 296 DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0}; 297 DISPID dispid; 298 CLSID clsid; 299 VARIANT var; 300 DWORD ret = ERROR_INSTALL_FAILURE; 301 302 CoInitialize(NULL); 303 304 /* Create MsiActiveScriptSite object */ 305 hr = create_activescriptsite(&scriptsite); 306 if (hr != S_OK) goto done; 307 308 /* Create an installer object */ 309 hr = create_msiserver(NULL, (void**)&scriptsite->installer); 310 if (hr != S_OK) goto done; 311 312 /* Create a session object */ 313 hr = create_session(hPackage, scriptsite->installer, &scriptsite->session); 314 if (hr != S_OK) goto done; 315 316 /* Create the scripting engine */ 317 type &= msidbCustomActionTypeJScript|msidbCustomActionTypeVBScript; 318 if (type == msidbCustomActionTypeJScript) 319 hr = CLSIDFromProgID(L"JScript", &clsid); 320 else if (type == msidbCustomActionTypeVBScript) 321 hr = CLSIDFromProgID(L"VBScript", &clsid); 322 else { 323 ERR("Unknown script type %d\n", type); 324 goto done; 325 } 326 if (FAILED(hr)) { 327 ERR("Could not find CLSID for Windows Script\n"); 328 goto done; 329 } 330 hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IActiveScript, (void **)&pActiveScript); 331 if (FAILED(hr)) { 332 ERR("Could not instantiate class for Windows Script\n"); 333 goto done; 334 } 335 336 hr = IActiveScript_QueryInterface(pActiveScript, &IID_IActiveScriptParse, (void **)&pActiveScriptParse); 337 if (FAILED(hr)) goto done; 338 339 hr = IActiveScript_SetScriptSite(pActiveScript, &scriptsite->IActiveScriptSite_iface); 340 if (FAILED(hr)) goto done; 341 342 hr = IActiveScriptParse_InitNew(pActiveScriptParse); 343 if (FAILED(hr)) goto done; 344 345 hr = IActiveScript_AddNamedItem(pActiveScript, L"Session", SCRIPTITEM_GLOBALMEMBERS|SCRIPTITEM_ISVISIBLE); 346 if (FAILED(hr)) goto done; 347 348 hr = IActiveScriptParse_ParseScriptText(pActiveScriptParse, script, NULL, NULL, NULL, 0, 0, 0L, NULL, NULL); 349 if (FAILED(hr)) goto done; 350 351 hr = IActiveScript_SetScriptState(pActiveScript, SCRIPTSTATE_CONNECTED); 352 if (FAILED(hr)) goto done; 353 354 /* Call a function if necessary through the IDispatch interface */ 355 if (function && function[0]) { 356 TRACE("Calling function %s\n", debugstr_w(function)); 357 358 hr = IActiveScript_GetScriptDispatch(pActiveScript, NULL, &pDispatch); 359 if (FAILED(hr)) goto done; 360 361 hr = IDispatch_GetIDsOfNames(pDispatch, &IID_NULL, (WCHAR **)&function, 1,LOCALE_USER_DEFAULT, &dispid); 362 if (FAILED(hr)) goto done; 363 364 hr = IDispatch_Invoke(pDispatch, dispid, &IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparamsNoArgs, &var, NULL, NULL); 365 if (FAILED(hr)) goto done; 366 367 hr = VariantChangeType(&var, &var, 0, VT_I4); 368 if (FAILED(hr)) goto done; 369 370 ret = map_return_value(V_I4(&var)); 371 372 VariantClear(&var); 373 } else { 374 /* If no function to be called, MSI behavior is to succeed */ 375 ret = ERROR_SUCCESS; 376 } 377 378done: 379 380 if (pDispatch) IDispatch_Release(pDispatch); 381 if (pActiveScript) IActiveScript_Release(pActiveScript); 382 if (pActiveScriptParse) IActiveScriptParse_Release(pActiveScriptParse); 383 if (scriptsite) 384 { 385 if (scriptsite->session) IDispatch_Release(scriptsite->session); 386 if (scriptsite->installer) IDispatch_Release(scriptsite->installer); 387 IActiveScriptSite_Release(&scriptsite->IActiveScriptSite_iface); 388 } 389 CoUninitialize(); /* must call even if CoInitialize failed */ 390 return ret; 391}