push 98f792e3155bc985dadb8ff382b74ad0a1d351b5
[wine/hacks.git] / dlls / msi / automation.c
blobfb8d4f578c0b1496a5e8fe0cdeea942d7dd6429c
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 "wine/debug.h"
34 #include "wine/unicode.h"
36 #include "msiserver.h"
37 #include "msiserver_dispids.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(msi);
42 * AutomationObject - "base" class for all automation objects. For each interface, we implement Invoke function
43 * called from AutomationObject::Invoke, and pass this function to create_automation_object.
46 typedef interface AutomationObject AutomationObject;
48 interface AutomationObject {
50 * VTables - We provide IDispatch, IProvideClassInfo, IProvideClassInfo2, IProvideMultipleClassInfo
52 const IDispatchVtbl *lpVtbl;
53 const IProvideMultipleClassInfoVtbl *lpvtblIProvideMultipleClassInfo;
55 /* Object reference count */
56 LONG ref;
58 /* Clsid for this class and it's appropriate ITypeInfo object */
59 LPCLSID clsid;
60 ITypeInfo *iTypeInfo;
62 /* The MSI handle of the current object */
63 MSIHANDLE msiHandle;
65 /* A function that is called from AutomationObject::Invoke, specific to this type of object. */
66 HRESULT (STDMETHODCALLTYPE *funcInvoke)(
67 AutomationObject* This,
68 DISPID dispIdMember,
69 REFIID riid,
70 LCID lcid,
71 WORD wFlags,
72 DISPPARAMS* pDispParams,
73 VARIANT* pVarResult,
74 EXCEPINFO* pExcepInfo,
75 UINT* puArgErr);
77 /* A function that is called from AutomationObject::Release when the object is being freed to free any private
78 * data structures (or NULL) */
79 void (STDMETHODCALLTYPE *funcFree)(AutomationObject* This);
83 * ListEnumerator - IEnumVARIANT implementation for MSI automation lists.
86 typedef interface ListEnumerator ListEnumerator;
88 interface ListEnumerator {
89 /* VTables */
90 const IEnumVARIANTVtbl *lpVtbl;
92 /* Object reference count */
93 LONG ref;
95 /* Current position and pointer to AutomationObject that stores actual data */
96 ULONG ulPos;
97 AutomationObject *pObj;
101 * Structures for additional data required by specific automation objects
104 typedef struct {
105 ULONG ulCount;
106 VARIANT *pVars;
107 } ListData;
109 typedef struct {
110 /* The parent Installer object */
111 IDispatch *pInstaller;
112 } SessionData;
114 /* VTables */
115 static const struct IDispatchVtbl AutomationObject_Vtbl;
116 static const struct IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl;
117 static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl;
119 /* Load type info so we don't have to process GetIDsOfNames */
120 HRESULT load_type_info(IDispatch *iface, ITypeInfo **pptinfo, REFIID clsid, LCID lcid)
122 HRESULT hr;
123 LPTYPELIB pLib = NULL;
124 LPTYPEINFO pInfo = NULL;
125 static const WCHAR szMsiServer[] = {'m','s','i','s','e','r','v','e','r','.','t','l','b'};
127 TRACE("(%p)->(%s,%d)\n", iface, debugstr_guid(clsid), lcid);
129 /* Load registered type library */
130 hr = LoadRegTypeLib(&LIBID_WindowsInstaller, 1, 0, lcid, &pLib);
131 if (FAILED(hr)) {
132 hr = LoadTypeLib(szMsiServer, &pLib);
133 if (FAILED(hr)) {
134 ERR("Could not load msiserver.tlb\n");
135 return hr;
139 /* Get type information for object */
140 hr = ITypeLib_GetTypeInfoOfGuid(pLib, clsid, &pInfo);
141 ITypeLib_Release(pLib);
142 if (FAILED(hr)) {
143 ERR("Could not load ITypeInfo for %s\n", debugstr_guid(clsid));
144 return hr;
146 *pptinfo = pInfo;
147 return S_OK;
150 /* Create the automation object, placing the result in the pointer ppObj. The automation object is created
151 * with the appropriate clsid and invocation function. */
152 HRESULT create_automation_object(MSIHANDLE msiHandle, IUnknown *pUnkOuter, LPVOID *ppObj, REFIID clsid,
153 HRESULT (STDMETHODCALLTYPE *funcInvoke)(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,
154 VARIANT*,EXCEPINFO*,UINT*),
155 void (STDMETHODCALLTYPE *funcFree)(AutomationObject*),
156 SIZE_T sizetPrivateData)
158 AutomationObject *object;
159 HRESULT hr;
161 TRACE("(%ld,%p,%p,%s,%p,%p,%ld)\n", (unsigned long)msiHandle, pUnkOuter, ppObj, debugstr_guid(clsid), funcInvoke, funcFree, sizetPrivateData);
163 if( pUnkOuter )
164 return CLASS_E_NOAGGREGATION;
166 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AutomationObject)+sizetPrivateData);
168 /* Set all the VTable references */
169 object->lpVtbl = &AutomationObject_Vtbl;
170 object->lpvtblIProvideMultipleClassInfo = &AutomationObject_IProvideMultipleClassInfo_Vtbl;
171 object->ref = 1;
173 /* Store data that was passed */
174 object->msiHandle = msiHandle;
175 object->clsid = (LPCLSID)clsid;
176 object->funcInvoke = funcInvoke;
177 object->funcFree = funcFree;
179 /* Load our TypeInfo so we don't have to process GetIDsOfNames */
180 object->iTypeInfo = NULL;
181 hr = load_type_info((IDispatch *)object, &object->iTypeInfo, clsid, 0x0);
182 if (FAILED(hr)) {
183 HeapFree(GetProcessHeap(), 0, object);
184 return hr;
187 *ppObj = object;
189 return S_OK;
192 /* Create a list enumerator, placing the result in the pointer ppObj. */
193 HRESULT create_list_enumerator(IUnknown *pUnkOuter, LPVOID *ppObj, AutomationObject *pObj, ULONG ulPos)
195 ListEnumerator *object;
197 TRACE("(%p,%p,%p,%uld)\n", pUnkOuter, ppObj, pObj, ulPos);
199 if( pUnkOuter )
200 return CLASS_E_NOAGGREGATION;
202 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ListEnumerator));
204 /* Set all the VTable references */
205 object->lpVtbl = &ListEnumerator_Vtbl;
206 object->ref = 1;
208 /* Store data that was passed */
209 object->ulPos = ulPos;
210 object->pObj = pObj;
211 if (pObj) IDispatch_AddRef((IDispatch *)pObj);
213 *ppObj = object;
214 return S_OK;
217 /* Macros to get pointer to AutomationObject from the other VTables. */
218 static inline AutomationObject *obj_from_IProvideMultipleClassInfo( IProvideMultipleClassInfo *iface )
220 return (AutomationObject *)((char*)iface - FIELD_OFFSET(AutomationObject, lpvtblIProvideMultipleClassInfo));
223 /* Macro to get pointer to private object data */
224 static inline void *private_data( AutomationObject *This )
226 return This + 1;
230 * AutomationObject methods
233 /*** IUnknown methods ***/
234 static HRESULT WINAPI AutomationObject_QueryInterface(IDispatch* iface, REFIID riid, void** ppvObject)
236 AutomationObject *This = (AutomationObject *)iface;
238 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
240 if (ppvObject == NULL)
241 return E_INVALIDARG;
243 *ppvObject = 0;
245 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDispatch) || IsEqualGUID(riid, This->clsid))
246 *ppvObject = This;
247 else if (IsEqualGUID(riid, &IID_IProvideClassInfo) ||
248 IsEqualGUID(riid, &IID_IProvideClassInfo2) ||
249 IsEqualGUID(riid, &IID_IProvideMultipleClassInfo))
250 *ppvObject = &This->lpvtblIProvideMultipleClassInfo;
251 else
253 TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid));
254 return E_NOINTERFACE;
258 * Query Interface always increases the reference count by one when it is
259 * successful
261 IClassFactory_AddRef(iface);
263 return S_OK;
266 static ULONG WINAPI AutomationObject_AddRef(IDispatch* iface)
268 AutomationObject *This = (AutomationObject *)iface;
270 TRACE("(%p/%p)\n", iface, This);
272 return InterlockedIncrement(&This->ref);
275 static ULONG WINAPI AutomationObject_Release(IDispatch* iface)
277 AutomationObject *This = (AutomationObject *)iface;
278 ULONG ref = InterlockedDecrement(&This->ref);
280 TRACE("(%p/%p)\n", iface, This);
282 if (!ref)
284 if (This->funcFree) This->funcFree(This);
285 MsiCloseHandle(This->msiHandle);
286 HeapFree(GetProcessHeap(), 0, This);
289 return ref;
292 /*** IDispatch methods ***/
293 static HRESULT WINAPI AutomationObject_GetTypeInfoCount(
294 IDispatch* iface,
295 UINT* pctinfo)
297 AutomationObject *This = (AutomationObject *)iface;
299 TRACE("(%p/%p)->(%p)\n", iface, This, pctinfo);
300 *pctinfo = 1;
301 return S_OK;
304 static HRESULT WINAPI AutomationObject_GetTypeInfo(
305 IDispatch* iface,
306 UINT iTInfo,
307 LCID lcid,
308 ITypeInfo** ppTInfo)
310 AutomationObject *This = (AutomationObject *)iface;
311 TRACE("(%p/%p)->(%d,%d,%p)\n", iface, This, iTInfo, lcid, ppTInfo);
313 ITypeInfo_AddRef(This->iTypeInfo);
314 *ppTInfo = This->iTypeInfo;
315 return S_OK;
318 static HRESULT WINAPI AutomationObject_GetIDsOfNames(
319 IDispatch* iface,
320 REFIID riid,
321 LPOLESTR* rgszNames,
322 UINT cNames,
323 LCID lcid,
324 DISPID* rgDispId)
326 AutomationObject *This = (AutomationObject *)iface;
327 HRESULT hr;
328 TRACE("(%p/%p)->(%p,%p,%d,%d,%p)\n", iface, This, riid, rgszNames, cNames, lcid, rgDispId);
330 if (!IsEqualGUID(riid, &IID_NULL)) return E_INVALIDARG;
331 hr = ITypeInfo_GetIDsOfNames(This->iTypeInfo, rgszNames, cNames, rgDispId);
332 if (hr == DISP_E_UNKNOWNNAME)
334 int idx;
335 for (idx=0; idx<cNames; idx++)
337 if (rgDispId[idx] == DISPID_UNKNOWN)
338 FIXME("Unknown member %s, clsid %s\n", debugstr_w(rgszNames[idx]), debugstr_guid(This->clsid));
341 return hr;
344 /* Maximum number of allowed function parameters+1 */
345 #define MAX_FUNC_PARAMS 20
347 /* Some error checking is done here to simplify individual object function invocation */
348 static HRESULT WINAPI AutomationObject_Invoke(
349 IDispatch* iface,
350 DISPID dispIdMember,
351 REFIID riid,
352 LCID lcid,
353 WORD wFlags,
354 DISPPARAMS* pDispParams,
355 VARIANT* pVarResult,
356 EXCEPINFO* pExcepInfo,
357 UINT* puArgErr)
359 AutomationObject *This = (AutomationObject *)iface;
360 HRESULT hr;
361 unsigned int uArgErr;
362 VARIANT varResultDummy;
363 BSTR bstrName = NULL;
365 TRACE("(%p/%p)->(%d,%p,%d,%d,%p,%p,%p,%p)\n", iface, This, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
367 if (!IsEqualIID(riid, &IID_NULL))
369 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
370 return DISP_E_UNKNOWNNAME;
373 if (wFlags & DISPATCH_PROPERTYGET && !pVarResult)
375 ERR("NULL pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
376 return DISP_E_PARAMNOTOPTIONAL;
379 /* This simplifies our individual object invocation functions */
380 if (puArgErr == NULL) puArgErr = &uArgErr;
381 if (pVarResult == NULL) pVarResult = &varResultDummy;
383 /* Assume return type is void unless determined otherwise */
384 VariantInit(pVarResult);
386 /* If we are tracing, we want to see the name of the member we are invoking */
387 if (TRACE_ON(msi))
389 ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL);
390 TRACE("Method %d, %s\n", dispIdMember, debugstr_w(bstrName));
393 hr = This->funcInvoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
395 if (hr == DISP_E_MEMBERNOTFOUND) {
396 if (bstrName == NULL) ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL);
397 FIXME("Method %d, %s wflags %d not implemented, clsid %s\n", dispIdMember, debugstr_w(bstrName), wFlags, debugstr_guid(This->clsid));
399 else if (pExcepInfo &&
400 (hr == DISP_E_PARAMNOTFOUND ||
401 hr == DISP_E_EXCEPTION)) {
402 static const WCHAR szComma[] = { ',',0 };
403 static WCHAR szExceptionSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
404 WCHAR szExceptionDescription[MAX_PATH];
405 BSTR bstrParamNames[MAX_FUNC_PARAMS];
406 unsigned namesNo, i;
407 BOOL bFirst = TRUE;
409 if (FAILED(ITypeInfo_GetNames(This->iTypeInfo, dispIdMember, bstrParamNames,
410 MAX_FUNC_PARAMS, &namesNo)))
412 TRACE("Failed to retrieve names for dispIdMember %d\n", dispIdMember);
414 else
416 memset(szExceptionDescription, 0, sizeof(szExceptionDescription));
417 for (i=0; i<namesNo; i++)
419 if (bFirst) bFirst = FALSE;
420 else {
421 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], szComma);
423 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], bstrParamNames[i]);
424 SysFreeString(bstrParamNames[i]);
427 memset(pExcepInfo, 0, sizeof(EXCEPINFO));
428 pExcepInfo->wCode = 1000;
429 pExcepInfo->bstrSource = SysAllocString(szExceptionSource);
430 pExcepInfo->bstrDescription = SysAllocString(szExceptionDescription);
431 hr = DISP_E_EXCEPTION;
435 /* Make sure we free the return variant if it is our dummy variant */
436 if (pVarResult == &varResultDummy) VariantClear(pVarResult);
438 /* Free function name if we retrieved it */
439 if (bstrName) SysFreeString(bstrName);
441 TRACE("Returning 0x%08x, %s\n", hr, SUCCEEDED(hr) ? "ok" : "not ok");
443 return hr;
446 static const struct IDispatchVtbl AutomationObject_Vtbl =
448 AutomationObject_QueryInterface,
449 AutomationObject_AddRef,
450 AutomationObject_Release,
451 AutomationObject_GetTypeInfoCount,
452 AutomationObject_GetTypeInfo,
453 AutomationObject_GetIDsOfNames,
454 AutomationObject_Invoke
458 * IProvideMultipleClassInfo methods
461 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_QueryInterface(
462 IProvideMultipleClassInfo* iface,
463 REFIID riid,
464 VOID** ppvoid)
466 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
467 return AutomationObject_QueryInterface((IDispatch *)This, riid, ppvoid);
470 static ULONG WINAPI AutomationObject_IProvideMultipleClassInfo_AddRef(IProvideMultipleClassInfo* iface)
472 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
473 return AutomationObject_AddRef((IDispatch *)This);
476 static ULONG WINAPI AutomationObject_IProvideMultipleClassInfo_Release(IProvideMultipleClassInfo* iface)
478 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
479 return AutomationObject_Release((IDispatch *)This);
482 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_GetClassInfo(IProvideMultipleClassInfo* iface, ITypeInfo** ppTI)
484 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
485 TRACE("(%p/%p)->(%p)\n", iface, This, ppTI);
486 return load_type_info((IDispatch *)This, ppTI, This->clsid, 0);
489 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_GetGUID(IProvideMultipleClassInfo* iface, DWORD dwGuidKind, GUID* pGUID)
491 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
492 TRACE("(%p/%p)->(%d,%s)\n", iface, This, dwGuidKind, debugstr_guid(pGUID));
494 if (dwGuidKind != GUIDKIND_DEFAULT_SOURCE_DISP_IID)
495 return E_INVALIDARG;
496 else {
497 *pGUID = *This->clsid;
498 return S_OK;
502 static HRESULT WINAPI AutomationObject_GetMultiTypeInfoCount(IProvideMultipleClassInfo* iface, ULONG* pcti)
504 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
506 TRACE("(%p/%p)->(%p)\n", iface, This, pcti);
507 *pcti = 1;
508 return S_OK;
511 static HRESULT WINAPI AutomationObject_GetInfoOfIndex(IProvideMultipleClassInfo* iface,
512 ULONG iti,
513 DWORD dwFlags,
514 ITypeInfo** pptiCoClass,
515 DWORD* pdwTIFlags,
516 ULONG* pcdispidReserved,
517 IID* piidPrimary,
518 IID* piidSource)
520 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
522 TRACE("(%p/%p)->(%d,%d,%p,%p,%p,%p,%p)\n", iface, This, iti, dwFlags, pptiCoClass, pdwTIFlags, pcdispidReserved, piidPrimary, piidSource);
524 if (iti != 0)
525 return E_INVALIDARG;
527 if (dwFlags & MULTICLASSINFO_GETTYPEINFO)
528 load_type_info((IDispatch *)This, pptiCoClass, This->clsid, 0);
530 if (dwFlags & MULTICLASSINFO_GETNUMRESERVEDDISPIDS)
532 *pdwTIFlags = 0;
533 *pcdispidReserved = 0;
536 if (dwFlags & MULTICLASSINFO_GETIIDPRIMARY){
537 *piidPrimary = *This->clsid;
540 if (dwFlags & MULTICLASSINFO_GETIIDSOURCE){
541 *piidSource = *This->clsid;
544 return S_OK;
547 static const IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl =
549 AutomationObject_IProvideMultipleClassInfo_QueryInterface,
550 AutomationObject_IProvideMultipleClassInfo_AddRef,
551 AutomationObject_IProvideMultipleClassInfo_Release,
552 AutomationObject_IProvideMultipleClassInfo_GetClassInfo,
553 AutomationObject_IProvideMultipleClassInfo_GetGUID,
554 AutomationObject_GetMultiTypeInfoCount,
555 AutomationObject_GetInfoOfIndex
559 * ListEnumerator methods
562 /*** IUnknown methods ***/
563 static HRESULT WINAPI ListEnumerator_QueryInterface(IEnumVARIANT* iface, REFIID riid, void** ppvObject)
565 ListEnumerator *This = (ListEnumerator *)iface;
567 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
569 if (ppvObject == NULL)
570 return E_INVALIDARG;
572 *ppvObject = 0;
574 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IEnumVARIANT))
575 *ppvObject = This;
576 else
578 TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid));
579 return E_NOINTERFACE;
582 IClassFactory_AddRef(iface);
583 return S_OK;
586 static ULONG WINAPI ListEnumerator_AddRef(IEnumVARIANT* iface)
588 ListEnumerator *This = (ListEnumerator *)iface;
590 TRACE("(%p/%p)\n", iface, This);
592 return InterlockedIncrement(&This->ref);
595 static ULONG WINAPI ListEnumerator_Release(IEnumVARIANT* iface)
597 ListEnumerator *This = (ListEnumerator *)iface;
598 ULONG ref = InterlockedDecrement(&This->ref);
600 TRACE("(%p/%p)\n", iface, This);
602 if (!ref)
604 if (This->pObj) IDispatch_Release((IDispatch *)This->pObj);
605 HeapFree(GetProcessHeap(), 0, This);
608 return ref;
611 /* IEnumVARIANT methods */
613 static HRESULT WINAPI ListEnumerator_Next(IEnumVARIANT* iface, ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched)
615 ListEnumerator *This = (ListEnumerator *)iface;
616 ListData *data = (ListData *)private_data(This->pObj);
617 ULONG idx, local;
619 TRACE("(%p,%uld,%p,%p)\n", iface, celt, rgVar, pCeltFetched);
621 if (pCeltFetched != NULL)
622 *pCeltFetched = 0;
624 if (rgVar == NULL)
625 return S_FALSE;
627 for (local = 0; local < celt; local++)
628 VariantInit(&rgVar[local]);
630 for (idx = This->ulPos, local = 0; idx < data->ulCount && local < celt; idx++, local++)
631 VariantCopy(&rgVar[local], &data->pVars[idx]);
633 if (pCeltFetched != NULL)
634 *pCeltFetched = local;
635 This->ulPos = idx;
637 return (local < celt) ? S_FALSE : S_OK;
640 static HRESULT WINAPI ListEnumerator_Skip(IEnumVARIANT* iface, ULONG celt)
642 ListEnumerator *This = (ListEnumerator *)iface;
643 ListData *data = (ListData *)private_data(This->pObj);
645 TRACE("(%p,%uld)\n", iface, celt);
647 This->ulPos += celt;
648 if (This->ulPos >= data->ulCount)
650 This->ulPos = data->ulCount;
651 return S_FALSE;
653 return S_OK;
656 static HRESULT WINAPI ListEnumerator_Reset(IEnumVARIANT* iface)
658 ListEnumerator *This = (ListEnumerator *)iface;
660 TRACE("(%p)\n", iface);
662 This->ulPos = 0;
663 return S_OK;
666 static HRESULT WINAPI ListEnumerator_Clone(IEnumVARIANT* iface, IEnumVARIANT **ppEnum)
668 ListEnumerator *This = (ListEnumerator *)iface;
669 HRESULT hr;
671 TRACE("(%p,%p)\n", iface, ppEnum);
673 if (ppEnum == NULL)
674 return S_FALSE;
676 *ppEnum = NULL;
677 hr = create_list_enumerator(NULL, (LPVOID *)ppEnum, This->pObj, 0);
678 if (FAILED(hr))
680 if (*ppEnum)
681 IUnknown_Release(*ppEnum);
682 return hr;
685 IUnknown_AddRef(*ppEnum);
686 return S_OK;
689 static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl =
691 ListEnumerator_QueryInterface,
692 ListEnumerator_AddRef,
693 ListEnumerator_Release,
694 ListEnumerator_Next,
695 ListEnumerator_Skip,
696 ListEnumerator_Reset,
697 ListEnumerator_Clone
701 * Individual Object Invocation Functions
704 /* Helper function that copies a passed parameter instead of using VariantChangeType like the actual DispGetParam.
705 This function is only for VARIANT type parameters that have several types that cannot be properly discriminated
706 using DispGetParam/VariantChangeType. */
707 HRESULT WINAPI DispGetParam_CopyOnly(
708 DISPPARAMS *pdispparams, /* [in] Parameter list */
709 UINT *position, /* [in] Position of parameter to copy in pdispparams; on return will contain calculated position */
710 VARIANT *pvarResult) /* [out] Destination for resulting variant */
712 /* position is counted backwards */
713 UINT pos;
715 TRACE("position=%d, cArgs=%d, cNamedArgs=%d\n",
716 *position, pdispparams->cArgs, pdispparams->cNamedArgs);
717 if (*position < pdispparams->cArgs) {
718 /* positional arg? */
719 pos = pdispparams->cArgs - *position - 1;
720 } else {
721 /* FIXME: is this how to handle named args? */
722 for (pos=0; pos<pdispparams->cNamedArgs; pos++)
723 if (pdispparams->rgdispidNamedArgs[pos] == *position) break;
725 if (pos==pdispparams->cNamedArgs)
726 return DISP_E_PARAMNOTFOUND;
728 *position = pos;
729 return VariantCopyInd(pvarResult,
730 &pdispparams->rgvarg[pos]);
733 static HRESULT WINAPI SummaryInfoImpl_Invoke(
734 AutomationObject* This,
735 DISPID dispIdMember,
736 REFIID riid,
737 LCID lcid,
738 WORD wFlags,
739 DISPPARAMS* pDispParams,
740 VARIANT* pVarResult,
741 EXCEPINFO* pExcepInfo,
742 UINT* puArgErr)
744 UINT ret;
745 VARIANTARG varg0, varg1;
746 FILETIME ft, ftlocal;
747 SYSTEMTIME st;
748 HRESULT hr;
750 VariantInit(&varg0);
751 VariantInit(&varg1);
753 switch (dispIdMember)
755 case DISPID_SUMMARYINFO_PROPERTY:
756 if (wFlags & DISPATCH_PROPERTYGET)
758 UINT type;
759 INT value;
760 DWORD size = 0;
761 DATE date;
762 LPWSTR str;
764 static WCHAR szEmpty[] = {0};
766 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
767 if (FAILED(hr)) return hr;
768 ret = MsiSummaryInfoGetPropertyW(This->msiHandle, V_I4(&varg0), &type, &value,
769 &ft, szEmpty, &size);
770 if (ret != ERROR_SUCCESS &&
771 ret != ERROR_MORE_DATA)
773 ERR("MsiSummaryInfoGetProperty returned %d\n", ret);
774 return DISP_E_EXCEPTION;
777 switch (type)
779 case VT_EMPTY:
780 break;
782 case VT_I2:
783 case VT_I4:
784 V_VT(pVarResult) = VT_I4;
785 V_I4(pVarResult) = value;
786 break;
788 case VT_LPSTR:
789 if (!(str = msi_alloc(++size * sizeof(WCHAR))))
790 ERR("Out of memory\n");
791 else if ((ret = MsiSummaryInfoGetPropertyW(This->msiHandle, V_I4(&varg0), &type, NULL,
792 NULL, str, &size)) != ERROR_SUCCESS)
793 ERR("MsiSummaryInfoGetProperty returned %d\n", ret);
794 else
796 V_VT(pVarResult) = VT_BSTR;
797 V_BSTR(pVarResult) = SysAllocString(str);
799 msi_free(str);
800 break;
802 case VT_FILETIME:
803 FileTimeToLocalFileTime(&ft, &ftlocal);
804 FileTimeToSystemTime(&ftlocal, &st);
805 SystemTimeToVariantTime(&st, &date);
807 V_VT(pVarResult) = VT_DATE;
808 V_DATE(pVarResult) = date;
809 break;
811 default:
812 ERR("Unhandled variant type %d\n", type);
815 else if (wFlags & DISPATCH_PROPERTYPUT)
817 UINT posValue = DISPID_PROPERTYPUT;
819 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
820 if (FAILED(hr)) return hr;
821 hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg1);
822 if (FAILED(hr))
824 *puArgErr = posValue;
825 return hr;
828 switch (V_VT(&varg1))
830 case VT_I2:
831 case VT_I4:
832 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), V_VT(&varg1), V_I4(&varg1), NULL, NULL);
833 break;
835 case VT_DATE:
836 VariantTimeToSystemTime(V_DATE(&varg1), &st);
837 SystemTimeToFileTime(&st, &ftlocal);
838 LocalFileTimeToFileTime(&ftlocal, &ft);
839 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), VT_FILETIME, 0, &ft, NULL);
840 break;
842 case VT_BSTR:
843 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), VT_LPSTR, 0, NULL, V_BSTR(&varg1));
844 break;
846 default:
847 FIXME("Unhandled variant type %d\n", V_VT(&varg1));
848 VariantClear(&varg1);
849 return DISP_E_EXCEPTION;
852 if (ret != ERROR_SUCCESS)
854 ERR("MsiSummaryInfoSetPropertyW returned %d\n", ret);
855 return DISP_E_EXCEPTION;
858 else return DISP_E_MEMBERNOTFOUND;
859 break;
861 case DISPID_SUMMARYINFO_PROPERTYCOUNT:
862 if (wFlags & DISPATCH_PROPERTYGET) {
863 UINT count;
864 if ((ret = MsiSummaryInfoGetPropertyCount(This->msiHandle, &count)) != ERROR_SUCCESS)
865 ERR("MsiSummaryInfoGetPropertyCount returned %d\n", ret);
866 else
868 V_VT(pVarResult) = VT_I4;
869 V_I4(pVarResult) = count;
872 else return DISP_E_MEMBERNOTFOUND;
873 break;
875 default:
876 return DISP_E_MEMBERNOTFOUND;
879 VariantClear(&varg1);
880 VariantClear(&varg0);
882 return S_OK;
885 static HRESULT WINAPI RecordImpl_Invoke(
886 AutomationObject* This,
887 DISPID dispIdMember,
888 REFIID riid,
889 LCID lcid,
890 WORD wFlags,
891 DISPPARAMS* pDispParams,
892 VARIANT* pVarResult,
893 EXCEPINFO* pExcepInfo,
894 UINT* puArgErr)
896 WCHAR *szString;
897 DWORD dwLen;
898 UINT ret;
899 VARIANTARG varg0, varg1;
900 HRESULT hr;
902 VariantInit(&varg0);
903 VariantInit(&varg1);
905 switch (dispIdMember)
907 case DISPID_RECORD_FIELDCOUNT:
908 if (wFlags & DISPATCH_PROPERTYGET) {
909 V_VT(pVarResult) = VT_I4;
910 V_I4(pVarResult) = MsiRecordGetFieldCount(This->msiHandle);
912 else return DISP_E_MEMBERNOTFOUND;
913 break;
915 case DISPID_RECORD_STRINGDATA:
916 if (wFlags & DISPATCH_PROPERTYGET) {
917 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
918 if (FAILED(hr)) return hr;
919 V_VT(pVarResult) = VT_BSTR;
920 V_BSTR(pVarResult) = NULL;
921 if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
923 if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
924 ERR("Out of memory\n");
925 else if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
926 V_BSTR(pVarResult) = SysAllocString(szString);
927 msi_free(szString);
929 if (ret != ERROR_SUCCESS)
930 ERR("MsiRecordGetString returned %d\n", ret);
931 } else if (wFlags & DISPATCH_PROPERTYPUT) {
932 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
933 if (FAILED(hr)) return hr;
934 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BSTR, &varg1, puArgErr);
935 if (FAILED(hr)) return hr;
936 if ((ret = MsiRecordSetStringW(This->msiHandle, V_I4(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
938 VariantClear(&varg1);
939 ERR("MsiRecordSetString returned %d\n", ret);
940 return DISP_E_EXCEPTION;
943 else return DISP_E_MEMBERNOTFOUND;
944 break;
946 case DISPID_RECORD_INTEGERDATA:
947 if (wFlags & DISPATCH_PROPERTYGET) {
948 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
949 if (FAILED(hr)) return hr;
950 V_VT(pVarResult) = VT_I4;
951 V_I4(pVarResult) = MsiRecordGetInteger(This->msiHandle, V_I4(&varg0));
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, DISPID_PROPERTYPUT, VT_I4, &varg1, puArgErr);
956 if (FAILED(hr)) return hr;
957 if ((ret = MsiRecordSetInteger(This->msiHandle, V_I4(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
959 ERR("MsiRecordSetInteger returned %d\n", ret);
960 return DISP_E_EXCEPTION;
963 else return DISP_E_MEMBERNOTFOUND;
964 break;
966 default:
967 return DISP_E_MEMBERNOTFOUND;
970 VariantClear(&varg1);
971 VariantClear(&varg0);
973 return S_OK;
976 static HRESULT WINAPI ListImpl_Invoke(
977 AutomationObject* This,
978 DISPID dispIdMember,
979 REFIID riid,
980 LCID lcid,
981 WORD wFlags,
982 DISPPARAMS* pDispParams,
983 VARIANT* pVarResult,
984 EXCEPINFO* pExcepInfo,
985 UINT* puArgErr)
987 ListData *data = (ListData *)private_data(This);
988 HRESULT hr;
989 VARIANTARG varg0;
990 IUnknown *pUnk = NULL;
992 VariantInit(&varg0);
994 switch (dispIdMember)
996 case DISPID_LIST__NEWENUM:
997 if (wFlags & DISPATCH_METHOD) {
998 V_VT(pVarResult) = VT_UNKNOWN;
999 if (SUCCEEDED(hr = create_list_enumerator(NULL, (LPVOID *)&pUnk, This, 0)))
1001 IUnknown_AddRef(pUnk);
1002 V_UNKNOWN(pVarResult) = pUnk;
1004 else
1005 ERR("Failed to create IEnumVARIANT object, hresult 0x%08x\n", hr);
1007 else return DISP_E_MEMBERNOTFOUND;
1008 break;
1010 case DISPID_LIST_ITEM:
1011 if (wFlags & DISPATCH_PROPERTYGET) {
1012 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1013 if (FAILED(hr)) return hr;
1014 if (V_I4(&varg0) < 0 || V_I4(&varg0) >= data->ulCount)
1015 return DISP_E_BADINDEX;
1016 VariantCopy(pVarResult, &data->pVars[V_I4(&varg0)]);
1018 else return DISP_E_MEMBERNOTFOUND;
1019 break;
1021 case DISPID_LIST_COUNT:
1022 if (wFlags & DISPATCH_PROPERTYGET) {
1023 V_VT(pVarResult) = VT_I4;
1024 V_I4(pVarResult) = data->ulCount;
1026 else return DISP_E_MEMBERNOTFOUND;
1027 break;
1029 default:
1030 return DISP_E_MEMBERNOTFOUND;
1033 VariantClear(&varg0);
1035 return S_OK;
1038 static void WINAPI ListImpl_Free(AutomationObject *This)
1040 ListData *data = private_data(This);
1041 ULONG idx;
1043 for (idx=0; idx<data->ulCount; idx++)
1044 VariantClear(&data->pVars[idx]);
1045 HeapFree(GetProcessHeap(), 0, data->pVars);
1048 static HRESULT WINAPI ViewImpl_Invoke(
1049 AutomationObject* This,
1050 DISPID dispIdMember,
1051 REFIID riid,
1052 LCID lcid,
1053 WORD wFlags,
1054 DISPPARAMS* pDispParams,
1055 VARIANT* pVarResult,
1056 EXCEPINFO* pExcepInfo,
1057 UINT* puArgErr)
1059 MSIHANDLE msiHandle;
1060 IDispatch *pDispatch = NULL;
1061 UINT ret;
1062 VARIANTARG varg0, varg1;
1063 HRESULT hr;
1065 VariantInit(&varg0);
1066 VariantInit(&varg1);
1068 switch (dispIdMember)
1070 case DISPID_VIEW_EXECUTE:
1071 if (wFlags & DISPATCH_METHOD)
1073 hr = DispGetParam(pDispParams, 0, VT_DISPATCH, &varg0, puArgErr);
1074 if (SUCCEEDED(hr) && V_DISPATCH(&varg0) != NULL)
1075 MsiViewExecute(This->msiHandle, ((AutomationObject *)V_DISPATCH(&varg0))->msiHandle);
1076 else
1077 MsiViewExecute(This->msiHandle, 0);
1079 else return DISP_E_MEMBERNOTFOUND;
1080 break;
1082 case DISPID_VIEW_FETCH:
1083 if (wFlags & DISPATCH_METHOD)
1085 V_VT(pVarResult) = VT_DISPATCH;
1086 if ((ret = MsiViewFetch(This->msiHandle, &msiHandle)) == ERROR_SUCCESS)
1088 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Record, RecordImpl_Invoke, NULL, 0)))
1090 IDispatch_AddRef(pDispatch);
1091 V_DISPATCH(pVarResult) = pDispatch;
1093 else
1094 ERR("Failed to create Record object, hresult 0x%08x\n", hr);
1096 else if (ret == ERROR_NO_MORE_ITEMS)
1097 V_DISPATCH(pVarResult) = NULL;
1098 else
1100 ERR("MsiViewFetch returned %d\n", ret);
1101 return DISP_E_EXCEPTION;
1104 else return DISP_E_MEMBERNOTFOUND;
1105 break;
1107 case DISPID_VIEW_MODIFY:
1108 if (wFlags & DISPATCH_METHOD)
1110 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1111 if (FAILED(hr)) return hr;
1112 hr = DispGetParam(pDispParams, 1, VT_DISPATCH, &varg1, puArgErr);
1113 if (FAILED(hr)) return hr;
1114 if (!V_DISPATCH(&varg1)) return DISP_E_EXCEPTION;
1115 if ((ret = MsiViewModify(This->msiHandle, V_I4(&varg0), ((AutomationObject *)V_DISPATCH(&varg1))->msiHandle)) != ERROR_SUCCESS)
1117 VariantClear(&varg1);
1118 ERR("MsiViewModify returned %d\n", ret);
1119 return DISP_E_EXCEPTION;
1122 else return DISP_E_MEMBERNOTFOUND;
1123 break;
1125 case DISPID_VIEW_CLOSE:
1126 if (wFlags & DISPATCH_METHOD)
1128 MsiViewClose(This->msiHandle);
1130 else return DISP_E_MEMBERNOTFOUND;
1131 break;
1133 default:
1134 return DISP_E_MEMBERNOTFOUND;
1137 VariantClear(&varg1);
1138 VariantClear(&varg0);
1140 return S_OK;
1143 static HRESULT WINAPI DatabaseImpl_Invoke(
1144 AutomationObject* This,
1145 DISPID dispIdMember,
1146 REFIID riid,
1147 LCID lcid,
1148 WORD wFlags,
1149 DISPPARAMS* pDispParams,
1150 VARIANT* pVarResult,
1151 EXCEPINFO* pExcepInfo,
1152 UINT* puArgErr)
1154 MSIHANDLE msiHandle;
1155 IDispatch *pDispatch = NULL;
1156 UINT ret;
1157 VARIANTARG varg0, varg1;
1158 HRESULT hr;
1160 VariantInit(&varg0);
1161 VariantInit(&varg1);
1163 switch (dispIdMember)
1165 case DISPID_DATABASE_SUMMARYINFORMATION:
1166 if (wFlags & DISPATCH_PROPERTYGET)
1168 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1169 if (FAILED(hr))
1170 V_I4(&varg0) = 0;
1172 V_VT(pVarResult) = VT_DISPATCH;
1173 if ((ret = MsiGetSummaryInformationW(This->msiHandle, NULL, V_I4(&varg0), &msiHandle)) == ERROR_SUCCESS)
1175 hr = create_automation_object(msiHandle, NULL, (LPVOID *)&pDispatch, &DIID_SummaryInfo, SummaryInfoImpl_Invoke, NULL, 0);
1176 if (SUCCEEDED(hr))
1178 IDispatch_AddRef(pDispatch);
1179 V_DISPATCH(pVarResult) = pDispatch;
1181 else
1182 ERR("Failed to create SummaryInfo object: 0x%08x\n", hr);
1184 else
1186 ERR("MsiGetSummaryInformation returned %d\n", ret);
1187 return DISP_E_EXCEPTION;
1190 else return DISP_E_MEMBERNOTFOUND;
1191 break;
1193 case DISPID_DATABASE_OPENVIEW:
1194 if (wFlags & DISPATCH_METHOD)
1196 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1197 if (FAILED(hr)) return hr;
1198 V_VT(pVarResult) = VT_DISPATCH;
1199 if ((ret = MsiDatabaseOpenViewW(This->msiHandle, V_BSTR(&varg0), &msiHandle)) == ERROR_SUCCESS)
1201 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_View, ViewImpl_Invoke, NULL, 0)))
1203 IDispatch_AddRef(pDispatch);
1204 V_DISPATCH(pVarResult) = pDispatch;
1206 else
1207 ERR("Failed to create View object, hresult 0x%08x\n", hr);
1209 else
1211 VariantClear(&varg0);
1212 ERR("MsiDatabaseOpenView returned %d\n", ret);
1213 return DISP_E_EXCEPTION;
1216 else return DISP_E_MEMBERNOTFOUND;
1217 break;
1219 default:
1220 return DISP_E_MEMBERNOTFOUND;
1223 VariantClear(&varg1);
1224 VariantClear(&varg0);
1226 return S_OK;
1229 static HRESULT WINAPI SessionImpl_Invoke(
1230 AutomationObject* This,
1231 DISPID dispIdMember,
1232 REFIID riid,
1233 LCID lcid,
1234 WORD wFlags,
1235 DISPPARAMS* pDispParams,
1236 VARIANT* pVarResult,
1237 EXCEPINFO* pExcepInfo,
1238 UINT* puArgErr)
1240 SessionData *data = private_data(This);
1241 WCHAR *szString;
1242 DWORD dwLen;
1243 IDispatch *pDispatch = NULL;
1244 MSIHANDLE msiHandle;
1245 LANGID langId;
1246 UINT ret;
1247 INSTALLSTATE iInstalled, iAction;
1248 VARIANTARG varg0, varg1;
1249 HRESULT hr;
1251 VariantInit(&varg0);
1252 VariantInit(&varg1);
1254 switch (dispIdMember)
1256 case DISPID_SESSION_INSTALLER:
1257 if (wFlags & DISPATCH_PROPERTYGET) {
1258 V_VT(pVarResult) = VT_DISPATCH;
1259 IDispatch_AddRef(data->pInstaller);
1260 V_DISPATCH(pVarResult) = data->pInstaller;
1262 else return DISP_E_MEMBERNOTFOUND;
1263 break;
1265 case DISPID_SESSION_PROPERTY:
1266 if (wFlags & DISPATCH_PROPERTYGET) {
1267 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1268 if (FAILED(hr)) return hr;
1269 V_VT(pVarResult) = VT_BSTR;
1270 V_BSTR(pVarResult) = NULL;
1271 if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
1273 if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
1274 ERR("Out of memory\n");
1275 else if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
1276 V_BSTR(pVarResult) = SysAllocString(szString);
1277 msi_free(szString);
1279 if (ret != ERROR_SUCCESS)
1280 ERR("MsiGetProperty returned %d\n", ret);
1281 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1282 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1283 if (FAILED(hr)) return hr;
1284 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BSTR, &varg1, puArgErr);
1285 if (FAILED(hr)) {
1286 VariantClear(&varg0);
1287 return hr;
1289 if ((ret = MsiSetPropertyW(This->msiHandle, V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
1291 VariantClear(&varg0);
1292 VariantClear(&varg1);
1293 ERR("MsiSetProperty returned %d\n", ret);
1294 return DISP_E_EXCEPTION;
1297 else return DISP_E_MEMBERNOTFOUND;
1298 break;
1300 case DISPID_SESSION_LANGUAGE:
1301 if (wFlags & DISPATCH_PROPERTYGET) {
1302 langId = MsiGetLanguage(This->msiHandle);
1303 V_VT(pVarResult) = VT_I4;
1304 V_I4(pVarResult) = langId;
1306 else return DISP_E_MEMBERNOTFOUND;
1307 break;
1309 case DISPID_SESSION_MODE:
1310 if (wFlags & DISPATCH_PROPERTYGET) {
1311 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1312 if (FAILED(hr)) return hr;
1313 V_VT(pVarResult) = VT_BOOL;
1314 V_BOOL(pVarResult) = MsiGetMode(This->msiHandle, V_I4(&varg0));
1315 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1316 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1317 if (FAILED(hr)) return hr;
1318 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BOOL, &varg1, puArgErr);
1319 if (FAILED(hr)) return hr;
1320 if ((ret = MsiSetMode(This->msiHandle, V_I4(&varg0), V_BOOL(&varg1))) != ERROR_SUCCESS)
1322 ERR("MsiSetMode returned %d\n", ret);
1323 return DISP_E_EXCEPTION;
1326 else return DISP_E_MEMBERNOTFOUND;
1327 break;
1329 case DISPID_SESSION_DATABASE:
1330 if (wFlags & DISPATCH_PROPERTYGET) {
1331 V_VT(pVarResult) = VT_DISPATCH;
1332 if ((msiHandle = MsiGetActiveDatabase(This->msiHandle)))
1334 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Database, DatabaseImpl_Invoke, NULL, 0)))
1336 IDispatch_AddRef(pDispatch);
1337 V_DISPATCH(pVarResult) = pDispatch;
1339 else
1340 ERR("Failed to create Database object, hresult 0x%08x\n", hr);
1342 else
1344 ERR("MsiGetActiveDatabase failed\n");
1345 return DISP_E_EXCEPTION;
1348 else return DISP_E_MEMBERNOTFOUND;
1349 break;
1351 case DISPID_SESSION_DOACTION:
1352 if (wFlags & DISPATCH_METHOD) {
1353 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1354 if (FAILED(hr)) return hr;
1355 ret = MsiDoActionW(This->msiHandle, V_BSTR(&varg0));
1356 V_VT(pVarResult) = VT_I4;
1357 switch (ret)
1359 case ERROR_FUNCTION_NOT_CALLED:
1360 V_I4(pVarResult) = msiDoActionStatusNoAction;
1361 break;
1362 case ERROR_SUCCESS:
1363 V_I4(pVarResult) = msiDoActionStatusSuccess;
1364 break;
1365 case ERROR_INSTALL_USEREXIT:
1366 V_I4(pVarResult) = msiDoActionStatusUserExit;
1367 break;
1368 case ERROR_INSTALL_FAILURE:
1369 V_I4(pVarResult) = msiDoActionStatusFailure;
1370 break;
1371 case ERROR_INSTALL_SUSPEND:
1372 V_I4(pVarResult) = msiDoActionStatusSuspend;
1373 break;
1374 case ERROR_MORE_DATA:
1375 V_I4(pVarResult) = msiDoActionStatusFinished;
1376 break;
1377 case ERROR_INVALID_HANDLE_STATE:
1378 V_I4(pVarResult) = msiDoActionStatusWrongState;
1379 break;
1380 case ERROR_INVALID_DATA:
1381 V_I4(pVarResult) = msiDoActionStatusBadActionData;
1382 break;
1383 default:
1384 VariantClear(&varg0);
1385 FIXME("MsiDoAction returned unhandled value %d\n", ret);
1386 return DISP_E_EXCEPTION;
1389 else return DISP_E_MEMBERNOTFOUND;
1390 break;
1392 case DISPID_SESSION_EVALUATECONDITION:
1393 if (wFlags & DISPATCH_METHOD) {
1394 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1395 if (FAILED(hr)) return hr;
1396 V_VT(pVarResult) = VT_I4;
1397 V_I4(pVarResult) = MsiEvaluateConditionW(This->msiHandle, V_BSTR(&varg0));
1399 else return DISP_E_MEMBERNOTFOUND;
1400 break;
1402 case DISPID_SESSION_SETINSTALLLEVEL:
1403 if (wFlags & DISPATCH_METHOD) {
1404 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1405 if (FAILED(hr)) return hr;
1406 if ((ret = MsiSetInstallLevel(This->msiHandle, V_I4(&varg0))) != ERROR_SUCCESS)
1408 ERR("MsiSetInstallLevel returned %d\n", ret);
1409 return DISP_E_EXCEPTION;
1412 else return DISP_E_MEMBERNOTFOUND;
1413 break;
1415 case DISPID_SESSION_FEATURECURRENTSTATE:
1416 if (wFlags & DISPATCH_PROPERTYGET) {
1417 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1418 if (FAILED(hr)) return hr;
1419 V_VT(pVarResult) = VT_I4;
1420 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1421 V_I4(pVarResult) = iInstalled;
1422 else
1424 ERR("MsiGetFeatureState returned %d\n", ret);
1425 V_I4(pVarResult) = msiInstallStateUnknown;
1428 else return DISP_E_MEMBERNOTFOUND;
1429 break;
1431 case DISPID_SESSION_FEATUREREQUESTSTATE:
1432 if (wFlags & DISPATCH_PROPERTYGET) {
1433 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1434 if (FAILED(hr)) return hr;
1435 V_VT(pVarResult) = VT_I4;
1436 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1437 V_I4(pVarResult) = iAction;
1438 else
1440 ERR("MsiGetFeatureState returned %d\n", ret);
1441 V_I4(pVarResult) = msiInstallStateUnknown;
1443 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1444 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1445 if (FAILED(hr)) return hr;
1446 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_I4, &varg1, puArgErr);
1447 if (FAILED(hr)) {
1448 VariantClear(&varg0);
1449 return hr;
1451 if ((ret = MsiSetFeatureStateW(This->msiHandle, V_BSTR(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
1453 VariantClear(&varg0);
1454 ERR("MsiSetFeatureState returned %d\n", ret);
1455 return DISP_E_EXCEPTION;
1458 else return DISP_E_MEMBERNOTFOUND;
1459 break;
1461 default:
1462 return DISP_E_MEMBERNOTFOUND;
1465 VariantClear(&varg1);
1466 VariantClear(&varg0);
1468 return S_OK;
1471 /* Fill the variant pointed to by pVarResult with the value & size returned by RegQueryValueEx as dictated by the
1472 * registry value type. Used by Installer::RegistryValue. */
1473 static void variant_from_registry_value(VARIANT *pVarResult, DWORD dwType, LPBYTE lpData, DWORD dwSize)
1475 static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
1476 static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
1477 WCHAR *szString = (WCHAR *)lpData;
1478 LPWSTR szNewString = NULL;
1479 DWORD dwNewSize = 0;
1480 int idx;
1482 switch (dwType)
1484 /* Registry strings may not be null terminated so we must use SysAllocStringByteLen/Len */
1485 case REG_MULTI_SZ: /* Multi SZ change internal null characters to newlines */
1486 idx = (dwSize/sizeof(WCHAR))-1;
1487 while (idx >= 0 && !szString[idx]) idx--;
1488 for (; idx >= 0; idx--)
1489 if (!szString[idx]) szString[idx] = '\n';
1490 case REG_SZ:
1491 V_VT(pVarResult) = VT_BSTR;
1492 V_BSTR(pVarResult) = SysAllocStringByteLen((LPCSTR)szString, dwSize);
1493 break;
1495 case REG_EXPAND_SZ:
1496 if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1497 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1498 else if (!(szNewString = msi_alloc(dwNewSize)))
1499 ERR("Out of memory\n");
1500 else if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1501 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1502 else
1504 V_VT(pVarResult) = VT_BSTR;
1505 V_BSTR(pVarResult) = SysAllocStringLen(szNewString, dwNewSize);
1507 msi_free(szNewString);
1508 break;
1510 case REG_DWORD:
1511 V_VT(pVarResult) = VT_I4;
1512 V_I4(pVarResult) = *((DWORD *)lpData);
1513 break;
1515 case REG_QWORD:
1516 V_VT(pVarResult) = VT_BSTR;
1517 V_BSTR(pVarResult) = SysAllocString(szREG_); /* Weird string, don't know why native returns it */
1518 break;
1520 case REG_BINARY:
1521 V_VT(pVarResult) = VT_BSTR;
1522 V_BSTR(pVarResult) = SysAllocString(szREG_BINARY);
1523 break;
1525 case REG_NONE:
1526 V_VT(pVarResult) = VT_EMPTY;
1527 break;
1529 default:
1530 FIXME("Unhandled registry value type %d\n", dwType);
1534 static HRESULT WINAPI InstallerImpl_Invoke(
1535 AutomationObject* This,
1536 DISPID dispIdMember,
1537 REFIID riid,
1538 LCID lcid,
1539 WORD wFlags,
1540 DISPPARAMS* pDispParams,
1541 VARIANT* pVarResult,
1542 EXCEPINFO* pExcepInfo,
1543 UINT* puArgErr)
1545 MSIHANDLE msiHandle;
1546 IDispatch *pDispatch = NULL;
1547 UINT ret;
1548 VARIANTARG varg0, varg1, varg2;
1549 HRESULT hr;
1550 LPWSTR szString = NULL;
1551 DWORD dwSize = 0;
1553 VariantInit(&varg0);
1554 VariantInit(&varg1);
1555 VariantInit(&varg2);
1557 switch (dispIdMember)
1559 case DISPID_INSTALLER_CREATERECORD:
1560 if (wFlags & DISPATCH_METHOD)
1562 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1563 if (FAILED(hr)) return hr;
1564 V_VT(pVarResult) = VT_DISPATCH;
1565 if ((msiHandle = MsiCreateRecord(V_I4(&varg0))))
1567 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Record, RecordImpl_Invoke, NULL, 0)))
1569 IDispatch_AddRef(pDispatch);
1570 V_DISPATCH(pVarResult) = pDispatch;
1572 else
1573 ERR("Failed to create Record object, hresult 0x%08x\n", hr);
1575 else
1577 ERR("MsiCreateRecord failed\n");
1578 return DISP_E_EXCEPTION;
1581 else return DISP_E_MEMBERNOTFOUND;
1582 break;
1584 case DISPID_INSTALLER_OPENPACKAGE:
1585 if (wFlags & DISPATCH_METHOD)
1587 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1588 if (FAILED(hr)) return hr;
1589 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1590 if (FAILED(hr))
1592 VariantClear(&varg0);
1593 return hr;
1595 V_VT(pVarResult) = VT_DISPATCH;
1596 if ((ret = MsiOpenPackageExW(V_BSTR(&varg0), V_I4(&varg1), &msiHandle)) == ERROR_SUCCESS)
1598 if (SUCCEEDED(hr = create_session(msiHandle, (IDispatch *)This, &pDispatch)))
1600 IDispatch_AddRef(pDispatch);
1601 V_DISPATCH(pVarResult) = pDispatch;
1603 else
1604 ERR("Failed to create Session object, hresult 0x%08x\n", hr);
1606 else
1608 VariantClear(&varg0);
1609 ERR("MsiOpenPackageEx returned %d\n", ret);
1610 return DISP_E_EXCEPTION;
1613 else return DISP_E_MEMBERNOTFOUND;
1614 break;
1616 case DISPID_INSTALLER_OPENDATABASE:
1617 if (wFlags & DISPATCH_METHOD)
1619 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1620 if (FAILED(hr)) return hr;
1622 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1623 if (FAILED(hr))
1625 VariantClear(&varg0);
1626 return hr;
1629 V_VT(pVarResult) = VT_DISPATCH;
1630 if ((ret = MsiOpenDatabaseW(V_BSTR(&varg0), V_BSTR(&varg1), &msiHandle)) == ERROR_SUCCESS)
1632 hr = create_automation_object(msiHandle, NULL, (LPVOID *)&pDispatch,
1633 &DIID_Database, DatabaseImpl_Invoke, NULL, 0);
1634 if (SUCCEEDED(hr))
1636 IDispatch_AddRef(pDispatch);
1637 V_DISPATCH(pVarResult) = pDispatch;
1639 else
1640 ERR("Failed to create Database object: 0x%08x\n", hr);
1642 else
1644 VariantClear(&varg0);
1645 VariantClear(&varg1);
1646 ERR("MsiOpenDatabase returned %d\n", ret);
1647 return DISP_E_EXCEPTION;
1650 else return DISP_E_MEMBERNOTFOUND;
1651 break;
1653 case DISPID_INSTALLER_INSTALLPRODUCT:
1654 if (wFlags & DISPATCH_METHOD)
1656 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1657 if (FAILED(hr)) return hr;
1658 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1659 if (FAILED(hr))
1661 VariantClear(&varg0);
1662 return hr;
1664 if ((ret = MsiInstallProductW(V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
1666 VariantClear(&varg1);
1667 VariantClear(&varg0);
1668 ERR("MsiInstallProduct returned %d\n", ret);
1669 return DISP_E_EXCEPTION;
1672 else return DISP_E_MEMBERNOTFOUND;
1673 break;
1675 case DISPID_INSTALLER_REGISTRYVALUE:
1676 if (wFlags & DISPATCH_METHOD) {
1677 HKEY hkey;
1678 DWORD dwType;
1679 UINT posValue = 2; /* Save valuePos so we can save puArgErr if we are unable to do our type conversions */
1681 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1682 if (FAILED(hr)) return hr;
1683 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1684 if (FAILED(hr)) return hr;
1685 hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg2);
1686 if (FAILED(hr))
1688 VariantClear(&varg1);
1689 return hr;
1691 ret = RegOpenKeyW((HKEY)V_I4(&varg0), V_BSTR(&varg1), &hkey);
1693 /* Third parameter can be VT_EMPTY, VT_I4, or VT_BSTR */
1694 switch (V_VT(&varg2))
1696 case VT_EMPTY: /* Return VT_BOOL as to whether or not registry key exists */
1697 V_VT(pVarResult) = VT_BOOL;
1698 V_BOOL(pVarResult) = (ret == ERROR_SUCCESS);
1699 break;
1701 case VT_BSTR: /* Return value of specified key if it exists */
1702 if (ret == ERROR_SUCCESS &&
1703 (ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL, NULL, NULL, &dwSize)) == ERROR_SUCCESS)
1705 if (!(szString = msi_alloc(dwSize)))
1706 ERR("Out of memory\n");
1707 else if ((ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL, &dwType, (LPBYTE)szString, &dwSize)) == ERROR_SUCCESS)
1708 variant_from_registry_value(pVarResult, dwType, (LPBYTE)szString, dwSize);
1711 if (ret != ERROR_SUCCESS)
1713 msi_free(szString);
1714 VariantClear(&varg2);
1715 VariantClear(&varg1);
1716 return DISP_E_BADINDEX;
1718 break;
1720 default: /* Try to make it into VT_I4, can use VariantChangeType for this */
1721 hr = VariantChangeType(&varg2, &varg2, 0, VT_I4);
1722 if (SUCCEEDED(hr) && ret != ERROR_SUCCESS) hr = DISP_E_BADINDEX; /* Conversion fine, but couldn't find key */
1723 if (FAILED(hr))
1725 if (hr == DISP_E_TYPEMISMATCH) *puArgErr = posValue;
1726 VariantClear(&varg2); /* Unknown type, so let's clear it */
1727 VariantClear(&varg1);
1728 return hr;
1731 /* Retrieve class name or maximum value name or subkey name size */
1732 if (!V_I4(&varg2))
1733 ret = RegQueryInfoKeyW(hkey, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1734 else if (V_I4(&varg2) > 0)
1735 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL);
1736 else /* V_I4(&varg2) < 0 */
1737 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
1739 if (ret == ERROR_SUCCESS)
1741 if (!(szString = msi_alloc(++dwSize * sizeof(WCHAR))))
1742 ERR("Out of memory\n");
1743 else if (!V_I4(&varg2))
1744 ret = RegQueryInfoKeyW(hkey, szString, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1745 else if (V_I4(&varg2) > 0)
1746 ret = RegEnumValueW(hkey, V_I4(&varg2)-1, szString, &dwSize, 0, 0, NULL, NULL);
1747 else /* V_I4(&varg2) < 0 */
1748 ret = RegEnumKeyW(hkey, -1 - V_I4(&varg2), szString, dwSize);
1750 if (szString && ret == ERROR_SUCCESS)
1752 V_VT(pVarResult) = VT_BSTR;
1753 V_BSTR(pVarResult) = SysAllocString(szString);
1758 msi_free(szString);
1759 RegCloseKey(hkey);
1761 else return DISP_E_MEMBERNOTFOUND;
1762 break;
1764 case DISPID_INSTALLER_PRODUCTSTATE:
1765 if (wFlags & DISPATCH_PROPERTYGET) {
1766 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1767 if (FAILED(hr)) return hr;
1768 V_VT(pVarResult) = VT_I4;
1769 V_I4(pVarResult) = MsiQueryProductStateW(V_BSTR(&varg0));
1771 else return DISP_E_MEMBERNOTFOUND;
1772 break;
1774 case DISPID_INSTALLER_PRODUCTINFO:
1775 if (wFlags & DISPATCH_PROPERTYGET) {
1776 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1777 if (FAILED(hr)) return hr;
1778 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1779 if (FAILED(hr))
1781 VariantClear(&varg0);
1782 return hr;
1784 V_VT(pVarResult) = VT_BSTR;
1785 V_BSTR(pVarResult) = NULL;
1786 if ((ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), NULL, &dwSize)) == ERROR_SUCCESS)
1788 if (!(szString = msi_alloc((++dwSize)*sizeof(WCHAR))))
1789 ERR("Out of memory\n");
1790 else if ((ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), szString, &dwSize)) == ERROR_SUCCESS)
1791 V_BSTR(pVarResult) = SysAllocString(szString);
1792 msi_free(szString);
1794 if (ret != ERROR_SUCCESS)
1796 ERR("MsiGetProductInfo returned %d\n", ret);
1797 VariantClear(&varg1);
1798 VariantClear(&varg0);
1799 return DISP_E_EXCEPTION;
1802 else return DISP_E_MEMBERNOTFOUND;
1803 break;
1805 case DISPID_INSTALLER_PRODUCTS:
1806 if (wFlags & DISPATCH_PROPERTYGET)
1808 ListData *ldata = NULL;
1809 ULONG idx = 0;
1810 WCHAR szProductBuf[GUID_SIZE];
1812 /* Find number of products */
1813 while ((ret = MsiEnumProductsW(idx, szProductBuf)) == ERROR_SUCCESS) idx++;
1814 if (ret != ERROR_NO_MORE_ITEMS)
1816 ERR("MsiEnumProducts returned %d\n", ret);
1817 return DISP_E_EXCEPTION;
1820 V_VT(pVarResult) = VT_DISPATCH;
1821 if (SUCCEEDED(hr = create_automation_object(0, NULL, (LPVOID*)&pDispatch, &DIID_StringList, ListImpl_Invoke, ListImpl_Free, sizeof(ListData))))
1823 IDispatch_AddRef(pDispatch);
1824 V_DISPATCH(pVarResult) = pDispatch;
1826 /* Save product strings */
1827 ldata = (ListData *)private_data((AutomationObject *)pDispatch);
1828 if (!(ldata->pVars = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(VARIANT)*idx)))
1829 ERR("Out of memory\n");
1830 else
1832 ldata->ulCount = idx;
1833 for (idx = 0; idx < ldata->ulCount; idx++)
1835 ret = MsiEnumProductsW(idx, szProductBuf);
1836 VariantInit(&ldata->pVars[idx]);
1837 V_VT(&ldata->pVars[idx]) = VT_BSTR;
1838 V_BSTR(&ldata->pVars[idx]) = SysAllocString(szProductBuf);
1842 else
1843 ERR("Failed to create StringList object, hresult 0x%08x\n", hr);
1845 else return DISP_E_MEMBERNOTFOUND;
1846 break;
1848 case DISPID_INSTALLER_RELATEDPRODUCTS:
1849 if (wFlags & DISPATCH_PROPERTYGET)
1851 ListData *ldata = NULL;
1852 ULONG idx = 0;
1853 WCHAR szProductBuf[GUID_SIZE];
1855 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1856 if (FAILED(hr)) return hr;
1858 /* Find number of related products */
1859 while ((ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, szProductBuf)) == ERROR_SUCCESS) idx++;
1860 if (ret != ERROR_NO_MORE_ITEMS)
1862 VariantClear(&varg0);
1863 ERR("MsiEnumRelatedProducts returned %d\n", ret);
1864 return DISP_E_EXCEPTION;
1867 V_VT(pVarResult) = VT_DISPATCH;
1868 if (SUCCEEDED(hr = create_automation_object(0, NULL, (LPVOID*)&pDispatch, &DIID_StringList, ListImpl_Invoke, ListImpl_Free, sizeof(ListData))))
1870 IDispatch_AddRef(pDispatch);
1871 V_DISPATCH(pVarResult) = pDispatch;
1873 /* Save product strings */
1874 ldata = (ListData *)private_data((AutomationObject *)pDispatch);
1875 if (!(ldata->pVars = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(VARIANT)*idx)))
1876 ERR("Out of memory\n");
1877 else
1879 ldata->ulCount = idx;
1880 for (idx = 0; idx < ldata->ulCount; idx++)
1882 ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, szProductBuf);
1883 VariantInit(&ldata->pVars[idx]);
1884 V_VT(&ldata->pVars[idx]) = VT_BSTR;
1885 V_BSTR(&ldata->pVars[idx]) = SysAllocString(szProductBuf);
1889 else
1890 ERR("Failed to create StringList object, hresult 0x%08x\n", hr);
1892 else return DISP_E_MEMBERNOTFOUND;
1893 break;
1895 default:
1896 return DISP_E_MEMBERNOTFOUND;
1899 VariantClear(&varg2);
1900 VariantClear(&varg1);
1901 VariantClear(&varg0);
1903 return S_OK;
1906 /* Wrapper around create_automation_object to create an installer object. */
1907 HRESULT create_msiserver(IUnknown *pOuter, LPVOID *ppObj)
1909 return create_automation_object(0, pOuter, ppObj, &DIID_Installer, InstallerImpl_Invoke, NULL, 0);
1912 /* Wrapper around create_automation_object to create a session object. */
1913 HRESULT create_session(MSIHANDLE msiHandle, IDispatch *pInstaller, IDispatch **pDispatch)
1915 HRESULT hr = create_automation_object(msiHandle, NULL, (LPVOID)pDispatch, &DIID_Session, SessionImpl_Invoke, NULL, sizeof(SessionData));
1916 if (SUCCEEDED(hr) && pDispatch && *pDispatch)
1917 ((SessionData *)private_data((AutomationObject *)*pDispatch))->pInstaller = pInstaller;
1918 return hr;