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