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