msi: Read the disk prompt source list property from the user-unmanaged context.
[wine.git] / dlls / msi / automation.c
blobdc94cbc3459ef5b949066bad5e86ae8fe03e784d
1 /*
2 * Implementation of OLE Automation for Microsoft Installer (msi.dll)
4 * Copyright 2007 Misha Koshelev
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.
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.
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
21 #define COBJMACROS
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"
37 #include "msiserver.h"
38 #include "msiserver_dispids.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(msi);
43 * AutomationObject - "base" class for all automation objects. For each interface, we implement Invoke function
44 * called from AutomationObject::Invoke, and pass this function to create_automation_object.
47 typedef interface AutomationObject AutomationObject;
49 interface AutomationObject {
51 * VTables - We provide IDispatch, IProvideClassInfo, IProvideClassInfo2, IProvideMultipleClassInfo
53 const IDispatchVtbl *lpVtbl;
54 const IProvideMultipleClassInfoVtbl *lpvtblIProvideMultipleClassInfo;
56 /* Object reference count */
57 LONG ref;
59 /* Clsid for this class and it's appropriate ITypeInfo object */
60 LPCLSID clsid;
61 ITypeInfo *iTypeInfo;
63 /* The MSI handle of the current object */
64 MSIHANDLE msiHandle;
66 /* A function that is called from AutomationObject::Invoke, specific to this type of object. */
67 HRESULT (STDMETHODCALLTYPE *funcInvoke)(
68 AutomationObject* This,
69 DISPID dispIdMember,
70 REFIID riid,
71 LCID lcid,
72 WORD wFlags,
73 DISPPARAMS* pDispParams,
74 VARIANT* pVarResult,
75 EXCEPINFO* pExcepInfo,
76 UINT* puArgErr);
78 /* A function that is called from AutomationObject::Release when the object is being freed to free any private
79 * data structures (or NULL) */
80 void (STDMETHODCALLTYPE *funcFree)(AutomationObject* This);
84 * ListEnumerator - IEnumVARIANT implementation for MSI automation lists.
87 typedef interface ListEnumerator ListEnumerator;
89 interface ListEnumerator {
90 /* VTables */
91 const IEnumVARIANTVtbl *lpVtbl;
93 /* Object reference count */
94 LONG ref;
96 /* Current position and pointer to AutomationObject that stores actual data */
97 ULONG ulPos;
98 AutomationObject *pObj;
102 * Structures for additional data required by specific automation objects
105 typedef struct {
106 ULONG ulCount;
107 VARIANT *pVars;
108 } ListData;
110 typedef struct {
111 /* The parent Installer object */
112 IDispatch *pInstaller;
113 } SessionData;
115 /* VTables */
116 static const struct IDispatchVtbl AutomationObject_Vtbl;
117 static const struct IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl;
118 static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl;
120 /* Load type info so we don't have to process GetIDsOfNames */
121 HRESULT load_type_info(IDispatch *iface, ITypeInfo **pptinfo, REFIID clsid, LCID lcid)
123 HRESULT hr;
124 LPTYPELIB pLib = NULL;
125 LPTYPEINFO pInfo = NULL;
126 static const WCHAR szMsiServer[] = {'m','s','i','s','e','r','v','e','r','.','t','l','b'};
128 TRACE("(%p)->(%s,%d)\n", iface, debugstr_guid(clsid), lcid);
130 /* Load registered type library */
131 hr = LoadRegTypeLib(&LIBID_WindowsInstaller, 1, 0, lcid, &pLib);
132 if (FAILED(hr)) {
133 hr = LoadTypeLib(szMsiServer, &pLib);
134 if (FAILED(hr)) {
135 ERR("Could not load msiserver.tlb\n");
136 return hr;
140 /* Get type information for object */
141 hr = ITypeLib_GetTypeInfoOfGuid(pLib, clsid, &pInfo);
142 ITypeLib_Release(pLib);
143 if (FAILED(hr)) {
144 ERR("Could not load ITypeInfo for %s\n", debugstr_guid(clsid));
145 return hr;
147 *pptinfo = pInfo;
148 return S_OK;
151 /* Create the automation object, placing the result in the pointer ppObj. The automation object is created
152 * with the appropriate clsid and invocation function. */
153 HRESULT create_automation_object(MSIHANDLE msiHandle, IUnknown *pUnkOuter, LPVOID *ppObj, REFIID clsid,
154 HRESULT (STDMETHODCALLTYPE *funcInvoke)(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,
155 VARIANT*,EXCEPINFO*,UINT*),
156 void (STDMETHODCALLTYPE *funcFree)(AutomationObject*),
157 SIZE_T sizetPrivateData)
159 AutomationObject *object;
160 HRESULT hr;
162 TRACE("(%ld,%p,%p,%s,%p,%p,%ld)\n", (unsigned long)msiHandle, pUnkOuter, ppObj, debugstr_guid(clsid), funcInvoke, funcFree, sizetPrivateData);
164 if( pUnkOuter )
165 return CLASS_E_NOAGGREGATION;
167 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AutomationObject)+sizetPrivateData);
169 /* Set all the VTable references */
170 object->lpVtbl = &AutomationObject_Vtbl;
171 object->lpvtblIProvideMultipleClassInfo = &AutomationObject_IProvideMultipleClassInfo_Vtbl;
172 object->ref = 1;
174 /* Store data that was passed */
175 object->msiHandle = msiHandle;
176 object->clsid = (LPCLSID)clsid;
177 object->funcInvoke = funcInvoke;
178 object->funcFree = funcFree;
180 /* Load our TypeInfo so we don't have to process GetIDsOfNames */
181 object->iTypeInfo = NULL;
182 hr = load_type_info((IDispatch *)object, &object->iTypeInfo, clsid, 0x0);
183 if (FAILED(hr)) {
184 HeapFree(GetProcessHeap(), 0, object);
185 return hr;
188 *ppObj = object;
190 return S_OK;
193 /* Create a list enumerator, placing the result in the pointer ppObj. */
194 HRESULT create_list_enumerator(IUnknown *pUnkOuter, LPVOID *ppObj, AutomationObject *pObj, ULONG ulPos)
196 ListEnumerator *object;
198 TRACE("(%p,%p,%p,%uld)\n", pUnkOuter, ppObj, pObj, ulPos);
200 if( pUnkOuter )
201 return CLASS_E_NOAGGREGATION;
203 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ListEnumerator));
205 /* Set all the VTable references */
206 object->lpVtbl = &ListEnumerator_Vtbl;
207 object->ref = 1;
209 /* Store data that was passed */
210 object->ulPos = ulPos;
211 object->pObj = pObj;
212 if (pObj) IDispatch_AddRef((IDispatch *)pObj);
214 *ppObj = object;
215 return S_OK;
218 /* Macros to get pointer to AutomationObject from the other VTables. */
219 static inline AutomationObject *obj_from_IProvideMultipleClassInfo( IProvideMultipleClassInfo *iface )
221 return (AutomationObject *)((char*)iface - FIELD_OFFSET(AutomationObject, lpvtblIProvideMultipleClassInfo));
224 /* Macro to get pointer to private object data */
225 static inline void *private_data( AutomationObject *This )
227 return This + 1;
231 * AutomationObject methods
234 /*** IUnknown methods ***/
235 static HRESULT WINAPI AutomationObject_QueryInterface(IDispatch* iface, REFIID riid, void** ppvObject)
237 AutomationObject *This = (AutomationObject *)iface;
239 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
241 if (ppvObject == NULL)
242 return E_INVALIDARG;
244 *ppvObject = 0;
246 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDispatch) || IsEqualGUID(riid, This->clsid))
247 *ppvObject = This;
248 else if (IsEqualGUID(riid, &IID_IProvideClassInfo) ||
249 IsEqualGUID(riid, &IID_IProvideClassInfo2) ||
250 IsEqualGUID(riid, &IID_IProvideMultipleClassInfo))
251 *ppvObject = &This->lpvtblIProvideMultipleClassInfo;
252 else
254 TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid));
255 return E_NOINTERFACE;
259 * Query Interface always increases the reference count by one when it is
260 * successful
262 IClassFactory_AddRef(iface);
264 return S_OK;
267 static ULONG WINAPI AutomationObject_AddRef(IDispatch* iface)
269 AutomationObject *This = (AutomationObject *)iface;
271 TRACE("(%p/%p)\n", iface, This);
273 return InterlockedIncrement(&This->ref);
276 static ULONG WINAPI AutomationObject_Release(IDispatch* iface)
278 AutomationObject *This = (AutomationObject *)iface;
279 ULONG ref = InterlockedDecrement(&This->ref);
281 TRACE("(%p/%p)\n", iface, This);
283 if (!ref)
285 if (This->funcFree) This->funcFree(This);
286 ITypeInfo_Release(This->iTypeInfo);
287 MsiCloseHandle(This->msiHandle);
288 HeapFree(GetProcessHeap(), 0, This);
291 return ref;
294 /*** IDispatch methods ***/
295 static HRESULT WINAPI AutomationObject_GetTypeInfoCount(
296 IDispatch* iface,
297 UINT* pctinfo)
299 AutomationObject *This = (AutomationObject *)iface;
301 TRACE("(%p/%p)->(%p)\n", iface, This, pctinfo);
302 *pctinfo = 1;
303 return S_OK;
306 static HRESULT WINAPI AutomationObject_GetTypeInfo(
307 IDispatch* iface,
308 UINT iTInfo,
309 LCID lcid,
310 ITypeInfo** ppTInfo)
312 AutomationObject *This = (AutomationObject *)iface;
313 TRACE("(%p/%p)->(%d,%d,%p)\n", iface, This, iTInfo, lcid, ppTInfo);
315 ITypeInfo_AddRef(This->iTypeInfo);
316 *ppTInfo = This->iTypeInfo;
317 return S_OK;
320 static HRESULT WINAPI AutomationObject_GetIDsOfNames(
321 IDispatch* iface,
322 REFIID riid,
323 LPOLESTR* rgszNames,
324 UINT cNames,
325 LCID lcid,
326 DISPID* rgDispId)
328 AutomationObject *This = (AutomationObject *)iface;
329 HRESULT hr;
330 TRACE("(%p/%p)->(%p,%p,%d,%d,%p)\n", iface, This, riid, rgszNames, cNames, lcid, rgDispId);
332 if (!IsEqualGUID(riid, &IID_NULL)) return E_INVALIDARG;
333 hr = ITypeInfo_GetIDsOfNames(This->iTypeInfo, rgszNames, cNames, rgDispId);
334 if (hr == DISP_E_UNKNOWNNAME)
336 int idx;
337 for (idx=0; idx<cNames; idx++)
339 if (rgDispId[idx] == DISPID_UNKNOWN)
340 FIXME("Unknown member %s, clsid %s\n", debugstr_w(rgszNames[idx]), debugstr_guid(This->clsid));
343 return hr;
346 /* Maximum number of allowed function parameters+1 */
347 #define MAX_FUNC_PARAMS 20
349 /* Some error checking is done here to simplify individual object function invocation */
350 static HRESULT WINAPI AutomationObject_Invoke(
351 IDispatch* iface,
352 DISPID dispIdMember,
353 REFIID riid,
354 LCID lcid,
355 WORD wFlags,
356 DISPPARAMS* pDispParams,
357 VARIANT* pVarResult,
358 EXCEPINFO* pExcepInfo,
359 UINT* puArgErr)
361 AutomationObject *This = (AutomationObject *)iface;
362 HRESULT hr;
363 unsigned int uArgErr;
364 VARIANT varResultDummy;
365 BSTR bstrName = NULL;
367 TRACE("(%p/%p)->(%d,%p,%d,%d,%p,%p,%p,%p)\n", iface, This, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
369 if (!IsEqualIID(riid, &IID_NULL))
371 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
372 return DISP_E_UNKNOWNNAME;
375 if (wFlags & DISPATCH_PROPERTYGET && !pVarResult)
377 ERR("NULL pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
378 return DISP_E_PARAMNOTOPTIONAL;
381 /* This simplifies our individual object invocation functions */
382 if (puArgErr == NULL) puArgErr = &uArgErr;
383 if (pVarResult == NULL) pVarResult = &varResultDummy;
385 /* Assume return type is void unless determined otherwise */
386 VariantInit(pVarResult);
388 /* If we are tracing, we want to see the name of the member we are invoking */
389 if (TRACE_ON(msi))
391 ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL);
392 TRACE("Method %d, %s\n", dispIdMember, debugstr_w(bstrName));
395 hr = This->funcInvoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
397 if (hr == DISP_E_MEMBERNOTFOUND) {
398 if (bstrName == NULL) ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL);
399 FIXME("Method %d, %s wflags %d not implemented, clsid %s\n", dispIdMember, debugstr_w(bstrName), wFlags, debugstr_guid(This->clsid));
401 else if (pExcepInfo &&
402 (hr == DISP_E_PARAMNOTFOUND ||
403 hr == DISP_E_EXCEPTION)) {
404 static const WCHAR szComma[] = { ',',0 };
405 static WCHAR szExceptionSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
406 WCHAR szExceptionDescription[MAX_PATH];
407 BSTR bstrParamNames[MAX_FUNC_PARAMS];
408 unsigned namesNo, i;
409 BOOL bFirst = TRUE;
411 if (FAILED(ITypeInfo_GetNames(This->iTypeInfo, dispIdMember, bstrParamNames,
412 MAX_FUNC_PARAMS, &namesNo)))
414 TRACE("Failed to retrieve names for dispIdMember %d\n", dispIdMember);
416 else
418 memset(szExceptionDescription, 0, sizeof(szExceptionDescription));
419 for (i=0; i<namesNo; i++)
421 if (bFirst) bFirst = FALSE;
422 else {
423 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], szComma);
425 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], bstrParamNames[i]);
426 SysFreeString(bstrParamNames[i]);
429 memset(pExcepInfo, 0, sizeof(EXCEPINFO));
430 pExcepInfo->wCode = 1000;
431 pExcepInfo->bstrSource = SysAllocString(szExceptionSource);
432 pExcepInfo->bstrDescription = SysAllocString(szExceptionDescription);
433 hr = DISP_E_EXCEPTION;
437 /* Make sure we free the return variant if it is our dummy variant */
438 if (pVarResult == &varResultDummy) VariantClear(pVarResult);
440 /* Free function name if we retrieved it */
441 if (bstrName) SysFreeString(bstrName);
443 TRACE("Returning 0x%08x, %s\n", hr, SUCCEEDED(hr) ? "ok" : "not ok");
445 return hr;
448 static const struct IDispatchVtbl AutomationObject_Vtbl =
450 AutomationObject_QueryInterface,
451 AutomationObject_AddRef,
452 AutomationObject_Release,
453 AutomationObject_GetTypeInfoCount,
454 AutomationObject_GetTypeInfo,
455 AutomationObject_GetIDsOfNames,
456 AutomationObject_Invoke
460 * IProvideMultipleClassInfo methods
463 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_QueryInterface(
464 IProvideMultipleClassInfo* iface,
465 REFIID riid,
466 VOID** ppvoid)
468 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
469 return AutomationObject_QueryInterface((IDispatch *)This, riid, ppvoid);
472 static ULONG WINAPI AutomationObject_IProvideMultipleClassInfo_AddRef(IProvideMultipleClassInfo* iface)
474 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
475 return AutomationObject_AddRef((IDispatch *)This);
478 static ULONG WINAPI AutomationObject_IProvideMultipleClassInfo_Release(IProvideMultipleClassInfo* iface)
480 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
481 return AutomationObject_Release((IDispatch *)This);
484 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_GetClassInfo(IProvideMultipleClassInfo* iface, ITypeInfo** ppTI)
486 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
487 TRACE("(%p/%p)->(%p)\n", iface, This, ppTI);
488 return load_type_info((IDispatch *)This, ppTI, This->clsid, 0);
491 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_GetGUID(IProvideMultipleClassInfo* iface, DWORD dwGuidKind, GUID* pGUID)
493 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
494 TRACE("(%p/%p)->(%d,%s)\n", iface, This, dwGuidKind, debugstr_guid(pGUID));
496 if (dwGuidKind != GUIDKIND_DEFAULT_SOURCE_DISP_IID)
497 return E_INVALIDARG;
498 else {
499 *pGUID = *This->clsid;
500 return S_OK;
504 static HRESULT WINAPI AutomationObject_GetMultiTypeInfoCount(IProvideMultipleClassInfo* iface, ULONG* pcti)
506 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
508 TRACE("(%p/%p)->(%p)\n", iface, This, pcti);
509 *pcti = 1;
510 return S_OK;
513 static HRESULT WINAPI AutomationObject_GetInfoOfIndex(IProvideMultipleClassInfo* iface,
514 ULONG iti,
515 DWORD dwFlags,
516 ITypeInfo** pptiCoClass,
517 DWORD* pdwTIFlags,
518 ULONG* pcdispidReserved,
519 IID* piidPrimary,
520 IID* piidSource)
522 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
524 TRACE("(%p/%p)->(%d,%d,%p,%p,%p,%p,%p)\n", iface, This, iti, dwFlags, pptiCoClass, pdwTIFlags, pcdispidReserved, piidPrimary, piidSource);
526 if (iti != 0)
527 return E_INVALIDARG;
529 if (dwFlags & MULTICLASSINFO_GETTYPEINFO)
530 load_type_info((IDispatch *)This, pptiCoClass, This->clsid, 0);
532 if (dwFlags & MULTICLASSINFO_GETNUMRESERVEDDISPIDS)
534 *pdwTIFlags = 0;
535 *pcdispidReserved = 0;
538 if (dwFlags & MULTICLASSINFO_GETIIDPRIMARY){
539 *piidPrimary = *This->clsid;
542 if (dwFlags & MULTICLASSINFO_GETIIDSOURCE){
543 *piidSource = *This->clsid;
546 return S_OK;
549 static const IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl =
551 AutomationObject_IProvideMultipleClassInfo_QueryInterface,
552 AutomationObject_IProvideMultipleClassInfo_AddRef,
553 AutomationObject_IProvideMultipleClassInfo_Release,
554 AutomationObject_IProvideMultipleClassInfo_GetClassInfo,
555 AutomationObject_IProvideMultipleClassInfo_GetGUID,
556 AutomationObject_GetMultiTypeInfoCount,
557 AutomationObject_GetInfoOfIndex
561 * ListEnumerator methods
564 /*** IUnknown methods ***/
565 static HRESULT WINAPI ListEnumerator_QueryInterface(IEnumVARIANT* iface, REFIID riid, void** ppvObject)
567 ListEnumerator *This = (ListEnumerator *)iface;
569 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
571 if (ppvObject == NULL)
572 return E_INVALIDARG;
574 *ppvObject = 0;
576 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IEnumVARIANT))
577 *ppvObject = This;
578 else
580 TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid));
581 return E_NOINTERFACE;
584 IClassFactory_AddRef(iface);
585 return S_OK;
588 static ULONG WINAPI ListEnumerator_AddRef(IEnumVARIANT* iface)
590 ListEnumerator *This = (ListEnumerator *)iface;
592 TRACE("(%p/%p)\n", iface, This);
594 return InterlockedIncrement(&This->ref);
597 static ULONG WINAPI ListEnumerator_Release(IEnumVARIANT* iface)
599 ListEnumerator *This = (ListEnumerator *)iface;
600 ULONG ref = InterlockedDecrement(&This->ref);
602 TRACE("(%p/%p)\n", iface, This);
604 if (!ref)
606 if (This->pObj) IDispatch_Release((IDispatch *)This->pObj);
607 HeapFree(GetProcessHeap(), 0, This);
610 return ref;
613 /* IEnumVARIANT methods */
615 static HRESULT WINAPI ListEnumerator_Next(IEnumVARIANT* iface, ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched)
617 ListEnumerator *This = (ListEnumerator *)iface;
618 ListData *data = (ListData *)private_data(This->pObj);
619 ULONG idx, local;
621 TRACE("(%p,%uld,%p,%p)\n", iface, celt, rgVar, pCeltFetched);
623 if (pCeltFetched != NULL)
624 *pCeltFetched = 0;
626 if (rgVar == NULL)
627 return S_FALSE;
629 for (local = 0; local < celt; local++)
630 VariantInit(&rgVar[local]);
632 for (idx = This->ulPos, local = 0; idx < data->ulCount && local < celt; idx++, local++)
633 VariantCopy(&rgVar[local], &data->pVars[idx]);
635 if (pCeltFetched != NULL)
636 *pCeltFetched = local;
637 This->ulPos = idx;
639 return (local < celt) ? S_FALSE : S_OK;
642 static HRESULT WINAPI ListEnumerator_Skip(IEnumVARIANT* iface, ULONG celt)
644 ListEnumerator *This = (ListEnumerator *)iface;
645 ListData *data = (ListData *)private_data(This->pObj);
647 TRACE("(%p,%uld)\n", iface, celt);
649 This->ulPos += celt;
650 if (This->ulPos >= data->ulCount)
652 This->ulPos = data->ulCount;
653 return S_FALSE;
655 return S_OK;
658 static HRESULT WINAPI ListEnumerator_Reset(IEnumVARIANT* iface)
660 ListEnumerator *This = (ListEnumerator *)iface;
662 TRACE("(%p)\n", iface);
664 This->ulPos = 0;
665 return S_OK;
668 static HRESULT WINAPI ListEnumerator_Clone(IEnumVARIANT* iface, IEnumVARIANT **ppEnum)
670 ListEnumerator *This = (ListEnumerator *)iface;
671 HRESULT hr;
673 TRACE("(%p,%p)\n", iface, ppEnum);
675 if (ppEnum == NULL)
676 return S_FALSE;
678 *ppEnum = NULL;
679 hr = create_list_enumerator(NULL, (LPVOID *)ppEnum, This->pObj, 0);
680 if (FAILED(hr))
682 if (*ppEnum)
683 IUnknown_Release(*ppEnum);
684 return hr;
687 return S_OK;
690 static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl =
692 ListEnumerator_QueryInterface,
693 ListEnumerator_AddRef,
694 ListEnumerator_Release,
695 ListEnumerator_Next,
696 ListEnumerator_Skip,
697 ListEnumerator_Reset,
698 ListEnumerator_Clone
702 * Individual Object Invocation Functions
705 /* Helper function that copies a passed parameter instead of using VariantChangeType like the actual DispGetParam.
706 This function is only for VARIANT type parameters that have several types that cannot be properly discriminated
707 using DispGetParam/VariantChangeType. */
708 HRESULT WINAPI DispGetParam_CopyOnly(
709 DISPPARAMS *pdispparams, /* [in] Parameter list */
710 UINT *position, /* [in] Position of parameter to copy in pdispparams; on return will contain calculated position */
711 VARIANT *pvarResult) /* [out] Destination for resulting variant */
713 /* position is counted backwards */
714 UINT pos;
716 TRACE("position=%d, cArgs=%d, cNamedArgs=%d\n",
717 *position, pdispparams->cArgs, pdispparams->cNamedArgs);
718 if (*position < pdispparams->cArgs) {
719 /* positional arg? */
720 pos = pdispparams->cArgs - *position - 1;
721 } else {
722 /* FIXME: is this how to handle named args? */
723 for (pos=0; pos<pdispparams->cNamedArgs; pos++)
724 if (pdispparams->rgdispidNamedArgs[pos] == *position) break;
726 if (pos==pdispparams->cNamedArgs)
727 return DISP_E_PARAMNOTFOUND;
729 *position = pos;
730 return VariantCopyInd(pvarResult,
731 &pdispparams->rgvarg[pos]);
734 static HRESULT WINAPI SummaryInfoImpl_Invoke(
735 AutomationObject* This,
736 DISPID dispIdMember,
737 REFIID riid,
738 LCID lcid,
739 WORD wFlags,
740 DISPPARAMS* pDispParams,
741 VARIANT* pVarResult,
742 EXCEPINFO* pExcepInfo,
743 UINT* puArgErr)
745 UINT ret;
746 VARIANTARG varg0, varg1;
747 FILETIME ft, ftlocal;
748 SYSTEMTIME st;
749 HRESULT hr;
751 VariantInit(&varg0);
752 VariantInit(&varg1);
754 switch (dispIdMember)
756 case DISPID_SUMMARYINFO_PROPERTY:
757 if (wFlags & DISPATCH_PROPERTYGET)
759 UINT type;
760 INT value;
761 DWORD size = 0;
762 DATE date;
763 LPWSTR str;
765 static WCHAR szEmpty[] = {0};
767 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
768 if (FAILED(hr)) return hr;
769 ret = MsiSummaryInfoGetPropertyW(This->msiHandle, V_I4(&varg0), &type, &value,
770 &ft, szEmpty, &size);
771 if (ret != ERROR_SUCCESS &&
772 ret != ERROR_MORE_DATA)
774 ERR("MsiSummaryInfoGetProperty returned %d\n", ret);
775 return DISP_E_EXCEPTION;
778 switch (type)
780 case VT_EMPTY:
781 break;
783 case VT_I2:
784 case VT_I4:
785 V_VT(pVarResult) = VT_I4;
786 V_I4(pVarResult) = value;
787 break;
789 case VT_LPSTR:
790 if (!(str = msi_alloc(++size * sizeof(WCHAR))))
791 ERR("Out of memory\n");
792 else if ((ret = MsiSummaryInfoGetPropertyW(This->msiHandle, V_I4(&varg0), &type, NULL,
793 NULL, str, &size)) != ERROR_SUCCESS)
794 ERR("MsiSummaryInfoGetProperty returned %d\n", ret);
795 else
797 V_VT(pVarResult) = VT_BSTR;
798 V_BSTR(pVarResult) = SysAllocString(str);
800 msi_free(str);
801 break;
803 case VT_FILETIME:
804 FileTimeToLocalFileTime(&ft, &ftlocal);
805 FileTimeToSystemTime(&ftlocal, &st);
806 SystemTimeToVariantTime(&st, &date);
808 V_VT(pVarResult) = VT_DATE;
809 V_DATE(pVarResult) = date;
810 break;
812 default:
813 ERR("Unhandled variant type %d\n", type);
816 else if (wFlags & DISPATCH_PROPERTYPUT)
818 UINT posValue = DISPID_PROPERTYPUT;
820 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
821 if (FAILED(hr)) return hr;
822 hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg1);
823 if (FAILED(hr))
825 *puArgErr = posValue;
826 return hr;
829 switch (V_VT(&varg1))
831 case VT_I2:
832 case VT_I4:
833 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), V_VT(&varg1), V_I4(&varg1), NULL, NULL);
834 break;
836 case VT_DATE:
837 VariantTimeToSystemTime(V_DATE(&varg1), &st);
838 SystemTimeToFileTime(&st, &ftlocal);
839 LocalFileTimeToFileTime(&ftlocal, &ft);
840 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), VT_FILETIME, 0, &ft, NULL);
841 break;
843 case VT_BSTR:
844 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), VT_LPSTR, 0, NULL, V_BSTR(&varg1));
845 break;
847 default:
848 FIXME("Unhandled variant type %d\n", V_VT(&varg1));
849 VariantClear(&varg1);
850 return DISP_E_EXCEPTION;
853 if (ret != ERROR_SUCCESS)
855 ERR("MsiSummaryInfoSetPropertyW returned %d\n", ret);
856 return DISP_E_EXCEPTION;
859 else return DISP_E_MEMBERNOTFOUND;
860 break;
862 case DISPID_SUMMARYINFO_PROPERTYCOUNT:
863 if (wFlags & DISPATCH_PROPERTYGET) {
864 UINT count;
865 if ((ret = MsiSummaryInfoGetPropertyCount(This->msiHandle, &count)) != ERROR_SUCCESS)
866 ERR("MsiSummaryInfoGetPropertyCount returned %d\n", ret);
867 else
869 V_VT(pVarResult) = VT_I4;
870 V_I4(pVarResult) = count;
873 else return DISP_E_MEMBERNOTFOUND;
874 break;
876 default:
877 return DISP_E_MEMBERNOTFOUND;
880 VariantClear(&varg1);
881 VariantClear(&varg0);
883 return S_OK;
886 static HRESULT WINAPI RecordImpl_Invoke(
887 AutomationObject* This,
888 DISPID dispIdMember,
889 REFIID riid,
890 LCID lcid,
891 WORD wFlags,
892 DISPPARAMS* pDispParams,
893 VARIANT* pVarResult,
894 EXCEPINFO* pExcepInfo,
895 UINT* puArgErr)
897 WCHAR *szString;
898 DWORD dwLen;
899 UINT ret;
900 VARIANTARG varg0, varg1;
901 HRESULT hr;
903 VariantInit(&varg0);
904 VariantInit(&varg1);
906 switch (dispIdMember)
908 case DISPID_RECORD_FIELDCOUNT:
909 if (wFlags & DISPATCH_PROPERTYGET) {
910 V_VT(pVarResult) = VT_I4;
911 V_I4(pVarResult) = MsiRecordGetFieldCount(This->msiHandle);
913 else return DISP_E_MEMBERNOTFOUND;
914 break;
916 case DISPID_RECORD_STRINGDATA:
917 if (wFlags & DISPATCH_PROPERTYGET) {
918 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
919 if (FAILED(hr)) return hr;
920 V_VT(pVarResult) = VT_BSTR;
921 V_BSTR(pVarResult) = NULL;
922 if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
924 if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
925 ERR("Out of memory\n");
926 else if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
927 V_BSTR(pVarResult) = SysAllocString(szString);
928 msi_free(szString);
930 if (ret != ERROR_SUCCESS)
931 ERR("MsiRecordGetString returned %d\n", ret);
932 } else if (wFlags & DISPATCH_PROPERTYPUT) {
933 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
934 if (FAILED(hr)) return hr;
935 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BSTR, &varg1, puArgErr);
936 if (FAILED(hr)) return hr;
937 if ((ret = MsiRecordSetStringW(This->msiHandle, V_I4(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
939 VariantClear(&varg1);
940 ERR("MsiRecordSetString returned %d\n", ret);
941 return DISP_E_EXCEPTION;
944 else return DISP_E_MEMBERNOTFOUND;
945 break;
947 case DISPID_RECORD_INTEGERDATA:
948 if (wFlags & DISPATCH_PROPERTYGET) {
949 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
950 if (FAILED(hr)) return hr;
951 V_VT(pVarResult) = VT_I4;
952 V_I4(pVarResult) = MsiRecordGetInteger(This->msiHandle, V_I4(&varg0));
953 } else if (wFlags & DISPATCH_PROPERTYPUT) {
954 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
955 if (FAILED(hr)) return hr;
956 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_I4, &varg1, puArgErr);
957 if (FAILED(hr)) return hr;
958 if ((ret = MsiRecordSetInteger(This->msiHandle, V_I4(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
960 ERR("MsiRecordSetInteger returned %d\n", ret);
961 return DISP_E_EXCEPTION;
964 else return DISP_E_MEMBERNOTFOUND;
965 break;
967 default:
968 return DISP_E_MEMBERNOTFOUND;
971 VariantClear(&varg1);
972 VariantClear(&varg0);
974 return S_OK;
977 static HRESULT WINAPI ListImpl_Invoke(
978 AutomationObject* This,
979 DISPID dispIdMember,
980 REFIID riid,
981 LCID lcid,
982 WORD wFlags,
983 DISPPARAMS* pDispParams,
984 VARIANT* pVarResult,
985 EXCEPINFO* pExcepInfo,
986 UINT* puArgErr)
988 ListData *data = (ListData *)private_data(This);
989 HRESULT hr;
990 VARIANTARG varg0;
991 IUnknown *pUnk = NULL;
993 VariantInit(&varg0);
995 switch (dispIdMember)
997 case DISPID_LIST__NEWENUM:
998 if (wFlags & DISPATCH_METHOD) {
999 V_VT(pVarResult) = VT_UNKNOWN;
1000 if (SUCCEEDED(hr = create_list_enumerator(NULL, (LPVOID *)&pUnk, This, 0)))
1001 V_UNKNOWN(pVarResult) = pUnk;
1002 else
1003 ERR("Failed to create IEnumVARIANT object, hresult 0x%08x\n", hr);
1005 else return DISP_E_MEMBERNOTFOUND;
1006 break;
1008 case DISPID_LIST_ITEM:
1009 if (wFlags & DISPATCH_PROPERTYGET) {
1010 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1011 if (FAILED(hr)) return hr;
1012 if (V_I4(&varg0) < 0 || V_I4(&varg0) >= data->ulCount)
1013 return DISP_E_BADINDEX;
1014 VariantCopy(pVarResult, &data->pVars[V_I4(&varg0)]);
1016 else return DISP_E_MEMBERNOTFOUND;
1017 break;
1019 case DISPID_LIST_COUNT:
1020 if (wFlags & DISPATCH_PROPERTYGET) {
1021 V_VT(pVarResult) = VT_I4;
1022 V_I4(pVarResult) = data->ulCount;
1024 else return DISP_E_MEMBERNOTFOUND;
1025 break;
1027 default:
1028 return DISP_E_MEMBERNOTFOUND;
1031 VariantClear(&varg0);
1033 return S_OK;
1036 static void WINAPI ListImpl_Free(AutomationObject *This)
1038 ListData *data = private_data(This);
1039 ULONG idx;
1041 for (idx=0; idx<data->ulCount; idx++)
1042 VariantClear(&data->pVars[idx]);
1043 HeapFree(GetProcessHeap(), 0, data->pVars);
1046 static HRESULT WINAPI ViewImpl_Invoke(
1047 AutomationObject* This,
1048 DISPID dispIdMember,
1049 REFIID riid,
1050 LCID lcid,
1051 WORD wFlags,
1052 DISPPARAMS* pDispParams,
1053 VARIANT* pVarResult,
1054 EXCEPINFO* pExcepInfo,
1055 UINT* puArgErr)
1057 MSIHANDLE msiHandle;
1058 IDispatch *pDispatch = NULL;
1059 UINT ret;
1060 VARIANTARG varg0, varg1;
1061 HRESULT hr;
1063 VariantInit(&varg0);
1064 VariantInit(&varg1);
1066 switch (dispIdMember)
1068 case DISPID_VIEW_EXECUTE:
1069 if (wFlags & DISPATCH_METHOD)
1071 hr = DispGetParam(pDispParams, 0, VT_DISPATCH, &varg0, puArgErr);
1072 if (SUCCEEDED(hr) && V_DISPATCH(&varg0) != NULL)
1073 MsiViewExecute(This->msiHandle, ((AutomationObject *)V_DISPATCH(&varg0))->msiHandle);
1074 else
1075 MsiViewExecute(This->msiHandle, 0);
1077 else return DISP_E_MEMBERNOTFOUND;
1078 break;
1080 case DISPID_VIEW_FETCH:
1081 if (wFlags & DISPATCH_METHOD)
1083 V_VT(pVarResult) = VT_DISPATCH;
1084 if ((ret = MsiViewFetch(This->msiHandle, &msiHandle)) == ERROR_SUCCESS)
1086 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Record, RecordImpl_Invoke, NULL, 0)))
1087 V_DISPATCH(pVarResult) = pDispatch;
1088 else
1089 ERR("Failed to create Record object, hresult 0x%08x\n", hr);
1091 else if (ret == ERROR_NO_MORE_ITEMS)
1092 V_DISPATCH(pVarResult) = NULL;
1093 else
1095 ERR("MsiViewFetch returned %d\n", ret);
1096 return DISP_E_EXCEPTION;
1099 else return DISP_E_MEMBERNOTFOUND;
1100 break;
1102 case DISPID_VIEW_MODIFY:
1103 if (wFlags & DISPATCH_METHOD)
1105 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1106 if (FAILED(hr)) return hr;
1107 hr = DispGetParam(pDispParams, 1, VT_DISPATCH, &varg1, puArgErr);
1108 if (FAILED(hr)) return hr;
1109 if (!V_DISPATCH(&varg1)) return DISP_E_EXCEPTION;
1110 if ((ret = MsiViewModify(This->msiHandle, V_I4(&varg0), ((AutomationObject *)V_DISPATCH(&varg1))->msiHandle)) != ERROR_SUCCESS)
1112 VariantClear(&varg1);
1113 ERR("MsiViewModify returned %d\n", ret);
1114 return DISP_E_EXCEPTION;
1117 else return DISP_E_MEMBERNOTFOUND;
1118 break;
1120 case DISPID_VIEW_CLOSE:
1121 if (wFlags & DISPATCH_METHOD)
1123 MsiViewClose(This->msiHandle);
1125 else return DISP_E_MEMBERNOTFOUND;
1126 break;
1128 default:
1129 return DISP_E_MEMBERNOTFOUND;
1132 VariantClear(&varg1);
1133 VariantClear(&varg0);
1135 return S_OK;
1138 static HRESULT WINAPI DatabaseImpl_Invoke(
1139 AutomationObject* This,
1140 DISPID dispIdMember,
1141 REFIID riid,
1142 LCID lcid,
1143 WORD wFlags,
1144 DISPPARAMS* pDispParams,
1145 VARIANT* pVarResult,
1146 EXCEPINFO* pExcepInfo,
1147 UINT* puArgErr)
1149 MSIHANDLE msiHandle;
1150 IDispatch *pDispatch = NULL;
1151 UINT ret;
1152 VARIANTARG varg0, varg1;
1153 HRESULT hr;
1155 VariantInit(&varg0);
1156 VariantInit(&varg1);
1158 switch (dispIdMember)
1160 case DISPID_DATABASE_SUMMARYINFORMATION:
1161 if (wFlags & DISPATCH_PROPERTYGET)
1163 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1164 if (FAILED(hr))
1165 V_I4(&varg0) = 0;
1167 V_VT(pVarResult) = VT_DISPATCH;
1168 if ((ret = MsiGetSummaryInformationW(This->msiHandle, NULL, V_I4(&varg0), &msiHandle)) == ERROR_SUCCESS)
1170 hr = create_automation_object(msiHandle, NULL, (LPVOID *)&pDispatch, &DIID_SummaryInfo, SummaryInfoImpl_Invoke, NULL, 0);
1171 if (SUCCEEDED(hr))
1172 V_DISPATCH(pVarResult) = pDispatch;
1173 else
1174 ERR("Failed to create SummaryInfo object: 0x%08x\n", hr);
1176 else
1178 ERR("MsiGetSummaryInformation returned %d\n", ret);
1179 return DISP_E_EXCEPTION;
1182 else return DISP_E_MEMBERNOTFOUND;
1183 break;
1185 case DISPID_DATABASE_OPENVIEW:
1186 if (wFlags & DISPATCH_METHOD)
1188 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1189 if (FAILED(hr)) return hr;
1190 V_VT(pVarResult) = VT_DISPATCH;
1191 if ((ret = MsiDatabaseOpenViewW(This->msiHandle, V_BSTR(&varg0), &msiHandle)) == ERROR_SUCCESS)
1193 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_View, ViewImpl_Invoke, NULL, 0)))
1194 V_DISPATCH(pVarResult) = pDispatch;
1195 else
1196 ERR("Failed to create View object, hresult 0x%08x\n", hr);
1198 else
1200 VariantClear(&varg0);
1201 ERR("MsiDatabaseOpenView returned %d\n", ret);
1202 return DISP_E_EXCEPTION;
1205 else return DISP_E_MEMBERNOTFOUND;
1206 break;
1208 default:
1209 return DISP_E_MEMBERNOTFOUND;
1212 VariantClear(&varg1);
1213 VariantClear(&varg0);
1215 return S_OK;
1218 static HRESULT WINAPI SessionImpl_Invoke(
1219 AutomationObject* This,
1220 DISPID dispIdMember,
1221 REFIID riid,
1222 LCID lcid,
1223 WORD wFlags,
1224 DISPPARAMS* pDispParams,
1225 VARIANT* pVarResult,
1226 EXCEPINFO* pExcepInfo,
1227 UINT* puArgErr)
1229 SessionData *data = private_data(This);
1230 WCHAR *szString;
1231 DWORD dwLen;
1232 IDispatch *pDispatch = NULL;
1233 MSIHANDLE msiHandle;
1234 LANGID langId;
1235 UINT ret;
1236 INSTALLSTATE iInstalled, iAction;
1237 VARIANTARG varg0, varg1;
1238 HRESULT hr;
1240 VariantInit(&varg0);
1241 VariantInit(&varg1);
1243 switch (dispIdMember)
1245 case DISPID_SESSION_INSTALLER:
1246 if (wFlags & DISPATCH_PROPERTYGET) {
1247 V_VT(pVarResult) = VT_DISPATCH;
1248 IDispatch_AddRef(data->pInstaller);
1249 V_DISPATCH(pVarResult) = data->pInstaller;
1251 else return DISP_E_MEMBERNOTFOUND;
1252 break;
1254 case DISPID_SESSION_PROPERTY:
1255 if (wFlags & DISPATCH_PROPERTYGET) {
1256 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1257 if (FAILED(hr)) return hr;
1258 V_VT(pVarResult) = VT_BSTR;
1259 V_BSTR(pVarResult) = NULL;
1260 if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
1262 if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
1263 ERR("Out of memory\n");
1264 else if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
1265 V_BSTR(pVarResult) = SysAllocString(szString);
1266 msi_free(szString);
1268 if (ret != ERROR_SUCCESS)
1269 ERR("MsiGetProperty returned %d\n", ret);
1270 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1271 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1272 if (FAILED(hr)) return hr;
1273 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BSTR, &varg1, puArgErr);
1274 if (FAILED(hr)) {
1275 VariantClear(&varg0);
1276 return hr;
1278 if ((ret = MsiSetPropertyW(This->msiHandle, V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
1280 VariantClear(&varg0);
1281 VariantClear(&varg1);
1282 ERR("MsiSetProperty returned %d\n", ret);
1283 return DISP_E_EXCEPTION;
1286 else return DISP_E_MEMBERNOTFOUND;
1287 break;
1289 case DISPID_SESSION_LANGUAGE:
1290 if (wFlags & DISPATCH_PROPERTYGET) {
1291 langId = MsiGetLanguage(This->msiHandle);
1292 V_VT(pVarResult) = VT_I4;
1293 V_I4(pVarResult) = langId;
1295 else return DISP_E_MEMBERNOTFOUND;
1296 break;
1298 case DISPID_SESSION_MODE:
1299 if (wFlags & DISPATCH_PROPERTYGET) {
1300 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1301 if (FAILED(hr)) return hr;
1302 V_VT(pVarResult) = VT_BOOL;
1303 V_BOOL(pVarResult) = MsiGetMode(This->msiHandle, V_I4(&varg0));
1304 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1305 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1306 if (FAILED(hr)) return hr;
1307 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BOOL, &varg1, puArgErr);
1308 if (FAILED(hr)) return hr;
1309 if ((ret = MsiSetMode(This->msiHandle, V_I4(&varg0), V_BOOL(&varg1))) != ERROR_SUCCESS)
1311 ERR("MsiSetMode returned %d\n", ret);
1312 return DISP_E_EXCEPTION;
1315 else return DISP_E_MEMBERNOTFOUND;
1316 break;
1318 case DISPID_SESSION_DATABASE:
1319 if (wFlags & DISPATCH_PROPERTYGET) {
1320 V_VT(pVarResult) = VT_DISPATCH;
1321 if ((msiHandle = MsiGetActiveDatabase(This->msiHandle)))
1323 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Database, DatabaseImpl_Invoke, NULL, 0)))
1324 V_DISPATCH(pVarResult) = pDispatch;
1325 else
1326 ERR("Failed to create Database object, hresult 0x%08x\n", hr);
1328 else
1330 ERR("MsiGetActiveDatabase failed\n");
1331 return DISP_E_EXCEPTION;
1334 else return DISP_E_MEMBERNOTFOUND;
1335 break;
1337 case DISPID_SESSION_DOACTION:
1338 if (wFlags & DISPATCH_METHOD) {
1339 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1340 if (FAILED(hr)) return hr;
1341 ret = MsiDoActionW(This->msiHandle, V_BSTR(&varg0));
1342 V_VT(pVarResult) = VT_I4;
1343 switch (ret)
1345 case ERROR_FUNCTION_NOT_CALLED:
1346 V_I4(pVarResult) = msiDoActionStatusNoAction;
1347 break;
1348 case ERROR_SUCCESS:
1349 V_I4(pVarResult) = msiDoActionStatusSuccess;
1350 break;
1351 case ERROR_INSTALL_USEREXIT:
1352 V_I4(pVarResult) = msiDoActionStatusUserExit;
1353 break;
1354 case ERROR_INSTALL_FAILURE:
1355 V_I4(pVarResult) = msiDoActionStatusFailure;
1356 break;
1357 case ERROR_INSTALL_SUSPEND:
1358 V_I4(pVarResult) = msiDoActionStatusSuspend;
1359 break;
1360 case ERROR_MORE_DATA:
1361 V_I4(pVarResult) = msiDoActionStatusFinished;
1362 break;
1363 case ERROR_INVALID_HANDLE_STATE:
1364 V_I4(pVarResult) = msiDoActionStatusWrongState;
1365 break;
1366 case ERROR_INVALID_DATA:
1367 V_I4(pVarResult) = msiDoActionStatusBadActionData;
1368 break;
1369 default:
1370 VariantClear(&varg0);
1371 FIXME("MsiDoAction returned unhandled value %d\n", ret);
1372 return DISP_E_EXCEPTION;
1375 else return DISP_E_MEMBERNOTFOUND;
1376 break;
1378 case DISPID_SESSION_EVALUATECONDITION:
1379 if (wFlags & DISPATCH_METHOD) {
1380 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1381 if (FAILED(hr)) return hr;
1382 V_VT(pVarResult) = VT_I4;
1383 V_I4(pVarResult) = MsiEvaluateConditionW(This->msiHandle, V_BSTR(&varg0));
1385 else return DISP_E_MEMBERNOTFOUND;
1386 break;
1388 case DISPID_SESSION_SETINSTALLLEVEL:
1389 if (wFlags & DISPATCH_METHOD) {
1390 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1391 if (FAILED(hr)) return hr;
1392 if ((ret = MsiSetInstallLevel(This->msiHandle, V_I4(&varg0))) != ERROR_SUCCESS)
1394 ERR("MsiSetInstallLevel returned %d\n", ret);
1395 return DISP_E_EXCEPTION;
1398 else return DISP_E_MEMBERNOTFOUND;
1399 break;
1401 case DISPID_SESSION_FEATURECURRENTSTATE:
1402 if (wFlags & DISPATCH_PROPERTYGET) {
1403 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1404 if (FAILED(hr)) return hr;
1405 V_VT(pVarResult) = VT_I4;
1406 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1407 V_I4(pVarResult) = iInstalled;
1408 else
1410 ERR("MsiGetFeatureState returned %d\n", ret);
1411 V_I4(pVarResult) = msiInstallStateUnknown;
1414 else return DISP_E_MEMBERNOTFOUND;
1415 break;
1417 case DISPID_SESSION_FEATUREREQUESTSTATE:
1418 if (wFlags & DISPATCH_PROPERTYGET) {
1419 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1420 if (FAILED(hr)) return hr;
1421 V_VT(pVarResult) = VT_I4;
1422 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1423 V_I4(pVarResult) = iAction;
1424 else
1426 ERR("MsiGetFeatureState returned %d\n", ret);
1427 V_I4(pVarResult) = msiInstallStateUnknown;
1429 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1430 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1431 if (FAILED(hr)) return hr;
1432 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_I4, &varg1, puArgErr);
1433 if (FAILED(hr)) {
1434 VariantClear(&varg0);
1435 return hr;
1437 if ((ret = MsiSetFeatureStateW(This->msiHandle, V_BSTR(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
1439 VariantClear(&varg0);
1440 ERR("MsiSetFeatureState returned %d\n", ret);
1441 return DISP_E_EXCEPTION;
1444 else return DISP_E_MEMBERNOTFOUND;
1445 break;
1447 default:
1448 return DISP_E_MEMBERNOTFOUND;
1451 VariantClear(&varg1);
1452 VariantClear(&varg0);
1454 return S_OK;
1457 /* Fill the variant pointed to by pVarResult with the value & size returned by RegQueryValueEx as dictated by the
1458 * registry value type. Used by Installer::RegistryValue. */
1459 static void variant_from_registry_value(VARIANT *pVarResult, DWORD dwType, LPBYTE lpData, DWORD dwSize)
1461 static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
1462 static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
1463 WCHAR *szString = (WCHAR *)lpData;
1464 LPWSTR szNewString = NULL;
1465 DWORD dwNewSize = 0;
1466 int idx;
1468 switch (dwType)
1470 /* Registry strings may not be null terminated so we must use SysAllocStringByteLen/Len */
1471 case REG_MULTI_SZ: /* Multi SZ change internal null characters to newlines */
1472 idx = (dwSize/sizeof(WCHAR))-1;
1473 while (idx >= 0 && !szString[idx]) idx--;
1474 for (; idx >= 0; idx--)
1475 if (!szString[idx]) szString[idx] = '\n';
1476 case REG_SZ:
1477 V_VT(pVarResult) = VT_BSTR;
1478 V_BSTR(pVarResult) = SysAllocStringByteLen((LPCSTR)szString, dwSize);
1479 break;
1481 case REG_EXPAND_SZ:
1482 if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1483 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1484 else if (!(szNewString = msi_alloc(dwNewSize)))
1485 ERR("Out of memory\n");
1486 else if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1487 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1488 else
1490 V_VT(pVarResult) = VT_BSTR;
1491 V_BSTR(pVarResult) = SysAllocStringLen(szNewString, dwNewSize);
1493 msi_free(szNewString);
1494 break;
1496 case REG_DWORD:
1497 V_VT(pVarResult) = VT_I4;
1498 V_I4(pVarResult) = *((DWORD *)lpData);
1499 break;
1501 case REG_QWORD:
1502 V_VT(pVarResult) = VT_BSTR;
1503 V_BSTR(pVarResult) = SysAllocString(szREG_); /* Weird string, don't know why native returns it */
1504 break;
1506 case REG_BINARY:
1507 V_VT(pVarResult) = VT_BSTR;
1508 V_BSTR(pVarResult) = SysAllocString(szREG_BINARY);
1509 break;
1511 case REG_NONE:
1512 V_VT(pVarResult) = VT_EMPTY;
1513 break;
1515 default:
1516 FIXME("Unhandled registry value type %d\n", dwType);
1520 static HRESULT WINAPI InstallerImpl_Invoke(
1521 AutomationObject* This,
1522 DISPID dispIdMember,
1523 REFIID riid,
1524 LCID lcid,
1525 WORD wFlags,
1526 DISPPARAMS* pDispParams,
1527 VARIANT* pVarResult,
1528 EXCEPINFO* pExcepInfo,
1529 UINT* puArgErr)
1531 MSIHANDLE msiHandle;
1532 IDispatch *pDispatch = NULL;
1533 UINT ret;
1534 VARIANTARG varg0, varg1, varg2;
1535 HRESULT hr;
1536 LPWSTR szString = NULL;
1537 DWORD dwSize = 0;
1539 VariantInit(&varg0);
1540 VariantInit(&varg1);
1541 VariantInit(&varg2);
1543 switch (dispIdMember)
1545 case DISPID_INSTALLER_CREATERECORD:
1546 if (wFlags & DISPATCH_METHOD)
1548 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1549 if (FAILED(hr)) return hr;
1550 V_VT(pVarResult) = VT_DISPATCH;
1551 if ((msiHandle = MsiCreateRecord(V_I4(&varg0))))
1553 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Record, RecordImpl_Invoke, NULL, 0)))
1554 V_DISPATCH(pVarResult) = pDispatch;
1555 else
1556 ERR("Failed to create Record object, hresult 0x%08x\n", hr);
1558 else
1560 ERR("MsiCreateRecord failed\n");
1561 return DISP_E_EXCEPTION;
1564 else return DISP_E_MEMBERNOTFOUND;
1565 break;
1567 case DISPID_INSTALLER_OPENPACKAGE:
1568 if (wFlags & DISPATCH_METHOD)
1570 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1571 if (FAILED(hr)) return hr;
1572 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1573 if (FAILED(hr))
1575 VariantClear(&varg0);
1576 return hr;
1578 V_VT(pVarResult) = VT_DISPATCH;
1579 if ((ret = MsiOpenPackageExW(V_BSTR(&varg0), V_I4(&varg1), &msiHandle)) == ERROR_SUCCESS)
1581 if (SUCCEEDED(hr = create_session(msiHandle, (IDispatch *)This, &pDispatch)))
1582 V_DISPATCH(pVarResult) = pDispatch;
1583 else
1584 ERR("Failed to create Session object, hresult 0x%08x\n", hr);
1586 else
1588 VariantClear(&varg0);
1589 ERR("MsiOpenPackageEx returned %d\n", ret);
1590 return DISP_E_EXCEPTION;
1593 else return DISP_E_MEMBERNOTFOUND;
1594 break;
1596 case DISPID_INSTALLER_OPENDATABASE:
1597 if (wFlags & DISPATCH_METHOD)
1599 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1600 if (FAILED(hr)) return hr;
1602 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1603 if (FAILED(hr))
1605 VariantClear(&varg0);
1606 return hr;
1609 V_VT(pVarResult) = VT_DISPATCH;
1610 if ((ret = MsiOpenDatabaseW(V_BSTR(&varg0), V_BSTR(&varg1), &msiHandle)) == ERROR_SUCCESS)
1612 hr = create_automation_object(msiHandle, NULL, (LPVOID *)&pDispatch,
1613 &DIID_Database, DatabaseImpl_Invoke, NULL, 0);
1614 if (SUCCEEDED(hr))
1615 V_DISPATCH(pVarResult) = pDispatch;
1616 else
1617 ERR("Failed to create Database object: 0x%08x\n", hr);
1619 else
1621 VariantClear(&varg0);
1622 VariantClear(&varg1);
1623 ERR("MsiOpenDatabase returned %d\n", ret);
1624 return DISP_E_EXCEPTION;
1627 else return DISP_E_MEMBERNOTFOUND;
1628 break;
1630 case DISPID_INSTALLER_INSTALLPRODUCT:
1631 if (wFlags & DISPATCH_METHOD)
1633 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1634 if (FAILED(hr)) return hr;
1635 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1636 if (FAILED(hr))
1638 VariantClear(&varg0);
1639 return hr;
1641 if ((ret = MsiInstallProductW(V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
1643 VariantClear(&varg1);
1644 VariantClear(&varg0);
1645 ERR("MsiInstallProduct returned %d\n", ret);
1646 return DISP_E_EXCEPTION;
1649 else return DISP_E_MEMBERNOTFOUND;
1650 break;
1652 case DISPID_INSTALLER_VERSION:
1653 if (wFlags & DISPATCH_PROPERTYGET) {
1654 DLLVERSIONINFO verinfo;
1655 WCHAR version[MAX_PATH];
1657 static const WCHAR format[] = {'%','d','.','%','d','.','%','d','.','%','d',0};
1659 verinfo.cbSize = sizeof(DLLVERSIONINFO);
1660 hr = DllGetVersion(&verinfo);
1661 if (FAILED(hr)) return hr;
1663 sprintfW(version, format, verinfo.dwMajorVersion, verinfo.dwMinorVersion,
1664 verinfo.dwBuildNumber, verinfo.dwPlatformID);
1666 V_VT(pVarResult) = VT_BSTR;
1667 V_BSTR(pVarResult) = SysAllocString(version);
1669 else return DISP_E_MEMBERNOTFOUND;
1670 break;
1672 case DISPID_INSTALLER_REGISTRYVALUE:
1673 if (wFlags & DISPATCH_METHOD) {
1674 HKEY hkey;
1675 DWORD dwType;
1676 UINT posValue = 2; /* Save valuePos so we can save puArgErr if we are unable to do our type conversions */
1678 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1679 if (FAILED(hr)) return hr;
1680 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1681 if (FAILED(hr)) return hr;
1682 hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg2);
1683 if (FAILED(hr))
1685 VariantClear(&varg1);
1686 return hr;
1688 ret = RegOpenKeyW((HKEY)V_I4(&varg0), V_BSTR(&varg1), &hkey);
1690 /* Third parameter can be VT_EMPTY, VT_I4, or VT_BSTR */
1691 switch (V_VT(&varg2))
1693 case VT_EMPTY: /* Return VT_BOOL as to whether or not registry key exists */
1694 V_VT(pVarResult) = VT_BOOL;
1695 V_BOOL(pVarResult) = (ret == ERROR_SUCCESS);
1696 break;
1698 case VT_BSTR: /* Return value of specified key if it exists */
1699 if (ret == ERROR_SUCCESS &&
1700 (ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL, NULL, NULL, &dwSize)) == ERROR_SUCCESS)
1702 if (!(szString = msi_alloc(dwSize)))
1703 ERR("Out of memory\n");
1704 else if ((ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL, &dwType, (LPBYTE)szString, &dwSize)) == ERROR_SUCCESS)
1705 variant_from_registry_value(pVarResult, dwType, (LPBYTE)szString, dwSize);
1708 if (ret != ERROR_SUCCESS)
1710 msi_free(szString);
1711 VariantClear(&varg2);
1712 VariantClear(&varg1);
1713 return DISP_E_BADINDEX;
1715 break;
1717 default: /* Try to make it into VT_I4, can use VariantChangeType for this */
1718 hr = VariantChangeType(&varg2, &varg2, 0, VT_I4);
1719 if (SUCCEEDED(hr) && ret != ERROR_SUCCESS) hr = DISP_E_BADINDEX; /* Conversion fine, but couldn't find key */
1720 if (FAILED(hr))
1722 if (hr == DISP_E_TYPEMISMATCH) *puArgErr = posValue;
1723 VariantClear(&varg2); /* Unknown type, so let's clear it */
1724 VariantClear(&varg1);
1725 return hr;
1728 /* Retrieve class name or maximum value name or subkey name size */
1729 if (!V_I4(&varg2))
1730 ret = RegQueryInfoKeyW(hkey, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1731 else if (V_I4(&varg2) > 0)
1732 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL);
1733 else /* V_I4(&varg2) < 0 */
1734 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
1736 if (ret == ERROR_SUCCESS)
1738 if (!(szString = msi_alloc(++dwSize * sizeof(WCHAR))))
1739 ERR("Out of memory\n");
1740 else if (!V_I4(&varg2))
1741 ret = RegQueryInfoKeyW(hkey, szString, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1742 else if (V_I4(&varg2) > 0)
1743 ret = RegEnumValueW(hkey, V_I4(&varg2)-1, szString, &dwSize, 0, 0, NULL, NULL);
1744 else /* V_I4(&varg2) < 0 */
1745 ret = RegEnumKeyW(hkey, -1 - V_I4(&varg2), szString, dwSize);
1747 if (szString && ret == ERROR_SUCCESS)
1749 V_VT(pVarResult) = VT_BSTR;
1750 V_BSTR(pVarResult) = SysAllocString(szString);
1755 msi_free(szString);
1756 RegCloseKey(hkey);
1758 else return DISP_E_MEMBERNOTFOUND;
1759 break;
1761 case DISPID_INSTALLER_PRODUCTSTATE:
1762 if (wFlags & DISPATCH_PROPERTYGET) {
1763 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1764 if (FAILED(hr)) return hr;
1765 V_VT(pVarResult) = VT_I4;
1766 V_I4(pVarResult) = MsiQueryProductStateW(V_BSTR(&varg0));
1768 else return DISP_E_MEMBERNOTFOUND;
1769 break;
1771 case DISPID_INSTALLER_PRODUCTINFO:
1772 if (wFlags & DISPATCH_PROPERTYGET) {
1773 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1774 if (FAILED(hr)) return hr;
1775 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1776 if (FAILED(hr))
1778 VariantClear(&varg0);
1779 return hr;
1781 V_VT(pVarResult) = VT_BSTR;
1782 V_BSTR(pVarResult) = NULL;
1783 if ((ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), NULL, &dwSize)) == ERROR_SUCCESS)
1785 if (!(szString = msi_alloc((++dwSize)*sizeof(WCHAR))))
1786 ERR("Out of memory\n");
1787 else if ((ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), szString, &dwSize)) == ERROR_SUCCESS)
1788 V_BSTR(pVarResult) = SysAllocString(szString);
1789 msi_free(szString);
1791 if (ret != ERROR_SUCCESS)
1793 ERR("MsiGetProductInfo returned %d\n", ret);
1794 VariantClear(&varg1);
1795 VariantClear(&varg0);
1796 return DISP_E_EXCEPTION;
1799 else return DISP_E_MEMBERNOTFOUND;
1800 break;
1802 case DISPID_INSTALLER_PRODUCTS:
1803 if (wFlags & DISPATCH_PROPERTYGET)
1805 ListData *ldata = NULL;
1806 ULONG idx = 0;
1807 WCHAR szProductBuf[GUID_SIZE];
1809 /* Find number of products */
1810 while ((ret = MsiEnumProductsW(idx, szProductBuf)) == ERROR_SUCCESS) idx++;
1811 if (ret != ERROR_NO_MORE_ITEMS)
1813 ERR("MsiEnumProducts returned %d\n", ret);
1814 return DISP_E_EXCEPTION;
1817 V_VT(pVarResult) = VT_DISPATCH;
1818 if (SUCCEEDED(hr = create_automation_object(0, NULL, (LPVOID*)&pDispatch, &DIID_StringList, ListImpl_Invoke, ListImpl_Free, sizeof(ListData))))
1820 V_DISPATCH(pVarResult) = pDispatch;
1822 /* Save product strings */
1823 ldata = (ListData *)private_data((AutomationObject *)pDispatch);
1824 if (!(ldata->pVars = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(VARIANT)*idx)))
1825 ERR("Out of memory\n");
1826 else
1828 ldata->ulCount = idx;
1829 for (idx = 0; idx < ldata->ulCount; idx++)
1831 ret = MsiEnumProductsW(idx, szProductBuf);
1832 VariantInit(&ldata->pVars[idx]);
1833 V_VT(&ldata->pVars[idx]) = VT_BSTR;
1834 V_BSTR(&ldata->pVars[idx]) = SysAllocString(szProductBuf);
1838 else
1839 ERR("Failed to create StringList object, hresult 0x%08x\n", hr);
1841 else return DISP_E_MEMBERNOTFOUND;
1842 break;
1844 case DISPID_INSTALLER_RELATEDPRODUCTS:
1845 if (wFlags & DISPATCH_PROPERTYGET)
1847 ListData *ldata = NULL;
1848 ULONG idx = 0;
1849 WCHAR szProductBuf[GUID_SIZE];
1851 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1852 if (FAILED(hr)) return hr;
1854 /* Find number of related products */
1855 while ((ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, szProductBuf)) == ERROR_SUCCESS) idx++;
1856 if (ret != ERROR_NO_MORE_ITEMS)
1858 VariantClear(&varg0);
1859 ERR("MsiEnumRelatedProducts returned %d\n", ret);
1860 return DISP_E_EXCEPTION;
1863 V_VT(pVarResult) = VT_DISPATCH;
1864 if (SUCCEEDED(hr = create_automation_object(0, NULL, (LPVOID*)&pDispatch, &DIID_StringList, ListImpl_Invoke, ListImpl_Free, sizeof(ListData))))
1866 V_DISPATCH(pVarResult) = pDispatch;
1868 /* Save product strings */
1869 ldata = (ListData *)private_data((AutomationObject *)pDispatch);
1870 if (!(ldata->pVars = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(VARIANT)*idx)))
1871 ERR("Out of memory\n");
1872 else
1874 ldata->ulCount = idx;
1875 for (idx = 0; idx < ldata->ulCount; idx++)
1877 ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, szProductBuf);
1878 VariantInit(&ldata->pVars[idx]);
1879 V_VT(&ldata->pVars[idx]) = VT_BSTR;
1880 V_BSTR(&ldata->pVars[idx]) = SysAllocString(szProductBuf);
1884 else
1885 ERR("Failed to create StringList object, hresult 0x%08x\n", hr);
1887 else return DISP_E_MEMBERNOTFOUND;
1888 break;
1890 default:
1891 return DISP_E_MEMBERNOTFOUND;
1894 VariantClear(&varg2);
1895 VariantClear(&varg1);
1896 VariantClear(&varg0);
1898 return S_OK;
1901 /* Wrapper around create_automation_object to create an installer object. */
1902 HRESULT create_msiserver(IUnknown *pOuter, LPVOID *ppObj)
1904 return create_automation_object(0, pOuter, ppObj, &DIID_Installer, InstallerImpl_Invoke, NULL, 0);
1907 /* Wrapper around create_automation_object to create a session object. */
1908 HRESULT create_session(MSIHANDLE msiHandle, IDispatch *pInstaller, IDispatch **pDispatch)
1910 HRESULT hr = create_automation_object(msiHandle, NULL, (LPVOID)pDispatch, &DIID_Session, SessionImpl_Invoke, NULL, sizeof(SessionData));
1911 if (SUCCEEDED(hr) && pDispatch && *pDispatch)
1912 ((SessionData *)private_data((AutomationObject *)*pDispatch))->pInstaller = pInstaller;
1913 return hr;