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