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