msi: Improve parsing of the package platform.
[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         case REG_SZ:
1514             V_VT(pVarResult) = VT_BSTR;
1515             V_BSTR(pVarResult) = SysAllocStringByteLen((LPCSTR)szString, dwSize);
1516             break;
1517
1518         case REG_EXPAND_SZ:
1519             if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1520                 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1521             else if (!(szNewString = msi_alloc(dwNewSize * sizeof(WCHAR))))
1522                 ERR("Out of memory\n");
1523             else if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1524                 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1525             else
1526             {
1527                 V_VT(pVarResult) = VT_BSTR;
1528                 V_BSTR(pVarResult) = SysAllocStringLen(szNewString, dwNewSize);
1529             }
1530             msi_free(szNewString);
1531             break;
1532
1533         case REG_DWORD:
1534             V_VT(pVarResult) = VT_I4;
1535             V_I4(pVarResult) = *((DWORD *)lpData);
1536             break;
1537
1538         case REG_QWORD:
1539             V_VT(pVarResult) = VT_BSTR;
1540             V_BSTR(pVarResult) = SysAllocString(szREG_);   /* Weird string, don't know why native returns it */
1541             break;
1542
1543         case REG_BINARY:
1544             V_VT(pVarResult) = VT_BSTR;
1545             V_BSTR(pVarResult) = SysAllocString(szREG_BINARY);
1546             break;
1547
1548         case REG_NONE:
1549             V_VT(pVarResult) = VT_EMPTY;
1550             break;
1551
1552         default:
1553             FIXME("Unhandled registry value type %d\n", dwType);
1554     }
1555 }
1556
1557 static HRESULT InstallerImpl_CreateRecord(WORD wFlags,
1558                                           DISPPARAMS* pDispParams,
1559                                           VARIANT* pVarResult,
1560                                           EXCEPINFO* pExcepInfo,
1561                                           UINT* puArgErr)
1562 {
1563     HRESULT hr;
1564     VARIANTARG varg0;
1565     MSIHANDLE hrec;
1566     IDispatch* dispatch;
1567
1568     if (!(wFlags & DISPATCH_METHOD))
1569         return DISP_E_MEMBERNOTFOUND;
1570
1571     VariantInit(&varg0);
1572     hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1573     if (FAILED(hr))
1574         return hr;
1575
1576     V_VT(pVarResult) = VT_DISPATCH;
1577
1578     hrec = MsiCreateRecord(V_I4(&varg0));
1579     if (!hrec)
1580         return DISP_E_EXCEPTION;
1581
1582     hr = create_automation_object(hrec, NULL, (LPVOID*)&dispatch,
1583                                   &DIID_Record, RecordImpl_Invoke, NULL, 0);
1584     if (SUCCEEDED(hr))
1585         V_DISPATCH(pVarResult) = dispatch;
1586
1587     return hr;
1588 }
1589
1590 static HRESULT InstallerImpl_OpenPackage(AutomationObject* This,
1591                                          WORD wFlags,
1592                                          DISPPARAMS* pDispParams,
1593                                          VARIANT* pVarResult,
1594                                          EXCEPINFO* pExcepInfo,
1595                                          UINT* puArgErr)
1596 {
1597     UINT ret;
1598     HRESULT hr;
1599     MSIHANDLE hpkg;
1600     IDispatch* dispatch;
1601     VARIANTARG varg0, varg1;
1602
1603     if (!(wFlags & DISPATCH_METHOD))
1604         return DISP_E_MEMBERNOTFOUND;
1605
1606     if (pDispParams->cArgs == 0)
1607         return DISP_E_TYPEMISMATCH;
1608
1609     if (V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1]) != VT_BSTR)
1610         return DISP_E_TYPEMISMATCH;
1611
1612     VariantInit(&varg0);
1613     hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1614     if (FAILED(hr))
1615         return hr;
1616
1617     VariantInit(&varg1);
1618     if (pDispParams->cArgs == 2)
1619     {
1620         hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1621         if (FAILED(hr))
1622             goto done;
1623     }
1624     else
1625     {
1626         V_VT(&varg1) = VT_I4;
1627         V_I4(&varg1) = 0;
1628     }
1629
1630     V_VT(pVarResult) = VT_DISPATCH;
1631
1632     ret = MsiOpenPackageExW(V_BSTR(&varg0), V_I4(&varg1), &hpkg);
1633     if (ret != ERROR_SUCCESS)
1634     {
1635         hr = DISP_E_EXCEPTION;
1636         goto done;
1637     }
1638
1639     hr = create_session(hpkg, (IDispatch *)This, &dispatch);
1640     if (SUCCEEDED(hr))
1641         V_DISPATCH(pVarResult) = dispatch;
1642
1643 done:
1644     VariantClear(&varg0);
1645     VariantClear(&varg1);
1646     return hr;
1647 }
1648
1649 static HRESULT InstallerImpl_OpenProduct(WORD wFlags,
1650                                          DISPPARAMS* pDispParams,
1651                                          VARIANT* pVarResult,
1652                                          EXCEPINFO* pExcepInfo,
1653                                          UINT* puArgErr)
1654 {
1655     HRESULT hr;
1656     VARIANTARG varg0;
1657
1658     if (!(wFlags & DISPATCH_METHOD))
1659         return DISP_E_MEMBERNOTFOUND;
1660
1661     VariantInit(&varg0);
1662     hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1663     if (FAILED(hr))
1664         return hr;
1665
1666     FIXME("%s\n", debugstr_w(V_BSTR(&varg0)));
1667
1668     VariantInit(pVarResult);
1669
1670     VariantClear(&varg0);
1671     return S_OK;
1672 }
1673
1674 static HRESULT InstallerImpl_OpenDatabase(WORD wFlags,
1675                                           DISPPARAMS* pDispParams,
1676                                           VARIANT* pVarResult,
1677                                           EXCEPINFO* pExcepInfo,
1678                                           UINT* puArgErr)
1679 {
1680     UINT ret;
1681     HRESULT hr;
1682     MSIHANDLE hdb;
1683     IDispatch* dispatch;
1684     VARIANTARG varg0, varg1;
1685
1686     if (!(wFlags & DISPATCH_METHOD))
1687         return DISP_E_MEMBERNOTFOUND;
1688
1689     VariantInit(&varg0);
1690     hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1691     if (FAILED(hr))
1692         return hr;
1693
1694     VariantInit(&varg1);
1695     hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1696     if (FAILED(hr))
1697         goto done;
1698
1699     V_VT(pVarResult) = VT_DISPATCH;
1700
1701     ret = MsiOpenDatabaseW(V_BSTR(&varg0), V_BSTR(&varg1), &hdb);
1702     if (ret != ERROR_SUCCESS)
1703     {
1704         hr = DISP_E_EXCEPTION;
1705         goto done;
1706     }
1707
1708     hr = create_automation_object(hdb, NULL, (LPVOID *)&dispatch,
1709                                   &DIID_Database, DatabaseImpl_Invoke, NULL, 0);
1710     if (SUCCEEDED(hr))
1711         V_DISPATCH(pVarResult) = dispatch;
1712
1713 done:
1714     VariantClear(&varg0);
1715     VariantClear(&varg1);
1716     return hr;
1717 }
1718
1719 static HRESULT InstallerImpl_SummaryInformation(WORD wFlags,
1720                                                 DISPPARAMS* pDispParams,
1721                                                 VARIANT* pVarResult,
1722                                                 EXCEPINFO* pExcepInfo,
1723                                                 UINT* puArgErr)
1724 {
1725     if (!(wFlags & DISPATCH_METHOD))
1726         return DISP_E_MEMBERNOTFOUND;
1727
1728     FIXME("\n");
1729
1730     VariantInit(pVarResult);
1731     return S_OK;
1732 }
1733
1734 static HRESULT InstallerImpl_UILevel(WORD wFlags,
1735                                      DISPPARAMS* pDispParams,
1736                                      VARIANT* pVarResult,
1737                                      EXCEPINFO* pExcepInfo,
1738                                      UINT* puArgErr)
1739 {
1740     HRESULT hr;
1741     VARIANTARG varg0;
1742     INSTALLUILEVEL ui;
1743
1744     if (!(wFlags & DISPATCH_PROPERTYPUT) && !(wFlags & DISPATCH_PROPERTYGET))
1745         return DISP_E_MEMBERNOTFOUND;
1746
1747     if (wFlags & DISPATCH_PROPERTYPUT)
1748     {
1749         VariantInit(&varg0);
1750         hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1751         if (FAILED(hr))
1752             return hr;
1753
1754         ui = MsiSetInternalUI(V_I4(&varg0), NULL);
1755         if (ui == INSTALLUILEVEL_NOCHANGE)
1756             return DISP_E_EXCEPTION;
1757     }
1758     else if (wFlags & DISPATCH_PROPERTYGET)
1759     {
1760         ui = MsiSetInternalUI(INSTALLUILEVEL_NOCHANGE, NULL);
1761         if (ui == INSTALLUILEVEL_NOCHANGE)
1762             return DISP_E_EXCEPTION;
1763
1764         V_VT(pVarResult) = VT_I4;
1765         V_I4(pVarResult) = ui;
1766     }
1767
1768     return S_OK;
1769 }
1770
1771 static HRESULT InstallerImpl_EnableLog(WORD wFlags,
1772                                        DISPPARAMS* pDispParams,
1773                                        VARIANT* pVarResult,
1774                                        EXCEPINFO* pExcepInfo,
1775                                        UINT* puArgErr)
1776 {
1777     if (!(wFlags & DISPATCH_METHOD))
1778         return DISP_E_MEMBERNOTFOUND;
1779
1780     FIXME("\n");
1781
1782     VariantInit(pVarResult);
1783     return S_OK;
1784 }
1785
1786 static HRESULT InstallerImpl_InstallProduct(WORD wFlags,
1787                                             DISPPARAMS* pDispParams,
1788                                             VARIANT* pVarResult,
1789                                             EXCEPINFO* pExcepInfo,
1790                                             UINT* puArgErr)
1791 {
1792     UINT ret;
1793     HRESULT hr;
1794     VARIANTARG varg0, varg1;
1795
1796     if (!(wFlags & DISPATCH_METHOD))
1797         return DISP_E_MEMBERNOTFOUND;
1798
1799     VariantInit(&varg0);
1800     hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1801     if (FAILED(hr))
1802         return hr;
1803
1804     VariantInit(&varg1);
1805     hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1806     if (FAILED(hr))
1807         goto done;
1808
1809     ret = MsiInstallProductW(V_BSTR(&varg0), V_BSTR(&varg1));
1810     if (ret != ERROR_SUCCESS)
1811     {
1812         hr = DISP_E_EXCEPTION;
1813         goto done;
1814     }
1815
1816 done:
1817     VariantClear(&varg0);
1818     VariantClear(&varg1);
1819     return hr;
1820 }
1821
1822 static HRESULT InstallerImpl_Version(WORD wFlags,
1823                                      VARIANT* pVarResult,
1824                                      EXCEPINFO* pExcepInfo,
1825                                      UINT* puArgErr)
1826 {
1827     HRESULT hr;
1828     DLLVERSIONINFO verinfo;
1829     WCHAR version[MAX_PATH];
1830
1831     static const WCHAR format[] = {
1832         '%','d','.','%','d','.','%','d','.','%','d',0};
1833
1834     if (!(wFlags & DISPATCH_PROPERTYGET))
1835         return DISP_E_MEMBERNOTFOUND;
1836
1837     verinfo.cbSize = sizeof(DLLVERSIONINFO);
1838     hr = DllGetVersion(&verinfo);
1839     if (FAILED(hr))
1840         return hr;
1841
1842     sprintfW(version, format, verinfo.dwMajorVersion, verinfo.dwMinorVersion,
1843              verinfo.dwBuildNumber, verinfo.dwPlatformID);
1844
1845     V_VT(pVarResult) = VT_BSTR;
1846     V_BSTR(pVarResult) = SysAllocString(version);
1847     return S_OK;
1848 }
1849
1850 static HRESULT InstallerImpl_LastErrorRecord(WORD wFlags,
1851                                              DISPPARAMS* pDispParams,
1852                                              VARIANT* pVarResult,
1853                                              EXCEPINFO* pExcepInfo,
1854                                              UINT* puArgErr)
1855 {
1856     if (!(wFlags & DISPATCH_METHOD))
1857         return DISP_E_MEMBERNOTFOUND;
1858
1859     FIXME("\n");
1860
1861     VariantInit(pVarResult);
1862     return S_OK;
1863 }
1864
1865 static HRESULT InstallerImpl_RegistryValue(WORD wFlags,
1866                                            DISPPARAMS* pDispParams,
1867                                            VARIANT* pVarResult,
1868                                            EXCEPINFO* pExcepInfo,
1869                                            UINT* puArgErr)
1870 {
1871     UINT ret;
1872     HKEY hkey = NULL;
1873     HRESULT hr;
1874     UINT posValue;
1875     DWORD type, size;
1876     LPWSTR szString = NULL;
1877     VARIANTARG varg0, varg1, varg2;
1878
1879     if (!(wFlags & DISPATCH_METHOD))
1880         return DISP_E_MEMBERNOTFOUND;
1881
1882     VariantInit(&varg0);
1883     hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1884     if (FAILED(hr))
1885         return hr;
1886
1887     VariantInit(&varg1);
1888     hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1889     if (FAILED(hr))
1890         goto done;
1891
1892     /* Save valuePos so we can save puArgErr if we are unable to do our type
1893      * conversions.
1894      */
1895     posValue = 2;
1896     VariantInit(&varg2);
1897     hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg2);
1898     if (FAILED(hr))
1899         goto done;
1900
1901     if (V_I4(&varg0) >= REG_INDEX_CLASSES_ROOT &&
1902         V_I4(&varg0) <= REG_INDEX_DYN_DATA)
1903     {
1904         V_I4(&varg0) |= (UINT_PTR)HKEY_CLASSES_ROOT;
1905     }
1906
1907     ret = RegOpenKeyW((HKEY)(UINT_PTR)V_I4(&varg0), V_BSTR(&varg1), &hkey);
1908
1909     /* Only VT_EMPTY case can do anything if the key doesn't exist. */
1910     if (ret != ERROR_SUCCESS && V_VT(&varg2) != VT_EMPTY)
1911     {
1912         hr = DISP_E_BADINDEX;
1913         goto done;
1914     }
1915
1916     /* Third parameter can be VT_EMPTY, VT_I4, or VT_BSTR */
1917     switch (V_VT(&varg2))
1918     {
1919         /* Return VT_BOOL clarifying whether registry key exists or not. */
1920         case VT_EMPTY:
1921             V_VT(pVarResult) = VT_BOOL;
1922             V_BOOL(pVarResult) = (ret == ERROR_SUCCESS);
1923             break;
1924
1925         /* Return the value of specified key if it exists. */
1926         case VT_BSTR:
1927             ret = RegQueryValueExW(hkey, V_BSTR(&varg2),
1928                                    NULL, NULL, NULL, &size);
1929             if (ret != ERROR_SUCCESS)
1930             {
1931                 hr = DISP_E_BADINDEX;
1932                 goto done;
1933             }
1934
1935             szString = msi_alloc(size);
1936             if (!szString)
1937             {
1938                 hr = E_OUTOFMEMORY;
1939                 goto done;
1940             }
1941
1942             ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL,
1943                                    &type, (LPBYTE)szString, &size);
1944             if (ret != ERROR_SUCCESS)
1945             {
1946                 msi_free(szString);
1947                 hr = DISP_E_BADINDEX;
1948                 goto done;
1949             }
1950
1951             variant_from_registry_value(pVarResult, type,
1952                                         (LPBYTE)szString, size);
1953             msi_free(szString);
1954             break;
1955
1956         /* Try to make it into VT_I4, can use VariantChangeType for this. */
1957         default:
1958             hr = VariantChangeType(&varg2, &varg2, 0, VT_I4);
1959             if (FAILED(hr))
1960             {
1961                 if (hr == DISP_E_TYPEMISMATCH)
1962                     *puArgErr = posValue;
1963
1964                 goto done;
1965             }
1966
1967             /* Retrieve class name or maximum value name or subkey name size. */
1968             if (!V_I4(&varg2))
1969                 ret = RegQueryInfoKeyW(hkey, NULL, &size, NULL, NULL, NULL,
1970                                        NULL, NULL, NULL, NULL, NULL, NULL);
1971             else if (V_I4(&varg2) > 0)
1972                 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL,
1973                                        NULL, NULL, &size, NULL, NULL, NULL);
1974             else /* V_I4(&varg2) < 0 */
1975                 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, &size,
1976                                        NULL, NULL, NULL, NULL, NULL, NULL);
1977
1978             if (ret != ERROR_SUCCESS)
1979                 goto done;
1980
1981             szString = msi_alloc(++size * sizeof(WCHAR));
1982             if (!szString)
1983             {
1984                 hr = E_OUTOFMEMORY;
1985                 goto done;
1986             }
1987
1988             if (!V_I4(&varg2))
1989                 ret = RegQueryInfoKeyW(hkey, szString, &size,NULL, NULL, NULL,
1990                                        NULL, NULL, NULL, NULL, NULL, NULL);
1991             else if (V_I4(&varg2) > 0)
1992                 ret = RegEnumValueW(hkey, V_I4(&varg2)-1, szString,
1993                                     &size, 0, 0, NULL, NULL);
1994             else /* V_I4(&varg2) < 0 */
1995                 ret = RegEnumKeyW(hkey, -1 - V_I4(&varg2), szString, size);
1996
1997             if (ret == ERROR_SUCCESS)
1998             {
1999                 V_VT(pVarResult) = VT_BSTR;
2000                 V_BSTR(pVarResult) = SysAllocString(szString);
2001             }
2002
2003             msi_free(szString);
2004     }
2005
2006 done:
2007     VariantClear(&varg0);
2008     VariantClear(&varg1);
2009     VariantClear(&varg2);
2010     RegCloseKey(hkey);
2011     return hr;
2012 }
2013
2014 static HRESULT InstallerImpl_Environment(WORD wFlags,
2015                                          DISPPARAMS* pDispParams,
2016                                          VARIANT* pVarResult,
2017                                          EXCEPINFO* pExcepInfo,
2018                                          UINT* puArgErr)
2019 {
2020     if (!(wFlags & DISPATCH_METHOD))
2021         return DISP_E_MEMBERNOTFOUND;
2022
2023     FIXME("\n");
2024
2025     VariantInit(pVarResult);
2026     return S_OK;
2027 }
2028
2029 static HRESULT InstallerImpl_FileAttributes(WORD wFlags,
2030                                             DISPPARAMS* pDispParams,
2031                                             VARIANT* pVarResult,
2032                                             EXCEPINFO* pExcepInfo,
2033                                             UINT* puArgErr)
2034 {
2035     if (!(wFlags & DISPATCH_METHOD))
2036         return DISP_E_MEMBERNOTFOUND;
2037
2038     FIXME("\n");
2039
2040     VariantInit(pVarResult);
2041     return S_OK;
2042 }
2043
2044 static HRESULT InstallerImpl_FileSize(WORD wFlags,
2045                                       DISPPARAMS* pDispParams,
2046                                       VARIANT* pVarResult,
2047                                       EXCEPINFO* pExcepInfo,
2048                                       UINT* puArgErr)
2049 {
2050     if (!(wFlags & DISPATCH_METHOD))
2051         return DISP_E_MEMBERNOTFOUND;
2052
2053     FIXME("\n");
2054
2055     VariantInit(pVarResult);
2056     return S_OK;
2057 }
2058
2059 static HRESULT InstallerImpl_FileVersion(WORD wFlags,
2060                                          DISPPARAMS* pDispParams,
2061                                          VARIANT* pVarResult,
2062                                          EXCEPINFO* pExcepInfo,
2063                                          UINT* puArgErr)
2064 {
2065     if (!(wFlags & DISPATCH_METHOD))
2066         return DISP_E_MEMBERNOTFOUND;
2067
2068     FIXME("\n");
2069
2070     VariantInit(pVarResult);
2071     return S_OK;
2072 }
2073
2074 static HRESULT InstallerImpl_ProductState(WORD wFlags,
2075                                           DISPPARAMS* pDispParams,
2076                                           VARIANT* pVarResult,
2077                                           EXCEPINFO* pExcepInfo,
2078                                           UINT* puArgErr)
2079 {
2080     HRESULT hr;
2081     VARIANTARG varg0;
2082
2083     if (!(wFlags & DISPATCH_PROPERTYGET))
2084         return DISP_E_MEMBERNOTFOUND;
2085
2086     VariantInit(&varg0);
2087     hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
2088     if (FAILED(hr))
2089         return hr;
2090
2091     V_VT(pVarResult) = VT_I4;
2092     V_I4(pVarResult) = MsiQueryProductStateW(V_BSTR(&varg0));
2093
2094     VariantClear(&varg0);
2095     return S_OK;
2096 }
2097
2098 static HRESULT InstallerImpl_ProductInfo(WORD wFlags,
2099                                          DISPPARAMS* pDispParams,
2100                                          VARIANT* pVarResult,
2101                                          EXCEPINFO* pExcepInfo,
2102                                          UINT* puArgErr)
2103 {
2104     UINT ret;
2105     HRESULT hr;
2106     DWORD size;
2107     LPWSTR str = NULL;
2108     VARIANTARG varg0, varg1;
2109
2110     if (!(wFlags & DISPATCH_PROPERTYGET))
2111         return DISP_E_MEMBERNOTFOUND;
2112
2113     VariantInit(&varg0);
2114     hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
2115     if (FAILED(hr))
2116         return hr;
2117
2118     VariantInit(&varg1);
2119     hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
2120     if (FAILED(hr))
2121         goto done;
2122
2123     V_VT(pVarResult) = VT_BSTR;
2124     V_BSTR(pVarResult) = NULL;
2125
2126     ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), NULL, &size);
2127     if (ret != ERROR_SUCCESS)
2128     {
2129         hr = DISP_E_EXCEPTION;
2130         goto done;
2131     }
2132
2133     str = msi_alloc(++size * sizeof(WCHAR));
2134     if (!str)
2135     {
2136         hr = E_OUTOFMEMORY;
2137         goto done;
2138     }
2139
2140     ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), str, &size);
2141     if (ret != ERROR_SUCCESS)
2142     {
2143         hr = DISP_E_EXCEPTION;
2144         goto done;
2145     }
2146
2147     V_BSTR(pVarResult) = SysAllocString(str);
2148     hr = S_OK;
2149
2150 done:
2151     msi_free(str);
2152     VariantClear(&varg0);
2153     VariantClear(&varg1);
2154     return hr;
2155 }
2156
2157 static void cleanup_products(IDispatch* dispatch, ULONG count)
2158 {
2159     UINT i;
2160     ListData* ldata = private_data((AutomationObject *)dispatch);
2161
2162     for (i = 0; i < count - 1; i++)
2163         VariantClear(&ldata->pVars[i]);
2164
2165     ldata->ulCount = 0;
2166     msi_free(ldata->pVars);
2167
2168     IDispatch_Release(dispatch);
2169 }
2170
2171 static HRESULT InstallerImpl_Products(WORD wFlags,
2172                                       DISPPARAMS* pDispParams,
2173                                       VARIANT* pVarResult,
2174                                       EXCEPINFO* pExcepInfo,
2175                                       UINT* puArgErr)
2176 {
2177     UINT ret;
2178     HRESULT hr;
2179     ULONG idx = 0;
2180     ListData *ldata;
2181     IDispatch *dispatch;
2182     WCHAR product[GUID_SIZE];
2183
2184     if (!(wFlags & DISPATCH_PROPERTYGET))
2185         return DISP_E_MEMBERNOTFOUND;
2186
2187     /* Find number of products. */
2188     while ((ret = MsiEnumProductsW(idx, product)) == ERROR_SUCCESS)
2189         idx++;
2190
2191     if (ret != ERROR_NO_MORE_ITEMS)
2192         return DISP_E_EXCEPTION;
2193
2194     V_VT(pVarResult) = VT_DISPATCH;
2195     hr = create_automation_object(0, NULL, (LPVOID*)&dispatch,
2196                                   &DIID_StringList, ListImpl_Invoke,
2197                                   ListImpl_Free, sizeof(ListData));
2198     if (FAILED(hr))
2199         return hr;
2200
2201     V_DISPATCH(pVarResult) = dispatch;
2202
2203     /* Save product strings. */
2204     ldata = private_data((AutomationObject *)dispatch);
2205     ldata->ulCount = 0;
2206     ldata->pVars = msi_alloc_zero(sizeof(VARIANT) * idx);
2207     if (!ldata->pVars)
2208     {
2209         IDispatch_Release(dispatch);
2210         return E_OUTOFMEMORY;
2211     }
2212
2213     ldata->ulCount = idx;
2214     for (idx = 0; idx < ldata->ulCount; idx++)
2215     {
2216         ret = MsiEnumProductsW(idx, product);
2217         if (ret != ERROR_SUCCESS)
2218         {
2219             cleanup_products(dispatch, idx - 1);
2220             return DISP_E_EXCEPTION;
2221         }
2222
2223         VariantInit(&ldata->pVars[idx]);
2224         V_VT(&ldata->pVars[idx]) = VT_BSTR;
2225         V_BSTR(&ldata->pVars[idx]) = SysAllocString(product);
2226     }
2227
2228     return S_OK;
2229 }
2230
2231 static HRESULT InstallerImpl_RelatedProducts(WORD wFlags,
2232                                              DISPPARAMS* pDispParams,
2233                                              VARIANT* pVarResult,
2234                                              EXCEPINFO* pExcepInfo,
2235                                              UINT* puArgErr)
2236 {
2237     UINT ret;
2238     ULONG idx;
2239     HRESULT hr;
2240     ListData *ldata;
2241     VARIANTARG varg0;
2242     IDispatch* dispatch;
2243     WCHAR product[GUID_SIZE];
2244
2245     if (!(wFlags & DISPATCH_PROPERTYGET))
2246         return DISP_E_MEMBERNOTFOUND;
2247
2248     VariantInit(&varg0);
2249     hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
2250     if (FAILED(hr))
2251         return hr;
2252
2253     /* Find number of related products. */
2254     idx = 0;
2255     do
2256     {
2257         ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, product);
2258         if (ret == ERROR_SUCCESS)
2259             idx++;
2260     } while (ret == ERROR_SUCCESS);
2261
2262     if (ret != ERROR_NO_MORE_ITEMS)
2263     {
2264         hr = DISP_E_EXCEPTION;
2265         goto done;
2266     }
2267
2268     V_VT(pVarResult) = VT_DISPATCH;
2269
2270     hr = create_automation_object(0, NULL, (LPVOID*)&dispatch,
2271                                   &DIID_StringList, ListImpl_Invoke,
2272                                   ListImpl_Free, sizeof(ListData));
2273     if (FAILED(hr))
2274         goto done;
2275
2276     V_DISPATCH(pVarResult) = dispatch;
2277
2278     /* Save product strings. */
2279     ldata = private_data((AutomationObject *)dispatch);
2280     ldata->pVars = msi_alloc(sizeof(VARIANT) * idx);
2281     if (!ldata->pVars)
2282     {
2283         IDispatch_Release(dispatch);
2284         hr = E_OUTOFMEMORY;
2285         goto done;
2286     }
2287
2288     ldata->ulCount = idx;
2289     for (idx = 0; idx < ldata->ulCount; idx++)
2290     {
2291         ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, product);
2292         if (ret != ERROR_SUCCESS)
2293         {
2294             cleanup_products(dispatch, idx - 1);
2295             hr = DISP_E_EXCEPTION;
2296             goto done;
2297         }
2298
2299         VariantInit(&ldata->pVars[idx]);
2300         V_VT(&ldata->pVars[idx]) = VT_BSTR;
2301         V_BSTR(&ldata->pVars[idx]) = SysAllocString(product);
2302     }
2303
2304     hr = S_OK;
2305
2306 done:
2307     VariantClear(&varg0);
2308     return hr;
2309 }
2310
2311 static HRESULT InstallerImpl_Invoke(
2312         AutomationObject* This,
2313         DISPID dispIdMember,
2314         REFIID riid,
2315         LCID lcid,
2316         WORD wFlags,
2317         DISPPARAMS* pDispParams,
2318         VARIANT* pVarResult,
2319         EXCEPINFO* pExcepInfo,
2320         UINT* puArgErr)
2321 {
2322     switch (dispIdMember)
2323     {
2324         case DISPID_INSTALLER_CREATERECORD:
2325             return InstallerImpl_CreateRecord(wFlags, pDispParams,
2326                                               pVarResult, pExcepInfo, puArgErr);
2327
2328         case DISPID_INSTALLER_OPENPACKAGE:
2329             return InstallerImpl_OpenPackage(This, wFlags, pDispParams,
2330                                              pVarResult, pExcepInfo, puArgErr);
2331
2332         case DISPID_INSTALLER_OPENPRODUCT:
2333             return InstallerImpl_OpenProduct(wFlags, pDispParams,
2334                                              pVarResult, pExcepInfo, puArgErr);
2335
2336         case DISPID_INSTALLER_OPENDATABASE:
2337             return InstallerImpl_OpenDatabase(wFlags, pDispParams,
2338                                               pVarResult, pExcepInfo, puArgErr);
2339
2340         case DISPID_INSTALLER_SUMMARYINFORMATION:
2341             return InstallerImpl_SummaryInformation(wFlags, pDispParams,
2342                                                     pVarResult, pExcepInfo,
2343                                                     puArgErr);
2344
2345         case DISPID_INSTALLER_UILEVEL:
2346             return InstallerImpl_UILevel(wFlags, pDispParams,
2347                                          pVarResult, pExcepInfo, puArgErr);
2348
2349         case DISPID_INSTALLER_ENABLELOG:
2350             return InstallerImpl_EnableLog(wFlags, pDispParams,
2351                                            pVarResult, pExcepInfo, puArgErr);
2352
2353         case DISPID_INSTALLER_INSTALLPRODUCT:
2354             return InstallerImpl_InstallProduct(wFlags, pDispParams,
2355                                                 pVarResult, pExcepInfo,
2356                                                 puArgErr);
2357
2358         case DISPID_INSTALLER_VERSION:
2359             return InstallerImpl_Version(wFlags, pVarResult,
2360                                          pExcepInfo, puArgErr);
2361
2362         case DISPID_INSTALLER_LASTERRORRECORD:
2363             return InstallerImpl_LastErrorRecord(wFlags, pDispParams,
2364                                                  pVarResult, pExcepInfo,
2365                                                  puArgErr);
2366
2367         case DISPID_INSTALLER_REGISTRYVALUE:
2368             return InstallerImpl_RegistryValue(wFlags, pDispParams,
2369                                                pVarResult, pExcepInfo,
2370                                                puArgErr);
2371
2372         case DISPID_INSTALLER_ENVIRONMENT:
2373             return InstallerImpl_Environment(wFlags, pDispParams,
2374                                              pVarResult, pExcepInfo, puArgErr);
2375
2376         case DISPID_INSTALLER_FILEATTRIBUTES:
2377             return InstallerImpl_FileAttributes(wFlags, pDispParams,
2378                                                 pVarResult, pExcepInfo,
2379                                                 puArgErr);
2380
2381         case DISPID_INSTALLER_FILESIZE:
2382             return InstallerImpl_FileSize(wFlags, pDispParams,
2383                                           pVarResult, pExcepInfo, puArgErr);
2384
2385         case DISPID_INSTALLER_FILEVERSION:
2386             return InstallerImpl_FileVersion(wFlags, pDispParams,
2387                                              pVarResult, pExcepInfo, puArgErr);
2388
2389         case DISPID_INSTALLER_PRODUCTSTATE:
2390             return InstallerImpl_ProductState(wFlags, pDispParams,
2391                                               pVarResult, pExcepInfo, puArgErr);
2392
2393         case DISPID_INSTALLER_PRODUCTINFO:
2394             return InstallerImpl_ProductInfo(wFlags, pDispParams,
2395                                              pVarResult, pExcepInfo, puArgErr);
2396
2397         case DISPID_INSTALLER_PRODUCTS:
2398             return InstallerImpl_Products(wFlags, pDispParams,
2399                                           pVarResult, pExcepInfo, puArgErr);
2400
2401         case DISPID_INSTALLER_RELATEDPRODUCTS:
2402             return InstallerImpl_RelatedProducts(wFlags, pDispParams,
2403                                                  pVarResult, pExcepInfo,
2404                                                  puArgErr);
2405
2406         default:
2407             return DISP_E_MEMBERNOTFOUND;
2408     }
2409 }
2410
2411 /* Wrapper around create_automation_object to create an installer object. */
2412 HRESULT create_msiserver(IUnknown *pOuter, LPVOID *ppObj)
2413 {
2414     return create_automation_object(0, pOuter, ppObj, &DIID_Installer, InstallerImpl_Invoke, NULL, 0);
2415 }
2416
2417 /* Wrapper around create_automation_object to create a session object. */
2418 HRESULT create_session(MSIHANDLE msiHandle, IDispatch *pInstaller, IDispatch **pDispatch)
2419 {
2420     HRESULT hr = create_automation_object(msiHandle, NULL, (LPVOID)pDispatch, &DIID_Session, SessionImpl_Invoke, NULL, sizeof(SessionData));
2421     if (SUCCEEDED(hr) && pDispatch && *pDispatch)
2422         ((SessionData *)private_data((AutomationObject *)*pDispatch))->pInstaller = pInstaller;
2423     return hr;
2424 }