1 /* 2 * Implementation of OLE Automation 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 "winreg.h" 29 #include "msidefs.h" 30 #include "msipriv.h" 31 #include "activscp.h" 32 #include "oleauto.h" 33 #include "shlwapi.h" 34 #include "wine/debug.h" 35 #include "wine/unicode.h" 36 37 #include "msiserver.h" 38 #include "msiserver_dispids.h" 39 40 WINE_DEFAULT_DEBUG_CHANNEL(msi); 41 42 #define REG_INDEX_CLASSES_ROOT 0 43 #define REG_INDEX_DYN_DATA 6 44 45 typedef struct AutomationObject AutomationObject; 46 47 /* function that is called from AutomationObject::Invoke, specific to this type of object */ 48 typedef HRESULT (*auto_invoke_func)(AutomationObject* This, 49 DISPID dispIdMember, REFIID riid, LCID lcid, WORD flags, DISPPARAMS* pDispParams, 50 VARIANT* result, EXCEPINFO* ei, UINT* arg_err); 51 /* function that is called from AutomationObject::Release when the object is being freed 52 to free any private data structures (or NULL) */ 53 typedef void (*auto_free_func)(AutomationObject* This); 54 55 typedef struct { 56 REFIID riid; 57 auto_invoke_func fn_invoke; 58 auto_free_func fn_free; 59 } tid_id_t; 60 61 62 static HRESULT database_invoke(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*); 63 static HRESULT installer_invoke(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*); 64 static HRESULT record_invoke(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*); 65 static HRESULT session_invoke(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*); 66 static HRESULT list_invoke(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*); 67 static void list_free(AutomationObject*); 68 static HRESULT summaryinfo_invoke(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*); 69 static HRESULT view_invoke(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*); 70 71 static tid_id_t tid_ids[] = { 72 { &DIID_Database, database_invoke }, 73 { &DIID_Installer, installer_invoke }, 74 { &DIID_Record, record_invoke }, 75 { &DIID_Session, session_invoke }, 76 { &DIID_StringList, list_invoke, list_free }, 77 { &DIID_SummaryInfo, summaryinfo_invoke }, 78 { &DIID_View, view_invoke } 79 }; 80 81 static ITypeLib *typelib; 82 static ITypeInfo *typeinfos[LAST_tid]; 83 84 static const IID *get_riid_from_tid(tid_t tid) 85 { 86 return tid_ids[tid].riid; 87 } 88 89 HRESULT get_typeinfo(tid_t tid, ITypeInfo **typeinfo) 90 { 91 HRESULT hr; 92 93 if (!typelib) 94 { 95 ITypeLib *lib; 96 97 hr = LoadRegTypeLib(&LIBID_WindowsInstaller, 1, 0, LOCALE_NEUTRAL, &lib); 98 if (FAILED(hr)) { 99 static const WCHAR msiserverW[] = {'m','s','i','s','e','r','v','e','r','.','t','l','b',0}; 100 hr = LoadTypeLib(msiserverW, &lib); 101 if (FAILED(hr)) { 102 ERR("Could not load msiserver.tlb\n"); 103 return hr; 104 } 105 } 106 107 if (InterlockedCompareExchangePointer((void**)&typelib, lib, NULL)) 108 ITypeLib_Release(lib); 109 } 110 111 if (!typeinfos[tid]) 112 { 113 ITypeInfo *ti; 114 115 hr = ITypeLib_GetTypeInfoOfGuid(typelib, get_riid_from_tid(tid), &ti); 116 if (FAILED(hr)) { 117 ERR("Could not load ITypeInfo for %s\n", debugstr_guid(get_riid_from_tid(tid))); 118 return hr; 119 } 120 121 if(InterlockedCompareExchangePointer((void**)(typeinfos+tid), ti, NULL)) 122 ITypeInfo_Release(ti); 123 } 124 125 *typeinfo = typeinfos[tid]; 126 return S_OK; 127 } 128 129 void release_typelib(void) 130 { 131 unsigned i; 132 133 for (i = 0; i < sizeof(typeinfos)/sizeof(*typeinfos); i++) 134 if (typeinfos[i]) 135 ITypeInfo_Release(typeinfos[i]); 136 137 if (typelib) 138 ITypeLib_Release(typelib); 139 } 140 141 /* 142 * AutomationObject - "base" class for all automation objects. For each interface, we implement Invoke function 143 * called from AutomationObject::Invoke. 144 */ 145 struct AutomationObject { 146 IDispatch IDispatch_iface; 147 IProvideMultipleClassInfo IProvideMultipleClassInfo_iface; 148 LONG ref; 149 150 /* type id for this class */ 151 tid_t tid; 152 153 /* The MSI handle of the current object */ 154 MSIHANDLE msiHandle; 155 }; 156 157 typedef struct { 158 AutomationObject autoobj; 159 int count; 160 VARIANT *data; 161 } ListObject; 162 163 static HRESULT create_database(MSIHANDLE, IDispatch**); 164 static HRESULT create_list_enumerator(ListObject*, void**); 165 static HRESULT create_summaryinfo(MSIHANDLE, IDispatch**); 166 static HRESULT create_view(MSIHANDLE, IDispatch**); 167 168 /* ListEnumerator - IEnumVARIANT implementation for MSI automation lists */ 169 typedef struct { 170 IEnumVARIANT IEnumVARIANT_iface; 171 LONG ref; 172 173 /* Current position and pointer to AutomationObject that stores actual data */ 174 ULONG pos; 175 ListObject *list; 176 } ListEnumerator; 177 178 typedef struct { 179 AutomationObject autoobj; 180 IDispatch *installer; 181 } SessionObject; 182 183 static inline AutomationObject *impl_from_IProvideMultipleClassInfo( IProvideMultipleClassInfo *iface ) 184 { 185 return CONTAINING_RECORD(iface, AutomationObject, IProvideMultipleClassInfo_iface); 186 } 187 188 static inline AutomationObject *impl_from_IDispatch( IDispatch *iface ) 189 { 190 return CONTAINING_RECORD(iface, AutomationObject, IDispatch_iface); 191 } 192 193 /* AutomationObject methods */ 194 static HRESULT WINAPI AutomationObject_QueryInterface(IDispatch* iface, REFIID riid, void** ppvObject) 195 { 196 AutomationObject *This = impl_from_IDispatch(iface); 197 198 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject); 199 200 if (ppvObject == NULL) 201 return E_INVALIDARG; 202 203 *ppvObject = 0; 204 205 if (IsEqualGUID(riid, &IID_IUnknown) || 206 IsEqualGUID(riid, &IID_IDispatch) || 207 IsEqualGUID(riid, get_riid_from_tid(This->tid))) 208 *ppvObject = &This->IDispatch_iface; 209 else if (IsEqualGUID(riid, &IID_IProvideClassInfo) || 210 IsEqualGUID(riid, &IID_IProvideClassInfo2) || 211 IsEqualGUID(riid, &IID_IProvideMultipleClassInfo)) 212 *ppvObject = &This->IProvideMultipleClassInfo_iface; 213 else 214 { 215 TRACE("() : asking for unsupported interface %s\n", debugstr_guid(riid)); 216 return E_NOINTERFACE; 217 } 218 219 IDispatch_AddRef(iface); 220 221 return S_OK; 222 } 223 224 static ULONG WINAPI AutomationObject_AddRef(IDispatch* iface) 225 { 226 AutomationObject *This = impl_from_IDispatch(iface); 227 228 TRACE("(%p/%p)\n", iface, This); 229 230 return InterlockedIncrement(&This->ref); 231 } 232 233 static ULONG WINAPI AutomationObject_Release(IDispatch* iface) 234 { 235 AutomationObject *This = impl_from_IDispatch(iface); 236 ULONG ref = InterlockedDecrement(&This->ref); 237 238 TRACE("(%p/%p)\n", iface, This); 239 240 if (!ref) 241 { 242 if (tid_ids[This->tid].fn_free) tid_ids[This->tid].fn_free(This); 243 MsiCloseHandle(This->msiHandle); 244 msi_free(This); 245 } 246 247 return ref; 248 } 249 250 static HRESULT WINAPI AutomationObject_GetTypeInfoCount( 251 IDispatch* iface, 252 UINT* pctinfo) 253 { 254 AutomationObject *This = impl_from_IDispatch(iface); 255 256 TRACE("(%p/%p)->(%p)\n", iface, This, pctinfo); 257 *pctinfo = 1; 258 return S_OK; 259 } 260 261 static HRESULT WINAPI AutomationObject_GetTypeInfo( 262 IDispatch* iface, 263 UINT iTInfo, 264 LCID lcid, 265 ITypeInfo** ppTInfo) 266 { 267 AutomationObject *This = impl_from_IDispatch(iface); 268 HRESULT hr; 269 270 TRACE("(%p/%p)->(%d,%d,%p)\n", iface, This, iTInfo, lcid, ppTInfo); 271 272 hr = get_typeinfo(This->tid, ppTInfo); 273 if (FAILED(hr)) 274 return hr; 275 276 ITypeInfo_AddRef(*ppTInfo); 277 return hr; 278 } 279 280 static HRESULT WINAPI AutomationObject_GetIDsOfNames( 281 IDispatch* iface, 282 REFIID riid, 283 LPOLESTR* rgszNames, 284 UINT cNames, 285 LCID lcid, 286 DISPID* rgDispId) 287 { 288 AutomationObject *This = impl_from_IDispatch(iface); 289 ITypeInfo *ti; 290 HRESULT hr; 291 292 TRACE("(%p/%p)->(%s, %p, %d, %d, %p)\n", iface, This, 293 debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId); 294 295 if (!IsEqualGUID(riid, &IID_NULL)) return E_INVALIDARG; 296 297 hr = get_typeinfo(This->tid, &ti); 298 if (FAILED(hr)) 299 return hr; 300 301 hr = ITypeInfo_GetIDsOfNames(ti, rgszNames, cNames, rgDispId); 302 if (hr == DISP_E_UNKNOWNNAME) 303 { 304 UINT idx; 305 for (idx=0; idx<cNames; idx++) 306 { 307 if (rgDispId[idx] == DISPID_UNKNOWN) 308 FIXME("Unknown member %s, clsid %s\n", debugstr_w(rgszNames[idx]), debugstr_guid(get_riid_from_tid(This->tid))); 309 } 310 } 311 return hr; 312 } 313 314 /* Maximum number of allowed function parameters+1 */ 315 #define MAX_FUNC_PARAMS 20 316 317 /* Some error checking is done here to simplify individual object function invocation */ 318 static HRESULT WINAPI AutomationObject_Invoke( 319 IDispatch* iface, 320 DISPID dispIdMember, 321 REFIID riid, 322 LCID lcid, 323 WORD wFlags, 324 DISPPARAMS* pDispParams, 325 VARIANT* pVarResult, 326 EXCEPINFO* pExcepInfo, 327 UINT* puArgErr) 328 { 329 AutomationObject *This = impl_from_IDispatch(iface); 330 HRESULT hr; 331 unsigned int uArgErr; 332 VARIANT varResultDummy; 333 BSTR bstrName = NULL; 334 ITypeInfo *ti; 335 336 TRACE("(%p/%p)->(%d, %s, %d, %d, %p, %p, %p, %p)\n", iface, This, 337 dispIdMember, debugstr_guid(riid), lcid, wFlags, 338 pDispParams, pVarResult, pExcepInfo, puArgErr); 339 340 if (!IsEqualIID(riid, &IID_NULL)) 341 { 342 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid)); 343 return DISP_E_UNKNOWNNAME; 344 } 345 346 if (wFlags & DISPATCH_PROPERTYGET && !pVarResult) 347 { 348 ERR("NULL pVarResult not allowed when DISPATCH_PROPERTYGET specified\n"); 349 return DISP_E_PARAMNOTOPTIONAL; 350 } 351 352 /* This simplifies our individual object invocation functions */ 353 if (puArgErr == NULL) puArgErr = &uArgErr; 354 if (pVarResult == NULL) pVarResult = &varResultDummy; 355 356 hr = get_typeinfo(This->tid, &ti); 357 if (FAILED(hr)) 358 return hr; 359 360 /* Assume return type is void unless determined otherwise */ 361 VariantInit(pVarResult); 362 363 /* If we are tracing, we want to see the name of the member we are invoking */ 364 if (TRACE_ON(msi)) 365 { 366 ITypeInfo_GetDocumentation(ti, dispIdMember, &bstrName, NULL, NULL, NULL); 367 TRACE("Method %d, %s\n", dispIdMember, debugstr_w(bstrName)); 368 } 369 370 hr = tid_ids[This->tid].fn_invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr); 371 372 if (hr == DISP_E_MEMBERNOTFOUND) { 373 if (bstrName == NULL) ITypeInfo_GetDocumentation(ti, dispIdMember, &bstrName, NULL, NULL, NULL); 374 FIXME("Method %d, %s wflags %d not implemented, clsid %s\n", dispIdMember, debugstr_w(bstrName), wFlags, 375 debugstr_guid(get_riid_from_tid(This->tid))); 376 } 377 else if (pExcepInfo && 378 (hr == DISP_E_PARAMNOTFOUND || 379 hr == DISP_E_EXCEPTION)) { 380 static const WCHAR szComma[] = { ',',0 }; 381 static const WCHAR szExceptionSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0}; 382 WCHAR szExceptionDescription[MAX_PATH]; 383 BSTR bstrParamNames[MAX_FUNC_PARAMS]; 384 unsigned namesNo, i; 385 BOOL bFirst = TRUE; 386 387 if (FAILED(ITypeInfo_GetNames(ti, dispIdMember, bstrParamNames, 388 MAX_FUNC_PARAMS, &namesNo))) 389 { 390 TRACE("Failed to retrieve names for dispIdMember %d\n", dispIdMember); 391 } 392 else 393 { 394 memset(szExceptionDescription, 0, sizeof(szExceptionDescription)); 395 for (i=0; i<namesNo; i++) 396 { 397 if (bFirst) bFirst = FALSE; 398 else { 399 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], szComma); 400 } 401 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], bstrParamNames[i]); 402 SysFreeString(bstrParamNames[i]); 403 } 404 405 memset(pExcepInfo, 0, sizeof(EXCEPINFO)); 406 pExcepInfo->wCode = 1000; 407 pExcepInfo->bstrSource = SysAllocString(szExceptionSource); 408 pExcepInfo->bstrDescription = SysAllocString(szExceptionDescription); 409 hr = DISP_E_EXCEPTION; 410 } 411 } 412 413 /* Make sure we free the return variant if it is our dummy variant */ 414 if (pVarResult == &varResultDummy) VariantClear(pVarResult); 415 416 /* Free function name if we retrieved it */ 417 SysFreeString(bstrName); 418 419 TRACE("Returning 0x%08x, %s\n", hr, SUCCEEDED(hr) ? "ok" : "not ok"); 420 421 return hr; 422 } 423 424 static const struct IDispatchVtbl AutomationObjectVtbl = 425 { 426 AutomationObject_QueryInterface, 427 AutomationObject_AddRef, 428 AutomationObject_Release, 429 AutomationObject_GetTypeInfoCount, 430 AutomationObject_GetTypeInfo, 431 AutomationObject_GetIDsOfNames, 432 AutomationObject_Invoke 433 }; 434 435 /* 436 * IProvideMultipleClassInfo methods 437 */ 438 439 static HRESULT WINAPI ProvideMultipleClassInfo_QueryInterface( 440 IProvideMultipleClassInfo* iface, 441 REFIID riid, 442 VOID** ppvoid) 443 { 444 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface); 445 return IDispatch_QueryInterface(&This->IDispatch_iface, riid, ppvoid); 446 } 447 448 static ULONG WINAPI ProvideMultipleClassInfo_AddRef(IProvideMultipleClassInfo* iface) 449 { 450 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface); 451 return IDispatch_AddRef(&This->IDispatch_iface); 452 } 453 454 static ULONG WINAPI ProvideMultipleClassInfo_Release(IProvideMultipleClassInfo* iface) 455 { 456 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface); 457 return IDispatch_Release(&This->IDispatch_iface); 458 } 459 460 static HRESULT WINAPI ProvideMultipleClassInfo_GetClassInfo(IProvideMultipleClassInfo* iface, ITypeInfo** ppTI) 461 { 462 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface); 463 HRESULT hr; 464 465 TRACE("(%p/%p)->(%p)\n", iface, This, ppTI); 466 467 hr = get_typeinfo(This->tid, ppTI); 468 if (SUCCEEDED(hr)) 469 ITypeInfo_AddRef(*ppTI); 470 471 return hr; 472 } 473 474 static HRESULT WINAPI ProvideMultipleClassInfo_GetGUID(IProvideMultipleClassInfo* iface, DWORD dwGuidKind, GUID* pGUID) 475 { 476 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface); 477 TRACE("(%p/%p)->(%d,%s)\n", iface, This, dwGuidKind, debugstr_guid(pGUID)); 478 479 if (dwGuidKind != GUIDKIND_DEFAULT_SOURCE_DISP_IID) 480 return E_INVALIDARG; 481 else { 482 *pGUID = *get_riid_from_tid(This->tid); 483 return S_OK; 484 } 485 } 486 487 static HRESULT WINAPI ProvideMultipleClassInfo_GetMultiTypeInfoCount(IProvideMultipleClassInfo* iface, ULONG* pcti) 488 { 489 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface); 490 491 TRACE("(%p/%p)->(%p)\n", iface, This, pcti); 492 *pcti = 1; 493 return S_OK; 494 } 495 496 static HRESULT WINAPI ProvideMultipleClassInfo_GetInfoOfIndex(IProvideMultipleClassInfo* iface, 497 ULONG iti, 498 DWORD dwFlags, 499 ITypeInfo** ti, 500 DWORD* pdwTIFlags, 501 ULONG* pcdispidReserved, 502 IID* piidPrimary, 503 IID* piidSource) 504 { 505 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface); 506 507 TRACE("(%p/%p)->(%d,%d,%p,%p,%p,%p,%p)\n", iface, This, iti, dwFlags, ti, pdwTIFlags, pcdispidReserved, piidPrimary, piidSource); 508 509 if (iti != 0) 510 return E_INVALIDARG; 511 512 if (dwFlags & MULTICLASSINFO_GETTYPEINFO) 513 { 514 HRESULT hr = get_typeinfo(This->tid, ti); 515 if (FAILED(hr)) 516 return hr; 517 518 ITypeInfo_AddRef(*ti); 519 } 520 521 if (dwFlags & MULTICLASSINFO_GETNUMRESERVEDDISPIDS) 522 { 523 *pdwTIFlags = 0; 524 *pcdispidReserved = 0; 525 } 526 527 if (dwFlags & MULTICLASSINFO_GETIIDPRIMARY) 528 *piidPrimary = *get_riid_from_tid(This->tid); 529 530 if (dwFlags & MULTICLASSINFO_GETIIDSOURCE) 531 *piidSource = *get_riid_from_tid(This->tid); 532 533 return S_OK; 534 } 535 536 static const IProvideMultipleClassInfoVtbl ProvideMultipleClassInfoVtbl = 537 { 538 ProvideMultipleClassInfo_QueryInterface, 539 ProvideMultipleClassInfo_AddRef, 540 ProvideMultipleClassInfo_Release, 541 ProvideMultipleClassInfo_GetClassInfo, 542 ProvideMultipleClassInfo_GetGUID, 543 ProvideMultipleClassInfo_GetMultiTypeInfoCount, 544 ProvideMultipleClassInfo_GetInfoOfIndex 545 }; 546 547 static HRESULT init_automation_object(AutomationObject *This, MSIHANDLE msiHandle, tid_t tid) 548 { 549 TRACE("(%p, %d, %s)\n", This, msiHandle, debugstr_guid(get_riid_from_tid(tid))); 550 551 This->IDispatch_iface.lpVtbl = &AutomationObjectVtbl; 552 This->IProvideMultipleClassInfo_iface.lpVtbl = &ProvideMultipleClassInfoVtbl; 553 This->ref = 1; 554 555 This->msiHandle = msiHandle; 556 This->tid = tid; 557 558 return S_OK; 559 } 560 561 /* 562 * ListEnumerator methods 563 */ 564 565 static inline ListEnumerator *impl_from_IEnumVARIANT(IEnumVARIANT* iface) 566 { 567 return CONTAINING_RECORD(iface, ListEnumerator, IEnumVARIANT_iface); 568 } 569 570 static HRESULT WINAPI ListEnumerator_QueryInterface(IEnumVARIANT* iface, REFIID riid, 571 void** ppvObject) 572 { 573 ListEnumerator *This = impl_from_IEnumVARIANT(iface); 574 575 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject); 576 577 if (ppvObject == NULL) 578 return E_INVALIDARG; 579 580 *ppvObject = 0; 581 582 if (IsEqualGUID(riid, &IID_IUnknown) || 583 IsEqualGUID(riid, &IID_IEnumVARIANT)) 584 { 585 *ppvObject = &This->IEnumVARIANT_iface; 586 } 587 else 588 { 589 TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid)); 590 return E_NOINTERFACE; 591 } 592 593 IEnumVARIANT_AddRef(iface); 594 return S_OK; 595 } 596 597 static ULONG WINAPI ListEnumerator_AddRef(IEnumVARIANT* iface) 598 { 599 ListEnumerator *This = impl_from_IEnumVARIANT(iface); 600 601 TRACE("(%p/%p)\n", iface, This); 602 603 return InterlockedIncrement(&This->ref); 604 } 605 606 static ULONG WINAPI ListEnumerator_Release(IEnumVARIANT* iface) 607 { 608 ListEnumerator *This = impl_from_IEnumVARIANT(iface); 609 ULONG ref = InterlockedDecrement(&This->ref); 610 611 TRACE("(%p/%p)\n", iface, This); 612 613 if (!ref) 614 { 615 if (This->list) IDispatch_Release(&This->list->autoobj.IDispatch_iface); 616 msi_free(This); 617 } 618 619 return ref; 620 } 621 622 static HRESULT WINAPI ListEnumerator_Next(IEnumVARIANT* iface, ULONG celt, VARIANT* rgVar, 623 ULONG* fetched) 624 { 625 ListEnumerator *This = impl_from_IEnumVARIANT(iface); 626 ULONG i, local; 627 628 TRACE("(%p, %uld, %p, %p)\n", iface, celt, rgVar, fetched); 629 630 if (fetched) *fetched = 0; 631 632 if (!rgVar) 633 return S_FALSE; 634 635 for (local = 0; local < celt; local++) 636 VariantInit(&rgVar[local]); 637 638 for (i = This->pos, local = 0; i < This->list->count && local < celt; i++, local++) 639 VariantCopy(&rgVar[local], &This->list->data[i]); 640 641 if (fetched) *fetched = local; 642 This->pos = i; 643 644 return (local < celt) ? S_FALSE : S_OK; 645 } 646 647 static HRESULT WINAPI ListEnumerator_Skip(IEnumVARIANT* iface, ULONG celt) 648 { 649 ListEnumerator *This = impl_from_IEnumVARIANT(iface); 650 651 TRACE("(%p,%uld)\n", iface, celt); 652 653 This->pos += celt; 654 if (This->pos >= This->list->count) 655 { 656 This->pos = This->list->count; 657 return S_FALSE; 658 } 659 660 return S_OK; 661 } 662 663 static HRESULT WINAPI ListEnumerator_Reset(IEnumVARIANT* iface) 664 { 665 ListEnumerator *This = impl_from_IEnumVARIANT(iface); 666 667 TRACE("(%p)\n", iface); 668 669 This->pos = 0; 670 return S_OK; 671 } 672 673 static HRESULT WINAPI ListEnumerator_Clone(IEnumVARIANT* iface, IEnumVARIANT **ppEnum) 674 { 675 ListEnumerator *This = impl_from_IEnumVARIANT(iface); 676 HRESULT hr; 677 678 TRACE("(%p,%p)\n", iface, ppEnum); 679 680 if (ppEnum == NULL) 681 return S_FALSE; 682 683 *ppEnum = NULL; 684 hr = create_list_enumerator(This->list, (LPVOID *)ppEnum); 685 if (FAILED(hr)) 686 { 687 if (*ppEnum) IEnumVARIANT_Release(*ppEnum); 688 return hr; 689 } 690 691 return S_OK; 692 } 693 694 static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl = 695 { 696 ListEnumerator_QueryInterface, 697 ListEnumerator_AddRef, 698 ListEnumerator_Release, 699 ListEnumerator_Next, 700 ListEnumerator_Skip, 701 ListEnumerator_Reset, 702 ListEnumerator_Clone 703 }; 704 705 /* Create a list enumerator, placing the result in the pointer ppObj. */ 706 static HRESULT create_list_enumerator(ListObject *list, void **ppObj) 707 { 708 ListEnumerator *object; 709 710 TRACE("(%p, %p)\n", list, ppObj); 711 712 object = msi_alloc(sizeof(ListEnumerator)); 713 714 /* Set all the VTable references */ 715 object->IEnumVARIANT_iface.lpVtbl = &ListEnumerator_Vtbl; 716 object->ref = 1; 717 718 /* Store data that was passed */ 719 object->pos = 0; 720 object->list = list; 721 if (list) IDispatch_AddRef(&list->autoobj.IDispatch_iface); 722 723 *ppObj = object; 724 return S_OK; 725 } 726 727 /* 728 * Individual Object Invocation Functions 729 */ 730 731 /* Helper function that copies a passed parameter instead of using VariantChangeType like the actual DispGetParam. 732 This function is only for VARIANT type parameters that have several types that cannot be properly discriminated 733 using DispGetParam/VariantChangeType. */ 734 static HRESULT DispGetParam_CopyOnly( 735 DISPPARAMS *pdispparams, /* [in] Parameter list */ 736 UINT *position, /* [in] Position of parameter to copy in pdispparams; on return will contain calculated position */ 737 VARIANT *pvarResult) /* [out] Destination for resulting variant */ 738 { 739 /* position is counted backwards */ 740 UINT pos; 741 742 TRACE("position=%d, cArgs=%d, cNamedArgs=%d\n", 743 *position, pdispparams->cArgs, pdispparams->cNamedArgs); 744 if (*position < pdispparams->cArgs) { 745 /* positional arg? */ 746 pos = pdispparams->cArgs - *position - 1; 747 } else { 748 /* FIXME: is this how to handle named args? */ 749 for (pos=0; pos<pdispparams->cNamedArgs; pos++) 750 if (pdispparams->rgdispidNamedArgs[pos] == *position) break; 751 752 if (pos==pdispparams->cNamedArgs) 753 return DISP_E_PARAMNOTFOUND; 754 } 755 *position = pos; 756 return VariantCopyInd(pvarResult, 757 &pdispparams->rgvarg[pos]); 758 } 759 760 static HRESULT summaryinfo_invoke( 761 AutomationObject* This, 762 DISPID dispIdMember, 763 REFIID riid, 764 LCID lcid, 765 WORD wFlags, 766 DISPPARAMS* pDispParams, 767 VARIANT* pVarResult, 768 EXCEPINFO* pExcepInfo, 769 UINT* puArgErr) 770 { 771 UINT ret; 772 VARIANTARG varg0, varg1; 773 FILETIME ft, ftlocal; 774 SYSTEMTIME st; 775 HRESULT hr; 776 777 VariantInit(&varg0); 778 VariantInit(&varg1); 779 780 switch (dispIdMember) 781 { 782 case DISPID_SUMMARYINFO_PROPERTY: 783 if (wFlags & DISPATCH_PROPERTYGET) 784 { 785 UINT type; 786 INT value; 787 DWORD size = 0; 788 DATE date; 789 LPWSTR str; 790 791 static WCHAR szEmpty[] = {0}; 792 793 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr); 794 if (FAILED(hr)) return hr; 795 ret = MsiSummaryInfoGetPropertyW(This->msiHandle, V_I4(&varg0), &type, &value, 796 &ft, szEmpty, &size); 797 if (ret != ERROR_SUCCESS && 798 ret != ERROR_MORE_DATA) 799 { 800 ERR("MsiSummaryInfoGetProperty returned %d\n", ret); 801 return DISP_E_EXCEPTION; 802 } 803 804 switch (type) 805 { 806 case VT_EMPTY: 807 break; 808 809 case VT_I2: 810 case VT_I4: 811 V_VT(pVarResult) = VT_I4; 812 V_I4(pVarResult) = value; 813 break; 814 815 case VT_LPSTR: 816 if (!(str = msi_alloc(++size * sizeof(WCHAR)))) 817 ERR("Out of memory\n"); 818 else if ((ret = MsiSummaryInfoGetPropertyW(This->msiHandle, V_I4(&varg0), &type, NULL, 819 NULL, str, &size)) != ERROR_SUCCESS) 820 ERR("MsiSummaryInfoGetProperty returned %d\n", ret); 821 else 822 { 823 V_VT(pVarResult) = VT_BSTR; 824 V_BSTR(pVarResult) = SysAllocString(str); 825 } 826 msi_free(str); 827 break; 828 829 case VT_FILETIME: 830 FileTimeToLocalFileTime(&ft, &ftlocal); 831 FileTimeToSystemTime(&ftlocal, &st); 832 SystemTimeToVariantTime(&st, &date); 833 834 V_VT(pVarResult) = VT_DATE; 835 V_DATE(pVarResult) = date; 836 break; 837 838 default: 839 ERR("Unhandled variant type %d\n", type); 840 } 841 } 842 else if (wFlags & DISPATCH_PROPERTYPUT) 843 { 844 UINT posValue = DISPID_PROPERTYPUT; 845 846 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr); 847 if (FAILED(hr)) return hr; 848 hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg1); 849 if (FAILED(hr)) 850 { 851 *puArgErr = posValue; 852 return hr; 853 } 854 855 switch (V_VT(&varg1)) 856 { 857 case VT_I2: 858 case VT_I4: 859 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), V_VT(&varg1), V_I4(&varg1), NULL, NULL); 860 break; 861 862 case VT_DATE: 863 VariantTimeToSystemTime(V_DATE(&varg1), &st); 864 SystemTimeToFileTime(&st, &ftlocal); 865 LocalFileTimeToFileTime(&ftlocal, &ft); 866 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), VT_FILETIME, 0, &ft, NULL); 867 break; 868 869 case VT_BSTR: 870 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), VT_LPSTR, 0, NULL, V_BSTR(&varg1)); 871 break; 872 873 default: 874 FIXME("Unhandled variant type %d\n", V_VT(&varg1)); 875 VariantClear(&varg1); 876 return DISP_E_EXCEPTION; 877 } 878 879 if (ret != ERROR_SUCCESS) 880 { 881 ERR("MsiSummaryInfoSetPropertyW returned %d\n", ret); 882 return DISP_E_EXCEPTION; 883 } 884 } 885 else return DISP_E_MEMBERNOTFOUND; 886 break; 887 888 case DISPID_SUMMARYINFO_PROPERTYCOUNT: 889 if (wFlags & DISPATCH_PROPERTYGET) { 890 UINT count; 891 if ((ret = MsiSummaryInfoGetPropertyCount(This->msiHandle, &count)) != ERROR_SUCCESS) 892 ERR("MsiSummaryInfoGetPropertyCount returned %d\n", ret); 893 else 894 { 895 V_VT(pVarResult) = VT_I4; 896 V_I4(pVarResult) = count; 897 } 898 } 899 else return DISP_E_MEMBERNOTFOUND; 900 break; 901 902 default: 903 return DISP_E_MEMBERNOTFOUND; 904 } 905 906 VariantClear(&varg1); 907 VariantClear(&varg0); 908 909 return S_OK; 910 } 911 912 static HRESULT record_invoke( 913 AutomationObject* This, 914 DISPID dispIdMember, 915 REFIID riid, 916 LCID lcid, 917 WORD wFlags, 918 DISPPARAMS* pDispParams, 919 VARIANT* pVarResult, 920 EXCEPINFO* pExcepInfo, 921 UINT* puArgErr) 922 { 923 WCHAR *szString; 924 DWORD dwLen = 0; 925 UINT ret; 926 VARIANTARG varg0, varg1; 927 HRESULT hr; 928 929 VariantInit(&varg0); 930 VariantInit(&varg1); 931 932 switch (dispIdMember) 933 { 934 case DISPID_RECORD_FIELDCOUNT: 935 if (wFlags & DISPATCH_PROPERTYGET) { 936 V_VT(pVarResult) = VT_I4; 937 V_I4(pVarResult) = MsiRecordGetFieldCount(This->msiHandle); 938 } 939 else return DISP_E_MEMBERNOTFOUND; 940 break; 941 942 case DISPID_RECORD_STRINGDATA: 943 if (wFlags & DISPATCH_PROPERTYGET) { 944 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr); 945 if (FAILED(hr)) return hr; 946 V_VT(pVarResult) = VT_BSTR; 947 V_BSTR(pVarResult) = NULL; 948 if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), NULL, &dwLen)) == ERROR_SUCCESS) 949 { 950 if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR)))) 951 ERR("Out of memory\n"); 952 else if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), szString, &dwLen)) == ERROR_SUCCESS) 953 V_BSTR(pVarResult) = SysAllocString(szString); 954 msi_free(szString); 955 } 956 if (ret != ERROR_SUCCESS) 957 ERR("MsiRecordGetString returned %d\n", ret); 958 } else if (wFlags & DISPATCH_PROPERTYPUT) { 959 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr); 960 if (FAILED(hr)) return hr; 961 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr); 962 if (FAILED(hr)) return hr; 963 if ((ret = MsiRecordSetStringW(This->msiHandle, V_I4(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS) 964 { 965 VariantClear(&varg1); 966 ERR("MsiRecordSetString returned %d\n", ret); 967 return DISP_E_EXCEPTION; 968 } 969 } 970 else return DISP_E_MEMBERNOTFOUND; 971 break; 972 973 case DISPID_RECORD_INTEGERDATA: 974 if (wFlags & DISPATCH_PROPERTYGET) { 975 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr); 976 if (FAILED(hr)) return hr; 977 V_VT(pVarResult) = VT_I4; 978 V_I4(pVarResult) = MsiRecordGetInteger(This->msiHandle, V_I4(&varg0)); 979 } else if (wFlags & DISPATCH_PROPERTYPUT) { 980 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr); 981 if (FAILED(hr)) return hr; 982 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr); 983 if (FAILED(hr)) return hr; 984 if ((ret = MsiRecordSetInteger(This->msiHandle, V_I4(&varg0), V_I4(&varg1))) != ERROR_SUCCESS) 985 { 986 ERR("MsiRecordSetInteger returned %d\n", ret); 987 return DISP_E_EXCEPTION; 988 } 989 } 990 else return DISP_E_MEMBERNOTFOUND; 991 break; 992 993 default: 994 return DISP_E_MEMBERNOTFOUND; 995 } 996 997 VariantClear(&varg1); 998 VariantClear(&varg0); 999 1000 return S_OK; 1001 } 1002 1003 static HRESULT create_record(MSIHANDLE msiHandle, IDispatch **disp) 1004 { 1005 AutomationObject *record; 1006 HRESULT hr; 1007 1008 record = msi_alloc(sizeof(*record)); 1009 if (!record) return E_OUTOFMEMORY; 1010 1011 hr = init_automation_object(record, msiHandle, Record_tid); 1012 if (hr != S_OK) 1013 { 1014 msi_free(record); 1015 return hr; 1016 } 1017 1018 *disp = &record->IDispatch_iface; 1019 1020 return hr; 1021 } 1022 1023 static HRESULT list_invoke( 1024 AutomationObject* This, 1025 DISPID dispIdMember, 1026 REFIID riid, 1027 LCID lcid, 1028 WORD wFlags, 1029 DISPPARAMS* pDispParams, 1030 VARIANT* pVarResult, 1031 EXCEPINFO* pExcepInfo, 1032 UINT* puArgErr) 1033 { 1034 ListObject *list = CONTAINING_RECORD(This, ListObject, autoobj); 1035 IUnknown *pUnk = NULL; 1036 HRESULT hr; 1037 1038 switch (dispIdMember) 1039 { 1040 case DISPID_LIST__NEWENUM: 1041 if (wFlags & DISPATCH_METHOD) { 1042 V_VT(pVarResult) = VT_UNKNOWN; 1043 if (SUCCEEDED(hr = create_list_enumerator(list, (LPVOID *)&pUnk))) 1044 V_UNKNOWN(pVarResult) = pUnk; 1045 else 1046 ERR("Failed to create IEnumVARIANT object, hresult 0x%08x\n", hr); 1047 } 1048 else return DISP_E_MEMBERNOTFOUND; 1049 break; 1050 1051 case DISPID_LIST_ITEM: 1052 if (wFlags & DISPATCH_PROPERTYGET) { 1053 VARIANTARG index; 1054 1055 VariantInit(&index); 1056 hr = DispGetParam(pDispParams, 0, VT_I4, &index, puArgErr); 1057 if (FAILED(hr)) return hr; 1058 if (V_I4(&index) < 0 || V_I4(&index) >= list->count) 1059 return DISP_E_BADINDEX; 1060 VariantCopy(pVarResult, &list->data[V_I4(&index)]); 1061 } 1062 else return DISP_E_MEMBERNOTFOUND; 1063 break; 1064 1065 case DISPID_LIST_COUNT: 1066 if (wFlags & DISPATCH_PROPERTYGET) { 1067 V_VT(pVarResult) = VT_I4; 1068 V_I4(pVarResult) = list->count; 1069 } 1070 else return DISP_E_MEMBERNOTFOUND; 1071 break; 1072 1073 default: 1074 return DISP_E_MEMBERNOTFOUND; 1075 } 1076 1077 return S_OK; 1078 } 1079 1080 static void list_free(AutomationObject *This) 1081 { 1082 ListObject *list = CONTAINING_RECORD(This, ListObject, autoobj); 1083 int i; 1084 1085 for (i = 0; i < list->count; i++) 1086 VariantClear(&list->data[i]); 1087 msi_free(list->data); 1088 } 1089 1090 static HRESULT get_products_count(const WCHAR *product, int *len) 1091 { 1092 int i = 0; 1093 1094 while (1) 1095 { 1096 WCHAR dataW[GUID_SIZE]; 1097 UINT ret; 1098 1099 /* all or related only */ 1100 if (product) 1101 ret = MsiEnumRelatedProductsW(product, 0, i, dataW); 1102 else 1103 ret = MsiEnumProductsW(i, dataW); 1104 1105 if (ret == ERROR_NO_MORE_ITEMS) break; 1106 1107 if (ret != ERROR_SUCCESS) 1108 return DISP_E_EXCEPTION; 1109 1110 i++; 1111 } 1112 1113 *len = i; 1114 1115 return S_OK; 1116 } 1117 1118 static HRESULT create_list(const WCHAR *product, IDispatch **dispatch) 1119 { 1120 ListObject *list; 1121 HRESULT hr; 1122 int i; 1123 1124 list = msi_alloc_zero(sizeof(ListObject)); 1125 if (!list) return E_OUTOFMEMORY; 1126 1127 hr = init_automation_object(&list->autoobj, 0, StringList_tid); 1128 if (hr != S_OK) 1129 { 1130 msi_free(list); 1131 return hr; 1132 } 1133 1134 *dispatch = &list->autoobj.IDispatch_iface; 1135 1136 hr = get_products_count(product, &list->count); 1137 if (hr != S_OK) 1138 { 1139 IDispatch_Release(*dispatch); 1140 return hr; 1141 } 1142 1143 list->data = msi_alloc(list->count*sizeof(VARIANT)); 1144 if (!list->data) 1145 { 1146 IDispatch_Release(*dispatch); 1147 return E_OUTOFMEMORY; 1148 } 1149 1150 for (i = 0; i < list->count; i++) 1151 { 1152 WCHAR dataW[GUID_SIZE]; 1153 UINT ret; 1154 1155 /* all or related only */ 1156 if (product) 1157 ret = MsiEnumRelatedProductsW(product, 0, i, dataW); 1158 else 1159 ret = MsiEnumProductsW(i, dataW); 1160 1161 if (ret == ERROR_NO_MORE_ITEMS) break; 1162 1163 V_VT(&list->data[i]) = VT_BSTR; 1164 V_BSTR(&list->data[i]) = SysAllocString(dataW); 1165 } 1166 1167 return S_OK; 1168 } 1169 1170 static HRESULT view_invoke( 1171 AutomationObject* This, 1172 DISPID dispIdMember, 1173 REFIID riid, 1174 LCID lcid, 1175 WORD wFlags, 1176 DISPPARAMS* pDispParams, 1177 VARIANT* pVarResult, 1178 EXCEPINFO* pExcepInfo, 1179 UINT* puArgErr) 1180 { 1181 MSIHANDLE msiHandle; 1182 UINT ret; 1183 VARIANTARG varg0, varg1; 1184 HRESULT hr; 1185 1186 VariantInit(&varg0); 1187 VariantInit(&varg1); 1188 1189 switch (dispIdMember) 1190 { 1191 case DISPID_VIEW_EXECUTE: 1192 if (wFlags & DISPATCH_METHOD) 1193 { 1194 hr = DispGetParam(pDispParams, 0, VT_DISPATCH, &varg0, puArgErr); 1195 if (SUCCEEDED(hr) && V_DISPATCH(&varg0) != NULL) 1196 MsiViewExecute(This->msiHandle, ((AutomationObject *)V_DISPATCH(&varg0))->msiHandle); 1197 else 1198 MsiViewExecute(This->msiHandle, 0); 1199 } 1200 else return DISP_E_MEMBERNOTFOUND; 1201 break; 1202 1203 case DISPID_VIEW_FETCH: 1204 if (wFlags & DISPATCH_METHOD) 1205 { 1206 V_VT(pVarResult) = VT_DISPATCH; 1207 if ((ret = MsiViewFetch(This->msiHandle, &msiHandle)) == ERROR_SUCCESS) 1208 { 1209 if (FAILED(hr = create_record(msiHandle, &V_DISPATCH(pVarResult)))) 1210 ERR("Failed to create Record object, hresult 0x%08x\n", hr); 1211 } 1212 else if (ret == ERROR_NO_MORE_ITEMS) 1213 V_DISPATCH(pVarResult) = NULL; 1214 else 1215 { 1216 ERR("MsiViewFetch returned %d\n", ret); 1217 return DISP_E_EXCEPTION; 1218 } 1219 } 1220 else return DISP_E_MEMBERNOTFOUND; 1221 break; 1222 1223 case DISPID_VIEW_MODIFY: 1224 if (wFlags & DISPATCH_METHOD) 1225 { 1226 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr); 1227 if (FAILED(hr)) return hr; 1228 hr = DispGetParam(pDispParams, 1, VT_DISPATCH, &varg1, puArgErr); 1229 if (FAILED(hr)) return hr; 1230 if (!V_DISPATCH(&varg1)) return DISP_E_EXCEPTION; 1231 if ((ret = MsiViewModify(This->msiHandle, V_I4(&varg0), ((AutomationObject *)V_DISPATCH(&varg1))->msiHandle)) != ERROR_SUCCESS) 1232 { 1233 VariantClear(&varg1); 1234 ERR("MsiViewModify returned %d\n", ret); 1235 return DISP_E_EXCEPTION; 1236 } 1237 } 1238 else return DISP_E_MEMBERNOTFOUND; 1239 break; 1240 1241 case DISPID_VIEW_CLOSE: 1242 if (wFlags & DISPATCH_METHOD) 1243 { 1244 MsiViewClose(This->msiHandle); 1245 } 1246 else return DISP_E_MEMBERNOTFOUND; 1247 break; 1248 1249 default: 1250 return DISP_E_MEMBERNOTFOUND; 1251 } 1252 1253 VariantClear(&varg1); 1254 VariantClear(&varg0); 1255 1256 return S_OK; 1257 } 1258 1259 static HRESULT DatabaseImpl_LastErrorRecord(WORD wFlags, 1260 DISPPARAMS* pDispParams, 1261 VARIANT* pVarResult, 1262 EXCEPINFO* pExcepInfo, 1263 UINT* puArgErr) 1264 { 1265 if (!(wFlags & DISPATCH_METHOD)) 1266 return DISP_E_MEMBERNOTFOUND; 1267 1268 FIXME("\n"); 1269 1270 VariantInit(pVarResult); 1271 return S_OK; 1272 } 1273 1274 HRESULT database_invoke( 1275 AutomationObject* This, 1276 DISPID dispIdMember, 1277 REFIID riid, 1278 LCID lcid, 1279 WORD wFlags, 1280 DISPPARAMS* pDispParams, 1281 VARIANT* pVarResult, 1282 EXCEPINFO* pExcepInfo, 1283 UINT* puArgErr) 1284 { 1285 IDispatch *dispatch = NULL; 1286 MSIHANDLE msiHandle; 1287 UINT ret; 1288 VARIANTARG varg0, varg1; 1289 HRESULT hr; 1290 1291 VariantInit(&varg0); 1292 VariantInit(&varg1); 1293 1294 switch (dispIdMember) 1295 { 1296 case DISPID_DATABASE_SUMMARYINFORMATION: 1297 if (wFlags & DISPATCH_PROPERTYGET) 1298 { 1299 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr); 1300 if (FAILED(hr)) 1301 V_I4(&varg0) = 0; 1302 1303 V_VT(pVarResult) = VT_DISPATCH; 1304 if ((ret = MsiGetSummaryInformationW(This->msiHandle, NULL, V_I4(&varg0), &msiHandle)) == ERROR_SUCCESS) 1305 { 1306 hr = create_summaryinfo(msiHandle, &dispatch); 1307 if (SUCCEEDED(hr)) 1308 V_DISPATCH(pVarResult) = dispatch; 1309 else 1310 ERR("Failed to create SummaryInfo object: 0x%08x\n", hr); 1311 } 1312 else 1313 { 1314 ERR("MsiGetSummaryInformation returned %d\n", ret); 1315 return DISP_E_EXCEPTION; 1316 } 1317 } 1318 else return DISP_E_MEMBERNOTFOUND; 1319 break; 1320 1321 case DISPID_DATABASE_OPENVIEW: 1322 if (wFlags & DISPATCH_METHOD) 1323 { 1324 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr); 1325 if (FAILED(hr)) return hr; 1326 V_VT(pVarResult) = VT_DISPATCH; 1327 if ((ret = MsiDatabaseOpenViewW(This->msiHandle, V_BSTR(&varg0), &msiHandle)) == ERROR_SUCCESS) 1328 { 1329 if (SUCCEEDED(hr = create_view(msiHandle, &dispatch))) 1330 V_DISPATCH(pVarResult) = dispatch; 1331 else 1332 ERR("Failed to create View object, hresult 0x%08x\n", hr); 1333 } 1334 else 1335 { 1336 VariantClear(&varg0); 1337 ERR("MsiDatabaseOpenView returned %d\n", ret); 1338 return DISP_E_EXCEPTION; 1339 } 1340 } 1341 else return DISP_E_MEMBERNOTFOUND; 1342 break; 1343 1344 case DISPID_INSTALLER_LASTERRORRECORD: 1345 return DatabaseImpl_LastErrorRecord(wFlags, pDispParams, 1346 pVarResult, pExcepInfo, 1347 puArgErr); 1348 1349 default: 1350 return DISP_E_MEMBERNOTFOUND; 1351 } 1352 1353 VariantClear(&varg1); 1354 VariantClear(&varg0); 1355 1356 return S_OK; 1357 } 1358 1359 static HRESULT session_invoke( 1360 AutomationObject* This, 1361 DISPID dispIdMember, 1362 REFIID riid, 1363 LCID lcid, 1364 WORD wFlags, 1365 DISPPARAMS* pDispParams, 1366 VARIANT* pVarResult, 1367 EXCEPINFO* pExcepInfo, 1368 UINT* puArgErr) 1369 { 1370 SessionObject *session = CONTAINING_RECORD(This, SessionObject, autoobj); 1371 WCHAR *szString; 1372 DWORD dwLen = 0; 1373 MSIHANDLE msiHandle; 1374 LANGID langId; 1375 UINT ret; 1376 INSTALLSTATE iInstalled, iAction; 1377 VARIANTARG varg0, varg1; 1378 HRESULT hr; 1379 1380 VariantInit(&varg0); 1381 VariantInit(&varg1); 1382 1383 switch (dispIdMember) 1384 { 1385 case DISPID_SESSION_INSTALLER: 1386 if (wFlags & DISPATCH_PROPERTYGET) { 1387 V_VT(pVarResult) = VT_DISPATCH; 1388 IDispatch_AddRef(session->installer); 1389 V_DISPATCH(pVarResult) = session->installer; 1390 } 1391 else return DISP_E_MEMBERNOTFOUND; 1392 break; 1393 1394 case DISPID_SESSION_PROPERTY: 1395 if (wFlags & DISPATCH_PROPERTYGET) { 1396 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr); 1397 if (FAILED(hr)) return hr; 1398 V_VT(pVarResult) = VT_BSTR; 1399 V_BSTR(pVarResult) = NULL; 1400 if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), NULL, &dwLen)) == ERROR_SUCCESS) 1401 { 1402 if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR)))) 1403 ERR("Out of memory\n"); 1404 else if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), szString, &dwLen)) == ERROR_SUCCESS) 1405 V_BSTR(pVarResult) = SysAllocString(szString); 1406 msi_free(szString); 1407 } 1408 if (ret != ERROR_SUCCESS) 1409 ERR("MsiGetProperty returned %d\n", ret); 1410 } else if (wFlags & DISPATCH_PROPERTYPUT) { 1411 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr); 1412 if (FAILED(hr)) return hr; 1413 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr); 1414 if (FAILED(hr)) { 1415 VariantClear(&varg0); 1416 return hr; 1417 } 1418 if ((ret = MsiSetPropertyW(This->msiHandle, V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS) 1419 { 1420 VariantClear(&varg0); 1421 VariantClear(&varg1); 1422 ERR("MsiSetProperty returned %d\n", ret); 1423 return DISP_E_EXCEPTION; 1424 } 1425 } 1426 else return DISP_E_MEMBERNOTFOUND; 1427 break; 1428 1429 case DISPID_SESSION_LANGUAGE: 1430 if (wFlags & DISPATCH_PROPERTYGET) { 1431 langId = MsiGetLanguage(This->msiHandle); 1432 V_VT(pVarResult) = VT_I4; 1433 V_I4(pVarResult) = langId; 1434 } 1435 else return DISP_E_MEMBERNOTFOUND; 1436 break; 1437 1438 case DISPID_SESSION_MODE: 1439 if (wFlags & DISPATCH_PROPERTYGET) { 1440 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr); 1441 if (FAILED(hr)) return hr; 1442 V_VT(pVarResult) = VT_BOOL; 1443 V_BOOL(pVarResult) = MsiGetMode(This->msiHandle, V_I4(&varg0)) ? VARIANT_TRUE : VARIANT_FALSE; 1444 } else if (wFlags & DISPATCH_PROPERTYPUT) { 1445 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr); 1446 if (FAILED(hr)) return hr; 1447 hr = DispGetParam(pDispParams, 1, VT_BOOL, &varg1, puArgErr); 1448 if (FAILED(hr)) return hr; 1449 if ((ret = MsiSetMode(This->msiHandle, V_I4(&varg0), V_BOOL(&varg1))) != ERROR_SUCCESS) 1450 { 1451 ERR("MsiSetMode returned %d\n", ret); 1452 return DISP_E_EXCEPTION; 1453 } 1454 } 1455 else return DISP_E_MEMBERNOTFOUND; 1456 break; 1457 1458 case DISPID_SESSION_DATABASE: 1459 if (wFlags & DISPATCH_PROPERTYGET) { 1460 V_VT(pVarResult) = VT_DISPATCH; 1461 if ((msiHandle = MsiGetActiveDatabase(This->msiHandle))) 1462 { 1463 IDispatch *dispatch; 1464 1465 if (SUCCEEDED(hr = create_database(msiHandle, &dispatch))) 1466 V_DISPATCH(pVarResult) = dispatch; 1467 else 1468 ERR("Failed to create Database object, hresult 0x%08x\n", hr); 1469 } 1470 else 1471 { 1472 ERR("MsiGetActiveDatabase failed\n"); 1473 return DISP_E_EXCEPTION; 1474 } 1475 } 1476 else return DISP_E_MEMBERNOTFOUND; 1477 break; 1478 1479 case DISPID_SESSION_DOACTION: 1480 if (wFlags & DISPATCH_METHOD) { 1481 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr); 1482 if (FAILED(hr)) return hr; 1483 ret = MsiDoActionW(This->msiHandle, V_BSTR(&varg0)); 1484 V_VT(pVarResult) = VT_I4; 1485 switch (ret) 1486 { 1487 case ERROR_FUNCTION_NOT_CALLED: 1488 V_I4(pVarResult) = msiDoActionStatusNoAction; 1489 break; 1490 case ERROR_SUCCESS: 1491 V_I4(pVarResult) = msiDoActionStatusSuccess; 1492 break; 1493 case ERROR_INSTALL_USEREXIT: 1494 V_I4(pVarResult) = msiDoActionStatusUserExit; 1495 break; 1496 case ERROR_INSTALL_FAILURE: 1497 V_I4(pVarResult) = msiDoActionStatusFailure; 1498 break; 1499 case ERROR_INSTALL_SUSPEND: 1500 V_I4(pVarResult) = msiDoActionStatusSuspend; 1501 break; 1502 case ERROR_MORE_DATA: 1503 V_I4(pVarResult) = msiDoActionStatusFinished; 1504 break; 1505 case ERROR_INVALID_HANDLE_STATE: 1506 V_I4(pVarResult) = msiDoActionStatusWrongState; 1507 break; 1508 case ERROR_INVALID_DATA: 1509 V_I4(pVarResult) = msiDoActionStatusBadActionData; 1510 break; 1511 default: 1512 VariantClear(&varg0); 1513 FIXME("MsiDoAction returned unhandled value %d\n", ret); 1514 return DISP_E_EXCEPTION; 1515 } 1516 } 1517 else return DISP_E_MEMBERNOTFOUND; 1518 break; 1519 1520 case DISPID_SESSION_EVALUATECONDITION: 1521 if (wFlags & DISPATCH_METHOD) { 1522 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr); 1523 if (FAILED(hr)) return hr; 1524 V_VT(pVarResult) = VT_I4; 1525 V_I4(pVarResult) = MsiEvaluateConditionW(This->msiHandle, V_BSTR(&varg0)); 1526 } 1527 else return DISP_E_MEMBERNOTFOUND; 1528 break; 1529 1530 case DISPID_SESSION_MESSAGE: 1531 if(!(wFlags & DISPATCH_METHOD)) 1532 return DISP_E_MEMBERNOTFOUND; 1533 1534 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr); 1535 if (FAILED(hr)) return hr; 1536 hr = DispGetParam(pDispParams, 1, VT_DISPATCH, &varg1, puArgErr); 1537 if (FAILED(hr)) return hr; 1538 1539 V_VT(pVarResult) = VT_I4; 1540 V_I4(pVarResult) = 1541 MsiProcessMessage(This->msiHandle, V_I4(&varg0), ((AutomationObject *)V_DISPATCH(&varg1))->msiHandle); 1542 break; 1543 1544 case DISPID_SESSION_SETINSTALLLEVEL: 1545 if (wFlags & DISPATCH_METHOD) { 1546 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr); 1547 if (FAILED(hr)) return hr; 1548 if ((ret = MsiSetInstallLevel(This->msiHandle, V_I4(&varg0))) != ERROR_SUCCESS) 1549 { 1550 ERR("MsiSetInstallLevel returned %d\n", ret); 1551 return DISP_E_EXCEPTION; 1552 } 1553 } 1554 else return DISP_E_MEMBERNOTFOUND; 1555 break; 1556 1557 case DISPID_SESSION_FEATURECURRENTSTATE: 1558 if (wFlags & DISPATCH_PROPERTYGET) { 1559 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr); 1560 if (FAILED(hr)) return hr; 1561 V_VT(pVarResult) = VT_I4; 1562 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS) 1563 V_I4(pVarResult) = iInstalled; 1564 else 1565 { 1566 ERR("MsiGetFeatureState returned %d\n", ret); 1567 V_I4(pVarResult) = msiInstallStateUnknown; 1568 } 1569 } 1570 else return DISP_E_MEMBERNOTFOUND; 1571 break; 1572 1573 case DISPID_SESSION_FEATUREREQUESTSTATE: 1574 if (wFlags & DISPATCH_PROPERTYGET) { 1575 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr); 1576 if (FAILED(hr)) return hr; 1577 V_VT(pVarResult) = VT_I4; 1578 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS) 1579 V_I4(pVarResult) = iAction; 1580 else 1581 { 1582 ERR("MsiGetFeatureState returned %d\n", ret); 1583 V_I4(pVarResult) = msiInstallStateUnknown; 1584 } 1585 } else if (wFlags & DISPATCH_PROPERTYPUT) { 1586 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr); 1587 if (FAILED(hr)) return hr; 1588 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr); 1589 if (FAILED(hr)) { 1590 VariantClear(&varg0); 1591 return hr; 1592 } 1593 if ((ret = MsiSetFeatureStateW(This->msiHandle, V_BSTR(&varg0), V_I4(&varg1))) != ERROR_SUCCESS) 1594 { 1595 VariantClear(&varg0); 1596 ERR("MsiSetFeatureState returned %d\n", ret); 1597 return DISP_E_EXCEPTION; 1598 } 1599 } 1600 else return DISP_E_MEMBERNOTFOUND; 1601 break; 1602 1603 default: 1604 return DISP_E_MEMBERNOTFOUND; 1605 } 1606 1607 VariantClear(&varg1); 1608 VariantClear(&varg0); 1609 1610 return S_OK; 1611 } 1612 1613 /* Fill the variant pointed to by pVarResult with the value & size returned by RegQueryValueEx as dictated by the 1614 * registry value type. Used by Installer::RegistryValue. */ 1615 static void variant_from_registry_value(VARIANT *pVarResult, DWORD dwType, LPBYTE lpData, DWORD dwSize) 1616 { 1617 static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 }; 1618 static const WCHAR szREG_[] = { '(','R','E','G','_','?','?',')',0 }; 1619 WCHAR *szString = (WCHAR *)lpData; 1620 LPWSTR szNewString = NULL; 1621 DWORD dwNewSize = 0; 1622 int idx; 1623 1624 switch (dwType) 1625 { 1626 /* Registry strings may not be null terminated so we must use SysAllocStringByteLen/Len */ 1627 case REG_MULTI_SZ: /* Multi SZ change internal null characters to newlines */ 1628 idx = (dwSize/sizeof(WCHAR))-1; 1629 while (idx >= 0 && !szString[idx]) idx--; 1630 for (; idx >= 0; idx--) 1631 if (!szString[idx]) szString[idx] = '\n'; 1632 /* fall through */ 1633 case REG_SZ: 1634 V_VT(pVarResult) = VT_BSTR; 1635 V_BSTR(pVarResult) = SysAllocStringByteLen((LPCSTR)szString, dwSize); 1636 break; 1637 1638 case REG_EXPAND_SZ: 1639 if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize))) 1640 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError()); 1641 else if (!(szNewString = msi_alloc(dwNewSize * sizeof(WCHAR)))) 1642 ERR("Out of memory\n"); 1643 else if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize))) 1644 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError()); 1645 else 1646 { 1647 V_VT(pVarResult) = VT_BSTR; 1648 V_BSTR(pVarResult) = SysAllocStringLen(szNewString, dwNewSize); 1649 } 1650 msi_free(szNewString); 1651 break; 1652 1653 case REG_DWORD: 1654 V_VT(pVarResult) = VT_I4; 1655 V_I4(pVarResult) = *((DWORD *)lpData); 1656 break; 1657 1658 case REG_QWORD: 1659 V_VT(pVarResult) = VT_BSTR; 1660 V_BSTR(pVarResult) = SysAllocString(szREG_); /* Weird string, don't know why native returns it */ 1661 break; 1662 1663 case REG_BINARY: 1664 V_VT(pVarResult) = VT_BSTR; 1665 V_BSTR(pVarResult) = SysAllocString(szREG_BINARY); 1666 break; 1667 1668 case REG_NONE: 1669 V_VT(pVarResult) = VT_EMPTY; 1670 break; 1671 1672 default: 1673 FIXME("Unhandled registry value type %d\n", dwType); 1674 } 1675 } 1676 1677 static HRESULT InstallerImpl_CreateRecord(WORD wFlags, 1678 DISPPARAMS* pDispParams, 1679 VARIANT* pVarResult, 1680 EXCEPINFO* pExcepInfo, 1681 UINT* puArgErr) 1682 { 1683 HRESULT hr; 1684 VARIANTARG varg0; 1685 MSIHANDLE hrec; 1686 1687 if (!(wFlags & DISPATCH_METHOD)) 1688 return DISP_E_MEMBERNOTFOUND; 1689 1690 VariantInit(&varg0); 1691 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr); 1692 if (FAILED(hr)) 1693 return hr; 1694 1695 V_VT(pVarResult) = VT_DISPATCH; 1696 1697 hrec = MsiCreateRecord(V_I4(&varg0)); 1698 if (!hrec) 1699 return DISP_E_EXCEPTION; 1700 1701 return create_record(hrec, &V_DISPATCH(pVarResult)); 1702 } 1703 1704 static HRESULT InstallerImpl_OpenPackage(AutomationObject* This, 1705 WORD wFlags, 1706 DISPPARAMS* pDispParams, 1707 VARIANT* pVarResult, 1708 EXCEPINFO* pExcepInfo, 1709 UINT* puArgErr) 1710 { 1711 UINT ret; 1712 HRESULT hr; 1713 MSIHANDLE hpkg; 1714 IDispatch* dispatch; 1715 VARIANTARG varg0, varg1; 1716 1717 if (!(wFlags & DISPATCH_METHOD)) 1718 return DISP_E_MEMBERNOTFOUND; 1719 1720 if (pDispParams->cArgs == 0) 1721 return DISP_E_TYPEMISMATCH; 1722 1723 if (V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1]) != VT_BSTR) 1724 return DISP_E_TYPEMISMATCH; 1725 1726 VariantInit(&varg0); 1727 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr); 1728 if (FAILED(hr)) 1729 return hr; 1730 1731 VariantInit(&varg1); 1732 if (pDispParams->cArgs == 2) 1733 { 1734 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr); 1735 if (FAILED(hr)) 1736 goto done; 1737 } 1738 else 1739 { 1740 V_VT(&varg1) = VT_I4; 1741 V_I4(&varg1) = 0; 1742 } 1743 1744 V_VT(pVarResult) = VT_DISPATCH; 1745 1746 ret = MsiOpenPackageExW(V_BSTR(&varg0), V_I4(&varg1), &hpkg); 1747 if (ret != ERROR_SUCCESS) 1748 { 1749 hr = DISP_E_EXCEPTION; 1750 goto done; 1751 } 1752 1753 hr = create_session(hpkg, &This->IDispatch_iface, &dispatch); 1754 if (SUCCEEDED(hr)) 1755 V_DISPATCH(pVarResult) = dispatch; 1756 1757 done: 1758 VariantClear(&varg0); 1759 VariantClear(&varg1); 1760 return hr; 1761 } 1762 1763 static HRESULT InstallerImpl_OpenProduct(WORD wFlags, 1764 DISPPARAMS* pDispParams, 1765 VARIANT* pVarResult, 1766 EXCEPINFO* pExcepInfo, 1767 UINT* puArgErr) 1768 { 1769 HRESULT hr; 1770 VARIANTARG varg0; 1771 1772 if (!(wFlags & DISPATCH_METHOD)) 1773 return DISP_E_MEMBERNOTFOUND; 1774 1775 VariantInit(&varg0); 1776 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr); 1777 if (FAILED(hr)) 1778 return hr; 1779 1780 FIXME("%s\n", debugstr_w(V_BSTR(&varg0))); 1781 1782 VariantInit(pVarResult); 1783 1784 VariantClear(&varg0); 1785 return S_OK; 1786 } 1787 1788 static HRESULT InstallerImpl_OpenDatabase(WORD wFlags, 1789 DISPPARAMS* pDispParams, 1790 VARIANT* pVarResult, 1791 EXCEPINFO* pExcepInfo, 1792 UINT* puArgErr) 1793 { 1794 UINT ret; 1795 HRESULT hr; 1796 MSIHANDLE hdb; 1797 IDispatch* dispatch; 1798 VARIANTARG varg0, varg1; 1799 1800 if (!(wFlags & DISPATCH_METHOD)) 1801 return DISP_E_MEMBERNOTFOUND; 1802 1803 VariantInit(&varg0); 1804 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr); 1805 if (FAILED(hr)) 1806 return hr; 1807 1808 VariantInit(&varg1); 1809 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr); 1810 if (FAILED(hr)) 1811 goto done; 1812 1813 V_VT(pVarResult) = VT_DISPATCH; 1814 1815 ret = MsiOpenDatabaseW(V_BSTR(&varg0), V_BSTR(&varg1), &hdb); 1816 if (ret != ERROR_SUCCESS) 1817 { 1818 hr = DISP_E_EXCEPTION; 1819 goto done; 1820 } 1821 1822 hr = create_database(hdb, &dispatch); 1823 if (SUCCEEDED(hr)) 1824 V_DISPATCH(pVarResult) = dispatch; 1825 1826 done: 1827 VariantClear(&varg0); 1828 VariantClear(&varg1); 1829 return hr; 1830 } 1831 1832 static HRESULT InstallerImpl_SummaryInformation(WORD wFlags, 1833 DISPPARAMS* pDispParams, 1834 VARIANT* pVarResult, 1835 EXCEPINFO* pExcepInfo, 1836 UINT* puArgErr) 1837 { 1838 UINT ret; 1839 HRESULT hr; 1840 MSIHANDLE hsuminfo; 1841 IDispatch *dispatch; 1842 VARIANTARG varg0, varg1; 1843 1844 if (!(wFlags & DISPATCH_PROPERTYGET)) 1845 return DISP_E_MEMBERNOTFOUND; 1846 1847 VariantInit(&varg1); 1848 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr); 1849 if (FAILED(hr)) 1850 return hr; 1851 1852 VariantInit(&varg0); 1853 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr); 1854 if (FAILED(hr)) 1855 return hr; 1856 1857 ret = MsiGetSummaryInformationW(0, V_BSTR(&varg0), V_I4(&varg1), &hsuminfo); 1858 VariantClear(&varg0); 1859 if (ret != ERROR_SUCCESS) 1860 return DISP_E_EXCEPTION; 1861 1862 hr = create_summaryinfo(hsuminfo, &dispatch); 1863 if (FAILED(hr)) 1864 return hr; 1865 1866 V_VT(pVarResult) = VT_DISPATCH; 1867 V_DISPATCH(pVarResult) = dispatch; 1868 return S_OK; 1869 } 1870 1871 static HRESULT InstallerImpl_UILevel(WORD wFlags, 1872 DISPPARAMS* pDispParams, 1873 VARIANT* pVarResult, 1874 EXCEPINFO* pExcepInfo, 1875 UINT* puArgErr) 1876 { 1877 HRESULT hr; 1878 VARIANTARG varg0; 1879 INSTALLUILEVEL ui; 1880 1881 if (!(wFlags & DISPATCH_PROPERTYPUT) && !(wFlags & DISPATCH_PROPERTYGET)) 1882 return DISP_E_MEMBERNOTFOUND; 1883 1884 if (wFlags & DISPATCH_PROPERTYPUT) 1885 { 1886 VariantInit(&varg0); 1887 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr); 1888 if (FAILED(hr)) 1889 return hr; 1890 1891 ui = MsiSetInternalUI(V_I4(&varg0), NULL); 1892 if (ui == INSTALLUILEVEL_NOCHANGE) 1893 return DISP_E_EXCEPTION; 1894 } 1895 else if (wFlags & DISPATCH_PROPERTYGET) 1896 { 1897 ui = MsiSetInternalUI(INSTALLUILEVEL_NOCHANGE, NULL); 1898 if (ui == INSTALLUILEVEL_NOCHANGE) 1899 return DISP_E_EXCEPTION; 1900 1901 V_VT(pVarResult) = VT_I4; 1902 V_I4(pVarResult) = ui; 1903 } 1904 1905 return S_OK; 1906 } 1907 1908 static HRESULT InstallerImpl_EnableLog(WORD wFlags, 1909 DISPPARAMS* pDispParams, 1910 VARIANT* pVarResult, 1911 EXCEPINFO* pExcepInfo, 1912 UINT* puArgErr) 1913 { 1914 if (!(wFlags & DISPATCH_METHOD)) 1915 return DISP_E_MEMBERNOTFOUND; 1916 1917 FIXME("\n"); 1918 1919 VariantInit(pVarResult); 1920 return S_OK; 1921 } 1922 1923 static HRESULT InstallerImpl_InstallProduct(WORD wFlags, 1924 DISPPARAMS* pDispParams, 1925 VARIANT* pVarResult, 1926 EXCEPINFO* pExcepInfo, 1927 UINT* puArgErr) 1928 { 1929 UINT ret; 1930 HRESULT hr; 1931 VARIANTARG varg0, varg1; 1932 1933 if (!(wFlags & DISPATCH_METHOD)) 1934 return DISP_E_MEMBERNOTFOUND; 1935 1936 VariantInit(&varg0); 1937 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr); 1938 if (FAILED(hr)) 1939 return hr; 1940 1941 VariantInit(&varg1); 1942 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr); 1943 if (FAILED(hr)) 1944 goto done; 1945 1946 ret = MsiInstallProductW(V_BSTR(&varg0), V_BSTR(&varg1)); 1947 if (ret != ERROR_SUCCESS) 1948 { 1949 hr = DISP_E_EXCEPTION; 1950 goto done; 1951 } 1952 1953 done: 1954 VariantClear(&varg0); 1955 VariantClear(&varg1); 1956 return hr; 1957 } 1958 1959 static HRESULT InstallerImpl_Version(WORD wFlags, 1960 VARIANT* pVarResult, 1961 EXCEPINFO* pExcepInfo, 1962 UINT* puArgErr) 1963 { 1964 HRESULT hr; 1965 DLLVERSIONINFO verinfo; 1966 WCHAR version[MAX_PATH]; 1967 1968 static const WCHAR format[] = { 1969 '%','d','.','%','d','.','%','d','.','%','d',0}; 1970 1971 if (!(wFlags & DISPATCH_PROPERTYGET)) 1972 return DISP_E_MEMBERNOTFOUND; 1973 1974 verinfo.cbSize = sizeof(DLLVERSIONINFO); 1975 hr = DllGetVersion(&verinfo); 1976 if (FAILED(hr)) 1977 return hr; 1978 1979 sprintfW(version, format, verinfo.dwMajorVersion, verinfo.dwMinorVersion, 1980 verinfo.dwBuildNumber, verinfo.dwPlatformID); 1981 1982 V_VT(pVarResult) = VT_BSTR; 1983 V_BSTR(pVarResult) = SysAllocString(version); 1984 return S_OK; 1985 } 1986 1987 static HRESULT InstallerImpl_LastErrorRecord(WORD wFlags, 1988 DISPPARAMS* pDispParams, 1989 VARIANT* pVarResult, 1990 EXCEPINFO* pExcepInfo, 1991 UINT* puArgErr) 1992 { 1993 if (!(wFlags & DISPATCH_METHOD)) 1994 return DISP_E_MEMBERNOTFOUND; 1995 1996 FIXME("\n"); 1997 1998 VariantInit(pVarResult); 1999 return S_OK; 2000 } 2001 2002 static HRESULT InstallerImpl_RegistryValue(WORD wFlags, 2003 DISPPARAMS* pDispParams, 2004 VARIANT* pVarResult, 2005 EXCEPINFO* pExcepInfo, 2006 UINT* puArgErr) 2007 { 2008 UINT ret; 2009 HKEY hkey = NULL; 2010 HRESULT hr; 2011 UINT posValue; 2012 DWORD type, size; 2013 LPWSTR szString = NULL; 2014 VARIANTARG varg0, varg1, varg2; 2015 2016 if (!(wFlags & DISPATCH_METHOD)) 2017 return DISP_E_MEMBERNOTFOUND; 2018 2019 VariantInit(&varg0); 2020 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr); 2021 if (FAILED(hr)) 2022 return hr; 2023 2024 VariantInit(&varg1); 2025 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr); 2026 if (FAILED(hr)) 2027 goto done; 2028 2029 /* Save valuePos so we can save puArgErr if we are unable to do our type 2030 * conversions. 2031 */ 2032 posValue = 2; 2033 VariantInit(&varg2); 2034 hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg2); 2035 if (FAILED(hr)) 2036 goto done; 2037 2038 if (V_I4(&varg0) >= REG_INDEX_CLASSES_ROOT && 2039 V_I4(&varg0) <= REG_INDEX_DYN_DATA) 2040 { 2041 V_I4(&varg0) |= (UINT_PTR)HKEY_CLASSES_ROOT; 2042 } 2043 2044 ret = RegOpenKeyW((HKEY)(UINT_PTR)V_I4(&varg0), V_BSTR(&varg1), &hkey); 2045 2046 /* Only VT_EMPTY case can do anything if the key doesn't exist. */ 2047 if (ret != ERROR_SUCCESS && V_VT(&varg2) != VT_EMPTY) 2048 { 2049 hr = DISP_E_BADINDEX; 2050 goto done; 2051 } 2052 2053 /* Third parameter can be VT_EMPTY, VT_I4, or VT_BSTR */ 2054 switch (V_VT(&varg2)) 2055 { 2056 /* Return VT_BOOL clarifying whether registry key exists or not. */ 2057 case VT_EMPTY: 2058 V_VT(pVarResult) = VT_BOOL; 2059 V_BOOL(pVarResult) = (ret == ERROR_SUCCESS) ? VARIANT_TRUE : VARIANT_FALSE; 2060 break; 2061 2062 /* Return the value of specified key if it exists. */ 2063 case VT_BSTR: 2064 ret = RegQueryValueExW(hkey, V_BSTR(&varg2), 2065 NULL, NULL, NULL, &size); 2066 if (ret != ERROR_SUCCESS) 2067 { 2068 hr = DISP_E_BADINDEX; 2069 goto done; 2070 } 2071 2072 szString = msi_alloc(size); 2073 if (!szString) 2074 { 2075 hr = E_OUTOFMEMORY; 2076 goto done; 2077 } 2078 2079 ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL, 2080 &type, (LPBYTE)szString, &size); 2081 if (ret != ERROR_SUCCESS) 2082 { 2083 msi_free(szString); 2084 hr = DISP_E_BADINDEX; 2085 goto done; 2086 } 2087 2088 variant_from_registry_value(pVarResult, type, 2089 (LPBYTE)szString, size); 2090 msi_free(szString); 2091 break; 2092 2093 /* Try to make it into VT_I4, can use VariantChangeType for this. */ 2094 default: 2095 hr = VariantChangeType(&varg2, &varg2, 0, VT_I4); 2096 if (FAILED(hr)) 2097 { 2098 if (hr == DISP_E_TYPEMISMATCH) 2099 *puArgErr = posValue; 2100 2101 goto done; 2102 } 2103 2104 /* Retrieve class name or maximum value name or subkey name size. */ 2105 if (!V_I4(&varg2)) 2106 ret = RegQueryInfoKeyW(hkey, NULL, &size, NULL, NULL, NULL, 2107 NULL, NULL, NULL, NULL, NULL, NULL); 2108 else if (V_I4(&varg2) > 0) 2109 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, 2110 NULL, NULL, &size, NULL, NULL, NULL); 2111 else /* V_I4(&varg2) < 0 */ 2112 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, &size, 2113 NULL, NULL, NULL, NULL, NULL, NULL); 2114 2115 if (ret != ERROR_SUCCESS) 2116 goto done; 2117 2118 szString = msi_alloc(++size * sizeof(WCHAR)); 2119 if (!szString) 2120 { 2121 hr = E_OUTOFMEMORY; 2122 goto done; 2123 } 2124 2125 if (!V_I4(&varg2)) 2126 ret = RegQueryInfoKeyW(hkey, szString, &size,NULL, NULL, NULL, 2127 NULL, NULL, NULL, NULL, NULL, NULL); 2128 else if (V_I4(&varg2) > 0) 2129 ret = RegEnumValueW(hkey, V_I4(&varg2)-1, szString, 2130 &size, 0, 0, NULL, NULL); 2131 else /* V_I4(&varg2) < 0 */ 2132 ret = RegEnumKeyW(hkey, -1 - V_I4(&varg2), szString, size); 2133 2134 if (ret == ERROR_SUCCESS) 2135 { 2136 V_VT(pVarResult) = VT_BSTR; 2137 V_BSTR(pVarResult) = SysAllocString(szString); 2138 } 2139 2140 msi_free(szString); 2141 } 2142 2143 done: 2144 VariantClear(&varg0); 2145 VariantClear(&varg1); 2146 VariantClear(&varg2); 2147 RegCloseKey(hkey); 2148 return hr; 2149 } 2150 2151 static HRESULT InstallerImpl_Environment(WORD wFlags, 2152 DISPPARAMS* pDispParams, 2153 VARIANT* pVarResult, 2154 EXCEPINFO* pExcepInfo, 2155 UINT* puArgErr) 2156 { 2157 if (!(wFlags & DISPATCH_METHOD)) 2158 return DISP_E_MEMBERNOTFOUND; 2159 2160 FIXME("\n"); 2161 2162 VariantInit(pVarResult); 2163 return S_OK; 2164 } 2165 2166 static HRESULT InstallerImpl_FileAttributes(WORD wFlags, 2167 DISPPARAMS* pDispParams, 2168 VARIANT* pVarResult, 2169 EXCEPINFO* pExcepInfo, 2170 UINT* puArgErr) 2171 { 2172 if (!(wFlags & DISPATCH_METHOD)) 2173 return DISP_E_MEMBERNOTFOUND; 2174 2175 FIXME("\n"); 2176 2177 VariantInit(pVarResult); 2178 return S_OK; 2179 } 2180 2181 static HRESULT InstallerImpl_FileSize(WORD wFlags, 2182 DISPPARAMS* pDispParams, 2183 VARIANT* pVarResult, 2184 EXCEPINFO* pExcepInfo, 2185 UINT* puArgErr) 2186 { 2187 if (!(wFlags & DISPATCH_METHOD)) 2188 return DISP_E_MEMBERNOTFOUND; 2189 2190 FIXME("\n"); 2191 2192 VariantInit(pVarResult); 2193 return S_OK; 2194 } 2195 2196 static HRESULT InstallerImpl_FileVersion(WORD wFlags, 2197 DISPPARAMS* pDispParams, 2198 VARIANT* pVarResult, 2199 EXCEPINFO* pExcepInfo, 2200 UINT* puArgErr) 2201 { 2202 if (!(wFlags & DISPATCH_METHOD)) 2203 return DISP_E_MEMBERNOTFOUND; 2204 2205 FIXME("\n"); 2206 2207 VariantInit(pVarResult); 2208 return S_OK; 2209 } 2210 2211 static HRESULT InstallerImpl_ProductState(WORD wFlags, 2212 DISPPARAMS* pDispParams, 2213 VARIANT* pVarResult, 2214 EXCEPINFO* pExcepInfo, 2215 UINT* puArgErr) 2216 { 2217 HRESULT hr; 2218 VARIANTARG varg0; 2219 2220 if (!(wFlags & DISPATCH_PROPERTYGET)) 2221 return DISP_E_MEMBERNOTFOUND; 2222 2223 VariantInit(&varg0); 2224 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr); 2225 if (FAILED(hr)) 2226 return hr; 2227 2228 V_VT(pVarResult) = VT_I4; 2229 V_I4(pVarResult) = MsiQueryProductStateW(V_BSTR(&varg0)); 2230 2231 VariantClear(&varg0); 2232 return S_OK; 2233 } 2234 2235 static HRESULT InstallerImpl_ProductInfo(WORD wFlags, 2236 DISPPARAMS* pDispParams, 2237 VARIANT* pVarResult, 2238 EXCEPINFO* pExcepInfo, 2239 UINT* puArgErr) 2240 { 2241 UINT ret; 2242 HRESULT hr; 2243 DWORD size; 2244 LPWSTR str = NULL; 2245 VARIANTARG varg0, varg1; 2246 2247 if (!(wFlags & DISPATCH_PROPERTYGET)) 2248 return DISP_E_MEMBERNOTFOUND; 2249 2250 VariantInit(&varg0); 2251 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr); 2252 if (FAILED(hr)) 2253 return hr; 2254 2255 VariantInit(&varg1); 2256 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr); 2257 if (FAILED(hr)) 2258 goto done; 2259 2260 V_VT(pVarResult) = VT_BSTR; 2261 V_BSTR(pVarResult) = NULL; 2262 2263 ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), NULL, &size); 2264 if (ret != ERROR_SUCCESS) 2265 { 2266 hr = DISP_E_EXCEPTION; 2267 goto done; 2268 } 2269 2270 str = msi_alloc(++size * sizeof(WCHAR)); 2271 if (!str) 2272 { 2273 hr = E_OUTOFMEMORY; 2274 goto done; 2275 } 2276 2277 ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), str, &size); 2278 if (ret != ERROR_SUCCESS) 2279 { 2280 hr = DISP_E_EXCEPTION; 2281 goto done; 2282 } 2283 2284 V_BSTR(pVarResult) = SysAllocString(str); 2285 hr = S_OK; 2286 2287 done: 2288 msi_free(str); 2289 VariantClear(&varg0); 2290 VariantClear(&varg1); 2291 return hr; 2292 } 2293 2294 static HRESULT InstallerImpl_Products(WORD flags, 2295 DISPPARAMS* pDispParams, 2296 VARIANT* result, 2297 EXCEPINFO* pExcepInfo, 2298 UINT* puArgErr) 2299 { 2300 IDispatch *dispatch; 2301 HRESULT hr; 2302 2303 if (!(flags & DISPATCH_PROPERTYGET)) 2304 return DISP_E_MEMBERNOTFOUND; 2305 2306 hr = create_list(NULL, &dispatch); 2307 if (FAILED(hr)) 2308 return hr; 2309 2310 V_VT(result) = VT_DISPATCH; 2311 V_DISPATCH(result) = dispatch; 2312 2313 return hr; 2314 } 2315 2316 static HRESULT InstallerImpl_RelatedProducts(WORD flags, 2317 DISPPARAMS* pDispParams, 2318 VARIANT* result, 2319 EXCEPINFO* pExcepInfo, 2320 UINT* puArgErr) 2321 { 2322 IDispatch* dispatch; 2323 VARIANTARG related; 2324 HRESULT hr; 2325 2326 if (!(flags & DISPATCH_PROPERTYGET)) 2327 return DISP_E_MEMBERNOTFOUND; 2328 2329 VariantInit(&related); 2330 hr = DispGetParam(pDispParams, 0, VT_BSTR, &related, puArgErr); 2331 if (FAILED(hr)) 2332 return hr; 2333 2334 hr = create_list(V_BSTR(&related), &dispatch); 2335 VariantClear(&related); 2336 2337 V_VT(result) = VT_DISPATCH; 2338 V_DISPATCH(result) = dispatch; 2339 2340 return hr; 2341 } 2342 2343 static HRESULT installer_invoke( 2344 AutomationObject* This, 2345 DISPID dispIdMember, 2346 REFIID riid, 2347 LCID lcid, 2348 WORD wFlags, 2349 DISPPARAMS* pDispParams, 2350 VARIANT* pVarResult, 2351 EXCEPINFO* pExcepInfo, 2352 UINT* puArgErr) 2353 { 2354 switch (dispIdMember) 2355 { 2356 case DISPID_INSTALLER_CREATERECORD: 2357 return InstallerImpl_CreateRecord(wFlags, pDispParams, 2358 pVarResult, pExcepInfo, puArgErr); 2359 2360 case DISPID_INSTALLER_OPENPACKAGE: 2361 return InstallerImpl_OpenPackage(This, wFlags, pDispParams, 2362 pVarResult, pExcepInfo, puArgErr); 2363 2364 case DISPID_INSTALLER_OPENPRODUCT: 2365 return InstallerImpl_OpenProduct(wFlags, pDispParams, 2366 pVarResult, pExcepInfo, puArgErr); 2367 2368 case DISPID_INSTALLER_OPENDATABASE: 2369 return InstallerImpl_OpenDatabase(wFlags, pDispParams, 2370 pVarResult, pExcepInfo, puArgErr); 2371 2372 case DISPID_INSTALLER_SUMMARYINFORMATION: 2373 return InstallerImpl_SummaryInformation(wFlags, pDispParams, 2374 pVarResult, pExcepInfo, 2375 puArgErr); 2376 2377 case DISPID_INSTALLER_UILEVEL: 2378 return InstallerImpl_UILevel(wFlags, pDispParams, 2379 pVarResult, pExcepInfo, puArgErr); 2380 2381 case DISPID_INSTALLER_ENABLELOG: 2382 return InstallerImpl_EnableLog(wFlags, pDispParams, 2383 pVarResult, pExcepInfo, puArgErr); 2384 2385 case DISPID_INSTALLER_INSTALLPRODUCT: 2386 return InstallerImpl_InstallProduct(wFlags, pDispParams, 2387 pVarResult, pExcepInfo, 2388 puArgErr); 2389 2390 case DISPID_INSTALLER_VERSION: 2391 return InstallerImpl_Version(wFlags, pVarResult, 2392 pExcepInfo, puArgErr); 2393 2394 case DISPID_INSTALLER_LASTERRORRECORD: 2395 return InstallerImpl_LastErrorRecord(wFlags, pDispParams, 2396 pVarResult, pExcepInfo, 2397 puArgErr); 2398 2399 case DISPID_INSTALLER_REGISTRYVALUE: 2400 return InstallerImpl_RegistryValue(wFlags, pDispParams, 2401 pVarResult, pExcepInfo, 2402 puArgErr); 2403 2404 case DISPID_INSTALLER_ENVIRONMENT: 2405 return InstallerImpl_Environment(wFlags, pDispParams, 2406 pVarResult, pExcepInfo, puArgErr); 2407 2408 case DISPID_INSTALLER_FILEATTRIBUTES: 2409 return InstallerImpl_FileAttributes(wFlags, pDispParams, 2410 pVarResult, pExcepInfo, 2411 puArgErr); 2412 2413 case DISPID_INSTALLER_FILESIZE: 2414 return InstallerImpl_FileSize(wFlags, pDispParams, 2415 pVarResult, pExcepInfo, puArgErr); 2416 2417 case DISPID_INSTALLER_FILEVERSION: 2418 return InstallerImpl_FileVersion(wFlags, pDispParams, 2419 pVarResult, pExcepInfo, puArgErr); 2420 2421 case DISPID_INSTALLER_PRODUCTSTATE: 2422 return InstallerImpl_ProductState(wFlags, pDispParams, 2423 pVarResult, pExcepInfo, puArgErr); 2424 2425 case DISPID_INSTALLER_PRODUCTINFO: 2426 return InstallerImpl_ProductInfo(wFlags, pDispParams, 2427 pVarResult, pExcepInfo, puArgErr); 2428 2429 case DISPID_INSTALLER_PRODUCTS: 2430 return InstallerImpl_Products(wFlags, pDispParams, 2431 pVarResult, pExcepInfo, puArgErr); 2432 2433 case DISPID_INSTALLER_RELATEDPRODUCTS: 2434 return InstallerImpl_RelatedProducts(wFlags, pDispParams, 2435 pVarResult, pExcepInfo, 2436 puArgErr); 2437 2438 default: 2439 return DISP_E_MEMBERNOTFOUND; 2440 } 2441 } 2442 2443 HRESULT create_msiserver(IUnknown *outer, void **ppObj) 2444 { 2445 AutomationObject *installer; 2446 HRESULT hr; 2447 2448 TRACE("(%p %p)\n", outer, ppObj); 2449 2450 if (outer) 2451 return CLASS_E_NOAGGREGATION; 2452 2453 installer = msi_alloc(sizeof(AutomationObject)); 2454 if (!installer) return E_OUTOFMEMORY; 2455 2456 hr = init_automation_object(installer, 0, Installer_tid); 2457 if (hr != S_OK) 2458 { 2459 msi_free(installer); 2460 return hr; 2461 } 2462 2463 *ppObj = &installer->IDispatch_iface; 2464 2465 return hr; 2466 } 2467 2468 HRESULT create_session(MSIHANDLE msiHandle, IDispatch *installer, IDispatch **disp) 2469 { 2470 SessionObject *session; 2471 HRESULT hr; 2472 2473 session = msi_alloc(sizeof(SessionObject)); 2474 if (!session) return E_OUTOFMEMORY; 2475 2476 hr = init_automation_object(&session->autoobj, msiHandle, Session_tid); 2477 if (hr != S_OK) 2478 { 2479 msi_free(session); 2480 return hr; 2481 } 2482 2483 session->installer = installer; 2484 *disp = &session->autoobj.IDispatch_iface; 2485 2486 return hr; 2487 } 2488 2489 static HRESULT create_database(MSIHANDLE msiHandle, IDispatch **dispatch) 2490 { 2491 AutomationObject *database; 2492 HRESULT hr; 2493 2494 TRACE("(%d %p)\n", msiHandle, dispatch); 2495 2496 database = msi_alloc(sizeof(AutomationObject)); 2497 if (!database) return E_OUTOFMEMORY; 2498 2499 hr = init_automation_object(database, msiHandle, Database_tid); 2500 if (hr != S_OK) 2501 { 2502 msi_free(database); 2503 return hr; 2504 } 2505 2506 *dispatch = &database->IDispatch_iface; 2507 2508 return hr; 2509 } 2510 2511 static HRESULT create_view(MSIHANDLE msiHandle, IDispatch **dispatch) 2512 { 2513 AutomationObject *view; 2514 HRESULT hr; 2515 2516 TRACE("(%d %p)\n", msiHandle, dispatch); 2517 2518 view = msi_alloc(sizeof(AutomationObject)); 2519 if (!view) return E_OUTOFMEMORY; 2520 2521 hr = init_automation_object(view, msiHandle, View_tid); 2522 if (hr != S_OK) 2523 { 2524 msi_free(view); 2525 return hr; 2526 } 2527 2528 *dispatch = &view->IDispatch_iface; 2529 2530 return hr; 2531 } 2532 2533 static HRESULT create_summaryinfo(MSIHANDLE msiHandle, IDispatch **disp) 2534 { 2535 AutomationObject *info; 2536 HRESULT hr; 2537 2538 info = msi_alloc(sizeof(*info)); 2539 if (!info) return E_OUTOFMEMORY; 2540 2541 hr = init_automation_object(info, msiHandle, SummaryInfo_tid); 2542 if (hr != S_OK) 2543 { 2544 msi_free(info); 2545 return hr; 2546 } 2547 2548 *disp = &info->IDispatch_iface; 2549 2550 return hr; 2551 } 2552