msvcp100: Store locale string in _Yarn<char> class.
[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) IEnumVARIANT_Release(*ppEnum);
613         return hr;
614     }
615
616     return S_OK;
617 }
618
619 static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl =
620 {
621     ListEnumerator_QueryInterface,
622     ListEnumerator_AddRef,
623     ListEnumerator_Release,
624     ListEnumerator_Next,
625     ListEnumerator_Skip,
626     ListEnumerator_Reset,
627     ListEnumerator_Clone
628 };
629
630 /* Create a list enumerator, placing the result in the pointer ppObj.  */
631 static HRESULT create_list_enumerator(ListObject *list, void **ppObj)
632 {
633     ListEnumerator *object;
634
635     TRACE("(%p, %p)\n", list, ppObj);
636
637     object = msi_alloc(sizeof(ListEnumerator));
638
639     /* Set all the VTable references */
640     object->IEnumVARIANT_iface.lpVtbl = &ListEnumerator_Vtbl;
641     object->ref = 1;
642
643     /* Store data that was passed */
644     object->pos = 0;
645     object->list = list;
646     if (list) IDispatch_AddRef(&list->autoobj.IDispatch_iface);
647
648     *ppObj = object;
649     return S_OK;
650 }
651
652 /*
653  * Individual Object Invocation Functions
654  */
655
656 /* Helper function that copies a passed parameter instead of using VariantChangeType like the actual DispGetParam.
657    This function is only for VARIANT type parameters that have several types that cannot be properly discriminated
658    using DispGetParam/VariantChangeType. */
659 static HRESULT DispGetParam_CopyOnly(
660         DISPPARAMS *pdispparams, /* [in] Parameter list */
661         UINT        *position,    /* [in] Position of parameter to copy in pdispparams; on return will contain calculated position */
662         VARIANT    *pvarResult)  /* [out] Destination for resulting variant */
663 {
664     /* position is counted backwards */
665     UINT pos;
666
667     TRACE("position=%d, cArgs=%d, cNamedArgs=%d\n",
668           *position, pdispparams->cArgs, pdispparams->cNamedArgs);
669     if (*position < pdispparams->cArgs) {
670       /* positional arg? */
671       pos = pdispparams->cArgs - *position - 1;
672     } else {
673       /* FIXME: is this how to handle named args? */
674       for (pos=0; pos<pdispparams->cNamedArgs; pos++)
675         if (pdispparams->rgdispidNamedArgs[pos] == *position) break;
676
677       if (pos==pdispparams->cNamedArgs)
678         return DISP_E_PARAMNOTFOUND;
679     }
680     *position = pos;
681     return VariantCopyInd(pvarResult,
682                         &pdispparams->rgvarg[pos]);
683 }
684
685 static HRESULT SummaryInfoImpl_Invoke(
686         AutomationObject* This,
687         DISPID dispIdMember,
688         REFIID riid,
689         LCID lcid,
690         WORD wFlags,
691         DISPPARAMS* pDispParams,
692         VARIANT* pVarResult,
693         EXCEPINFO* pExcepInfo,
694         UINT* puArgErr)
695 {
696     UINT ret;
697     VARIANTARG varg0, varg1;
698     FILETIME ft, ftlocal;
699     SYSTEMTIME st;
700     HRESULT hr;
701
702     VariantInit(&varg0);
703     VariantInit(&varg1);
704
705     switch (dispIdMember)
706     {
707         case DISPID_SUMMARYINFO_PROPERTY:
708             if (wFlags & DISPATCH_PROPERTYGET)
709             {
710                 UINT type;
711                 INT value;
712                 DWORD size = 0;
713                 DATE date;
714                 LPWSTR str;
715
716                 static WCHAR szEmpty[] = {0};
717
718                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
719                 if (FAILED(hr)) return hr;
720                 ret = MsiSummaryInfoGetPropertyW(This->msiHandle, V_I4(&varg0), &type, &value,
721                                                  &ft, szEmpty, &size);
722                 if (ret != ERROR_SUCCESS &&
723                     ret != ERROR_MORE_DATA)
724                 {
725                     ERR("MsiSummaryInfoGetProperty returned %d\n", ret);
726                     return DISP_E_EXCEPTION;
727                 }
728
729                 switch (type)
730                 {
731                     case VT_EMPTY:
732                         break;
733
734                     case VT_I2:
735                     case VT_I4:
736                         V_VT(pVarResult) = VT_I4;
737                         V_I4(pVarResult) = value;
738                         break;
739
740                     case VT_LPSTR:
741                         if (!(str = msi_alloc(++size * sizeof(WCHAR))))
742                             ERR("Out of memory\n");
743                         else if ((ret = MsiSummaryInfoGetPropertyW(This->msiHandle, V_I4(&varg0), &type, NULL,
744                                                                    NULL, str, &size)) != ERROR_SUCCESS)
745                             ERR("MsiSummaryInfoGetProperty returned %d\n", ret);
746                         else
747                         {
748                             V_VT(pVarResult) = VT_BSTR;
749                             V_BSTR(pVarResult) = SysAllocString(str);
750                         }
751                         msi_free(str);
752                         break;
753
754                     case VT_FILETIME:
755                         FileTimeToLocalFileTime(&ft, &ftlocal);
756                         FileTimeToSystemTime(&ftlocal, &st);
757                         SystemTimeToVariantTime(&st, &date);
758
759                         V_VT(pVarResult) = VT_DATE;
760                         V_DATE(pVarResult) = date;
761                         break;
762
763                     default:
764                         ERR("Unhandled variant type %d\n", type);
765                 }
766             }
767             else if (wFlags & DISPATCH_PROPERTYPUT)
768             {
769                 UINT posValue = DISPID_PROPERTYPUT;
770
771                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
772                 if (FAILED(hr)) return hr;
773                 hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg1);
774                 if (FAILED(hr))
775                 {
776                     *puArgErr = posValue;
777                     return hr;
778                 }
779
780                 switch (V_VT(&varg1))
781                 {
782                     case VT_I2:
783                     case VT_I4:
784                         ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), V_VT(&varg1), V_I4(&varg1), NULL, NULL);
785                         break;
786
787                     case VT_DATE:
788                         VariantTimeToSystemTime(V_DATE(&varg1), &st);
789                         SystemTimeToFileTime(&st, &ftlocal);
790                         LocalFileTimeToFileTime(&ftlocal, &ft);
791                         ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), VT_FILETIME, 0, &ft, NULL);
792                         break;
793
794                     case VT_BSTR:
795                         ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), VT_LPSTR, 0, NULL, V_BSTR(&varg1));
796                         break;
797
798                     default:
799                         FIXME("Unhandled variant type %d\n", V_VT(&varg1));
800                         VariantClear(&varg1);
801                         return DISP_E_EXCEPTION;
802                 }
803
804                 if (ret != ERROR_SUCCESS)
805                 {
806                     ERR("MsiSummaryInfoSetPropertyW returned %d\n", ret);
807                     return DISP_E_EXCEPTION;
808                 }
809             }
810             else return DISP_E_MEMBERNOTFOUND;
811             break;
812
813         case DISPID_SUMMARYINFO_PROPERTYCOUNT:
814             if (wFlags & DISPATCH_PROPERTYGET) {
815                 UINT count;
816                 if ((ret = MsiSummaryInfoGetPropertyCount(This->msiHandle, &count)) != ERROR_SUCCESS)
817                     ERR("MsiSummaryInfoGetPropertyCount returned %d\n", ret);
818                 else
819                 {
820                     V_VT(pVarResult) = VT_I4;
821                     V_I4(pVarResult) = count;
822                 }
823             }
824             else return DISP_E_MEMBERNOTFOUND;
825             break;
826
827         default:
828             return DISP_E_MEMBERNOTFOUND;
829     }
830
831     VariantClear(&varg1);
832     VariantClear(&varg0);
833
834     return S_OK;
835 }
836
837 static HRESULT RecordImpl_Invoke(
838         AutomationObject* This,
839         DISPID dispIdMember,
840         REFIID riid,
841         LCID lcid,
842         WORD wFlags,
843         DISPPARAMS* pDispParams,
844         VARIANT* pVarResult,
845         EXCEPINFO* pExcepInfo,
846         UINT* puArgErr)
847 {
848     WCHAR *szString;
849     DWORD dwLen;
850     UINT ret;
851     VARIANTARG varg0, varg1;
852     HRESULT hr;
853
854     VariantInit(&varg0);
855     VariantInit(&varg1);
856
857     switch (dispIdMember)
858     {
859         case DISPID_RECORD_FIELDCOUNT:
860             if (wFlags & DISPATCH_PROPERTYGET) {
861                 V_VT(pVarResult) = VT_I4;
862                 V_I4(pVarResult) = MsiRecordGetFieldCount(This->msiHandle);
863             }
864             else return DISP_E_MEMBERNOTFOUND;
865             break;
866
867         case DISPID_RECORD_STRINGDATA:
868             if (wFlags & DISPATCH_PROPERTYGET) {
869                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
870                 if (FAILED(hr)) return hr;
871                 V_VT(pVarResult) = VT_BSTR;
872                 V_BSTR(pVarResult) = NULL;
873                 if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
874                 {
875                     if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
876                         ERR("Out of memory\n");
877                     else if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
878                         V_BSTR(pVarResult) = SysAllocString(szString);
879                     msi_free(szString);
880                 }
881                 if (ret != ERROR_SUCCESS)
882                     ERR("MsiRecordGetString returned %d\n", ret);
883             } else if (wFlags & DISPATCH_PROPERTYPUT) {
884                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
885                 if (FAILED(hr)) return hr;
886                 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
887                 if (FAILED(hr)) return hr;
888                 if ((ret = MsiRecordSetStringW(This->msiHandle, V_I4(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
889                 {
890                     VariantClear(&varg1);
891                     ERR("MsiRecordSetString returned %d\n", ret);
892                     return DISP_E_EXCEPTION;
893                 }
894             }
895             else return DISP_E_MEMBERNOTFOUND;
896             break;
897
898         case DISPID_RECORD_INTEGERDATA:
899             if (wFlags & DISPATCH_PROPERTYGET) {
900                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
901                 if (FAILED(hr)) return hr;
902                 V_VT(pVarResult) = VT_I4;
903                 V_I4(pVarResult) = MsiRecordGetInteger(This->msiHandle, V_I4(&varg0));
904             } else if (wFlags & DISPATCH_PROPERTYPUT) {
905                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
906                 if (FAILED(hr)) return hr;
907                 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
908                 if (FAILED(hr)) return hr;
909                 if ((ret = MsiRecordSetInteger(This->msiHandle, V_I4(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
910                 {
911                     ERR("MsiRecordSetInteger returned %d\n", ret);
912                     return DISP_E_EXCEPTION;
913                 }
914             }
915             else return DISP_E_MEMBERNOTFOUND;
916             break;
917
918          default:
919             return DISP_E_MEMBERNOTFOUND;
920     }
921
922     VariantClear(&varg1);
923     VariantClear(&varg0);
924
925     return S_OK;
926 }
927
928 static HRESULT create_record(MSIHANDLE msiHandle, IDispatch **disp)
929 {
930     AutomationObject *record;
931     HRESULT hr;
932
933     record = msi_alloc(sizeof(*record));
934     if (!record) return E_OUTOFMEMORY;
935
936     hr = init_automation_object(record, msiHandle, &DIID_Record, RecordImpl_Invoke, NULL);
937     if (hr != S_OK)
938     {
939         msi_free(record);
940         return hr;
941     }
942
943     *disp = &record->IDispatch_iface;
944
945     return hr;
946 }
947
948 static HRESULT ListImpl_Invoke(
949         AutomationObject* This,
950         DISPID dispIdMember,
951         REFIID riid,
952         LCID lcid,
953         WORD wFlags,
954         DISPPARAMS* pDispParams,
955         VARIANT* pVarResult,
956         EXCEPINFO* pExcepInfo,
957         UINT* puArgErr)
958 {
959     ListObject *list = (ListObject*)This;
960     IUnknown *pUnk = NULL;
961     HRESULT hr;
962
963     switch (dispIdMember)
964     {
965          case DISPID_LIST__NEWENUM:
966              if (wFlags & DISPATCH_METHOD) {
967                  V_VT(pVarResult) = VT_UNKNOWN;
968                  if (SUCCEEDED(hr = create_list_enumerator(list, (LPVOID *)&pUnk)))
969                      V_UNKNOWN(pVarResult) = pUnk;
970                  else
971                      ERR("Failed to create IEnumVARIANT object, hresult 0x%08x\n", hr);
972              }
973              else return DISP_E_MEMBERNOTFOUND;
974              break;
975
976          case DISPID_LIST_ITEM:
977              if (wFlags & DISPATCH_PROPERTYGET) {
978                 VARIANTARG index;
979
980                 VariantInit(&index);
981                 hr = DispGetParam(pDispParams, 0, VT_I4, &index, puArgErr);
982                 if (FAILED(hr)) return hr;
983                 if (V_I4(&index) < 0 || V_I4(&index) >= list->count)
984                     return DISP_E_BADINDEX;
985                 VariantCopy(pVarResult, &list->data[V_I4(&index)]);
986             }
987             else return DISP_E_MEMBERNOTFOUND;
988             break;
989
990          case DISPID_LIST_COUNT:
991             if (wFlags & DISPATCH_PROPERTYGET) {
992                 V_VT(pVarResult) = VT_I4;
993                 V_I4(pVarResult) = list->count;
994             }
995             else return DISP_E_MEMBERNOTFOUND;
996             break;
997
998          default:
999             return DISP_E_MEMBERNOTFOUND;
1000     }
1001
1002     return S_OK;
1003 }
1004
1005 static void ListImpl_Free(AutomationObject *This)
1006 {
1007     ListObject *list = (ListObject*)This;
1008     int i;
1009
1010     for (i = 0; i < list->count; i++)
1011         VariantClear(&list->data[i]);
1012     msi_free(list->data);
1013 }
1014
1015 static HRESULT get_products_count(const WCHAR *product, int *len)
1016 {
1017     int i = 0;
1018
1019     while (1)
1020     {
1021         WCHAR dataW[GUID_SIZE];
1022         UINT ret;
1023
1024         /* all or related only */
1025         if (product)
1026             ret = MsiEnumRelatedProductsW(product, 0, i, dataW);
1027         else
1028             ret = MsiEnumProductsW(i, dataW);
1029
1030         if (ret == ERROR_NO_MORE_ITEMS) break;
1031
1032         if (ret != ERROR_SUCCESS)
1033             return DISP_E_EXCEPTION;
1034
1035         i++;
1036     }
1037
1038     *len = i;
1039
1040     return S_OK;
1041 }
1042
1043 static HRESULT create_list(const WCHAR *product, IDispatch **dispatch)
1044 {
1045     ListObject *list;
1046     HRESULT hr;
1047     int i;
1048
1049     list = msi_alloc_zero(sizeof(ListObject));
1050     if (!list) return E_OUTOFMEMORY;
1051
1052     hr = init_automation_object(&list->autoobj, 0, &DIID_StringList, ListImpl_Invoke, ListImpl_Free);
1053     if (hr != S_OK)
1054     {
1055         msi_free(list);
1056         return hr;
1057     }
1058
1059     *dispatch = &list->autoobj.IDispatch_iface;
1060
1061     hr = get_products_count(product, &list->count);
1062     if (hr != S_OK)
1063     {
1064         IDispatch_Release(*dispatch);
1065         return hr;
1066     }
1067
1068     list->data = msi_alloc(list->count*sizeof(VARIANT));
1069     if (!list->data)
1070     {
1071         IDispatch_Release(*dispatch);
1072         return E_OUTOFMEMORY;
1073     }
1074
1075     for (i = 0; i < list->count; i++)
1076     {
1077         WCHAR dataW[GUID_SIZE];
1078         UINT ret;
1079
1080         /* all or related only */
1081         if (product)
1082             ret = MsiEnumRelatedProductsW(product, 0, i, dataW);
1083         else
1084             ret = MsiEnumProductsW(i, dataW);
1085
1086         if (ret == ERROR_NO_MORE_ITEMS) break;
1087
1088         V_VT(&list->data[i]) = VT_BSTR;
1089         V_BSTR(&list->data[i]) = SysAllocString(dataW);
1090     }
1091
1092     return S_OK;
1093 }
1094
1095 static HRESULT ViewImpl_Invoke(
1096         AutomationObject* This,
1097         DISPID dispIdMember,
1098         REFIID riid,
1099         LCID lcid,
1100         WORD wFlags,
1101         DISPPARAMS* pDispParams,
1102         VARIANT* pVarResult,
1103         EXCEPINFO* pExcepInfo,
1104         UINT* puArgErr)
1105 {
1106     MSIHANDLE msiHandle;
1107     UINT ret;
1108     VARIANTARG varg0, varg1;
1109     HRESULT hr;
1110
1111     VariantInit(&varg0);
1112     VariantInit(&varg1);
1113
1114     switch (dispIdMember)
1115     {
1116         case DISPID_VIEW_EXECUTE:
1117             if (wFlags & DISPATCH_METHOD)
1118             {
1119                 hr = DispGetParam(pDispParams, 0, VT_DISPATCH, &varg0, puArgErr);
1120                 if (SUCCEEDED(hr) && V_DISPATCH(&varg0) != NULL)
1121                     MsiViewExecute(This->msiHandle, ((AutomationObject *)V_DISPATCH(&varg0))->msiHandle);
1122                 else
1123                     MsiViewExecute(This->msiHandle, 0);
1124             }
1125             else return DISP_E_MEMBERNOTFOUND;
1126             break;
1127
1128         case DISPID_VIEW_FETCH:
1129             if (wFlags & DISPATCH_METHOD)
1130             {
1131                 V_VT(pVarResult) = VT_DISPATCH;
1132                 if ((ret = MsiViewFetch(This->msiHandle, &msiHandle)) == ERROR_SUCCESS)
1133                 {
1134                     IDispatch *dispatch = NULL;
1135
1136                     if (SUCCEEDED(hr = create_record(msiHandle, &dispatch)))
1137                         V_DISPATCH(pVarResult) = dispatch;
1138                     else
1139                         ERR("Failed to create Record object, hresult 0x%08x\n", hr);
1140                 }
1141                 else if (ret == ERROR_NO_MORE_ITEMS)
1142                     V_DISPATCH(pVarResult) = NULL;
1143                 else
1144                 {
1145                     ERR("MsiViewFetch returned %d\n", ret);
1146                     return DISP_E_EXCEPTION;
1147                 }
1148             }
1149             else return DISP_E_MEMBERNOTFOUND;
1150             break;
1151
1152         case DISPID_VIEW_MODIFY:
1153             if (wFlags & DISPATCH_METHOD)
1154             {
1155                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1156                 if (FAILED(hr)) return hr;
1157                 hr = DispGetParam(pDispParams, 1, VT_DISPATCH, &varg1, puArgErr);
1158                 if (FAILED(hr)) return hr;
1159                 if (!V_DISPATCH(&varg1)) return DISP_E_EXCEPTION;
1160                 if ((ret = MsiViewModify(This->msiHandle, V_I4(&varg0), ((AutomationObject *)V_DISPATCH(&varg1))->msiHandle)) != ERROR_SUCCESS)
1161                 {
1162                     VariantClear(&varg1);
1163                     ERR("MsiViewModify returned %d\n", ret);
1164                     return DISP_E_EXCEPTION;
1165                 }
1166             }
1167             else return DISP_E_MEMBERNOTFOUND;
1168             break;
1169
1170         case DISPID_VIEW_CLOSE:
1171             if (wFlags & DISPATCH_METHOD)
1172             {
1173                 MsiViewClose(This->msiHandle);
1174             }
1175             else return DISP_E_MEMBERNOTFOUND;
1176             break;
1177
1178          default:
1179             return DISP_E_MEMBERNOTFOUND;
1180     }
1181
1182     VariantClear(&varg1);
1183     VariantClear(&varg0);
1184
1185     return S_OK;
1186 }
1187
1188 static HRESULT DatabaseImpl_LastErrorRecord(WORD wFlags,
1189                                             DISPPARAMS* pDispParams,
1190                                             VARIANT* pVarResult,
1191                                             EXCEPINFO* pExcepInfo,
1192                                             UINT* puArgErr)
1193 {
1194     if (!(wFlags & DISPATCH_METHOD))
1195         return DISP_E_MEMBERNOTFOUND;
1196
1197     FIXME("\n");
1198
1199     VariantInit(pVarResult);
1200     return S_OK;
1201 }
1202
1203 static HRESULT DatabaseImpl_Invoke(
1204         AutomationObject* This,
1205         DISPID dispIdMember,
1206         REFIID riid,
1207         LCID lcid,
1208         WORD wFlags,
1209         DISPPARAMS* pDispParams,
1210         VARIANT* pVarResult,
1211         EXCEPINFO* pExcepInfo,
1212         UINT* puArgErr)
1213 {
1214     IDispatch *dispatch = NULL;
1215     MSIHANDLE msiHandle;
1216     UINT ret;
1217     VARIANTARG varg0, varg1;
1218     HRESULT hr;
1219
1220     VariantInit(&varg0);
1221     VariantInit(&varg1);
1222
1223     switch (dispIdMember)
1224     {
1225         case DISPID_DATABASE_SUMMARYINFORMATION:
1226             if (wFlags & DISPATCH_PROPERTYGET)
1227             {
1228                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1229                 if (FAILED(hr))
1230                     V_I4(&varg0) = 0;
1231
1232                 V_VT(pVarResult) = VT_DISPATCH;
1233                 if ((ret = MsiGetSummaryInformationW(This->msiHandle, NULL, V_I4(&varg0), &msiHandle)) == ERROR_SUCCESS)
1234                 {
1235                     hr = create_summaryinfo(msiHandle, &dispatch);
1236                     if (SUCCEEDED(hr))
1237                         V_DISPATCH(pVarResult) = dispatch;
1238                     else
1239                         ERR("Failed to create SummaryInfo object: 0x%08x\n", hr);
1240                 }
1241                 else
1242                 {
1243                     ERR("MsiGetSummaryInformation returned %d\n", ret);
1244                     return DISP_E_EXCEPTION;
1245                 }
1246             }
1247             else return DISP_E_MEMBERNOTFOUND;
1248             break;
1249
1250         case DISPID_DATABASE_OPENVIEW:
1251             if (wFlags & DISPATCH_METHOD)
1252             {
1253                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1254                 if (FAILED(hr)) return hr;
1255                 V_VT(pVarResult) = VT_DISPATCH;
1256                 if ((ret = MsiDatabaseOpenViewW(This->msiHandle, V_BSTR(&varg0), &msiHandle)) == ERROR_SUCCESS)
1257                 {
1258                     if (SUCCEEDED(hr = create_view(msiHandle, &dispatch)))
1259                         V_DISPATCH(pVarResult) = dispatch;
1260                     else
1261                         ERR("Failed to create View object, hresult 0x%08x\n", hr);
1262                 }
1263                 else
1264                 {
1265                     VariantClear(&varg0);
1266                     ERR("MsiDatabaseOpenView returned %d\n", ret);
1267                     return DISP_E_EXCEPTION;
1268                 }
1269             }
1270             else return DISP_E_MEMBERNOTFOUND;
1271             break;
1272
1273         case DISPID_INSTALLER_LASTERRORRECORD:
1274             return DatabaseImpl_LastErrorRecord(wFlags, pDispParams,
1275                                                 pVarResult, pExcepInfo,
1276                                                 puArgErr);
1277
1278          default:
1279             return DISP_E_MEMBERNOTFOUND;
1280     }
1281
1282     VariantClear(&varg1);
1283     VariantClear(&varg0);
1284
1285     return S_OK;
1286 }
1287
1288 static HRESULT SessionImpl_Invoke(
1289         AutomationObject* This,
1290         DISPID dispIdMember,
1291         REFIID riid,
1292         LCID lcid,
1293         WORD wFlags,
1294         DISPPARAMS* pDispParams,
1295         VARIANT* pVarResult,
1296         EXCEPINFO* pExcepInfo,
1297         UINT* puArgErr)
1298 {
1299     SessionObject *session = (SessionObject*)This;
1300     WCHAR *szString;
1301     DWORD dwLen;
1302     MSIHANDLE msiHandle;
1303     LANGID langId;
1304     UINT ret;
1305     INSTALLSTATE iInstalled, iAction;
1306     VARIANTARG varg0, varg1;
1307     HRESULT hr;
1308
1309     VariantInit(&varg0);
1310     VariantInit(&varg1);
1311
1312     switch (dispIdMember)
1313     {
1314         case DISPID_SESSION_INSTALLER:
1315             if (wFlags & DISPATCH_PROPERTYGET) {
1316                 V_VT(pVarResult) = VT_DISPATCH;
1317                 IDispatch_AddRef(session->installer);
1318                 V_DISPATCH(pVarResult) = session->installer;
1319             }
1320             else return DISP_E_MEMBERNOTFOUND;
1321             break;
1322
1323         case DISPID_SESSION_PROPERTY:
1324             if (wFlags & DISPATCH_PROPERTYGET) {
1325                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1326                 if (FAILED(hr)) return hr;
1327                 V_VT(pVarResult) = VT_BSTR;
1328                 V_BSTR(pVarResult) = NULL;
1329                 if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
1330                 {
1331                     if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
1332                         ERR("Out of memory\n");
1333                     else if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
1334                         V_BSTR(pVarResult) = SysAllocString(szString);
1335                     msi_free(szString);
1336                 }
1337                 if (ret != ERROR_SUCCESS)
1338                     ERR("MsiGetProperty returned %d\n", ret);
1339             } else if (wFlags & DISPATCH_PROPERTYPUT) {
1340                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1341                 if (FAILED(hr)) return hr;
1342                 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1343                 if (FAILED(hr)) {
1344                     VariantClear(&varg0);
1345                     return hr;
1346                 }
1347                 if ((ret = MsiSetPropertyW(This->msiHandle, V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
1348                 {
1349                     VariantClear(&varg0);
1350                     VariantClear(&varg1);
1351                     ERR("MsiSetProperty returned %d\n", ret);
1352                     return DISP_E_EXCEPTION;
1353                 }
1354             }
1355             else return DISP_E_MEMBERNOTFOUND;
1356             break;
1357
1358         case DISPID_SESSION_LANGUAGE:
1359             if (wFlags & DISPATCH_PROPERTYGET) {
1360                 langId = MsiGetLanguage(This->msiHandle);
1361                 V_VT(pVarResult) = VT_I4;
1362                 V_I4(pVarResult) = langId;
1363             }
1364             else return DISP_E_MEMBERNOTFOUND;
1365             break;
1366
1367         case DISPID_SESSION_MODE:
1368             if (wFlags & DISPATCH_PROPERTYGET) {
1369                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1370                 if (FAILED(hr)) return hr;
1371                 V_VT(pVarResult) = VT_BOOL;
1372                 V_BOOL(pVarResult) = MsiGetMode(This->msiHandle, V_I4(&varg0));
1373             } else if (wFlags & DISPATCH_PROPERTYPUT) {
1374                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1375                 if (FAILED(hr)) return hr;
1376                 hr = DispGetParam(pDispParams, 1, VT_BOOL, &varg1, puArgErr);
1377                 if (FAILED(hr)) return hr;
1378                 if ((ret = MsiSetMode(This->msiHandle, V_I4(&varg0), V_BOOL(&varg1))) != ERROR_SUCCESS)
1379                 {
1380                     ERR("MsiSetMode returned %d\n", ret);
1381                     return DISP_E_EXCEPTION;
1382                 }
1383             }
1384             else return DISP_E_MEMBERNOTFOUND;
1385             break;
1386
1387         case DISPID_SESSION_DATABASE:
1388             if (wFlags & DISPATCH_PROPERTYGET) {
1389                 V_VT(pVarResult) = VT_DISPATCH;
1390                 if ((msiHandle = MsiGetActiveDatabase(This->msiHandle)))
1391                 {
1392                     IDispatch *dispatch;
1393
1394                     if (SUCCEEDED(hr = create_database(msiHandle, &dispatch)))
1395                         V_DISPATCH(pVarResult) = dispatch;
1396                     else
1397                         ERR("Failed to create Database object, hresult 0x%08x\n", hr);
1398                 }
1399                 else
1400                 {
1401                     ERR("MsiGetActiveDatabase failed\n");
1402                     return DISP_E_EXCEPTION;
1403                 }
1404             }
1405             else return DISP_E_MEMBERNOTFOUND;
1406             break;
1407
1408         case DISPID_SESSION_DOACTION:
1409             if (wFlags & DISPATCH_METHOD) {
1410                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1411                 if (FAILED(hr)) return hr;
1412                 ret = MsiDoActionW(This->msiHandle, V_BSTR(&varg0));
1413                 V_VT(pVarResult) = VT_I4;
1414                 switch (ret)
1415                 {
1416                     case ERROR_FUNCTION_NOT_CALLED:
1417                         V_I4(pVarResult) = msiDoActionStatusNoAction;
1418                         break;
1419                     case ERROR_SUCCESS:
1420                         V_I4(pVarResult) = msiDoActionStatusSuccess;
1421                         break;
1422                     case ERROR_INSTALL_USEREXIT:
1423                         V_I4(pVarResult) = msiDoActionStatusUserExit;
1424                         break;
1425                     case ERROR_INSTALL_FAILURE:
1426                         V_I4(pVarResult) = msiDoActionStatusFailure;
1427                         break;
1428                     case ERROR_INSTALL_SUSPEND:
1429                         V_I4(pVarResult) = msiDoActionStatusSuspend;
1430                         break;
1431                     case ERROR_MORE_DATA:
1432                         V_I4(pVarResult) = msiDoActionStatusFinished;
1433                         break;
1434                     case ERROR_INVALID_HANDLE_STATE:
1435                         V_I4(pVarResult) = msiDoActionStatusWrongState;
1436                         break;
1437                     case ERROR_INVALID_DATA:
1438                         V_I4(pVarResult) = msiDoActionStatusBadActionData;
1439                         break;
1440                     default:
1441                         VariantClear(&varg0);
1442                         FIXME("MsiDoAction returned unhandled value %d\n", ret);
1443                         return DISP_E_EXCEPTION;
1444                 }
1445             }
1446             else return DISP_E_MEMBERNOTFOUND;
1447             break;
1448
1449         case DISPID_SESSION_EVALUATECONDITION:
1450             if (wFlags & DISPATCH_METHOD) {
1451                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1452                 if (FAILED(hr)) return hr;
1453                 V_VT(pVarResult) = VT_I4;
1454                 V_I4(pVarResult) = MsiEvaluateConditionW(This->msiHandle, V_BSTR(&varg0));
1455             }
1456             else return DISP_E_MEMBERNOTFOUND;
1457             break;
1458
1459         case DISPID_SESSION_MESSAGE:
1460             if(!(wFlags & DISPATCH_METHOD))
1461                 return DISP_E_MEMBERNOTFOUND;
1462
1463             hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1464             if (FAILED(hr)) return hr;
1465             hr = DispGetParam(pDispParams, 1, VT_DISPATCH, &varg1, puArgErr);
1466             if (FAILED(hr)) return hr;
1467
1468             V_VT(pVarResult) = VT_I4;
1469             V_I4(pVarResult) =
1470                 MsiProcessMessage(This->msiHandle, V_I4(&varg0), ((AutomationObject *)V_DISPATCH(&varg1))->msiHandle);
1471             break;
1472
1473         case DISPID_SESSION_SETINSTALLLEVEL:
1474             if (wFlags & DISPATCH_METHOD) {
1475                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1476                 if (FAILED(hr)) return hr;
1477                 if ((ret = MsiSetInstallLevel(This->msiHandle, V_I4(&varg0))) != ERROR_SUCCESS)
1478                 {
1479                     ERR("MsiSetInstallLevel returned %d\n", ret);
1480                     return DISP_E_EXCEPTION;
1481                 }
1482             }
1483             else return DISP_E_MEMBERNOTFOUND;
1484             break;
1485
1486         case DISPID_SESSION_FEATURECURRENTSTATE:
1487             if (wFlags & DISPATCH_PROPERTYGET) {
1488                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1489                 if (FAILED(hr)) return hr;
1490                 V_VT(pVarResult) = VT_I4;
1491                 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1492                     V_I4(pVarResult) = iInstalled;
1493                 else
1494                 {
1495                     ERR("MsiGetFeatureState returned %d\n", ret);
1496                     V_I4(pVarResult) = msiInstallStateUnknown;
1497                 }
1498             }
1499             else return DISP_E_MEMBERNOTFOUND;
1500             break;
1501
1502         case DISPID_SESSION_FEATUREREQUESTSTATE:
1503             if (wFlags & DISPATCH_PROPERTYGET) {
1504                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1505                 if (FAILED(hr)) return hr;
1506                 V_VT(pVarResult) = VT_I4;
1507                 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1508                     V_I4(pVarResult) = iAction;
1509                 else
1510                 {
1511                     ERR("MsiGetFeatureState returned %d\n", ret);
1512                     V_I4(pVarResult) = msiInstallStateUnknown;
1513                 }
1514             } else if (wFlags & DISPATCH_PROPERTYPUT) {
1515                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1516                 if (FAILED(hr)) return hr;
1517                 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1518                 if (FAILED(hr)) {
1519                     VariantClear(&varg0);
1520                     return hr;
1521                 }
1522                 if ((ret = MsiSetFeatureStateW(This->msiHandle, V_BSTR(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
1523                 {
1524                     VariantClear(&varg0);
1525                     ERR("MsiSetFeatureState returned %d\n", ret);
1526                     return DISP_E_EXCEPTION;
1527                 }
1528             }
1529             else return DISP_E_MEMBERNOTFOUND;
1530             break;
1531
1532          default:
1533             return DISP_E_MEMBERNOTFOUND;
1534     }
1535
1536     VariantClear(&varg1);
1537     VariantClear(&varg0);
1538
1539     return S_OK;
1540 }
1541
1542 /* Fill the variant pointed to by pVarResult with the value & size returned by RegQueryValueEx as dictated by the
1543  * registry value type. Used by Installer::RegistryValue. */
1544 static void variant_from_registry_value(VARIANT *pVarResult, DWORD dwType, LPBYTE lpData, DWORD dwSize)
1545 {
1546     static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
1547     static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
1548     WCHAR *szString = (WCHAR *)lpData;
1549     LPWSTR szNewString = NULL;
1550     DWORD dwNewSize = 0;
1551     int idx;
1552
1553     switch (dwType)
1554     {
1555         /* Registry strings may not be null terminated so we must use SysAllocStringByteLen/Len */
1556         case REG_MULTI_SZ: /* Multi SZ change internal null characters to newlines */
1557             idx = (dwSize/sizeof(WCHAR))-1;
1558             while (idx >= 0 && !szString[idx]) idx--;
1559             for (; idx >= 0; idx--)
1560                 if (!szString[idx]) szString[idx] = '\n';
1561             /* fall through */
1562         case REG_SZ:
1563             V_VT(pVarResult) = VT_BSTR;
1564             V_BSTR(pVarResult) = SysAllocStringByteLen((LPCSTR)szString, dwSize);
1565             break;
1566
1567         case REG_EXPAND_SZ:
1568             if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1569                 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1570             else if (!(szNewString = msi_alloc(dwNewSize * sizeof(WCHAR))))
1571                 ERR("Out of memory\n");
1572             else if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1573                 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1574             else
1575             {
1576                 V_VT(pVarResult) = VT_BSTR;
1577                 V_BSTR(pVarResult) = SysAllocStringLen(szNewString, dwNewSize);
1578             }
1579             msi_free(szNewString);
1580             break;
1581
1582         case REG_DWORD:
1583             V_VT(pVarResult) = VT_I4;
1584             V_I4(pVarResult) = *((DWORD *)lpData);
1585             break;
1586
1587         case REG_QWORD:
1588             V_VT(pVarResult) = VT_BSTR;
1589             V_BSTR(pVarResult) = SysAllocString(szREG_);   /* Weird string, don't know why native returns it */
1590             break;
1591
1592         case REG_BINARY:
1593             V_VT(pVarResult) = VT_BSTR;
1594             V_BSTR(pVarResult) = SysAllocString(szREG_BINARY);
1595             break;
1596
1597         case REG_NONE:
1598             V_VT(pVarResult) = VT_EMPTY;
1599             break;
1600
1601         default:
1602             FIXME("Unhandled registry value type %d\n", dwType);
1603     }
1604 }
1605
1606 static HRESULT InstallerImpl_CreateRecord(WORD wFlags,
1607                                           DISPPARAMS* pDispParams,
1608                                           VARIANT* pVarResult,
1609                                           EXCEPINFO* pExcepInfo,
1610                                           UINT* puArgErr)
1611 {
1612     HRESULT hr;
1613     VARIANTARG varg0;
1614     MSIHANDLE hrec;
1615     IDispatch* dispatch;
1616
1617     if (!(wFlags & DISPATCH_METHOD))
1618         return DISP_E_MEMBERNOTFOUND;
1619
1620     VariantInit(&varg0);
1621     hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1622     if (FAILED(hr))
1623         return hr;
1624
1625     V_VT(pVarResult) = VT_DISPATCH;
1626
1627     hrec = MsiCreateRecord(V_I4(&varg0));
1628     if (!hrec)
1629         return DISP_E_EXCEPTION;
1630
1631     hr = create_record(hrec, &dispatch);
1632     if (SUCCEEDED(hr))
1633         V_DISPATCH(pVarResult) = dispatch;
1634
1635     return hr;
1636 }
1637
1638 static HRESULT InstallerImpl_OpenPackage(AutomationObject* This,
1639                                          WORD wFlags,
1640                                          DISPPARAMS* pDispParams,
1641                                          VARIANT* pVarResult,
1642                                          EXCEPINFO* pExcepInfo,
1643                                          UINT* puArgErr)
1644 {
1645     UINT ret;
1646     HRESULT hr;
1647     MSIHANDLE hpkg;
1648     IDispatch* dispatch;
1649     VARIANTARG varg0, varg1;
1650
1651     if (!(wFlags & DISPATCH_METHOD))
1652         return DISP_E_MEMBERNOTFOUND;
1653
1654     if (pDispParams->cArgs == 0)
1655         return DISP_E_TYPEMISMATCH;
1656
1657     if (V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1]) != VT_BSTR)
1658         return DISP_E_TYPEMISMATCH;
1659
1660     VariantInit(&varg0);
1661     hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1662     if (FAILED(hr))
1663         return hr;
1664
1665     VariantInit(&varg1);
1666     if (pDispParams->cArgs == 2)
1667     {
1668         hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1669         if (FAILED(hr))
1670             goto done;
1671     }
1672     else
1673     {
1674         V_VT(&varg1) = VT_I4;
1675         V_I4(&varg1) = 0;
1676     }
1677
1678     V_VT(pVarResult) = VT_DISPATCH;
1679
1680     ret = MsiOpenPackageExW(V_BSTR(&varg0), V_I4(&varg1), &hpkg);
1681     if (ret != ERROR_SUCCESS)
1682     {
1683         hr = DISP_E_EXCEPTION;
1684         goto done;
1685     }
1686
1687     hr = create_session(hpkg, &This->IDispatch_iface, &dispatch);
1688     if (SUCCEEDED(hr))
1689         V_DISPATCH(pVarResult) = dispatch;
1690
1691 done:
1692     VariantClear(&varg0);
1693     VariantClear(&varg1);
1694     return hr;
1695 }
1696
1697 static HRESULT InstallerImpl_OpenProduct(WORD wFlags,
1698                                          DISPPARAMS* pDispParams,
1699                                          VARIANT* pVarResult,
1700                                          EXCEPINFO* pExcepInfo,
1701                                          UINT* puArgErr)
1702 {
1703     HRESULT hr;
1704     VARIANTARG varg0;
1705
1706     if (!(wFlags & DISPATCH_METHOD))
1707         return DISP_E_MEMBERNOTFOUND;
1708
1709     VariantInit(&varg0);
1710     hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1711     if (FAILED(hr))
1712         return hr;
1713
1714     FIXME("%s\n", debugstr_w(V_BSTR(&varg0)));
1715
1716     VariantInit(pVarResult);
1717
1718     VariantClear(&varg0);
1719     return S_OK;
1720 }
1721
1722 static HRESULT InstallerImpl_OpenDatabase(WORD wFlags,
1723                                           DISPPARAMS* pDispParams,
1724                                           VARIANT* pVarResult,
1725                                           EXCEPINFO* pExcepInfo,
1726                                           UINT* puArgErr)
1727 {
1728     UINT ret;
1729     HRESULT hr;
1730     MSIHANDLE hdb;
1731     IDispatch* dispatch;
1732     VARIANTARG varg0, varg1;
1733
1734     if (!(wFlags & DISPATCH_METHOD))
1735         return DISP_E_MEMBERNOTFOUND;
1736
1737     VariantInit(&varg0);
1738     hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1739     if (FAILED(hr))
1740         return hr;
1741
1742     VariantInit(&varg1);
1743     hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1744     if (FAILED(hr))
1745         goto done;
1746
1747     V_VT(pVarResult) = VT_DISPATCH;
1748
1749     ret = MsiOpenDatabaseW(V_BSTR(&varg0), V_BSTR(&varg1), &hdb);
1750     if (ret != ERROR_SUCCESS)
1751     {
1752         hr = DISP_E_EXCEPTION;
1753         goto done;
1754     }
1755
1756     hr = create_database(hdb, &dispatch);
1757     if (SUCCEEDED(hr))
1758         V_DISPATCH(pVarResult) = dispatch;
1759
1760 done:
1761     VariantClear(&varg0);
1762     VariantClear(&varg1);
1763     return hr;
1764 }
1765
1766 static HRESULT InstallerImpl_SummaryInformation(WORD wFlags,
1767                                                 DISPPARAMS* pDispParams,
1768                                                 VARIANT* pVarResult,
1769                                                 EXCEPINFO* pExcepInfo,
1770                                                 UINT* puArgErr)
1771 {
1772     if (!(wFlags & DISPATCH_METHOD))
1773         return DISP_E_MEMBERNOTFOUND;
1774
1775     FIXME("\n");
1776
1777     VariantInit(pVarResult);
1778     return S_OK;
1779 }
1780
1781 static HRESULT InstallerImpl_UILevel(WORD wFlags,
1782                                      DISPPARAMS* pDispParams,
1783                                      VARIANT* pVarResult,
1784                                      EXCEPINFO* pExcepInfo,
1785                                      UINT* puArgErr)
1786 {
1787     HRESULT hr;
1788     VARIANTARG varg0;
1789     INSTALLUILEVEL ui;
1790
1791     if (!(wFlags & DISPATCH_PROPERTYPUT) && !(wFlags & DISPATCH_PROPERTYGET))
1792         return DISP_E_MEMBERNOTFOUND;
1793
1794     if (wFlags & DISPATCH_PROPERTYPUT)
1795     {
1796         VariantInit(&varg0);
1797         hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1798         if (FAILED(hr))
1799             return hr;
1800
1801         ui = MsiSetInternalUI(V_I4(&varg0), NULL);
1802         if (ui == INSTALLUILEVEL_NOCHANGE)
1803             return DISP_E_EXCEPTION;
1804     }
1805     else if (wFlags & DISPATCH_PROPERTYGET)
1806     {
1807         ui = MsiSetInternalUI(INSTALLUILEVEL_NOCHANGE, NULL);
1808         if (ui == INSTALLUILEVEL_NOCHANGE)
1809             return DISP_E_EXCEPTION;
1810
1811         V_VT(pVarResult) = VT_I4;
1812         V_I4(pVarResult) = ui;
1813     }
1814
1815     return S_OK;
1816 }
1817
1818 static HRESULT InstallerImpl_EnableLog(WORD wFlags,
1819                                        DISPPARAMS* pDispParams,
1820                                        VARIANT* pVarResult,
1821                                        EXCEPINFO* pExcepInfo,
1822                                        UINT* puArgErr)
1823 {
1824     if (!(wFlags & DISPATCH_METHOD))
1825         return DISP_E_MEMBERNOTFOUND;
1826
1827     FIXME("\n");
1828
1829     VariantInit(pVarResult);
1830     return S_OK;
1831 }
1832
1833 static HRESULT InstallerImpl_InstallProduct(WORD wFlags,
1834                                             DISPPARAMS* pDispParams,
1835                                             VARIANT* pVarResult,
1836                                             EXCEPINFO* pExcepInfo,
1837                                             UINT* puArgErr)
1838 {
1839     UINT ret;
1840     HRESULT hr;
1841     VARIANTARG varg0, varg1;
1842
1843     if (!(wFlags & DISPATCH_METHOD))
1844         return DISP_E_MEMBERNOTFOUND;
1845
1846     VariantInit(&varg0);
1847     hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1848     if (FAILED(hr))
1849         return hr;
1850
1851     VariantInit(&varg1);
1852     hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1853     if (FAILED(hr))
1854         goto done;
1855
1856     ret = MsiInstallProductW(V_BSTR(&varg0), V_BSTR(&varg1));
1857     if (ret != ERROR_SUCCESS)
1858     {
1859         hr = DISP_E_EXCEPTION;
1860         goto done;
1861     }
1862
1863 done:
1864     VariantClear(&varg0);
1865     VariantClear(&varg1);
1866     return hr;
1867 }
1868
1869 static HRESULT InstallerImpl_Version(WORD wFlags,
1870                                      VARIANT* pVarResult,
1871                                      EXCEPINFO* pExcepInfo,
1872                                      UINT* puArgErr)
1873 {
1874     HRESULT hr;
1875     DLLVERSIONINFO verinfo;
1876     WCHAR version[MAX_PATH];
1877
1878     static const WCHAR format[] = {
1879         '%','d','.','%','d','.','%','d','.','%','d',0};
1880
1881     if (!(wFlags & DISPATCH_PROPERTYGET))
1882         return DISP_E_MEMBERNOTFOUND;
1883
1884     verinfo.cbSize = sizeof(DLLVERSIONINFO);
1885     hr = DllGetVersion(&verinfo);
1886     if (FAILED(hr))
1887         return hr;
1888
1889     sprintfW(version, format, verinfo.dwMajorVersion, verinfo.dwMinorVersion,
1890              verinfo.dwBuildNumber, verinfo.dwPlatformID);
1891
1892     V_VT(pVarResult) = VT_BSTR;
1893     V_BSTR(pVarResult) = SysAllocString(version);
1894     return S_OK;
1895 }
1896
1897 static HRESULT InstallerImpl_LastErrorRecord(WORD wFlags,
1898                                              DISPPARAMS* pDispParams,
1899                                              VARIANT* pVarResult,
1900                                              EXCEPINFO* pExcepInfo,
1901                                              UINT* puArgErr)
1902 {
1903     if (!(wFlags & DISPATCH_METHOD))
1904         return DISP_E_MEMBERNOTFOUND;
1905
1906     FIXME("\n");
1907
1908     VariantInit(pVarResult);
1909     return S_OK;
1910 }
1911
1912 static HRESULT InstallerImpl_RegistryValue(WORD wFlags,
1913                                            DISPPARAMS* pDispParams,
1914                                            VARIANT* pVarResult,
1915                                            EXCEPINFO* pExcepInfo,
1916                                            UINT* puArgErr)
1917 {
1918     UINT ret;
1919     HKEY hkey = NULL;
1920     HRESULT hr;
1921     UINT posValue;
1922     DWORD type, size;
1923     LPWSTR szString = NULL;
1924     VARIANTARG varg0, varg1, varg2;
1925
1926     if (!(wFlags & DISPATCH_METHOD))
1927         return DISP_E_MEMBERNOTFOUND;
1928
1929     VariantInit(&varg0);
1930     hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1931     if (FAILED(hr))
1932         return hr;
1933
1934     VariantInit(&varg1);
1935     hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1936     if (FAILED(hr))
1937         goto done;
1938
1939     /* Save valuePos so we can save puArgErr if we are unable to do our type
1940      * conversions.
1941      */
1942     posValue = 2;
1943     VariantInit(&varg2);
1944     hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg2);
1945     if (FAILED(hr))
1946         goto done;
1947
1948     if (V_I4(&varg0) >= REG_INDEX_CLASSES_ROOT &&
1949         V_I4(&varg0) <= REG_INDEX_DYN_DATA)
1950     {
1951         V_I4(&varg0) |= (UINT_PTR)HKEY_CLASSES_ROOT;
1952     }
1953
1954     ret = RegOpenKeyW((HKEY)(UINT_PTR)V_I4(&varg0), V_BSTR(&varg1), &hkey);
1955
1956     /* Only VT_EMPTY case can do anything if the key doesn't exist. */
1957     if (ret != ERROR_SUCCESS && V_VT(&varg2) != VT_EMPTY)
1958     {
1959         hr = DISP_E_BADINDEX;
1960         goto done;
1961     }
1962
1963     /* Third parameter can be VT_EMPTY, VT_I4, or VT_BSTR */
1964     switch (V_VT(&varg2))
1965     {
1966         /* Return VT_BOOL clarifying whether registry key exists or not. */
1967         case VT_EMPTY:
1968             V_VT(pVarResult) = VT_BOOL;
1969             V_BOOL(pVarResult) = (ret == ERROR_SUCCESS);
1970             break;
1971
1972         /* Return the value of specified key if it exists. */
1973         case VT_BSTR:
1974             ret = RegQueryValueExW(hkey, V_BSTR(&varg2),
1975                                    NULL, NULL, NULL, &size);
1976             if (ret != ERROR_SUCCESS)
1977             {
1978                 hr = DISP_E_BADINDEX;
1979                 goto done;
1980             }
1981
1982             szString = msi_alloc(size);
1983             if (!szString)
1984             {
1985                 hr = E_OUTOFMEMORY;
1986                 goto done;
1987             }
1988
1989             ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL,
1990                                    &type, (LPBYTE)szString, &size);
1991             if (ret != ERROR_SUCCESS)
1992             {
1993                 msi_free(szString);
1994                 hr = DISP_E_BADINDEX;
1995                 goto done;
1996             }
1997
1998             variant_from_registry_value(pVarResult, type,
1999                                         (LPBYTE)szString, size);
2000             msi_free(szString);
2001             break;
2002
2003         /* Try to make it into VT_I4, can use VariantChangeType for this. */
2004         default:
2005             hr = VariantChangeType(&varg2, &varg2, 0, VT_I4);
2006             if (FAILED(hr))
2007             {
2008                 if (hr == DISP_E_TYPEMISMATCH)
2009                     *puArgErr = posValue;
2010
2011                 goto done;
2012             }
2013
2014             /* Retrieve class name or maximum value name or subkey name size. */
2015             if (!V_I4(&varg2))
2016                 ret = RegQueryInfoKeyW(hkey, NULL, &size, NULL, NULL, NULL,
2017                                        NULL, NULL, NULL, NULL, NULL, NULL);
2018             else if (V_I4(&varg2) > 0)
2019                 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL,
2020                                        NULL, NULL, &size, NULL, NULL, NULL);
2021             else /* V_I4(&varg2) < 0 */
2022                 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, &size,
2023                                        NULL, NULL, NULL, NULL, NULL, NULL);
2024
2025             if (ret != ERROR_SUCCESS)
2026                 goto done;
2027
2028             szString = msi_alloc(++size * sizeof(WCHAR));
2029             if (!szString)
2030             {
2031                 hr = E_OUTOFMEMORY;
2032                 goto done;
2033             }
2034
2035             if (!V_I4(&varg2))
2036                 ret = RegQueryInfoKeyW(hkey, szString, &size,NULL, NULL, NULL,
2037                                        NULL, NULL, NULL, NULL, NULL, NULL);
2038             else if (V_I4(&varg2) > 0)
2039                 ret = RegEnumValueW(hkey, V_I4(&varg2)-1, szString,
2040                                     &size, 0, 0, NULL, NULL);
2041             else /* V_I4(&varg2) < 0 */
2042                 ret = RegEnumKeyW(hkey, -1 - V_I4(&varg2), szString, size);
2043
2044             if (ret == ERROR_SUCCESS)
2045             {
2046                 V_VT(pVarResult) = VT_BSTR;
2047                 V_BSTR(pVarResult) = SysAllocString(szString);
2048             }
2049
2050             msi_free(szString);
2051     }
2052
2053 done:
2054     VariantClear(&varg0);
2055     VariantClear(&varg1);
2056     VariantClear(&varg2);
2057     RegCloseKey(hkey);
2058     return hr;
2059 }
2060
2061 static HRESULT InstallerImpl_Environment(WORD wFlags,
2062                                          DISPPARAMS* pDispParams,
2063                                          VARIANT* pVarResult,
2064                                          EXCEPINFO* pExcepInfo,
2065                                          UINT* puArgErr)
2066 {
2067     if (!(wFlags & DISPATCH_METHOD))
2068         return DISP_E_MEMBERNOTFOUND;
2069
2070     FIXME("\n");
2071
2072     VariantInit(pVarResult);
2073     return S_OK;
2074 }
2075
2076 static HRESULT InstallerImpl_FileAttributes(WORD wFlags,
2077                                             DISPPARAMS* pDispParams,
2078                                             VARIANT* pVarResult,
2079                                             EXCEPINFO* pExcepInfo,
2080                                             UINT* puArgErr)
2081 {
2082     if (!(wFlags & DISPATCH_METHOD))
2083         return DISP_E_MEMBERNOTFOUND;
2084
2085     FIXME("\n");
2086
2087     VariantInit(pVarResult);
2088     return S_OK;
2089 }
2090
2091 static HRESULT InstallerImpl_FileSize(WORD wFlags,
2092                                       DISPPARAMS* pDispParams,
2093                                       VARIANT* pVarResult,
2094                                       EXCEPINFO* pExcepInfo,
2095                                       UINT* puArgErr)
2096 {
2097     if (!(wFlags & DISPATCH_METHOD))
2098         return DISP_E_MEMBERNOTFOUND;
2099
2100     FIXME("\n");
2101
2102     VariantInit(pVarResult);
2103     return S_OK;
2104 }
2105
2106 static HRESULT InstallerImpl_FileVersion(WORD wFlags,
2107                                          DISPPARAMS* pDispParams,
2108                                          VARIANT* pVarResult,
2109                                          EXCEPINFO* pExcepInfo,
2110                                          UINT* puArgErr)
2111 {
2112     if (!(wFlags & DISPATCH_METHOD))
2113         return DISP_E_MEMBERNOTFOUND;
2114
2115     FIXME("\n");
2116
2117     VariantInit(pVarResult);
2118     return S_OK;
2119 }
2120
2121 static HRESULT InstallerImpl_ProductState(WORD wFlags,
2122                                           DISPPARAMS* pDispParams,
2123                                           VARIANT* pVarResult,
2124                                           EXCEPINFO* pExcepInfo,
2125                                           UINT* puArgErr)
2126 {
2127     HRESULT hr;
2128     VARIANTARG varg0;
2129
2130     if (!(wFlags & DISPATCH_PROPERTYGET))
2131         return DISP_E_MEMBERNOTFOUND;
2132
2133     VariantInit(&varg0);
2134     hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
2135     if (FAILED(hr))
2136         return hr;
2137
2138     V_VT(pVarResult) = VT_I4;
2139     V_I4(pVarResult) = MsiQueryProductStateW(V_BSTR(&varg0));
2140
2141     VariantClear(&varg0);
2142     return S_OK;
2143 }
2144
2145 static HRESULT InstallerImpl_ProductInfo(WORD wFlags,
2146                                          DISPPARAMS* pDispParams,
2147                                          VARIANT* pVarResult,
2148                                          EXCEPINFO* pExcepInfo,
2149                                          UINT* puArgErr)
2150 {
2151     UINT ret;
2152     HRESULT hr;
2153     DWORD size;
2154     LPWSTR str = NULL;
2155     VARIANTARG varg0, varg1;
2156
2157     if (!(wFlags & DISPATCH_PROPERTYGET))
2158         return DISP_E_MEMBERNOTFOUND;
2159
2160     VariantInit(&varg0);
2161     hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
2162     if (FAILED(hr))
2163         return hr;
2164
2165     VariantInit(&varg1);
2166     hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
2167     if (FAILED(hr))
2168         goto done;
2169
2170     V_VT(pVarResult) = VT_BSTR;
2171     V_BSTR(pVarResult) = NULL;
2172
2173     ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), NULL, &size);
2174     if (ret != ERROR_SUCCESS)
2175     {
2176         hr = DISP_E_EXCEPTION;
2177         goto done;
2178     }
2179
2180     str = msi_alloc(++size * sizeof(WCHAR));
2181     if (!str)
2182     {
2183         hr = E_OUTOFMEMORY;
2184         goto done;
2185     }
2186
2187     ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), str, &size);
2188     if (ret != ERROR_SUCCESS)
2189     {
2190         hr = DISP_E_EXCEPTION;
2191         goto done;
2192     }
2193
2194     V_BSTR(pVarResult) = SysAllocString(str);
2195     hr = S_OK;
2196
2197 done:
2198     msi_free(str);
2199     VariantClear(&varg0);
2200     VariantClear(&varg1);
2201     return hr;
2202 }
2203
2204 static HRESULT InstallerImpl_Products(WORD flags,
2205                                       DISPPARAMS* pDispParams,
2206                                       VARIANT* result,
2207                                       EXCEPINFO* pExcepInfo,
2208                                       UINT* puArgErr)
2209 {
2210     IDispatch *dispatch;
2211     HRESULT hr;
2212
2213     if (!(flags & DISPATCH_PROPERTYGET))
2214         return DISP_E_MEMBERNOTFOUND;
2215
2216     hr = create_list(NULL, &dispatch);
2217     if (FAILED(hr))
2218         return hr;
2219
2220     V_VT(result) = VT_DISPATCH;
2221     V_DISPATCH(result) = dispatch;
2222
2223     return hr;
2224 }
2225
2226 static HRESULT InstallerImpl_RelatedProducts(WORD flags,
2227                                              DISPPARAMS* pDispParams,
2228                                              VARIANT* result,
2229                                              EXCEPINFO* pExcepInfo,
2230                                              UINT* puArgErr)
2231 {
2232     IDispatch* dispatch;
2233     VARIANTARG related;
2234     HRESULT hr;
2235
2236     if (!(flags & DISPATCH_PROPERTYGET))
2237         return DISP_E_MEMBERNOTFOUND;
2238
2239     VariantInit(&related);
2240     hr = DispGetParam(pDispParams, 0, VT_BSTR, &related, puArgErr);
2241     if (FAILED(hr))
2242         return hr;
2243
2244     hr = create_list(V_BSTR(&related), &dispatch);
2245     VariantClear(&related);
2246
2247     V_VT(result) = VT_DISPATCH;
2248     V_DISPATCH(result) = dispatch;
2249
2250     return hr;
2251 }
2252
2253 static HRESULT InstallerImpl_Invoke(
2254         AutomationObject* This,
2255         DISPID dispIdMember,
2256         REFIID riid,
2257         LCID lcid,
2258         WORD wFlags,
2259         DISPPARAMS* pDispParams,
2260         VARIANT* pVarResult,
2261         EXCEPINFO* pExcepInfo,
2262         UINT* puArgErr)
2263 {
2264     switch (dispIdMember)
2265     {
2266         case DISPID_INSTALLER_CREATERECORD:
2267             return InstallerImpl_CreateRecord(wFlags, pDispParams,
2268                                               pVarResult, pExcepInfo, puArgErr);
2269
2270         case DISPID_INSTALLER_OPENPACKAGE:
2271             return InstallerImpl_OpenPackage(This, wFlags, pDispParams,
2272                                              pVarResult, pExcepInfo, puArgErr);
2273
2274         case DISPID_INSTALLER_OPENPRODUCT:
2275             return InstallerImpl_OpenProduct(wFlags, pDispParams,
2276                                              pVarResult, pExcepInfo, puArgErr);
2277
2278         case DISPID_INSTALLER_OPENDATABASE:
2279             return InstallerImpl_OpenDatabase(wFlags, pDispParams,
2280                                               pVarResult, pExcepInfo, puArgErr);
2281
2282         case DISPID_INSTALLER_SUMMARYINFORMATION:
2283             return InstallerImpl_SummaryInformation(wFlags, pDispParams,
2284                                                     pVarResult, pExcepInfo,
2285                                                     puArgErr);
2286
2287         case DISPID_INSTALLER_UILEVEL:
2288             return InstallerImpl_UILevel(wFlags, pDispParams,
2289                                          pVarResult, pExcepInfo, puArgErr);
2290
2291         case DISPID_INSTALLER_ENABLELOG:
2292             return InstallerImpl_EnableLog(wFlags, pDispParams,
2293                                            pVarResult, pExcepInfo, puArgErr);
2294
2295         case DISPID_INSTALLER_INSTALLPRODUCT:
2296             return InstallerImpl_InstallProduct(wFlags, pDispParams,
2297                                                 pVarResult, pExcepInfo,
2298                                                 puArgErr);
2299
2300         case DISPID_INSTALLER_VERSION:
2301             return InstallerImpl_Version(wFlags, pVarResult,
2302                                          pExcepInfo, puArgErr);
2303
2304         case DISPID_INSTALLER_LASTERRORRECORD:
2305             return InstallerImpl_LastErrorRecord(wFlags, pDispParams,
2306                                                  pVarResult, pExcepInfo,
2307                                                  puArgErr);
2308
2309         case DISPID_INSTALLER_REGISTRYVALUE:
2310             return InstallerImpl_RegistryValue(wFlags, pDispParams,
2311                                                pVarResult, pExcepInfo,
2312                                                puArgErr);
2313
2314         case DISPID_INSTALLER_ENVIRONMENT:
2315             return InstallerImpl_Environment(wFlags, pDispParams,
2316                                              pVarResult, pExcepInfo, puArgErr);
2317
2318         case DISPID_INSTALLER_FILEATTRIBUTES:
2319             return InstallerImpl_FileAttributes(wFlags, pDispParams,
2320                                                 pVarResult, pExcepInfo,
2321                                                 puArgErr);
2322
2323         case DISPID_INSTALLER_FILESIZE:
2324             return InstallerImpl_FileSize(wFlags, pDispParams,
2325                                           pVarResult, pExcepInfo, puArgErr);
2326
2327         case DISPID_INSTALLER_FILEVERSION:
2328             return InstallerImpl_FileVersion(wFlags, pDispParams,
2329                                              pVarResult, pExcepInfo, puArgErr);
2330
2331         case DISPID_INSTALLER_PRODUCTSTATE:
2332             return InstallerImpl_ProductState(wFlags, pDispParams,
2333                                               pVarResult, pExcepInfo, puArgErr);
2334
2335         case DISPID_INSTALLER_PRODUCTINFO:
2336             return InstallerImpl_ProductInfo(wFlags, pDispParams,
2337                                              pVarResult, pExcepInfo, puArgErr);
2338
2339         case DISPID_INSTALLER_PRODUCTS:
2340             return InstallerImpl_Products(wFlags, pDispParams,
2341                                           pVarResult, pExcepInfo, puArgErr);
2342
2343         case DISPID_INSTALLER_RELATEDPRODUCTS:
2344             return InstallerImpl_RelatedProducts(wFlags, pDispParams,
2345                                                  pVarResult, pExcepInfo,
2346                                                  puArgErr);
2347
2348         default:
2349             return DISP_E_MEMBERNOTFOUND;
2350     }
2351 }
2352
2353 HRESULT create_msiserver(IUnknown *outer, void **ppObj)
2354 {
2355     AutomationObject *installer;
2356     HRESULT hr;
2357
2358     TRACE("(%p %p)\n", outer, ppObj);
2359
2360     if (outer)
2361         return CLASS_E_NOAGGREGATION;
2362
2363     installer = msi_alloc(sizeof(AutomationObject));
2364     if (!installer) return E_OUTOFMEMORY;
2365
2366     hr = init_automation_object(installer, 0, &DIID_Installer, InstallerImpl_Invoke, NULL);
2367     if (hr != S_OK)
2368     {
2369         msi_free(installer);
2370         return hr;
2371     }
2372
2373     *ppObj = &installer->IDispatch_iface;
2374
2375     return hr;
2376 }
2377
2378 HRESULT create_session(MSIHANDLE msiHandle, IDispatch *installer, IDispatch **disp)
2379 {
2380     SessionObject *session;
2381     HRESULT hr;
2382
2383     session = msi_alloc(sizeof(SessionObject));
2384     if (!session) return E_OUTOFMEMORY;
2385
2386     hr = init_automation_object(&session->autoobj, msiHandle, &DIID_Session, SessionImpl_Invoke, NULL);
2387     if (hr != S_OK)
2388     {
2389         msi_free(session);
2390         return hr;
2391     }
2392
2393     session->installer = installer;
2394     *disp = &session->autoobj.IDispatch_iface;
2395
2396     return hr;
2397 }
2398
2399 static HRESULT create_database(MSIHANDLE msiHandle, IDispatch **dispatch)
2400 {
2401     AutomationObject *database;
2402     HRESULT hr;
2403
2404     TRACE("(%d %p)\n", msiHandle, dispatch);
2405
2406     database = msi_alloc(sizeof(AutomationObject));
2407     if (!database) return E_OUTOFMEMORY;
2408
2409     hr = init_automation_object(database, msiHandle, &DIID_Database, DatabaseImpl_Invoke, NULL);
2410     if (hr != S_OK)
2411     {
2412         msi_free(database);
2413         return hr;
2414     }
2415
2416     *dispatch = &database->IDispatch_iface;
2417
2418     return hr;
2419 }
2420
2421 static HRESULT create_view(MSIHANDLE msiHandle, IDispatch **dispatch)
2422 {
2423     AutomationObject *view;
2424     HRESULT hr;
2425
2426     TRACE("(%d %p)\n", msiHandle, dispatch);
2427
2428     view = msi_alloc(sizeof(AutomationObject));
2429     if (!view) return E_OUTOFMEMORY;
2430
2431     hr = init_automation_object(view, msiHandle, &DIID_View, ViewImpl_Invoke, NULL);
2432     if (hr != S_OK)
2433     {
2434         msi_free(view);
2435         return hr;
2436     }
2437
2438     *dispatch = &view->IDispatch_iface;
2439
2440     return hr;
2441 }
2442
2443 static HRESULT create_summaryinfo(MSIHANDLE msiHandle, IDispatch **disp)
2444 {
2445     AutomationObject *info;
2446     HRESULT hr;
2447
2448     info = msi_alloc(sizeof(*info));
2449     if (!info) return E_OUTOFMEMORY;
2450
2451     hr = init_automation_object(info, msiHandle, &DIID_SummaryInfo, SummaryInfoImpl_Invoke, NULL);
2452     if (hr != S_OK)
2453     {
2454         msi_free(info);
2455         return hr;
2456     }
2457
2458     *disp = &info->IDispatch_iface;
2459
2460     return hr;
2461 }