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