fonts: Add a Tahoma replacement. Almost entirely based on a patch by Larry Snyder.
[wine] / dlls / msi / automation.c
1 /*
2  * Implementation of OLE Automation for Microsoft Installer (msi.dll)
3  *
4  * Copyright 2007 Misha Koshelev
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #define COBJMACROS
22
23 #include <stdarg.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winerror.h"
27 #include "winuser.h"
28 #include "winreg.h"
29 #include "msidefs.h"
30 #include "msipriv.h"
31 #include "activscp.h"
32 #include "oleauto.h"
33 #include "wine/debug.h"
34 #include "wine/unicode.h"
35
36 #include "msiserver.h"
37 #include "msiserver_dispids.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(msi);
40
41 /*
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.
44  */
45
46 typedef interface AutomationObject AutomationObject;
47
48 interface AutomationObject {
49     /*
50      * VTables - We provide IDispatch, IProvideClassInfo, IProvideClassInfo2, IProvideMultipleClassInfo
51      */
52     const IDispatchVtbl *lpVtbl;
53     const IProvideMultipleClassInfoVtbl *lpvtblIProvideMultipleClassInfo;
54
55     /* Object reference count */
56     LONG ref;
57
58     /* Clsid for this class and it's appropriate ITypeInfo object */
59     LPCLSID clsid;
60     ITypeInfo *iTypeInfo;
61
62     /* The MSI handle of the current object */
63     MSIHANDLE msiHandle;
64
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);
76
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);
80 };
81
82 /*
83  * ListEnumerator - IEnumVARIANT implementation for MSI automation lists.
84  */
85
86 typedef interface ListEnumerator ListEnumerator;
87
88 interface ListEnumerator {
89     /* VTables */
90     const IEnumVARIANTVtbl *lpVtbl;
91
92     /* Object reference count */
93     LONG ref;
94
95     /* Current position and pointer to AutomationObject that stores actual data */
96     ULONG ulPos;
97     AutomationObject *pObj;
98 };
99
100 /*
101  * Structures for additional data required by specific automation objects
102  */
103
104 typedef struct {
105     ULONG ulCount;
106     VARIANT *pVars;
107 } ListData;
108
109 typedef struct {
110     /* The parent Installer object */
111     IDispatch *pInstaller;
112 } SessionData;
113
114 /* VTables */
115 static const struct IDispatchVtbl AutomationObject_Vtbl;
116 static const struct IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl;
117 static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl;
118
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)
121 {
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'};
126
127     TRACE("(%p)->(%s,%d)\n", iface, debugstr_guid(clsid), lcid);
128
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;
136         }
137     }
138
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;
145     }
146     *pptinfo = pInfo;
147     return S_OK;
148 }
149
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)
157 {
158     AutomationObject *object;
159     HRESULT hr;
160
161     TRACE("(%ld,%p,%p,%s,%p,%p,%ld)\n", (unsigned long)msiHandle, pUnkOuter, ppObj, debugstr_guid(clsid), funcInvoke, funcFree, sizetPrivateData);
162
163     if( pUnkOuter )
164         return CLASS_E_NOAGGREGATION;
165
166     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AutomationObject)+sizetPrivateData);
167
168     /* Set all the VTable references */
169     object->lpVtbl = &AutomationObject_Vtbl;
170     object->lpvtblIProvideMultipleClassInfo = &AutomationObject_IProvideMultipleClassInfo_Vtbl;
171     object->ref = 1;
172
173     /* Store data that was passed */
174     object->msiHandle = msiHandle;
175     object->clsid = (LPCLSID)clsid;
176     object->funcInvoke = funcInvoke;
177     object->funcFree = funcFree;
178
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;
185     }
186
187     *ppObj = object;
188
189     return S_OK;
190 }
191
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)
194 {
195     ListEnumerator *object;
196
197     TRACE("(%p,%p,%p,%uld)\n", pUnkOuter, ppObj, pObj, ulPos);
198
199     if( pUnkOuter )
200         return CLASS_E_NOAGGREGATION;
201
202     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ListEnumerator));
203
204     /* Set all the VTable references */
205     object->lpVtbl = &ListEnumerator_Vtbl;
206     object->ref = 1;
207
208     /* Store data that was passed */
209     object->ulPos = ulPos;
210     object->pObj = pObj;
211     if (pObj) IDispatch_AddRef((IDispatch *)pObj);
212
213     *ppObj = object;
214     return S_OK;
215 }
216
217 /* Macros to get pointer to AutomationObject from the other VTables. */
218 static inline AutomationObject *obj_from_IProvideMultipleClassInfo( IProvideMultipleClassInfo *iface )
219 {
220     return (AutomationObject *)((char*)iface - FIELD_OFFSET(AutomationObject, lpvtblIProvideMultipleClassInfo));
221 }
222
223 /* Macro to get pointer to private object data */
224 static inline void *private_data( AutomationObject *This )
225 {
226     return This + 1;
227 }
228
229 /*
230  * AutomationObject methods
231  */
232
233 /*** IUnknown methods ***/
234 static HRESULT WINAPI AutomationObject_QueryInterface(IDispatch* iface, REFIID riid, void** ppvObject)
235 {
236     AutomationObject *This = (AutomationObject *)iface;
237
238     TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
239
240     if (ppvObject == NULL)
241       return E_INVALIDARG;
242
243     *ppvObject = 0;
244
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
252     {
253         TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid));
254         return E_NOINTERFACE;
255     }
256
257     /*
258      * Query Interface always increases the reference count by one when it is
259      * successful
260      */
261     IClassFactory_AddRef(iface);
262
263     return S_OK;
264 }
265
266 static ULONG WINAPI AutomationObject_AddRef(IDispatch* iface)
267 {
268     AutomationObject *This = (AutomationObject *)iface;
269
270     TRACE("(%p/%p)\n", iface, This);
271
272     return InterlockedIncrement(&This->ref);
273 }
274
275 static ULONG WINAPI AutomationObject_Release(IDispatch* iface)
276 {
277     AutomationObject *This = (AutomationObject *)iface;
278     ULONG ref = InterlockedDecrement(&This->ref);
279
280     TRACE("(%p/%p)\n", iface, This);
281
282     if (!ref)
283     {
284         if (This->funcFree) This->funcFree(This);
285         MsiCloseHandle(This->msiHandle);
286         HeapFree(GetProcessHeap(), 0, This);
287     }
288
289     return ref;
290 }
291
292 /*** IDispatch methods ***/
293 static HRESULT WINAPI AutomationObject_GetTypeInfoCount(
294         IDispatch* iface,
295         UINT* pctinfo)
296 {
297     AutomationObject *This = (AutomationObject *)iface;
298
299     TRACE("(%p/%p)->(%p)\n", iface, This, pctinfo);
300     *pctinfo = 1;
301     return S_OK;
302 }
303
304 static HRESULT WINAPI AutomationObject_GetTypeInfo(
305         IDispatch* iface,
306         UINT iTInfo,
307         LCID lcid,
308         ITypeInfo** ppTInfo)
309 {
310     AutomationObject *This = (AutomationObject *)iface;
311     TRACE("(%p/%p)->(%d,%d,%p)\n", iface, This, iTInfo, lcid, ppTInfo);
312
313     ITypeInfo_AddRef(This->iTypeInfo);
314     *ppTInfo = This->iTypeInfo;
315     return S_OK;
316 }
317
318 static HRESULT WINAPI AutomationObject_GetIDsOfNames(
319         IDispatch* iface,
320         REFIID riid,
321         LPOLESTR* rgszNames,
322         UINT cNames,
323         LCID lcid,
324         DISPID* rgDispId)
325 {
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);
329
330     if (!IsEqualGUID(riid, &IID_NULL)) return E_INVALIDARG;
331     hr = ITypeInfo_GetIDsOfNames(This->iTypeInfo, rgszNames, cNames, rgDispId);
332     if (hr == DISP_E_UNKNOWNNAME)
333     {
334         int idx;
335         for (idx=0; idx<cNames; idx++)
336         {
337             if (rgDispId[idx] == DISPID_UNKNOWN)
338                 FIXME("Unknown member %s, clsid %s\n", debugstr_w(rgszNames[idx]), debugstr_guid(This->clsid));
339         }
340     }
341     return hr;
342 }
343
344 /* Maximum number of allowed function parameters+1 */
345 #define MAX_FUNC_PARAMS 20
346
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)
358 {
359     AutomationObject *This = (AutomationObject *)iface;
360     HRESULT hr;
361     unsigned int uArgErr;
362     VARIANT varResultDummy;
363     BSTR bstrName = NULL;
364
365     TRACE("(%p/%p)->(%d,%p,%d,%d,%p,%p,%p,%p)\n", iface, This, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
366
367     if (!IsEqualIID(riid, &IID_NULL))
368     {
369         ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
370         return DISP_E_UNKNOWNNAME;
371     }
372
373     if (wFlags & DISPATCH_PROPERTYGET && !pVarResult)
374     {
375         ERR("NULL pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
376         return DISP_E_PARAMNOTOPTIONAL;
377     }
378
379     /* This simplifies our individual object invocation functions */
380     if (puArgErr == NULL) puArgErr = &uArgErr;
381     if (pVarResult == NULL) pVarResult = &varResultDummy;
382
383     /* Assume return type is void unless determined otherwise */
384     VariantInit(pVarResult);
385
386     /* If we are tracing, we want to see the name of the member we are invoking */
387     if (TRACE_ON(msi))
388     {
389         ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL);
390         TRACE("Method %d, %s\n", dispIdMember, debugstr_w(bstrName));
391     }
392
393     hr = This->funcInvoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
394
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));
398     }
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;
408
409         if (FAILED(ITypeInfo_GetNames(This->iTypeInfo, dispIdMember, bstrParamNames,
410                                       MAX_FUNC_PARAMS, &namesNo)))
411         {
412             TRACE("Failed to retrieve names for dispIdMember %d\n", dispIdMember);
413         }
414         else
415         {
416             memset(szExceptionDescription, 0, sizeof(szExceptionDescription));
417             for (i=0; i<namesNo; i++)
418             {
419                 if (bFirst) bFirst = FALSE;
420                 else {
421                     lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], szComma);
422                 }
423                 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], bstrParamNames[i]);
424                 SysFreeString(bstrParamNames[i]);
425             }
426
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;
432         }
433     }
434
435     /* Make sure we free the return variant if it is our dummy variant */
436     if (pVarResult == &varResultDummy) VariantClear(pVarResult);
437
438     /* Free function name if we retrieved it */
439     if (bstrName) SysFreeString(bstrName);
440
441     TRACE("Returning 0x%08x, %s\n", hr, SUCCEEDED(hr) ? "ok" : "not ok");
442
443     return hr;
444 }
445
446 static const struct IDispatchVtbl AutomationObject_Vtbl =
447 {
448     AutomationObject_QueryInterface,
449     AutomationObject_AddRef,
450     AutomationObject_Release,
451     AutomationObject_GetTypeInfoCount,
452     AutomationObject_GetTypeInfo,
453     AutomationObject_GetIDsOfNames,
454     AutomationObject_Invoke
455 };
456
457 /*
458  * IProvideMultipleClassInfo methods
459  */
460
461 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_QueryInterface(
462   IProvideMultipleClassInfo* iface,
463   REFIID     riid,
464   VOID**     ppvoid)
465 {
466     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
467     return AutomationObject_QueryInterface((IDispatch *)This, riid, ppvoid);
468 }
469
470 static ULONG WINAPI AutomationObject_IProvideMultipleClassInfo_AddRef(IProvideMultipleClassInfo* iface)
471 {
472     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
473     return AutomationObject_AddRef((IDispatch *)This);
474 }
475
476 static ULONG WINAPI AutomationObject_IProvideMultipleClassInfo_Release(IProvideMultipleClassInfo* iface)
477 {
478     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
479     return AutomationObject_Release((IDispatch *)This);
480 }
481
482 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_GetClassInfo(IProvideMultipleClassInfo* iface, ITypeInfo** ppTI)
483 {
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);
487 }
488
489 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_GetGUID(IProvideMultipleClassInfo* iface, DWORD dwGuidKind, GUID* pGUID)
490 {
491     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
492     TRACE("(%p/%p)->(%d,%s)\n", iface, This, dwGuidKind, debugstr_guid(pGUID));
493
494     if (dwGuidKind != GUIDKIND_DEFAULT_SOURCE_DISP_IID)
495         return E_INVALIDARG;
496     else {
497         *pGUID = *This->clsid;
498         return S_OK;
499     }
500 }
501
502 static HRESULT WINAPI AutomationObject_GetMultiTypeInfoCount(IProvideMultipleClassInfo* iface, ULONG* pcti)
503 {
504     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
505
506     TRACE("(%p/%p)->(%p)\n", iface, This, pcti);
507     *pcti = 1;
508     return S_OK;
509 }
510
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)
519 {
520     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
521
522     TRACE("(%p/%p)->(%d,%d,%p,%p,%p,%p,%p)\n", iface, This, iti, dwFlags, pptiCoClass, pdwTIFlags, pcdispidReserved, piidPrimary, piidSource);
523
524     if (iti != 0)
525         return E_INVALIDARG;
526
527     if (dwFlags & MULTICLASSINFO_GETTYPEINFO)
528         load_type_info((IDispatch *)This, pptiCoClass, This->clsid, 0);
529
530     if (dwFlags & MULTICLASSINFO_GETNUMRESERVEDDISPIDS)
531     {
532         *pdwTIFlags = 0;
533         *pcdispidReserved = 0;
534     }
535
536     if (dwFlags & MULTICLASSINFO_GETIIDPRIMARY){
537         *piidPrimary = *This->clsid;
538     }
539
540     if (dwFlags & MULTICLASSINFO_GETIIDSOURCE){
541         *piidSource = *This->clsid;
542     }
543
544     return S_OK;
545 }
546
547 static const IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl =
548 {
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
556 };
557
558 /*
559  * ListEnumerator methods
560  */
561
562 /*** IUnknown methods ***/
563 static HRESULT WINAPI ListEnumerator_QueryInterface(IEnumVARIANT* iface, REFIID riid, void** ppvObject)
564 {
565     ListEnumerator *This = (ListEnumerator *)iface;
566
567     TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
568
569     if (ppvObject == NULL)
570       return E_INVALIDARG;
571
572     *ppvObject = 0;
573
574     if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IEnumVARIANT))
575         *ppvObject = This;
576     else
577     {
578         TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid));
579         return E_NOINTERFACE;
580     }
581
582     IClassFactory_AddRef(iface);
583     return S_OK;
584 }
585
586 static ULONG WINAPI ListEnumerator_AddRef(IEnumVARIANT* iface)
587 {
588     ListEnumerator *This = (ListEnumerator *)iface;
589
590     TRACE("(%p/%p)\n", iface, This);
591
592     return InterlockedIncrement(&This->ref);
593 }
594
595 static ULONG WINAPI ListEnumerator_Release(IEnumVARIANT* iface)
596 {
597     ListEnumerator *This = (ListEnumerator *)iface;
598     ULONG ref = InterlockedDecrement(&This->ref);
599
600     TRACE("(%p/%p)\n", iface, This);
601
602     if (!ref)
603     {
604         if (This->pObj) IDispatch_Release((IDispatch *)This->pObj);
605         HeapFree(GetProcessHeap(), 0, This);
606     }
607
608     return ref;
609 }
610
611 /* IEnumVARIANT methods */
612
613 static HRESULT WINAPI ListEnumerator_Next(IEnumVARIANT* iface, ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched)
614 {
615     ListEnumerator *This = (ListEnumerator *)iface;
616     ListData *data = (ListData *)private_data(This->pObj);
617     ULONG idx, local;
618
619     TRACE("(%p,%uld,%p,%p)\n", iface, celt, rgVar, pCeltFetched);
620
621     if (pCeltFetched != NULL)
622         *pCeltFetched = 0;
623
624     if (rgVar == NULL)
625         return S_FALSE;
626
627     for (local = 0; local < celt; local++)
628         VariantInit(&rgVar[local]);
629
630     for (idx = This->ulPos, local = 0; idx < data->ulCount && local < celt; idx++, local++)
631         VariantCopy(&rgVar[local], &data->pVars[idx]);
632
633     if (pCeltFetched != NULL)
634         *pCeltFetched = local;
635     This->ulPos = idx;
636
637     return (local < celt) ? S_FALSE : S_OK;
638 }
639
640 static HRESULT WINAPI ListEnumerator_Skip(IEnumVARIANT* iface, ULONG celt)
641 {
642     ListEnumerator *This = (ListEnumerator *)iface;
643     ListData *data = (ListData *)private_data(This->pObj);
644
645     TRACE("(%p,%uld)\n", iface, celt);
646
647     This->ulPos += celt;
648     if (This->ulPos >= data->ulCount)
649     {
650         This->ulPos = data->ulCount;
651         return S_FALSE;
652     }
653     return S_OK;
654 }
655
656 static HRESULT WINAPI ListEnumerator_Reset(IEnumVARIANT* iface)
657 {
658     ListEnumerator *This = (ListEnumerator *)iface;
659
660     TRACE("(%p)\n", iface);
661
662     This->ulPos = 0;
663     return S_OK;
664 }
665
666 static HRESULT WINAPI ListEnumerator_Clone(IEnumVARIANT* iface, IEnumVARIANT **ppEnum)
667 {
668     ListEnumerator *This = (ListEnumerator *)iface;
669     HRESULT hr;
670
671     TRACE("(%p,%p)\n", iface, ppEnum);
672
673     if (ppEnum == NULL)
674         return S_FALSE;
675
676     *ppEnum = NULL;
677     hr = create_list_enumerator(NULL, (LPVOID *)ppEnum, This->pObj, 0);
678     if (FAILED(hr))
679     {
680         if (*ppEnum)
681             IUnknown_Release(*ppEnum);
682         return hr;
683     }
684
685     IUnknown_AddRef(*ppEnum);
686     return S_OK;
687 }
688
689 static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl =
690 {
691     ListEnumerator_QueryInterface,
692     ListEnumerator_AddRef,
693     ListEnumerator_Release,
694     ListEnumerator_Next,
695     ListEnumerator_Skip,
696     ListEnumerator_Reset,
697     ListEnumerator_Clone
698 };
699
700 /*
701  * Individual Object Invocation Functions
702  */
703
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 */
711 {
712     /* position is counted backwards */
713     UINT pos;
714
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;
724
725       if (pos==pdispparams->cNamedArgs)
726         return DISP_E_PARAMNOTFOUND;
727     }
728     *position = pos;
729     return VariantCopyInd(pvarResult,
730                         &pdispparams->rgvarg[pos]);
731 }
732
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)
743 {
744     UINT ret;
745     VARIANTARG varg0, varg1;
746     FILETIME ft, ftlocal;
747     SYSTEMTIME st;
748     HRESULT hr;
749
750     VariantInit(&varg0);
751     VariantInit(&varg1);
752
753     switch (dispIdMember)
754     {
755         case DISPID_SUMMARYINFO_PROPERTY:
756             if (wFlags & DISPATCH_PROPERTYGET)
757             {
758                 UINT type;
759                 INT value;
760                 DWORD size = 0;
761                 DATE date;
762                 LPWSTR str;
763
764                 static WCHAR szEmpty[] = {0};
765
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)
772                 {
773                     ERR("MsiSummaryInfoGetProperty returned %d\n", ret);
774                     return DISP_E_EXCEPTION;
775                 }
776
777                 switch (type)
778                 {
779                     case VT_EMPTY:
780                         break;
781
782                     case VT_I2:
783                     case VT_I4:
784                         V_VT(pVarResult) = VT_I4;
785                         V_I4(pVarResult) = value;
786                         break;
787
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
795                         {
796                             V_VT(pVarResult) = VT_BSTR;
797                             V_BSTR(pVarResult) = SysAllocString(str);
798                         }
799                         msi_free(str);
800                         break;
801
802                     case VT_FILETIME:
803                         FileTimeToLocalFileTime(&ft, &ftlocal);
804                         FileTimeToSystemTime(&ftlocal, &st);
805                         SystemTimeToVariantTime(&st, &date);
806
807                         V_VT(pVarResult) = VT_DATE;
808                         V_DATE(pVarResult) = date;
809                         break;
810
811                     default:
812                         ERR("Unhandled variant type %d\n", type);
813                 }
814             }
815             else if (wFlags & DISPATCH_PROPERTYPUT)
816             {
817                 UINT posValue = DISPID_PROPERTYPUT;
818
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))
823                 {
824                     *puArgErr = posValue;
825                     return hr;
826                 }
827
828                 switch (V_VT(&varg1))
829                 {
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;
834
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;
841
842                     case VT_BSTR:
843                         ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), VT_LPSTR, 0, NULL, V_BSTR(&varg1));
844                         break;
845
846                     default:
847                         FIXME("Unhandled variant type %d\n", V_VT(&varg1));
848                         VariantClear(&varg1);
849                         return DISP_E_EXCEPTION;
850                 }
851
852                 if (ret != ERROR_SUCCESS)
853                 {
854                     ERR("MsiSummaryInfoSetPropertyW returned %d\n", ret);
855                     return DISP_E_EXCEPTION;
856                 }
857             }
858             else return DISP_E_MEMBERNOTFOUND;
859             break;
860
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
867                 {
868                     V_VT(pVarResult) = VT_I4;
869                     V_I4(pVarResult) = count;
870                 }
871             }
872             else return DISP_E_MEMBERNOTFOUND;
873             break;
874
875         default:
876             return DISP_E_MEMBERNOTFOUND;
877     }
878
879     VariantClear(&varg1);
880     VariantClear(&varg0);
881
882     return S_OK;
883 }
884
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)
895 {
896     WCHAR *szString;
897     DWORD dwLen;
898     UINT ret;
899     VARIANTARG varg0, varg1;
900     HRESULT hr;
901
902     VariantInit(&varg0);
903     VariantInit(&varg1);
904
905     switch (dispIdMember)
906     {
907         case DISPID_RECORD_FIELDCOUNT:
908             if (wFlags & DISPATCH_PROPERTYGET) {
909                 V_VT(pVarResult) = VT_I4;
910                 V_I4(pVarResult) = MsiRecordGetFieldCount(This->msiHandle);
911             }
912             else return DISP_E_MEMBERNOTFOUND;
913             break;
914
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)
922                 {
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);
928                 }
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)
937                 {
938                     VariantClear(&varg1);
939                     ERR("MsiRecordSetString returned %d\n", ret);
940                     return DISP_E_EXCEPTION;
941                 }
942             }
943             else return DISP_E_MEMBERNOTFOUND;
944             break;
945
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)
958                 {
959                     ERR("MsiRecordSetInteger returned %d\n", ret);
960                     return DISP_E_EXCEPTION;
961                 }
962             }
963             else return DISP_E_MEMBERNOTFOUND;
964             break;
965
966          default:
967             return DISP_E_MEMBERNOTFOUND;
968     }
969
970     VariantClear(&varg1);
971     VariantClear(&varg0);
972
973     return S_OK;
974 }
975
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)
986 {
987     ListData *data = (ListData *)private_data(This);
988     HRESULT hr;
989     VARIANTARG varg0;
990     IUnknown *pUnk = NULL;
991
992     VariantInit(&varg0);
993
994     switch (dispIdMember)
995     {
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)))
1000                  {
1001                      IUnknown_AddRef(pUnk);
1002                      V_UNKNOWN(pVarResult) = pUnk;
1003                  }
1004                  else
1005                      ERR("Failed to create IEnumVARIANT object, hresult 0x%08x\n", hr);
1006              }
1007              else return DISP_E_MEMBERNOTFOUND;
1008              break;
1009
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)]);
1017             }
1018             else return DISP_E_MEMBERNOTFOUND;
1019             break;
1020
1021          case DISPID_LIST_COUNT:
1022             if (wFlags & DISPATCH_PROPERTYGET) {
1023                 V_VT(pVarResult) = VT_I4;
1024                 V_I4(pVarResult) = data->ulCount;
1025             }
1026             else return DISP_E_MEMBERNOTFOUND;
1027             break;
1028
1029          default:
1030             return DISP_E_MEMBERNOTFOUND;
1031     }
1032
1033     VariantClear(&varg0);
1034
1035     return S_OK;
1036 }
1037
1038 static void WINAPI ListImpl_Free(AutomationObject *This)
1039 {
1040     ListData *data = private_data(This);
1041     ULONG idx;
1042
1043     for (idx=0; idx<data->ulCount; idx++)
1044         VariantClear(&data->pVars[idx]);
1045     HeapFree(GetProcessHeap(), 0, data->pVars);
1046 }
1047
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)
1058 {
1059     MSIHANDLE msiHandle;
1060     IDispatch *pDispatch = NULL;
1061     UINT ret;
1062     VARIANTARG varg0, varg1;
1063     HRESULT hr;
1064
1065     VariantInit(&varg0);
1066     VariantInit(&varg1);
1067
1068     switch (dispIdMember)
1069     {
1070         case DISPID_VIEW_EXECUTE:
1071             if (wFlags & DISPATCH_METHOD)
1072             {
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);
1078             }
1079             else return DISP_E_MEMBERNOTFOUND;
1080             break;
1081
1082         case DISPID_VIEW_FETCH:
1083             if (wFlags & DISPATCH_METHOD)
1084             {
1085                 V_VT(pVarResult) = VT_DISPATCH;
1086                 if ((ret = MsiViewFetch(This->msiHandle, &msiHandle)) == ERROR_SUCCESS)
1087                 {
1088                     if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Record, RecordImpl_Invoke, NULL, 0)))
1089                     {
1090                         IDispatch_AddRef(pDispatch);
1091                         V_DISPATCH(pVarResult) = pDispatch;
1092                     }
1093                     else
1094                         ERR("Failed to create Record object, hresult 0x%08x\n", hr);
1095                 }
1096                 else if (ret == ERROR_NO_MORE_ITEMS)
1097                     V_DISPATCH(pVarResult) = NULL;
1098                 else
1099                 {
1100                     ERR("MsiViewFetch returned %d\n", ret);
1101                     return DISP_E_EXCEPTION;
1102                 }
1103             }
1104             else return DISP_E_MEMBERNOTFOUND;
1105             break;
1106
1107         case DISPID_VIEW_MODIFY:
1108             if (wFlags & DISPATCH_METHOD)
1109             {
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)
1116                 {
1117                     VariantClear(&varg1);
1118                     ERR("MsiViewModify returned %d\n", ret);
1119                     return DISP_E_EXCEPTION;
1120                 }
1121             }
1122             else return DISP_E_MEMBERNOTFOUND;
1123             break;
1124
1125         case DISPID_VIEW_CLOSE:
1126             if (wFlags & DISPATCH_METHOD)
1127             {
1128                 MsiViewClose(This->msiHandle);
1129             }
1130             else return DISP_E_MEMBERNOTFOUND;
1131             break;
1132
1133          default:
1134             return DISP_E_MEMBERNOTFOUND;
1135     }
1136
1137     VariantClear(&varg1);
1138     VariantClear(&varg0);
1139
1140     return S_OK;
1141 }
1142
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)
1153 {
1154     MSIHANDLE msiHandle;
1155     IDispatch *pDispatch = NULL;
1156     UINT ret;
1157     VARIANTARG varg0, varg1;
1158     HRESULT hr;
1159
1160     VariantInit(&varg0);
1161     VariantInit(&varg1);
1162
1163     switch (dispIdMember)
1164     {
1165         case DISPID_DATABASE_SUMMARYINFORMATION:
1166             if (wFlags & DISPATCH_PROPERTYGET)
1167             {
1168                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1169                 if (FAILED(hr))
1170                     V_I4(&varg0) = 0;
1171
1172                 V_VT(pVarResult) = VT_DISPATCH;
1173                 if ((ret = MsiGetSummaryInformationW(This->msiHandle, NULL, V_I4(&varg0), &msiHandle)) == ERROR_SUCCESS)
1174                 {
1175                     hr = create_automation_object(msiHandle, NULL, (LPVOID *)&pDispatch, &DIID_SummaryInfo, SummaryInfoImpl_Invoke, NULL, 0);
1176                     if (SUCCEEDED(hr))
1177                     {
1178                         IDispatch_AddRef(pDispatch);
1179                         V_DISPATCH(pVarResult) = pDispatch;
1180                     }
1181                     else
1182                         ERR("Failed to create SummaryInfo object: 0x%08x\n", hr);
1183                 }
1184                 else
1185                 {
1186                     ERR("MsiGetSummaryInformation returned %d\n", ret);
1187                     return DISP_E_EXCEPTION;
1188                 }
1189             }
1190             else return DISP_E_MEMBERNOTFOUND;
1191             break;
1192
1193         case DISPID_DATABASE_OPENVIEW:
1194             if (wFlags & DISPATCH_METHOD)
1195             {
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)
1200                 {
1201                     if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_View, ViewImpl_Invoke, NULL, 0)))
1202                     {
1203                         IDispatch_AddRef(pDispatch);
1204                         V_DISPATCH(pVarResult) = pDispatch;
1205                     }
1206                     else
1207                         ERR("Failed to create View object, hresult 0x%08x\n", hr);
1208                 }
1209                 else
1210                 {
1211                     VariantClear(&varg0);
1212                     ERR("MsiDatabaseOpenView returned %d\n", ret);
1213                     return DISP_E_EXCEPTION;
1214                 }
1215             }
1216             else return DISP_E_MEMBERNOTFOUND;
1217             break;
1218
1219          default:
1220             return DISP_E_MEMBERNOTFOUND;
1221     }
1222
1223     VariantClear(&varg1);
1224     VariantClear(&varg0);
1225
1226     return S_OK;
1227 }
1228
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)
1239 {
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;
1250
1251     VariantInit(&varg0);
1252     VariantInit(&varg1);
1253
1254     switch (dispIdMember)
1255     {
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;
1261             }
1262             else return DISP_E_MEMBERNOTFOUND;
1263             break;
1264
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)
1272                 {
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);
1278                 }
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;
1288                 }
1289                 if ((ret = MsiSetPropertyW(This->msiHandle, V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
1290                 {
1291                     VariantClear(&varg0);
1292                     VariantClear(&varg1);
1293                     ERR("MsiSetProperty returned %d\n", ret);
1294                     return DISP_E_EXCEPTION;
1295                 }
1296             }
1297             else return DISP_E_MEMBERNOTFOUND;
1298             break;
1299
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;
1305             }
1306             else return DISP_E_MEMBERNOTFOUND;
1307             break;
1308
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)
1321                 {
1322                     ERR("MsiSetMode returned %d\n", ret);
1323                     return DISP_E_EXCEPTION;
1324                 }
1325             }
1326             else return DISP_E_MEMBERNOTFOUND;
1327             break;
1328
1329         case DISPID_SESSION_DATABASE:
1330             if (wFlags & DISPATCH_PROPERTYGET) {
1331                 V_VT(pVarResult) = VT_DISPATCH;
1332                 if ((msiHandle = MsiGetActiveDatabase(This->msiHandle)))
1333                 {
1334                     if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Database, DatabaseImpl_Invoke, NULL, 0)))
1335                     {
1336                         IDispatch_AddRef(pDispatch);
1337                         V_DISPATCH(pVarResult) = pDispatch;
1338                     }
1339                     else
1340                         ERR("Failed to create Database object, hresult 0x%08x\n", hr);
1341                 }
1342                 else
1343                 {
1344                     ERR("MsiGetActiveDatabase failed\n");
1345                     return DISP_E_EXCEPTION;
1346                 }
1347             }
1348             else return DISP_E_MEMBERNOTFOUND;
1349             break;
1350
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)
1358                 {
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;
1387                 }
1388             }
1389             else return DISP_E_MEMBERNOTFOUND;
1390             break;
1391
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));
1398             }
1399             else return DISP_E_MEMBERNOTFOUND;
1400             break;
1401
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)
1407                 {
1408                     ERR("MsiSetInstallLevel returned %d\n", ret);
1409                     return DISP_E_EXCEPTION;
1410                 }
1411             }
1412             else return DISP_E_MEMBERNOTFOUND;
1413             break;
1414
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
1423                 {
1424                     ERR("MsiGetFeatureState returned %d\n", ret);
1425                     V_I4(pVarResult) = msiInstallStateUnknown;
1426                 }
1427             }
1428             else return DISP_E_MEMBERNOTFOUND;
1429             break;
1430
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
1439                 {
1440                     ERR("MsiGetFeatureState returned %d\n", ret);
1441                     V_I4(pVarResult) = msiInstallStateUnknown;
1442                 }
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;
1450                 }
1451                 if ((ret = MsiSetFeatureStateW(This->msiHandle, V_BSTR(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
1452                 {
1453                     VariantClear(&varg0);
1454                     ERR("MsiSetFeatureState returned %d\n", ret);
1455                     return DISP_E_EXCEPTION;
1456                 }
1457             }
1458             else return DISP_E_MEMBERNOTFOUND;
1459             break;
1460
1461          default:
1462             return DISP_E_MEMBERNOTFOUND;
1463     }
1464
1465     VariantClear(&varg1);
1466     VariantClear(&varg0);
1467
1468     return S_OK;
1469 }
1470
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)
1474 {
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;
1481
1482     switch (dwType)
1483     {
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;
1494
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
1503             {
1504                 V_VT(pVarResult) = VT_BSTR;
1505                 V_BSTR(pVarResult) = SysAllocStringLen(szNewString, dwNewSize);
1506             }
1507             msi_free(szNewString);
1508             break;
1509
1510         case REG_DWORD:
1511             V_VT(pVarResult) = VT_I4;
1512             V_I4(pVarResult) = *((DWORD *)lpData);
1513             break;
1514
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;
1519
1520         case REG_BINARY:
1521             V_VT(pVarResult) = VT_BSTR;
1522             V_BSTR(pVarResult) = SysAllocString(szREG_BINARY);
1523             break;
1524
1525         case REG_NONE:
1526             V_VT(pVarResult) = VT_EMPTY;
1527             break;
1528
1529         default:
1530             FIXME("Unhandled registry value type %d\n", dwType);
1531     }
1532 }
1533
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)
1544 {
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;
1552
1553     VariantInit(&varg0);
1554     VariantInit(&varg1);
1555     VariantInit(&varg2);
1556
1557     switch (dispIdMember)
1558     {
1559         case DISPID_INSTALLER_CREATERECORD:
1560             if (wFlags & DISPATCH_METHOD)
1561             {
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))))
1566                 {
1567                     if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Record, RecordImpl_Invoke, NULL, 0)))
1568                     {
1569                         IDispatch_AddRef(pDispatch);
1570                         V_DISPATCH(pVarResult) = pDispatch;
1571                     }
1572                     else
1573                         ERR("Failed to create Record object, hresult 0x%08x\n", hr);
1574                 }
1575                 else
1576                 {
1577                     ERR("MsiCreateRecord failed\n");
1578                     return DISP_E_EXCEPTION;
1579                 }
1580             }
1581             else return DISP_E_MEMBERNOTFOUND;
1582             break;
1583
1584         case DISPID_INSTALLER_OPENPACKAGE:
1585             if (wFlags & DISPATCH_METHOD)
1586             {
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))
1591                 {
1592                     VariantClear(&varg0);
1593                     return hr;
1594                 }
1595                 V_VT(pVarResult) = VT_DISPATCH;
1596                 if ((ret = MsiOpenPackageExW(V_BSTR(&varg0), V_I4(&varg1), &msiHandle)) == ERROR_SUCCESS)
1597                 {
1598                     if (SUCCEEDED(hr = create_session(msiHandle, (IDispatch *)This, &pDispatch)))
1599                     {
1600                         IDispatch_AddRef(pDispatch);
1601                         V_DISPATCH(pVarResult) = pDispatch;
1602                     }
1603                     else
1604                         ERR("Failed to create Session object, hresult 0x%08x\n", hr);
1605                 }
1606                 else
1607                 {
1608                     VariantClear(&varg0);
1609                     ERR("MsiOpenPackageEx returned %d\n", ret);
1610                     return DISP_E_EXCEPTION;
1611                 }
1612             }
1613             else return DISP_E_MEMBERNOTFOUND;
1614             break;
1615
1616         case DISPID_INSTALLER_OPENDATABASE:
1617             if (wFlags & DISPATCH_METHOD)
1618             {
1619                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1620                 if (FAILED(hr)) return hr;
1621
1622                 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1623                 if (FAILED(hr))
1624                 {
1625                     VariantClear(&varg0);
1626                     return hr;
1627                 }
1628
1629                 V_VT(pVarResult) = VT_DISPATCH;
1630                 if ((ret = MsiOpenDatabaseW(V_BSTR(&varg0), V_BSTR(&varg1), &msiHandle)) == ERROR_SUCCESS)
1631                 {
1632                     hr = create_automation_object(msiHandle, NULL, (LPVOID *)&pDispatch,
1633                                                   &DIID_Database, DatabaseImpl_Invoke, NULL, 0);
1634                     if (SUCCEEDED(hr))
1635                     {
1636                         IDispatch_AddRef(pDispatch);
1637                         V_DISPATCH(pVarResult) = pDispatch;
1638                     }
1639                     else
1640                         ERR("Failed to create Database object: 0x%08x\n", hr);
1641                 }
1642                 else
1643                 {
1644                     VariantClear(&varg0);
1645                     VariantClear(&varg1);
1646                     ERR("MsiOpenDatabase returned %d\n", ret);
1647                     return DISP_E_EXCEPTION;
1648                 }
1649             }
1650             else return DISP_E_MEMBERNOTFOUND;
1651             break;
1652
1653         case DISPID_INSTALLER_INSTALLPRODUCT:
1654             if (wFlags & DISPATCH_METHOD)
1655             {
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))
1660                 {
1661                     VariantClear(&varg0);
1662                     return hr;
1663                 }
1664                 if ((ret = MsiInstallProductW(V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
1665                 {
1666                     VariantClear(&varg1);
1667                     VariantClear(&varg0);
1668                     ERR("MsiInstallProduct returned %d\n", ret);
1669                     return DISP_E_EXCEPTION;
1670                 }
1671             }
1672             else return DISP_E_MEMBERNOTFOUND;
1673             break;
1674
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 */
1680
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))
1687                 {
1688                     VariantClear(&varg1);
1689                     return hr;
1690                 }
1691                 ret = RegOpenKeyW((HKEY)V_I4(&varg0), V_BSTR(&varg1), &hkey);
1692
1693                 /* Third parameter can be VT_EMPTY, VT_I4, or VT_BSTR */
1694                 switch (V_VT(&varg2))
1695                 {
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;
1700
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)
1704                         {
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);
1709                         }
1710
1711                         if (ret != ERROR_SUCCESS)
1712                         {
1713                             msi_free(szString);
1714                             VariantClear(&varg2);
1715                             VariantClear(&varg1);
1716                             return DISP_E_BADINDEX;
1717                         }
1718                         break;
1719
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))
1724                         {
1725                             if (hr == DISP_E_TYPEMISMATCH) *puArgErr = posValue;
1726                             VariantClear(&varg2);   /* Unknown type, so let's clear it */
1727                             VariantClear(&varg1);
1728                             return hr;
1729                         }
1730
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);
1738
1739                         if (ret == ERROR_SUCCESS)
1740                         {
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);
1749
1750                             if (szString && ret == ERROR_SUCCESS)
1751                             {
1752                                 V_VT(pVarResult) = VT_BSTR;
1753                                 V_BSTR(pVarResult) = SysAllocString(szString);
1754                             }
1755                         }
1756                 }
1757
1758                 msi_free(szString);
1759                 RegCloseKey(hkey);
1760             }
1761             else return DISP_E_MEMBERNOTFOUND;
1762             break;
1763
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));
1770             }
1771             else return DISP_E_MEMBERNOTFOUND;
1772             break;
1773
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))
1780                 {
1781                     VariantClear(&varg0);
1782                     return hr;
1783                 }
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)
1787                 {
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);
1793                 }
1794                 if (ret != ERROR_SUCCESS)
1795                 {
1796                     ERR("MsiGetProductInfo returned %d\n", ret);
1797                     VariantClear(&varg1);
1798                     VariantClear(&varg0);
1799                     return DISP_E_EXCEPTION;
1800                 }
1801             }
1802             else return DISP_E_MEMBERNOTFOUND;
1803             break;
1804
1805         case DISPID_INSTALLER_PRODUCTS:
1806             if (wFlags & DISPATCH_PROPERTYGET)
1807             {
1808                 ListData *ldata = NULL;
1809                 ULONG idx = 0;
1810                 WCHAR szProductBuf[GUID_SIZE];
1811
1812                 /* Find number of products */
1813                 while ((ret = MsiEnumProductsW(idx, szProductBuf)) == ERROR_SUCCESS) idx++;
1814                 if (ret != ERROR_NO_MORE_ITEMS)
1815                 {
1816                     ERR("MsiEnumProducts returned %d\n", ret);
1817                     return DISP_E_EXCEPTION;
1818                 }
1819
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))))
1822                 {
1823                     IDispatch_AddRef(pDispatch);
1824                     V_DISPATCH(pVarResult) = pDispatch;
1825
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
1831                     {
1832                         ldata->ulCount = idx;
1833                         for (idx = 0; idx < ldata->ulCount; idx++)
1834                         {
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);
1839                         }
1840                     }
1841                 }
1842                 else
1843                     ERR("Failed to create StringList object, hresult 0x%08x\n", hr);
1844             }
1845             else return DISP_E_MEMBERNOTFOUND;
1846             break;
1847
1848         case DISPID_INSTALLER_RELATEDPRODUCTS:
1849             if (wFlags & DISPATCH_PROPERTYGET)
1850             {
1851                 ListData *ldata = NULL;
1852                 ULONG idx = 0;
1853                 WCHAR szProductBuf[GUID_SIZE];
1854
1855                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1856                 if (FAILED(hr)) return hr;
1857
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)
1861                 {
1862                     VariantClear(&varg0);
1863                     ERR("MsiEnumRelatedProducts returned %d\n", ret);
1864                     return DISP_E_EXCEPTION;
1865                 }
1866
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))))
1869                 {
1870                     IDispatch_AddRef(pDispatch);
1871                     V_DISPATCH(pVarResult) = pDispatch;
1872
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
1878                     {
1879                         ldata->ulCount = idx;
1880                         for (idx = 0; idx < ldata->ulCount; idx++)
1881                         {
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);
1886                         }
1887                     }
1888                 }
1889                 else
1890                     ERR("Failed to create StringList object, hresult 0x%08x\n", hr);
1891             }
1892             else return DISP_E_MEMBERNOTFOUND;
1893             break;
1894
1895          default:
1896             return DISP_E_MEMBERNOTFOUND;
1897     }
1898
1899     VariantClear(&varg2);
1900     VariantClear(&varg1);
1901     VariantClear(&varg0);
1902
1903     return S_OK;
1904 }
1905
1906 /* Wrapper around create_automation_object to create an installer object. */
1907 HRESULT create_msiserver(IUnknown *pOuter, LPVOID *ppObj)
1908 {
1909     return create_automation_object(0, pOuter, ppObj, &DIID_Installer, InstallerImpl_Invoke, NULL, 0);
1910 }
1911
1912 /* Wrapper around create_automation_object to create a session object. */
1913 HRESULT create_session(MSIHANDLE msiHandle, IDispatch *pInstaller, IDispatch **pDispatch)
1914 {
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;
1919 }