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