msi: Refactor the Installer.ProductInfo method into InstallerImpl_ProductInfo.
[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 interface AutomationObject AutomationObject;
51
52 interface 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 (STDMETHODCALLTYPE *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 (STDMETHODCALLTYPE *funcFree)(AutomationObject* This);
84 };
85
86 /*
87  * ListEnumerator - IEnumVARIANT implementation for MSI automation lists.
88  */
89
90 typedef interface ListEnumerator ListEnumerator;
91
92 interface ListEnumerator {
93     /* VTables */
94     const IEnumVARIANTVtbl *lpVtbl;
95
96     /* Object reference count */
97     LONG ref;
98
99     /* Current position and pointer to AutomationObject that stores actual data */
100     ULONG ulPos;
101     AutomationObject *pObj;
102 };
103
104 /*
105  * Structures for additional data required by specific automation objects
106  */
107
108 typedef struct {
109     ULONG ulCount;
110     VARIANT *pVars;
111 } ListData;
112
113 typedef struct {
114     /* The parent Installer object */
115     IDispatch *pInstaller;
116 } SessionData;
117
118 /* VTables */
119 static const struct IDispatchVtbl AutomationObject_Vtbl;
120 static const struct IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl;
121 static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl;
122
123 /* Load type info so we don't have to process GetIDsOfNames */
124 HRESULT load_type_info(IDispatch *iface, ITypeInfo **pptinfo, REFIID clsid, LCID lcid)
125 {
126     HRESULT hr;
127     LPTYPELIB pLib = NULL;
128     LPTYPEINFO pInfo = NULL;
129     static const WCHAR szMsiServer[] = {'m','s','i','s','e','r','v','e','r','.','t','l','b'};
130
131     TRACE("(%p)->(%s,%d)\n", iface, debugstr_guid(clsid), lcid);
132
133     /* Load registered type library */
134     hr = LoadRegTypeLib(&LIBID_WindowsInstaller, 1, 0, lcid, &pLib);
135     if (FAILED(hr)) {
136         hr = LoadTypeLib(szMsiServer, &pLib);
137         if (FAILED(hr)) {
138             ERR("Could not load msiserver.tlb\n");
139             return hr;
140         }
141     }
142
143     /* Get type information for object */
144     hr = ITypeLib_GetTypeInfoOfGuid(pLib, clsid, &pInfo);
145     ITypeLib_Release(pLib);
146     if (FAILED(hr)) {
147         ERR("Could not load ITypeInfo for %s\n", debugstr_guid(clsid));
148         return hr;
149     }
150     *pptinfo = pInfo;
151     return S_OK;
152 }
153
154 /* Create the automation object, placing the result in the pointer ppObj. The automation object is created
155  * with the appropriate clsid and invocation function. */
156 static HRESULT create_automation_object(MSIHANDLE msiHandle, IUnknown *pUnkOuter, LPVOID *ppObj, REFIID clsid,
157             HRESULT (STDMETHODCALLTYPE *funcInvoke)(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,
158                                                     VARIANT*,EXCEPINFO*,UINT*),
159                                  void (STDMETHODCALLTYPE *funcFree)(AutomationObject*),
160                                  SIZE_T sizetPrivateData)
161 {
162     AutomationObject *object;
163     HRESULT hr;
164
165     TRACE("(%d,%p,%p,%s,%p,%p,%ld)\n", msiHandle, pUnkOuter, ppObj, debugstr_guid(clsid), funcInvoke, funcFree, sizetPrivateData);
166
167     if( pUnkOuter )
168         return CLASS_E_NOAGGREGATION;
169
170     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AutomationObject)+sizetPrivateData);
171
172     /* Set all the VTable references */
173     object->lpVtbl = &AutomationObject_Vtbl;
174     object->lpvtblIProvideMultipleClassInfo = &AutomationObject_IProvideMultipleClassInfo_Vtbl;
175     object->ref = 1;
176
177     /* Store data that was passed */
178     object->msiHandle = msiHandle;
179     object->clsid = (LPCLSID)clsid;
180     object->funcInvoke = funcInvoke;
181     object->funcFree = funcFree;
182
183     /* Load our TypeInfo so we don't have to process GetIDsOfNames */
184     object->iTypeInfo = NULL;
185     hr = load_type_info((IDispatch *)object, &object->iTypeInfo, clsid, 0x0);
186     if (FAILED(hr)) {
187         HeapFree(GetProcessHeap(), 0, object);
188         return hr;
189     }
190
191     *ppObj = object;
192
193     return S_OK;
194 }
195
196 /* Create a list enumerator, placing the result in the pointer ppObj.  */
197 static HRESULT create_list_enumerator(IUnknown *pUnkOuter, LPVOID *ppObj, AutomationObject *pObj, ULONG ulPos)
198 {
199     ListEnumerator *object;
200
201     TRACE("(%p,%p,%p,%uld)\n", pUnkOuter, ppObj, pObj, ulPos);
202
203     if( pUnkOuter )
204         return CLASS_E_NOAGGREGATION;
205
206     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ListEnumerator));
207
208     /* Set all the VTable references */
209     object->lpVtbl = &ListEnumerator_Vtbl;
210     object->ref = 1;
211
212     /* Store data that was passed */
213     object->ulPos = ulPos;
214     object->pObj = pObj;
215     if (pObj) IDispatch_AddRef((IDispatch *)pObj);
216
217     *ppObj = object;
218     return S_OK;
219 }
220
221 /* Macros to get pointer to AutomationObject from the other VTables. */
222 static inline AutomationObject *obj_from_IProvideMultipleClassInfo( IProvideMultipleClassInfo *iface )
223 {
224     return (AutomationObject *)((char*)iface - FIELD_OFFSET(AutomationObject, lpvtblIProvideMultipleClassInfo));
225 }
226
227 /* Macro to get pointer to private object data */
228 static inline void *private_data( AutomationObject *This )
229 {
230     return This + 1;
231 }
232
233 /*
234  * AutomationObject methods
235  */
236
237 /*** IUnknown methods ***/
238 static HRESULT WINAPI AutomationObject_QueryInterface(IDispatch* iface, REFIID riid, void** ppvObject)
239 {
240     AutomationObject *This = (AutomationObject *)iface;
241
242     TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
243
244     if (ppvObject == NULL)
245       return E_INVALIDARG;
246
247     *ppvObject = 0;
248
249     if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDispatch) || IsEqualGUID(riid, This->clsid))
250         *ppvObject = This;
251     else if (IsEqualGUID(riid, &IID_IProvideClassInfo) ||
252              IsEqualGUID(riid, &IID_IProvideClassInfo2) ||
253              IsEqualGUID(riid, &IID_IProvideMultipleClassInfo))
254         *ppvObject = &This->lpvtblIProvideMultipleClassInfo;
255     else
256     {
257         TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid));
258         return E_NOINTERFACE;
259     }
260
261     /*
262      * Query Interface always increases the reference count by one when it is
263      * successful
264      */
265     IClassFactory_AddRef(iface);
266
267     return S_OK;
268 }
269
270 static ULONG WINAPI AutomationObject_AddRef(IDispatch* iface)
271 {
272     AutomationObject *This = (AutomationObject *)iface;
273
274     TRACE("(%p/%p)\n", iface, This);
275
276     return InterlockedIncrement(&This->ref);
277 }
278
279 static ULONG WINAPI AutomationObject_Release(IDispatch* iface)
280 {
281     AutomationObject *This = (AutomationObject *)iface;
282     ULONG ref = InterlockedDecrement(&This->ref);
283
284     TRACE("(%p/%p)\n", iface, This);
285
286     if (!ref)
287     {
288         if (This->funcFree) This->funcFree(This);
289         ITypeInfo_Release(This->iTypeInfo);
290         MsiCloseHandle(This->msiHandle);
291         HeapFree(GetProcessHeap(), 0, This);
292     }
293
294     return ref;
295 }
296
297 /*** IDispatch methods ***/
298 static HRESULT WINAPI AutomationObject_GetTypeInfoCount(
299         IDispatch* iface,
300         UINT* pctinfo)
301 {
302     AutomationObject *This = (AutomationObject *)iface;
303
304     TRACE("(%p/%p)->(%p)\n", iface, This, pctinfo);
305     *pctinfo = 1;
306     return S_OK;
307 }
308
309 static HRESULT WINAPI AutomationObject_GetTypeInfo(
310         IDispatch* iface,
311         UINT iTInfo,
312         LCID lcid,
313         ITypeInfo** ppTInfo)
314 {
315     AutomationObject *This = (AutomationObject *)iface;
316     TRACE("(%p/%p)->(%d,%d,%p)\n", iface, This, iTInfo, lcid, ppTInfo);
317
318     ITypeInfo_AddRef(This->iTypeInfo);
319     *ppTInfo = This->iTypeInfo;
320     return S_OK;
321 }
322
323 static HRESULT WINAPI AutomationObject_GetIDsOfNames(
324         IDispatch* iface,
325         REFIID riid,
326         LPOLESTR* rgszNames,
327         UINT cNames,
328         LCID lcid,
329         DISPID* rgDispId)
330 {
331     AutomationObject *This = (AutomationObject *)iface;
332     HRESULT hr;
333     TRACE("(%p/%p)->(%p,%p,%d,%d,%p)\n", iface, This, riid, rgszNames, cNames, lcid, rgDispId);
334
335     if (!IsEqualGUID(riid, &IID_NULL)) return E_INVALIDARG;
336     hr = ITypeInfo_GetIDsOfNames(This->iTypeInfo, rgszNames, cNames, rgDispId);
337     if (hr == DISP_E_UNKNOWNNAME)
338     {
339         UINT idx;
340         for (idx=0; idx<cNames; idx++)
341         {
342             if (rgDispId[idx] == DISPID_UNKNOWN)
343                 FIXME("Unknown member %s, clsid %s\n", debugstr_w(rgszNames[idx]), debugstr_guid(This->clsid));
344         }
345     }
346     return hr;
347 }
348
349 /* Maximum number of allowed function parameters+1 */
350 #define MAX_FUNC_PARAMS 20
351
352 /* Some error checking is done here to simplify individual object function invocation */
353 static HRESULT WINAPI AutomationObject_Invoke(
354         IDispatch* iface,
355         DISPID dispIdMember,
356         REFIID riid,
357         LCID lcid,
358         WORD wFlags,
359         DISPPARAMS* pDispParams,
360         VARIANT* pVarResult,
361         EXCEPINFO* pExcepInfo,
362         UINT* puArgErr)
363 {
364     AutomationObject *This = (AutomationObject *)iface;
365     HRESULT hr;
366     unsigned int uArgErr;
367     VARIANT varResultDummy;
368     BSTR bstrName = NULL;
369
370     TRACE("(%p/%p)->(%d,%p,%d,%d,%p,%p,%p,%p)\n", iface, This, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
371
372     if (!IsEqualIID(riid, &IID_NULL))
373     {
374         ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
375         return DISP_E_UNKNOWNNAME;
376     }
377
378     if (wFlags & DISPATCH_PROPERTYGET && !pVarResult)
379     {
380         ERR("NULL pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
381         return DISP_E_PARAMNOTOPTIONAL;
382     }
383
384     /* This simplifies our individual object invocation functions */
385     if (puArgErr == NULL) puArgErr = &uArgErr;
386     if (pVarResult == NULL) pVarResult = &varResultDummy;
387
388     /* Assume return type is void unless determined otherwise */
389     VariantInit(pVarResult);
390
391     /* If we are tracing, we want to see the name of the member we are invoking */
392     if (TRACE_ON(msi))
393     {
394         ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL);
395         TRACE("Method %d, %s\n", dispIdMember, debugstr_w(bstrName));
396     }
397
398     hr = This->funcInvoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
399
400     if (hr == DISP_E_MEMBERNOTFOUND) {
401         if (bstrName == NULL) ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL);
402         FIXME("Method %d, %s wflags %d not implemented, clsid %s\n", dispIdMember, debugstr_w(bstrName), wFlags, debugstr_guid(This->clsid));
403     }
404     else if (pExcepInfo &&
405              (hr == DISP_E_PARAMNOTFOUND ||
406               hr == DISP_E_EXCEPTION)) {
407         static const WCHAR szComma[] = { ',',0 };
408         static const WCHAR szExceptionSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
409         WCHAR szExceptionDescription[MAX_PATH];
410         BSTR bstrParamNames[MAX_FUNC_PARAMS];
411         unsigned namesNo, i;
412         BOOL bFirst = TRUE;
413
414         if (FAILED(ITypeInfo_GetNames(This->iTypeInfo, dispIdMember, bstrParamNames,
415                                       MAX_FUNC_PARAMS, &namesNo)))
416         {
417             TRACE("Failed to retrieve names for dispIdMember %d\n", dispIdMember);
418         }
419         else
420         {
421             memset(szExceptionDescription, 0, sizeof(szExceptionDescription));
422             for (i=0; i<namesNo; i++)
423             {
424                 if (bFirst) bFirst = FALSE;
425                 else {
426                     lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], szComma);
427                 }
428                 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], bstrParamNames[i]);
429                 SysFreeString(bstrParamNames[i]);
430             }
431
432             memset(pExcepInfo, 0, sizeof(EXCEPINFO));
433             pExcepInfo->wCode = 1000;
434             pExcepInfo->bstrSource = SysAllocString(szExceptionSource);
435             pExcepInfo->bstrDescription = SysAllocString(szExceptionDescription);
436             hr = DISP_E_EXCEPTION;
437         }
438     }
439
440     /* Make sure we free the return variant if it is our dummy variant */
441     if (pVarResult == &varResultDummy) VariantClear(pVarResult);
442
443     /* Free function name if we retrieved it */
444     SysFreeString(bstrName);
445
446     TRACE("Returning 0x%08x, %s\n", hr, SUCCEEDED(hr) ? "ok" : "not ok");
447
448     return hr;
449 }
450
451 static const struct IDispatchVtbl AutomationObject_Vtbl =
452 {
453     AutomationObject_QueryInterface,
454     AutomationObject_AddRef,
455     AutomationObject_Release,
456     AutomationObject_GetTypeInfoCount,
457     AutomationObject_GetTypeInfo,
458     AutomationObject_GetIDsOfNames,
459     AutomationObject_Invoke
460 };
461
462 /*
463  * IProvideMultipleClassInfo methods
464  */
465
466 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_QueryInterface(
467   IProvideMultipleClassInfo* iface,
468   REFIID     riid,
469   VOID**     ppvoid)
470 {
471     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
472     return AutomationObject_QueryInterface((IDispatch *)This, riid, ppvoid);
473 }
474
475 static ULONG WINAPI AutomationObject_IProvideMultipleClassInfo_AddRef(IProvideMultipleClassInfo* iface)
476 {
477     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
478     return AutomationObject_AddRef((IDispatch *)This);
479 }
480
481 static ULONG WINAPI AutomationObject_IProvideMultipleClassInfo_Release(IProvideMultipleClassInfo* iface)
482 {
483     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
484     return AutomationObject_Release((IDispatch *)This);
485 }
486
487 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_GetClassInfo(IProvideMultipleClassInfo* iface, ITypeInfo** ppTI)
488 {
489     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
490     TRACE("(%p/%p)->(%p)\n", iface, This, ppTI);
491     return load_type_info((IDispatch *)This, ppTI, This->clsid, 0);
492 }
493
494 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_GetGUID(IProvideMultipleClassInfo* iface, DWORD dwGuidKind, GUID* pGUID)
495 {
496     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
497     TRACE("(%p/%p)->(%d,%s)\n", iface, This, dwGuidKind, debugstr_guid(pGUID));
498
499     if (dwGuidKind != GUIDKIND_DEFAULT_SOURCE_DISP_IID)
500         return E_INVALIDARG;
501     else {
502         *pGUID = *This->clsid;
503         return S_OK;
504     }
505 }
506
507 static HRESULT WINAPI AutomationObject_GetMultiTypeInfoCount(IProvideMultipleClassInfo* iface, ULONG* pcti)
508 {
509     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
510
511     TRACE("(%p/%p)->(%p)\n", iface, This, pcti);
512     *pcti = 1;
513     return S_OK;
514 }
515
516 static HRESULT WINAPI AutomationObject_GetInfoOfIndex(IProvideMultipleClassInfo* iface,
517         ULONG iti,
518         DWORD dwFlags,
519         ITypeInfo** pptiCoClass,
520         DWORD* pdwTIFlags,
521         ULONG* pcdispidReserved,
522         IID* piidPrimary,
523         IID* piidSource)
524 {
525     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
526
527     TRACE("(%p/%p)->(%d,%d,%p,%p,%p,%p,%p)\n", iface, This, iti, dwFlags, pptiCoClass, pdwTIFlags, pcdispidReserved, piidPrimary, piidSource);
528
529     if (iti != 0)
530         return E_INVALIDARG;
531
532     if (dwFlags & MULTICLASSINFO_GETTYPEINFO)
533         load_type_info((IDispatch *)This, pptiCoClass, This->clsid, 0);
534
535     if (dwFlags & MULTICLASSINFO_GETNUMRESERVEDDISPIDS)
536     {
537         *pdwTIFlags = 0;
538         *pcdispidReserved = 0;
539     }
540
541     if (dwFlags & MULTICLASSINFO_GETIIDPRIMARY){
542         *piidPrimary = *This->clsid;
543     }
544
545     if (dwFlags & MULTICLASSINFO_GETIIDSOURCE){
546         *piidSource = *This->clsid;
547     }
548
549     return S_OK;
550 }
551
552 static const IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl =
553 {
554     AutomationObject_IProvideMultipleClassInfo_QueryInterface,
555     AutomationObject_IProvideMultipleClassInfo_AddRef,
556     AutomationObject_IProvideMultipleClassInfo_Release,
557     AutomationObject_IProvideMultipleClassInfo_GetClassInfo,
558     AutomationObject_IProvideMultipleClassInfo_GetGUID,
559     AutomationObject_GetMultiTypeInfoCount,
560     AutomationObject_GetInfoOfIndex
561 };
562
563 /*
564  * ListEnumerator methods
565  */
566
567 /*** IUnknown methods ***/
568 static HRESULT WINAPI ListEnumerator_QueryInterface(IEnumVARIANT* iface, REFIID riid, void** ppvObject)
569 {
570     ListEnumerator *This = (ListEnumerator *)iface;
571
572     TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
573
574     if (ppvObject == NULL)
575       return E_INVALIDARG;
576
577     *ppvObject = 0;
578
579     if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IEnumVARIANT))
580         *ppvObject = This;
581     else
582     {
583         TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid));
584         return E_NOINTERFACE;
585     }
586
587     IClassFactory_AddRef(iface);
588     return S_OK;
589 }
590
591 static ULONG WINAPI ListEnumerator_AddRef(IEnumVARIANT* iface)
592 {
593     ListEnumerator *This = (ListEnumerator *)iface;
594
595     TRACE("(%p/%p)\n", iface, This);
596
597     return InterlockedIncrement(&This->ref);
598 }
599
600 static ULONG WINAPI ListEnumerator_Release(IEnumVARIANT* iface)
601 {
602     ListEnumerator *This = (ListEnumerator *)iface;
603     ULONG ref = InterlockedDecrement(&This->ref);
604
605     TRACE("(%p/%p)\n", iface, This);
606
607     if (!ref)
608     {
609         if (This->pObj) IDispatch_Release((IDispatch *)This->pObj);
610         HeapFree(GetProcessHeap(), 0, This);
611     }
612
613     return ref;
614 }
615
616 /* IEnumVARIANT methods */
617
618 static HRESULT WINAPI ListEnumerator_Next(IEnumVARIANT* iface, ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched)
619 {
620     ListEnumerator *This = (ListEnumerator *)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 = (ListEnumerator *)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 = (ListEnumerator *)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 = (ListEnumerator *)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 WINAPI 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 WINAPI 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 WINAPI 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 WINAPI 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     HeapFree(GetProcessHeap(), 0, data->pVars);
1047 }
1048
1049 static HRESULT WINAPI 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 WINAPI DatabaseImpl_Invoke(
1142         AutomationObject* This,
1143         DISPID dispIdMember,
1144         REFIID riid,
1145         LCID lcid,
1146         WORD wFlags,
1147         DISPPARAMS* pDispParams,
1148         VARIANT* pVarResult,
1149         EXCEPINFO* pExcepInfo,
1150         UINT* puArgErr)
1151 {
1152     MSIHANDLE msiHandle;
1153     IDispatch *pDispatch = NULL;
1154     UINT ret;
1155     VARIANTARG varg0, varg1;
1156     HRESULT hr;
1157
1158     VariantInit(&varg0);
1159     VariantInit(&varg1);
1160
1161     switch (dispIdMember)
1162     {
1163         case DISPID_DATABASE_SUMMARYINFORMATION:
1164             if (wFlags & DISPATCH_PROPERTYGET)
1165             {
1166                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1167                 if (FAILED(hr))
1168                     V_I4(&varg0) = 0;
1169
1170                 V_VT(pVarResult) = VT_DISPATCH;
1171                 if ((ret = MsiGetSummaryInformationW(This->msiHandle, NULL, V_I4(&varg0), &msiHandle)) == ERROR_SUCCESS)
1172                 {
1173                     hr = create_automation_object(msiHandle, NULL, (LPVOID *)&pDispatch, &DIID_SummaryInfo, SummaryInfoImpl_Invoke, NULL, 0);
1174                     if (SUCCEEDED(hr))
1175                         V_DISPATCH(pVarResult) = pDispatch;
1176                     else
1177                         ERR("Failed to create SummaryInfo object: 0x%08x\n", hr);
1178                 }
1179                 else
1180                 {
1181                     ERR("MsiGetSummaryInformation returned %d\n", ret);
1182                     return DISP_E_EXCEPTION;
1183                 }
1184             }
1185             else return DISP_E_MEMBERNOTFOUND;
1186             break;
1187
1188         case DISPID_DATABASE_OPENVIEW:
1189             if (wFlags & DISPATCH_METHOD)
1190             {
1191                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1192                 if (FAILED(hr)) return hr;
1193                 V_VT(pVarResult) = VT_DISPATCH;
1194                 if ((ret = MsiDatabaseOpenViewW(This->msiHandle, V_BSTR(&varg0), &msiHandle)) == ERROR_SUCCESS)
1195                 {
1196                     if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_View, ViewImpl_Invoke, NULL, 0)))
1197                         V_DISPATCH(pVarResult) = pDispatch;
1198                     else
1199                         ERR("Failed to create View object, hresult 0x%08x\n", hr);
1200                 }
1201                 else
1202                 {
1203                     VariantClear(&varg0);
1204                     ERR("MsiDatabaseOpenView returned %d\n", ret);
1205                     return DISP_E_EXCEPTION;
1206                 }
1207             }
1208             else return DISP_E_MEMBERNOTFOUND;
1209             break;
1210
1211          default:
1212             return DISP_E_MEMBERNOTFOUND;
1213     }
1214
1215     VariantClear(&varg1);
1216     VariantClear(&varg0);
1217
1218     return S_OK;
1219 }
1220
1221 static HRESULT WINAPI SessionImpl_Invoke(
1222         AutomationObject* This,
1223         DISPID dispIdMember,
1224         REFIID riid,
1225         LCID lcid,
1226         WORD wFlags,
1227         DISPPARAMS* pDispParams,
1228         VARIANT* pVarResult,
1229         EXCEPINFO* pExcepInfo,
1230         UINT* puArgErr)
1231 {
1232     SessionData *data = private_data(This);
1233     WCHAR *szString;
1234     DWORD dwLen;
1235     IDispatch *pDispatch = NULL;
1236     MSIHANDLE msiHandle;
1237     LANGID langId;
1238     UINT ret;
1239     INSTALLSTATE iInstalled, iAction;
1240     VARIANTARG varg0, varg1;
1241     HRESULT hr;
1242
1243     VariantInit(&varg0);
1244     VariantInit(&varg1);
1245
1246     switch (dispIdMember)
1247     {
1248         case DISPID_SESSION_INSTALLER:
1249             if (wFlags & DISPATCH_PROPERTYGET) {
1250                 V_VT(pVarResult) = VT_DISPATCH;
1251                 IDispatch_AddRef(data->pInstaller);
1252                 V_DISPATCH(pVarResult) = data->pInstaller;
1253             }
1254             else return DISP_E_MEMBERNOTFOUND;
1255             break;
1256
1257         case DISPID_SESSION_PROPERTY:
1258             if (wFlags & DISPATCH_PROPERTYGET) {
1259                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1260                 if (FAILED(hr)) return hr;
1261                 V_VT(pVarResult) = VT_BSTR;
1262                 V_BSTR(pVarResult) = NULL;
1263                 if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
1264                 {
1265                     if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
1266                         ERR("Out of memory\n");
1267                     else if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
1268                         V_BSTR(pVarResult) = SysAllocString(szString);
1269                     msi_free(szString);
1270                 }
1271                 if (ret != ERROR_SUCCESS)
1272                     ERR("MsiGetProperty returned %d\n", ret);
1273             } else if (wFlags & DISPATCH_PROPERTYPUT) {
1274                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1275                 if (FAILED(hr)) return hr;
1276                 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BSTR, &varg1, puArgErr);
1277                 if (FAILED(hr)) {
1278                     VariantClear(&varg0);
1279                     return hr;
1280                 }
1281                 if ((ret = MsiSetPropertyW(This->msiHandle, V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
1282                 {
1283                     VariantClear(&varg0);
1284                     VariantClear(&varg1);
1285                     ERR("MsiSetProperty returned %d\n", ret);
1286                     return DISP_E_EXCEPTION;
1287                 }
1288             }
1289             else return DISP_E_MEMBERNOTFOUND;
1290             break;
1291
1292         case DISPID_SESSION_LANGUAGE:
1293             if (wFlags & DISPATCH_PROPERTYGET) {
1294                 langId = MsiGetLanguage(This->msiHandle);
1295                 V_VT(pVarResult) = VT_I4;
1296                 V_I4(pVarResult) = langId;
1297             }
1298             else return DISP_E_MEMBERNOTFOUND;
1299             break;
1300
1301         case DISPID_SESSION_MODE:
1302             if (wFlags & DISPATCH_PROPERTYGET) {
1303                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1304                 if (FAILED(hr)) return hr;
1305                 V_VT(pVarResult) = VT_BOOL;
1306                 V_BOOL(pVarResult) = MsiGetMode(This->msiHandle, V_I4(&varg0));
1307             } else if (wFlags & DISPATCH_PROPERTYPUT) {
1308                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1309                 if (FAILED(hr)) return hr;
1310                 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BOOL, &varg1, puArgErr);
1311                 if (FAILED(hr)) return hr;
1312                 if ((ret = MsiSetMode(This->msiHandle, V_I4(&varg0), V_BOOL(&varg1))) != ERROR_SUCCESS)
1313                 {
1314                     ERR("MsiSetMode returned %d\n", ret);
1315                     return DISP_E_EXCEPTION;
1316                 }
1317             }
1318             else return DISP_E_MEMBERNOTFOUND;
1319             break;
1320
1321         case DISPID_SESSION_DATABASE:
1322             if (wFlags & DISPATCH_PROPERTYGET) {
1323                 V_VT(pVarResult) = VT_DISPATCH;
1324                 if ((msiHandle = MsiGetActiveDatabase(This->msiHandle)))
1325                 {
1326                     if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Database, DatabaseImpl_Invoke, NULL, 0)))
1327                         V_DISPATCH(pVarResult) = pDispatch;
1328                     else
1329                         ERR("Failed to create Database object, hresult 0x%08x\n", hr);
1330                 }
1331                 else
1332                 {
1333                     ERR("MsiGetActiveDatabase failed\n");
1334                     return DISP_E_EXCEPTION;
1335                 }
1336             }
1337             else return DISP_E_MEMBERNOTFOUND;
1338             break;
1339
1340         case DISPID_SESSION_DOACTION:
1341             if (wFlags & DISPATCH_METHOD) {
1342                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1343                 if (FAILED(hr)) return hr;
1344                 ret = MsiDoActionW(This->msiHandle, V_BSTR(&varg0));
1345                 V_VT(pVarResult) = VT_I4;
1346                 switch (ret)
1347                 {
1348                     case ERROR_FUNCTION_NOT_CALLED:
1349                         V_I4(pVarResult) = msiDoActionStatusNoAction;
1350                         break;
1351                     case ERROR_SUCCESS:
1352                         V_I4(pVarResult) = msiDoActionStatusSuccess;
1353                         break;
1354                     case ERROR_INSTALL_USEREXIT:
1355                         V_I4(pVarResult) = msiDoActionStatusUserExit;
1356                         break;
1357                     case ERROR_INSTALL_FAILURE:
1358                         V_I4(pVarResult) = msiDoActionStatusFailure;
1359                         break;
1360                     case ERROR_INSTALL_SUSPEND:
1361                         V_I4(pVarResult) = msiDoActionStatusSuspend;
1362                         break;
1363                     case ERROR_MORE_DATA:
1364                         V_I4(pVarResult) = msiDoActionStatusFinished;
1365                         break;
1366                     case ERROR_INVALID_HANDLE_STATE:
1367                         V_I4(pVarResult) = msiDoActionStatusWrongState;
1368                         break;
1369                     case ERROR_INVALID_DATA:
1370                         V_I4(pVarResult) = msiDoActionStatusBadActionData;
1371                         break;
1372                     default:
1373                         VariantClear(&varg0);
1374                         FIXME("MsiDoAction returned unhandled value %d\n", ret);
1375                         return DISP_E_EXCEPTION;
1376                 }
1377             }
1378             else return DISP_E_MEMBERNOTFOUND;
1379             break;
1380
1381         case DISPID_SESSION_EVALUATECONDITION:
1382             if (wFlags & DISPATCH_METHOD) {
1383                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1384                 if (FAILED(hr)) return hr;
1385                 V_VT(pVarResult) = VT_I4;
1386                 V_I4(pVarResult) = MsiEvaluateConditionW(This->msiHandle, V_BSTR(&varg0));
1387             }
1388             else return DISP_E_MEMBERNOTFOUND;
1389             break;
1390
1391         case DISPID_SESSION_MESSAGE:
1392             if(!(wFlags & DISPATCH_METHOD))
1393                 return DISP_E_MEMBERNOTFOUND;
1394
1395             hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1396             if (FAILED(hr)) return hr;
1397             hr = DispGetParam(pDispParams, 1, VT_DISPATCH, &varg1, puArgErr);
1398             if (FAILED(hr)) return hr;
1399
1400             V_VT(pVarResult) = VT_I4;
1401             V_I4(pVarResult) =
1402                 MsiProcessMessage(This->msiHandle, V_I4(&varg0), ((AutomationObject *)V_DISPATCH(&varg1))->msiHandle);
1403             break;
1404
1405         case DISPID_SESSION_SETINSTALLLEVEL:
1406             if (wFlags & DISPATCH_METHOD) {
1407                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1408                 if (FAILED(hr)) return hr;
1409                 if ((ret = MsiSetInstallLevel(This->msiHandle, V_I4(&varg0))) != ERROR_SUCCESS)
1410                 {
1411                     ERR("MsiSetInstallLevel returned %d\n", ret);
1412                     return DISP_E_EXCEPTION;
1413                 }
1414             }
1415             else return DISP_E_MEMBERNOTFOUND;
1416             break;
1417
1418         case DISPID_SESSION_FEATURECURRENTSTATE:
1419             if (wFlags & DISPATCH_PROPERTYGET) {
1420                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1421                 if (FAILED(hr)) return hr;
1422                 V_VT(pVarResult) = VT_I4;
1423                 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1424                     V_I4(pVarResult) = iInstalled;
1425                 else
1426                 {
1427                     ERR("MsiGetFeatureState returned %d\n", ret);
1428                     V_I4(pVarResult) = msiInstallStateUnknown;
1429                 }
1430             }
1431             else return DISP_E_MEMBERNOTFOUND;
1432             break;
1433
1434         case DISPID_SESSION_FEATUREREQUESTSTATE:
1435             if (wFlags & DISPATCH_PROPERTYGET) {
1436                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1437                 if (FAILED(hr)) return hr;
1438                 V_VT(pVarResult) = VT_I4;
1439                 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1440                     V_I4(pVarResult) = iAction;
1441                 else
1442                 {
1443                     ERR("MsiGetFeatureState returned %d\n", ret);
1444                     V_I4(pVarResult) = msiInstallStateUnknown;
1445                 }
1446             } else if (wFlags & DISPATCH_PROPERTYPUT) {
1447                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1448                 if (FAILED(hr)) return hr;
1449                 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_I4, &varg1, puArgErr);
1450                 if (FAILED(hr)) {
1451                     VariantClear(&varg0);
1452                     return hr;
1453                 }
1454                 if ((ret = MsiSetFeatureStateW(This->msiHandle, V_BSTR(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
1455                 {
1456                     VariantClear(&varg0);
1457                     ERR("MsiSetFeatureState returned %d\n", ret);
1458                     return DISP_E_EXCEPTION;
1459                 }
1460             }
1461             else return DISP_E_MEMBERNOTFOUND;
1462             break;
1463
1464          default:
1465             return DISP_E_MEMBERNOTFOUND;
1466     }
1467
1468     VariantClear(&varg1);
1469     VariantClear(&varg0);
1470
1471     return S_OK;
1472 }
1473
1474 /* Fill the variant pointed to by pVarResult with the value & size returned by RegQueryValueEx as dictated by the
1475  * registry value type. Used by Installer::RegistryValue. */
1476 static void variant_from_registry_value(VARIANT *pVarResult, DWORD dwType, LPBYTE lpData, DWORD dwSize)
1477 {
1478     static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
1479     static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
1480     WCHAR *szString = (WCHAR *)lpData;
1481     LPWSTR szNewString = NULL;
1482     DWORD dwNewSize = 0;
1483     int idx;
1484
1485     switch (dwType)
1486     {
1487         /* Registry strings may not be null terminated so we must use SysAllocStringByteLen/Len */
1488         case REG_MULTI_SZ: /* Multi SZ change internal null characters to newlines */
1489             idx = (dwSize/sizeof(WCHAR))-1;
1490             while (idx >= 0 && !szString[idx]) idx--;
1491             for (; idx >= 0; idx--)
1492                 if (!szString[idx]) szString[idx] = '\n';
1493         case REG_SZ:
1494             V_VT(pVarResult) = VT_BSTR;
1495             V_BSTR(pVarResult) = SysAllocStringByteLen((LPCSTR)szString, dwSize);
1496             break;
1497
1498         case REG_EXPAND_SZ:
1499             if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1500                 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1501             else if (!(szNewString = msi_alloc(dwNewSize * sizeof(WCHAR))))
1502                 ERR("Out of memory\n");
1503             else if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1504                 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1505             else
1506             {
1507                 V_VT(pVarResult) = VT_BSTR;
1508                 V_BSTR(pVarResult) = SysAllocStringLen(szNewString, dwNewSize);
1509             }
1510             msi_free(szNewString);
1511             break;
1512
1513         case REG_DWORD:
1514             V_VT(pVarResult) = VT_I4;
1515             V_I4(pVarResult) = *((DWORD *)lpData);
1516             break;
1517
1518         case REG_QWORD:
1519             V_VT(pVarResult) = VT_BSTR;
1520             V_BSTR(pVarResult) = SysAllocString(szREG_);   /* Weird string, don't know why native returns it */
1521             break;
1522
1523         case REG_BINARY:
1524             V_VT(pVarResult) = VT_BSTR;
1525             V_BSTR(pVarResult) = SysAllocString(szREG_BINARY);
1526             break;
1527
1528         case REG_NONE:
1529             V_VT(pVarResult) = VT_EMPTY;
1530             break;
1531
1532         default:
1533             FIXME("Unhandled registry value type %d\n", dwType);
1534     }
1535 }
1536
1537 static HRESULT InstallerImpl_CreateRecord(WORD wFlags,
1538                                           DISPPARAMS* pDispParams,
1539                                           VARIANT* pVarResult,
1540                                           EXCEPINFO* pExcepInfo,
1541                                           UINT* puArgErr)
1542 {
1543     HRESULT hr;
1544     VARIANTARG varg0;
1545     MSIHANDLE hrec;
1546     IDispatch* dispatch;
1547
1548     if (!(wFlags & DISPATCH_METHOD))
1549         return DISP_E_MEMBERNOTFOUND;
1550
1551     VariantInit(&varg0);
1552     hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1553     if (FAILED(hr))
1554         return hr;
1555
1556     V_VT(pVarResult) = VT_DISPATCH;
1557
1558     hrec = MsiCreateRecord(V_I4(&varg0));
1559     if (!hrec)
1560         return DISP_E_EXCEPTION;
1561
1562     hr = create_automation_object(hrec, NULL, (LPVOID*)&dispatch,
1563                                   &DIID_Record, RecordImpl_Invoke, NULL, 0);
1564     if (SUCCEEDED(hr))
1565         V_DISPATCH(pVarResult) = dispatch;
1566
1567     return hr;
1568 }
1569
1570 static HRESULT InstallerImpl_OpenPackage(AutomationObject* This,
1571                                          WORD wFlags,
1572                                          DISPPARAMS* pDispParams,
1573                                          VARIANT* pVarResult,
1574                                          EXCEPINFO* pExcepInfo,
1575                                          UINT* puArgErr)
1576 {
1577     UINT ret;
1578     HRESULT hr;
1579     MSIHANDLE hpkg;
1580     IDispatch* dispatch;
1581     VARIANTARG varg0, varg1;
1582
1583     if (!(wFlags & DISPATCH_METHOD))
1584         return DISP_E_MEMBERNOTFOUND;
1585
1586     if (pDispParams->cArgs == 0)
1587         return DISP_E_TYPEMISMATCH;
1588
1589     if (V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1]) != VT_BSTR)
1590         return DISP_E_TYPEMISMATCH;
1591
1592     VariantInit(&varg0);
1593     hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1594     if (FAILED(hr))
1595         return hr;
1596
1597     VariantInit(&varg1);
1598     if (pDispParams->cArgs == 2)
1599     {
1600         hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1601         if (FAILED(hr))
1602             goto done;
1603     }
1604     else
1605     {
1606         V_VT(&varg1) = VT_I4;
1607         V_I4(&varg1) = 0;
1608     }
1609
1610     V_VT(pVarResult) = VT_DISPATCH;
1611
1612     ret = MsiOpenPackageExW(V_BSTR(&varg0), V_I4(&varg1), &hpkg);
1613     if (ret != ERROR_SUCCESS)
1614     {
1615         hr = DISP_E_EXCEPTION;
1616         goto done;
1617     }
1618
1619     hr = create_session(hpkg, (IDispatch *)This, &dispatch);
1620     if (SUCCEEDED(hr))
1621         V_DISPATCH(pVarResult) = dispatch;
1622
1623 done:
1624     VariantClear(&varg0);
1625     VariantClear(&varg1);
1626     return hr;
1627 }
1628
1629 static HRESULT InstallerImpl_OpenProduct(WORD wFlags,
1630                                          DISPPARAMS* pDispParams,
1631                                          VARIANT* pVarResult,
1632                                          EXCEPINFO* pExcepInfo,
1633                                          UINT* puArgErr)
1634 {
1635     HRESULT hr;
1636     VARIANTARG varg0;
1637
1638     if (!(wFlags & DISPATCH_METHOD))
1639         return DISP_E_MEMBERNOTFOUND;
1640
1641     VariantInit(&varg0);
1642     hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1643     if (FAILED(hr))
1644         return hr;
1645
1646     FIXME("%s\n", debugstr_w(V_BSTR(&varg0)));
1647
1648     VariantInit(pVarResult);
1649
1650     VariantClear(&varg0);
1651     return S_OK;
1652 }
1653
1654 static HRESULT InstallerImpl_OpenDatabase(WORD wFlags,
1655                                           DISPPARAMS* pDispParams,
1656                                           VARIANT* pVarResult,
1657                                           EXCEPINFO* pExcepInfo,
1658                                           UINT* puArgErr)
1659 {
1660     UINT ret;
1661     HRESULT hr;
1662     MSIHANDLE hdb;
1663     IDispatch* dispatch;
1664     VARIANTARG varg0, varg1;
1665
1666     if (!(wFlags & DISPATCH_METHOD))
1667         return DISP_E_MEMBERNOTFOUND;
1668
1669     VariantInit(&varg0);
1670     hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1671     if (FAILED(hr))
1672         return hr;
1673
1674     VariantInit(&varg1);
1675     hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1676     if (FAILED(hr))
1677         goto done;
1678
1679     V_VT(pVarResult) = VT_DISPATCH;
1680
1681     ret = MsiOpenDatabaseW(V_BSTR(&varg0), V_BSTR(&varg1), &hdb);
1682     if (ret != ERROR_SUCCESS)
1683     {
1684         hr = DISP_E_EXCEPTION;
1685         goto done;
1686     }
1687
1688     hr = create_automation_object(hdb, NULL, (LPVOID *)&dispatch,
1689                                   &DIID_Database, DatabaseImpl_Invoke, NULL, 0);
1690     if (SUCCEEDED(hr))
1691         V_DISPATCH(pVarResult) = dispatch;
1692
1693 done:
1694     VariantClear(&varg0);
1695     VariantClear(&varg1);
1696     return hr;
1697 }
1698
1699 static HRESULT InstallerImpl_SummaryInformation(WORD wFlags,
1700                                                 DISPPARAMS* pDispParams,
1701                                                 VARIANT* pVarResult,
1702                                                 EXCEPINFO* pExcepInfo,
1703                                                 UINT* puArgErr)
1704 {
1705     if (!(wFlags & DISPATCH_METHOD))
1706         return DISP_E_MEMBERNOTFOUND;
1707
1708     FIXME("\n");
1709
1710     VariantInit(pVarResult);
1711     return S_OK;
1712 }
1713
1714 static HRESULT InstallerImpl_UILevel(WORD wFlags,
1715                                      DISPPARAMS* pDispParams,
1716                                      VARIANT* pVarResult,
1717                                      EXCEPINFO* pExcepInfo,
1718                                      UINT* puArgErr)
1719 {
1720     HRESULT hr;
1721     VARIANTARG varg0;
1722     INSTALLUILEVEL ui;
1723
1724     if (!(wFlags & DISPATCH_PROPERTYPUT) && !(wFlags & DISPATCH_PROPERTYGET))
1725         return DISP_E_MEMBERNOTFOUND;
1726
1727     if (wFlags & DISPATCH_PROPERTYPUT)
1728     {
1729         VariantInit(&varg0);
1730         hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1731         if (FAILED(hr))
1732             return hr;
1733
1734         ui = MsiSetInternalUI(V_I4(&varg0), NULL);
1735         if (ui == INSTALLUILEVEL_NOCHANGE)
1736             return DISP_E_EXCEPTION;
1737     }
1738     else if (wFlags & DISPATCH_PROPERTYGET)
1739     {
1740         ui = MsiSetInternalUI(INSTALLUILEVEL_NOCHANGE, NULL);
1741         if (ui == INSTALLUILEVEL_NOCHANGE)
1742             return DISP_E_EXCEPTION;
1743
1744         V_VT(pVarResult) = VT_I4;
1745         V_I4(pVarResult) = ui;
1746     }
1747
1748     return S_OK;
1749 }
1750
1751 static HRESULT InstallerImpl_EnableLog(WORD wFlags,
1752                                        DISPPARAMS* pDispParams,
1753                                        VARIANT* pVarResult,
1754                                        EXCEPINFO* pExcepInfo,
1755                                        UINT* puArgErr)
1756 {
1757     if (!(wFlags & DISPATCH_METHOD))
1758         return DISP_E_MEMBERNOTFOUND;
1759
1760     FIXME("\n");
1761
1762     VariantInit(pVarResult);
1763     return S_OK;
1764 }
1765
1766 static HRESULT InstallerImpl_InstallProduct(WORD wFlags,
1767                                             DISPPARAMS* pDispParams,
1768                                             VARIANT* pVarResult,
1769                                             EXCEPINFO* pExcepInfo,
1770                                             UINT* puArgErr)
1771 {
1772     UINT ret;
1773     HRESULT hr;
1774     VARIANTARG varg0, varg1;
1775
1776     if (!(wFlags & DISPATCH_METHOD))
1777         return DISP_E_MEMBERNOTFOUND;
1778
1779     VariantInit(&varg0);
1780     hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1781     if (FAILED(hr))
1782         return hr;
1783
1784     VariantInit(&varg1);
1785     hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1786     if (FAILED(hr))
1787         goto done;
1788
1789     ret = MsiInstallProductW(V_BSTR(&varg0), V_BSTR(&varg1));
1790     if (ret != ERROR_SUCCESS)
1791     {
1792         hr = DISP_E_EXCEPTION;
1793         goto done;
1794     }
1795
1796 done:
1797     VariantClear(&varg0);
1798     VariantClear(&varg1);
1799     return hr;
1800 }
1801
1802 static HRESULT InstallerImpl_Version(WORD wFlags,
1803                                      VARIANT* pVarResult,
1804                                      EXCEPINFO* pExcepInfo,
1805                                      UINT* puArgErr)
1806 {
1807     HRESULT hr;
1808     DLLVERSIONINFO verinfo;
1809     WCHAR version[MAX_PATH];
1810
1811     static const WCHAR format[] = {
1812         '%','d','.','%','d','.','%','d','.','%','d',0};
1813
1814     if (!(wFlags & DISPATCH_PROPERTYGET))
1815         return DISP_E_MEMBERNOTFOUND;
1816
1817     verinfo.cbSize = sizeof(DLLVERSIONINFO);
1818     hr = DllGetVersion(&verinfo);
1819     if (FAILED(hr))
1820         return hr;
1821
1822     sprintfW(version, format, verinfo.dwMajorVersion, verinfo.dwMinorVersion,
1823              verinfo.dwBuildNumber, verinfo.dwPlatformID);
1824
1825     V_VT(pVarResult) = VT_BSTR;
1826     V_BSTR(pVarResult) = SysAllocString(version);
1827     return S_OK;
1828 }
1829
1830 static HRESULT InstallerImpl_LastErrorRecord(WORD wFlags,
1831                                              DISPPARAMS* pDispParams,
1832                                              VARIANT* pVarResult,
1833                                              EXCEPINFO* pExcepInfo,
1834                                              UINT* puArgErr)
1835 {
1836     if (!(wFlags & DISPATCH_METHOD))
1837         return DISP_E_MEMBERNOTFOUND;
1838
1839     FIXME("\n");
1840
1841     VariantInit(pVarResult);
1842     return S_OK;
1843 }
1844
1845 static HRESULT InstallerImpl_RegistryValue(WORD wFlags,
1846                                            DISPPARAMS* pDispParams,
1847                                            VARIANT* pVarResult,
1848                                            EXCEPINFO* pExcepInfo,
1849                                            UINT* puArgErr)
1850 {
1851     UINT ret;
1852     HKEY hkey = NULL;
1853     HRESULT hr;
1854     UINT posValue;
1855     DWORD type, size;
1856     LPWSTR szString = NULL;
1857     VARIANTARG varg0, varg1, varg2;
1858
1859     if (!(wFlags & DISPATCH_METHOD))
1860         return DISP_E_MEMBERNOTFOUND;
1861
1862     VariantInit(&varg0);
1863     hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1864     if (FAILED(hr))
1865         return hr;
1866
1867     VariantInit(&varg1);
1868     hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1869     if (FAILED(hr))
1870         goto done;
1871
1872     /* Save valuePos so we can save puArgErr if we are unable to do our type
1873      * conversions.
1874      */
1875     posValue = 2;
1876     VariantInit(&varg2);
1877     hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg2);
1878     if (FAILED(hr))
1879         goto done;
1880
1881     if (V_I4(&varg0) >= REG_INDEX_CLASSES_ROOT &&
1882         V_I4(&varg0) <= REG_INDEX_DYN_DATA)
1883     {
1884         V_I4(&varg0) |= (UINT_PTR)HKEY_CLASSES_ROOT;
1885     }
1886
1887     ret = RegOpenKeyW((HKEY)(UINT_PTR)V_I4(&varg0), V_BSTR(&varg1), &hkey);
1888
1889     /* Only VT_EMPTY case can do anything if the key doesn't exist. */
1890     if (ret != ERROR_SUCCESS && V_VT(&varg2) != VT_EMPTY)
1891     {
1892         hr = DISP_E_BADINDEX;
1893         goto done;
1894     }
1895
1896     /* Third parameter can be VT_EMPTY, VT_I4, or VT_BSTR */
1897     switch (V_VT(&varg2))
1898     {
1899         /* Return VT_BOOL clarifying whether registry key exists or not. */
1900         case VT_EMPTY:
1901             V_VT(pVarResult) = VT_BOOL;
1902             V_BOOL(pVarResult) = (ret == ERROR_SUCCESS);
1903             break;
1904
1905         /* Return the value of specified key if it exists. */
1906         case VT_BSTR:
1907             ret = RegQueryValueExW(hkey, V_BSTR(&varg2),
1908                                    NULL, NULL, NULL, &size);
1909             if (ret != ERROR_SUCCESS)
1910             {
1911                 hr = DISP_E_BADINDEX;
1912                 goto done;
1913             }
1914
1915             szString = msi_alloc(size);
1916             if (!szString)
1917             {
1918                 hr = E_OUTOFMEMORY;
1919                 goto done;
1920             }
1921
1922             ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL,
1923                                    &type, (LPBYTE)szString, &size);
1924             if (ret != ERROR_SUCCESS)
1925             {
1926                 msi_free(szString);
1927                 hr = DISP_E_BADINDEX;
1928                 goto done;
1929             }
1930
1931             variant_from_registry_value(pVarResult, type,
1932                                         (LPBYTE)szString, size);
1933             msi_free(szString);
1934             break;
1935
1936         /* Try to make it into VT_I4, can use VariantChangeType for this. */
1937         default:
1938             hr = VariantChangeType(&varg2, &varg2, 0, VT_I4);
1939             if (FAILED(hr))
1940             {
1941                 if (hr == DISP_E_TYPEMISMATCH)
1942                     *puArgErr = posValue;
1943
1944                 goto done;
1945             }
1946
1947             /* Retrieve class name or maximum value name or subkey name size. */
1948             if (!V_I4(&varg2))
1949                 ret = RegQueryInfoKeyW(hkey, NULL, &size, NULL, NULL, NULL,
1950                                        NULL, NULL, NULL, NULL, NULL, NULL);
1951             else if (V_I4(&varg2) > 0)
1952                 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL,
1953                                        NULL, NULL, &size, NULL, NULL, NULL);
1954             else /* V_I4(&varg2) < 0 */
1955                 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, &size,
1956                                        NULL, NULL, NULL, NULL, NULL, NULL);
1957
1958             if (ret != ERROR_SUCCESS)
1959                 goto done;
1960
1961             szString = msi_alloc(++size * sizeof(WCHAR));
1962             if (!szString)
1963             {
1964                 hr = E_OUTOFMEMORY;
1965                 goto done;
1966             }
1967
1968             if (!V_I4(&varg2))
1969                 ret = RegQueryInfoKeyW(hkey, szString, &size,NULL, NULL, NULL,
1970                                        NULL, NULL, NULL, NULL, NULL, NULL);
1971             else if (V_I4(&varg2) > 0)
1972                 ret = RegEnumValueW(hkey, V_I4(&varg2)-1, szString,
1973                                     &size, 0, 0, NULL, NULL);
1974             else /* V_I4(&varg2) < 0 */
1975                 ret = RegEnumKeyW(hkey, -1 - V_I4(&varg2), szString, size);
1976
1977             if (ret == ERROR_SUCCESS)
1978             {
1979                 V_VT(pVarResult) = VT_BSTR;
1980                 V_BSTR(pVarResult) = SysAllocString(szString);
1981             }
1982
1983             msi_free(szString);
1984     }
1985
1986 done:
1987     VariantClear(&varg0);
1988     VariantClear(&varg1);
1989     VariantClear(&varg2);
1990     RegCloseKey(hkey);
1991     return hr;
1992 }
1993
1994 static HRESULT InstallerImpl_Environment(WORD wFlags,
1995                                          DISPPARAMS* pDispParams,
1996                                          VARIANT* pVarResult,
1997                                          EXCEPINFO* pExcepInfo,
1998                                          UINT* puArgErr)
1999 {
2000     if (!(wFlags & DISPATCH_METHOD))
2001         return DISP_E_MEMBERNOTFOUND;
2002
2003     FIXME("\n");
2004
2005     VariantInit(pVarResult);
2006     return S_OK;
2007 }
2008
2009 static HRESULT InstallerImpl_FileAttributes(WORD wFlags,
2010                                             DISPPARAMS* pDispParams,
2011                                             VARIANT* pVarResult,
2012                                             EXCEPINFO* pExcepInfo,
2013                                             UINT* puArgErr)
2014 {
2015     if (!(wFlags & DISPATCH_METHOD))
2016         return DISP_E_MEMBERNOTFOUND;
2017
2018     FIXME("\n");
2019
2020     VariantInit(pVarResult);
2021     return S_OK;
2022 }
2023
2024 static HRESULT InstallerImpl_FileSize(WORD wFlags,
2025                                       DISPPARAMS* pDispParams,
2026                                       VARIANT* pVarResult,
2027                                       EXCEPINFO* pExcepInfo,
2028                                       UINT* puArgErr)
2029 {
2030     if (!(wFlags & DISPATCH_METHOD))
2031         return DISP_E_MEMBERNOTFOUND;
2032
2033     FIXME("\n");
2034
2035     VariantInit(pVarResult);
2036     return S_OK;
2037 }
2038
2039 static HRESULT InstallerImpl_FileVersion(WORD wFlags,
2040                                          DISPPARAMS* pDispParams,
2041                                          VARIANT* pVarResult,
2042                                          EXCEPINFO* pExcepInfo,
2043                                          UINT* puArgErr)
2044 {
2045     if (!(wFlags & DISPATCH_METHOD))
2046         return DISP_E_MEMBERNOTFOUND;
2047
2048     FIXME("\n");
2049
2050     VariantInit(pVarResult);
2051     return S_OK;
2052 }
2053
2054 static HRESULT InstallerImpl_ProductState(WORD wFlags,
2055                                           DISPPARAMS* pDispParams,
2056                                           VARIANT* pVarResult,
2057                                           EXCEPINFO* pExcepInfo,
2058                                           UINT* puArgErr)
2059 {
2060     HRESULT hr;
2061     VARIANTARG varg0;
2062
2063     if (!(wFlags & DISPATCH_PROPERTYGET))
2064         return DISP_E_MEMBERNOTFOUND;
2065
2066     VariantInit(&varg0);
2067     hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
2068     if (FAILED(hr))
2069         return hr;
2070
2071     V_VT(pVarResult) = VT_I4;
2072     V_I4(pVarResult) = MsiQueryProductStateW(V_BSTR(&varg0));
2073
2074     VariantClear(&varg0);
2075     return S_OK;
2076 }
2077
2078 static HRESULT InstallerImpl_ProductInfo(WORD wFlags,
2079                                          DISPPARAMS* pDispParams,
2080                                          VARIANT* pVarResult,
2081                                          EXCEPINFO* pExcepInfo,
2082                                          UINT* puArgErr)
2083 {
2084     UINT ret;
2085     HRESULT hr;
2086     DWORD size;
2087     LPWSTR str;
2088     VARIANTARG varg0, varg1;
2089
2090     if (!(wFlags & DISPATCH_PROPERTYGET))
2091         return DISP_E_MEMBERNOTFOUND;
2092
2093     VariantInit(&varg0);
2094     hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
2095     if (FAILED(hr))
2096         return hr;
2097
2098     VariantInit(&varg1);
2099     hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
2100     if (FAILED(hr))
2101         goto done;
2102
2103     V_VT(pVarResult) = VT_BSTR;
2104     V_BSTR(pVarResult) = NULL;
2105
2106     ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), NULL, &size);
2107     if (ret != ERROR_SUCCESS)
2108     {
2109         hr = DISP_E_EXCEPTION;
2110         goto done;
2111     }
2112
2113     str = msi_alloc(++size * sizeof(WCHAR));
2114     if (!str)
2115     {
2116         hr = E_OUTOFMEMORY;
2117         goto done;
2118     }
2119
2120     ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), str, &size);
2121     msi_free(str);
2122
2123     if (ret != ERROR_SUCCESS)
2124     {
2125         hr = DISP_E_EXCEPTION;
2126         goto done;
2127     }
2128
2129     V_BSTR(pVarResult) = SysAllocString(str);
2130     hr = S_OK;
2131
2132 done:
2133     VariantClear(&varg0);
2134     VariantClear(&varg1);
2135     return hr;
2136 }
2137
2138 static HRESULT WINAPI InstallerImpl_Invoke(
2139         AutomationObject* This,
2140         DISPID dispIdMember,
2141         REFIID riid,
2142         LCID lcid,
2143         WORD wFlags,
2144         DISPPARAMS* pDispParams,
2145         VARIANT* pVarResult,
2146         EXCEPINFO* pExcepInfo,
2147         UINT* puArgErr)
2148 {
2149     IDispatch *pDispatch = NULL;
2150     UINT ret;
2151     VARIANTARG varg0, varg1, varg2;
2152     HRESULT hr;
2153
2154     VariantInit(&varg0);
2155     VariantInit(&varg1);
2156     VariantInit(&varg2);
2157
2158     switch (dispIdMember)
2159     {
2160         case DISPID_INSTALLER_CREATERECORD:
2161             return InstallerImpl_CreateRecord(wFlags, pDispParams,
2162                                               pVarResult, pExcepInfo, puArgErr);
2163
2164         case DISPID_INSTALLER_OPENPACKAGE:
2165             return InstallerImpl_OpenPackage(This, wFlags, pDispParams,
2166                                              pVarResult, pExcepInfo, puArgErr);
2167
2168         case DISPID_INSTALLER_OPENPRODUCT:
2169             return InstallerImpl_OpenProduct(wFlags, pDispParams,
2170                                              pVarResult, pExcepInfo, puArgErr);
2171
2172         case DISPID_INSTALLER_OPENDATABASE:
2173             return InstallerImpl_OpenDatabase(wFlags, pDispParams,
2174                                               pVarResult, pExcepInfo, puArgErr);
2175
2176         case DISPID_INSTALLER_SUMMARYINFORMATION:
2177             return InstallerImpl_SummaryInformation(wFlags, pDispParams,
2178                                                     pVarResult, pExcepInfo,
2179                                                     puArgErr);
2180
2181         case DISPID_INSTALLER_UILEVEL:
2182             return InstallerImpl_UILevel(wFlags, pDispParams,
2183                                          pVarResult, pExcepInfo, puArgErr);
2184
2185         case DISPID_INSTALLER_ENABLELOG:
2186             return InstallerImpl_EnableLog(wFlags, pDispParams,
2187                                            pVarResult, pExcepInfo, puArgErr);
2188
2189         case DISPID_INSTALLER_INSTALLPRODUCT:
2190             return InstallerImpl_InstallProduct(wFlags, pDispParams,
2191                                                 pVarResult, pExcepInfo,
2192                                                 puArgErr);
2193
2194         case DISPID_INSTALLER_VERSION:
2195             return InstallerImpl_Version(wFlags, pVarResult,
2196                                          pExcepInfo, puArgErr);
2197
2198         case DISPID_INSTALLER_LASTERRORRECORD:
2199             return InstallerImpl_LastErrorRecord(wFlags, pDispParams,
2200                                                  pVarResult, pExcepInfo,
2201                                                  puArgErr);
2202
2203         case DISPID_INSTALLER_REGISTRYVALUE:
2204             return InstallerImpl_RegistryValue(wFlags, pDispParams,
2205                                                pVarResult, pExcepInfo,
2206                                                puArgErr);
2207
2208         case DISPID_INSTALLER_ENVIRONMENT:
2209             return InstallerImpl_Environment(wFlags, pDispParams,
2210                                              pVarResult, pExcepInfo, puArgErr);
2211
2212         case DISPID_INSTALLER_FILEATTRIBUTES:
2213             return InstallerImpl_FileAttributes(wFlags, pDispParams,
2214                                                 pVarResult, pExcepInfo,
2215                                                 puArgErr);
2216
2217         case DISPID_INSTALLER_FILESIZE:
2218             return InstallerImpl_FileSize(wFlags, pDispParams,
2219                                           pVarResult, pExcepInfo, puArgErr);
2220
2221         case DISPID_INSTALLER_FILEVERSION:
2222             return InstallerImpl_FileVersion(wFlags, pDispParams,
2223                                              pVarResult, pExcepInfo, puArgErr);
2224
2225         case DISPID_INSTALLER_PRODUCTSTATE:
2226             return InstallerImpl_ProductState(wFlags, pDispParams,
2227                                               pVarResult, pExcepInfo, puArgErr);
2228
2229         case DISPID_INSTALLER_PRODUCTINFO:
2230             return InstallerImpl_ProductInfo(wFlags, pDispParams,
2231                                              pVarResult, pExcepInfo, puArgErr);
2232
2233         case DISPID_INSTALLER_PRODUCTS:
2234             if (wFlags & DISPATCH_PROPERTYGET)
2235             {
2236                 ListData *ldata = NULL;
2237                 ULONG idx = 0;
2238                 WCHAR szProductBuf[GUID_SIZE];
2239
2240                 /* Find number of products */
2241                 while ((ret = MsiEnumProductsW(idx, szProductBuf)) == ERROR_SUCCESS) idx++;
2242                 if (ret != ERROR_NO_MORE_ITEMS)
2243                 {
2244                     ERR("MsiEnumProducts returned %d\n", ret);
2245                     return DISP_E_EXCEPTION;
2246                 }
2247
2248                 V_VT(pVarResult) = VT_DISPATCH;
2249                 if (SUCCEEDED(hr = create_automation_object(0, NULL, (LPVOID*)&pDispatch, &DIID_StringList, ListImpl_Invoke, ListImpl_Free, sizeof(ListData))))
2250                 {
2251                     V_DISPATCH(pVarResult) = pDispatch;
2252
2253                     /* Save product strings */
2254                     ldata = private_data((AutomationObject *)pDispatch);
2255                     if (!(ldata->pVars = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(VARIANT)*idx)))
2256                         ERR("Out of memory\n");
2257                     else
2258                     {
2259                         ldata->ulCount = idx;
2260                         for (idx = 0; idx < ldata->ulCount; idx++)
2261                         {
2262                             ret = MsiEnumProductsW(idx, szProductBuf);
2263                             VariantInit(&ldata->pVars[idx]);
2264                             V_VT(&ldata->pVars[idx]) = VT_BSTR;
2265                             V_BSTR(&ldata->pVars[idx]) = SysAllocString(szProductBuf);
2266                         }
2267                     }
2268                 }
2269                 else
2270                     ERR("Failed to create StringList object, hresult 0x%08x\n", hr);
2271             }
2272             else return DISP_E_MEMBERNOTFOUND;
2273             break;
2274
2275         case DISPID_INSTALLER_RELATEDPRODUCTS:
2276             if (wFlags & DISPATCH_PROPERTYGET)
2277             {
2278                 ListData *ldata = NULL;
2279                 ULONG idx = 0;
2280                 WCHAR szProductBuf[GUID_SIZE];
2281
2282                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
2283                 if (FAILED(hr)) return hr;
2284
2285                 /* Find number of related products */
2286                 while ((ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, szProductBuf)) == ERROR_SUCCESS) idx++;
2287                 if (ret != ERROR_NO_MORE_ITEMS)
2288                 {
2289                     VariantClear(&varg0);
2290                     ERR("MsiEnumRelatedProducts returned %d\n", ret);
2291                     return DISP_E_EXCEPTION;
2292                 }
2293
2294                 V_VT(pVarResult) = VT_DISPATCH;
2295                 if (SUCCEEDED(hr = create_automation_object(0, NULL, (LPVOID*)&pDispatch, &DIID_StringList, ListImpl_Invoke, ListImpl_Free, sizeof(ListData))))
2296                 {
2297                     V_DISPATCH(pVarResult) = pDispatch;
2298
2299                     /* Save product strings */
2300                     ldata = private_data((AutomationObject *)pDispatch);
2301                     if (!(ldata->pVars = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(VARIANT)*idx)))
2302                         ERR("Out of memory\n");
2303                     else
2304                     {
2305                         ldata->ulCount = idx;
2306                         for (idx = 0; idx < ldata->ulCount; idx++)
2307                         {
2308                             ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, szProductBuf);
2309                             VariantInit(&ldata->pVars[idx]);
2310                             V_VT(&ldata->pVars[idx]) = VT_BSTR;
2311                             V_BSTR(&ldata->pVars[idx]) = SysAllocString(szProductBuf);
2312                         }
2313                     }
2314                 }
2315                 else
2316                     ERR("Failed to create StringList object, hresult 0x%08x\n", hr);
2317             }
2318             else return DISP_E_MEMBERNOTFOUND;
2319             break;
2320
2321          default:
2322             return DISP_E_MEMBERNOTFOUND;
2323     }
2324
2325     VariantClear(&varg2);
2326     VariantClear(&varg1);
2327     VariantClear(&varg0);
2328
2329     return S_OK;
2330 }
2331
2332 /* Wrapper around create_automation_object to create an installer object. */
2333 HRESULT create_msiserver(IUnknown *pOuter, LPVOID *ppObj)
2334 {
2335     return create_automation_object(0, pOuter, ppObj, &DIID_Installer, InstallerImpl_Invoke, NULL, 0);
2336 }
2337
2338 /* Wrapper around create_automation_object to create a session object. */
2339 HRESULT create_session(MSIHANDLE msiHandle, IDispatch *pInstaller, IDispatch **pDispatch)
2340 {
2341     HRESULT hr = create_automation_object(msiHandle, NULL, (LPVOID)pDispatch, &DIID_Session, SessionImpl_Invoke, NULL, sizeof(SessionData));
2342     if (SUCCEEDED(hr) && pDispatch && *pDispatch)
2343         ((SessionData *)private_data((AutomationObject *)*pDispatch))->pInstaller = pInstaller;
2344     return hr;
2345 }