urlmon: Don't create stgmed_obj for binding to object.
[wine] / dlls / msi / automation.c
1 /*
2  * Implementation of OLE Automation for Microsoft Installer (msi.dll)
3  *
4  * Copyright 2007 Misha Koshelev
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #define COBJMACROS
22
23 #include <stdarg.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winerror.h"
27 #include "winuser.h"
28 #include "winreg.h"
29 #include "msidefs.h"
30 #include "msipriv.h"
31 #include "activscp.h"
32 #include "oleauto.h"
33 #include "shlwapi.h"
34 #include "wine/debug.h"
35 #include "wine/unicode.h"
36
37 #include "msiserver.h"
38 #include "msiserver_dispids.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(msi);
41
42 /*
43  * AutomationObject - "base" class for all automation objects. For each interface, we implement Invoke function
44  *                    called from AutomationObject::Invoke, and pass this function to create_automation_object.
45  */
46
47 typedef interface AutomationObject AutomationObject;
48
49 interface AutomationObject {
50     /*
51      * VTables - We provide IDispatch, IProvideClassInfo, IProvideClassInfo2, IProvideMultipleClassInfo
52      */
53     const IDispatchVtbl *lpVtbl;
54     const IProvideMultipleClassInfoVtbl *lpvtblIProvideMultipleClassInfo;
55
56     /* Object reference count */
57     LONG ref;
58
59     /* Clsid for this class and it's appropriate ITypeInfo object */
60     LPCLSID clsid;
61     ITypeInfo *iTypeInfo;
62
63     /* The MSI handle of the current object */
64     MSIHANDLE msiHandle;
65
66     /* A function that is called from AutomationObject::Invoke, specific to this type of object. */
67     HRESULT (STDMETHODCALLTYPE *funcInvoke)(
68         AutomationObject* This,
69         DISPID dispIdMember,
70         REFIID riid,
71         LCID lcid,
72         WORD wFlags,
73         DISPPARAMS* pDispParams,
74         VARIANT* pVarResult,
75         EXCEPINFO* pExcepInfo,
76         UINT* puArgErr);
77
78     /* A function that is called from AutomationObject::Release when the object is being freed to free any private
79      * data structures (or NULL) */
80     void (STDMETHODCALLTYPE *funcFree)(AutomationObject* This);
81 };
82
83 /*
84  * ListEnumerator - IEnumVARIANT implementation for MSI automation lists.
85  */
86
87 typedef interface ListEnumerator ListEnumerator;
88
89 interface ListEnumerator {
90     /* VTables */
91     const IEnumVARIANTVtbl *lpVtbl;
92
93     /* Object reference count */
94     LONG ref;
95
96     /* Current position and pointer to AutomationObject that stores actual data */
97     ULONG ulPos;
98     AutomationObject *pObj;
99 };
100
101 /*
102  * Structures for additional data required by specific automation objects
103  */
104
105 typedef struct {
106     ULONG ulCount;
107     VARIANT *pVars;
108 } ListData;
109
110 typedef struct {
111     /* The parent Installer object */
112     IDispatch *pInstaller;
113 } SessionData;
114
115 /* VTables */
116 static const struct IDispatchVtbl AutomationObject_Vtbl;
117 static const struct IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl;
118 static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl;
119
120 /* Load type info so we don't have to process GetIDsOfNames */
121 HRESULT load_type_info(IDispatch *iface, ITypeInfo **pptinfo, REFIID clsid, LCID lcid)
122 {
123     HRESULT hr;
124     LPTYPELIB pLib = NULL;
125     LPTYPEINFO pInfo = NULL;
126     static const WCHAR szMsiServer[] = {'m','s','i','s','e','r','v','e','r','.','t','l','b'};
127
128     TRACE("(%p)->(%s,%d)\n", iface, debugstr_guid(clsid), lcid);
129
130     /* Load registered type library */
131     hr = LoadRegTypeLib(&LIBID_WindowsInstaller, 1, 0, lcid, &pLib);
132     if (FAILED(hr)) {
133         hr = LoadTypeLib(szMsiServer, &pLib);
134         if (FAILED(hr)) {
135             ERR("Could not load msiserver.tlb\n");
136             return hr;
137         }
138     }
139
140     /* Get type information for object */
141     hr = ITypeLib_GetTypeInfoOfGuid(pLib, clsid, &pInfo);
142     ITypeLib_Release(pLib);
143     if (FAILED(hr)) {
144         ERR("Could not load ITypeInfo for %s\n", debugstr_guid(clsid));
145         return hr;
146     }
147     *pptinfo = pInfo;
148     return S_OK;
149 }
150
151 /* Create the automation object, placing the result in the pointer ppObj. The automation object is created
152  * with the appropriate clsid and invocation function. */
153 HRESULT create_automation_object(MSIHANDLE msiHandle, IUnknown *pUnkOuter, LPVOID *ppObj, REFIID clsid,
154             HRESULT (STDMETHODCALLTYPE *funcInvoke)(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,
155                                                     VARIANT*,EXCEPINFO*,UINT*),
156                                  void (STDMETHODCALLTYPE *funcFree)(AutomationObject*),
157                                  SIZE_T sizetPrivateData)
158 {
159     AutomationObject *object;
160     HRESULT hr;
161
162     TRACE("(%ld,%p,%p,%s,%p,%p,%ld)\n", (unsigned long)msiHandle, pUnkOuter, ppObj, debugstr_guid(clsid), funcInvoke, funcFree, sizetPrivateData);
163
164     if( pUnkOuter )
165         return CLASS_E_NOAGGREGATION;
166
167     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AutomationObject)+sizetPrivateData);
168
169     /* Set all the VTable references */
170     object->lpVtbl = &AutomationObject_Vtbl;
171     object->lpvtblIProvideMultipleClassInfo = &AutomationObject_IProvideMultipleClassInfo_Vtbl;
172     object->ref = 1;
173
174     /* Store data that was passed */
175     object->msiHandle = msiHandle;
176     object->clsid = (LPCLSID)clsid;
177     object->funcInvoke = funcInvoke;
178     object->funcFree = funcFree;
179
180     /* Load our TypeInfo so we don't have to process GetIDsOfNames */
181     object->iTypeInfo = NULL;
182     hr = load_type_info((IDispatch *)object, &object->iTypeInfo, clsid, 0x0);
183     if (FAILED(hr)) {
184         HeapFree(GetProcessHeap(), 0, object);
185         return hr;
186     }
187
188     *ppObj = object;
189
190     return S_OK;
191 }
192
193 /* Create a list enumerator, placing the result in the pointer ppObj.  */
194 HRESULT create_list_enumerator(IUnknown *pUnkOuter, LPVOID *ppObj, AutomationObject *pObj, ULONG ulPos)
195 {
196     ListEnumerator *object;
197
198     TRACE("(%p,%p,%p,%uld)\n", pUnkOuter, ppObj, pObj, ulPos);
199
200     if( pUnkOuter )
201         return CLASS_E_NOAGGREGATION;
202
203     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ListEnumerator));
204
205     /* Set all the VTable references */
206     object->lpVtbl = &ListEnumerator_Vtbl;
207     object->ref = 1;
208
209     /* Store data that was passed */
210     object->ulPos = ulPos;
211     object->pObj = pObj;
212     if (pObj) IDispatch_AddRef((IDispatch *)pObj);
213
214     *ppObj = object;
215     return S_OK;
216 }
217
218 /* Macros to get pointer to AutomationObject from the other VTables. */
219 static inline AutomationObject *obj_from_IProvideMultipleClassInfo( IProvideMultipleClassInfo *iface )
220 {
221     return (AutomationObject *)((char*)iface - FIELD_OFFSET(AutomationObject, lpvtblIProvideMultipleClassInfo));
222 }
223
224 /* Macro to get pointer to private object data */
225 static inline void *private_data( AutomationObject *This )
226 {
227     return This + 1;
228 }
229
230 /*
231  * AutomationObject methods
232  */
233
234 /*** IUnknown methods ***/
235 static HRESULT WINAPI AutomationObject_QueryInterface(IDispatch* iface, REFIID riid, void** ppvObject)
236 {
237     AutomationObject *This = (AutomationObject *)iface;
238
239     TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
240
241     if (ppvObject == NULL)
242       return E_INVALIDARG;
243
244     *ppvObject = 0;
245
246     if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDispatch) || IsEqualGUID(riid, This->clsid))
247         *ppvObject = This;
248     else if (IsEqualGUID(riid, &IID_IProvideClassInfo) ||
249              IsEqualGUID(riid, &IID_IProvideClassInfo2) ||
250              IsEqualGUID(riid, &IID_IProvideMultipleClassInfo))
251         *ppvObject = &This->lpvtblIProvideMultipleClassInfo;
252     else
253     {
254         TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid));
255         return E_NOINTERFACE;
256     }
257
258     /*
259      * Query Interface always increases the reference count by one when it is
260      * successful
261      */
262     IClassFactory_AddRef(iface);
263
264     return S_OK;
265 }
266
267 static ULONG WINAPI AutomationObject_AddRef(IDispatch* iface)
268 {
269     AutomationObject *This = (AutomationObject *)iface;
270
271     TRACE("(%p/%p)\n", iface, This);
272
273     return InterlockedIncrement(&This->ref);
274 }
275
276 static ULONG WINAPI AutomationObject_Release(IDispatch* iface)
277 {
278     AutomationObject *This = (AutomationObject *)iface;
279     ULONG ref = InterlockedDecrement(&This->ref);
280
281     TRACE("(%p/%p)\n", iface, This);
282
283     if (!ref)
284     {
285         if (This->funcFree) This->funcFree(This);
286         ITypeInfo_Release(This->iTypeInfo);
287         MsiCloseHandle(This->msiHandle);
288         HeapFree(GetProcessHeap(), 0, This);
289     }
290
291     return ref;
292 }
293
294 /*** IDispatch methods ***/
295 static HRESULT WINAPI AutomationObject_GetTypeInfoCount(
296         IDispatch* iface,
297         UINT* pctinfo)
298 {
299     AutomationObject *This = (AutomationObject *)iface;
300
301     TRACE("(%p/%p)->(%p)\n", iface, This, pctinfo);
302     *pctinfo = 1;
303     return S_OK;
304 }
305
306 static HRESULT WINAPI AutomationObject_GetTypeInfo(
307         IDispatch* iface,
308         UINT iTInfo,
309         LCID lcid,
310         ITypeInfo** ppTInfo)
311 {
312     AutomationObject *This = (AutomationObject *)iface;
313     TRACE("(%p/%p)->(%d,%d,%p)\n", iface, This, iTInfo, lcid, ppTInfo);
314
315     ITypeInfo_AddRef(This->iTypeInfo);
316     *ppTInfo = This->iTypeInfo;
317     return S_OK;
318 }
319
320 static HRESULT WINAPI AutomationObject_GetIDsOfNames(
321         IDispatch* iface,
322         REFIID riid,
323         LPOLESTR* rgszNames,
324         UINT cNames,
325         LCID lcid,
326         DISPID* rgDispId)
327 {
328     AutomationObject *This = (AutomationObject *)iface;
329     HRESULT hr;
330     TRACE("(%p/%p)->(%p,%p,%d,%d,%p)\n", iface, This, riid, rgszNames, cNames, lcid, rgDispId);
331
332     if (!IsEqualGUID(riid, &IID_NULL)) return E_INVALIDARG;
333     hr = ITypeInfo_GetIDsOfNames(This->iTypeInfo, rgszNames, cNames, rgDispId);
334     if (hr == DISP_E_UNKNOWNNAME)
335     {
336         int idx;
337         for (idx=0; idx<cNames; idx++)
338         {
339             if (rgDispId[idx] == DISPID_UNKNOWN)
340                 FIXME("Unknown member %s, clsid %s\n", debugstr_w(rgszNames[idx]), debugstr_guid(This->clsid));
341         }
342     }
343     return hr;
344 }
345
346 /* Maximum number of allowed function parameters+1 */
347 #define MAX_FUNC_PARAMS 20
348
349 /* Some error checking is done here to simplify individual object function invocation */
350 static HRESULT WINAPI AutomationObject_Invoke(
351         IDispatch* iface,
352         DISPID dispIdMember,
353         REFIID riid,
354         LCID lcid,
355         WORD wFlags,
356         DISPPARAMS* pDispParams,
357         VARIANT* pVarResult,
358         EXCEPINFO* pExcepInfo,
359         UINT* puArgErr)
360 {
361     AutomationObject *This = (AutomationObject *)iface;
362     HRESULT hr;
363     unsigned int uArgErr;
364     VARIANT varResultDummy;
365     BSTR bstrName = NULL;
366
367     TRACE("(%p/%p)->(%d,%p,%d,%d,%p,%p,%p,%p)\n", iface, This, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
368
369     if (!IsEqualIID(riid, &IID_NULL))
370     {
371         ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
372         return DISP_E_UNKNOWNNAME;
373     }
374
375     if (wFlags & DISPATCH_PROPERTYGET && !pVarResult)
376     {
377         ERR("NULL pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
378         return DISP_E_PARAMNOTOPTIONAL;
379     }
380
381     /* This simplifies our individual object invocation functions */
382     if (puArgErr == NULL) puArgErr = &uArgErr;
383     if (pVarResult == NULL) pVarResult = &varResultDummy;
384
385     /* Assume return type is void unless determined otherwise */
386     VariantInit(pVarResult);
387
388     /* If we are tracing, we want to see the name of the member we are invoking */
389     if (TRACE_ON(msi))
390     {
391         ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL);
392         TRACE("Method %d, %s\n", dispIdMember, debugstr_w(bstrName));
393     }
394
395     hr = This->funcInvoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
396
397     if (hr == DISP_E_MEMBERNOTFOUND) {
398         if (bstrName == NULL) ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL);
399         FIXME("Method %d, %s wflags %d not implemented, clsid %s\n", dispIdMember, debugstr_w(bstrName), wFlags, debugstr_guid(This->clsid));
400     }
401     else if (pExcepInfo &&
402              (hr == DISP_E_PARAMNOTFOUND ||
403               hr == DISP_E_EXCEPTION)) {
404         static const WCHAR szComma[] = { ',',0 };
405         static WCHAR szExceptionSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
406         WCHAR szExceptionDescription[MAX_PATH];
407         BSTR bstrParamNames[MAX_FUNC_PARAMS];
408         unsigned namesNo, i;
409         BOOL bFirst = TRUE;
410
411         if (FAILED(ITypeInfo_GetNames(This->iTypeInfo, dispIdMember, bstrParamNames,
412                                       MAX_FUNC_PARAMS, &namesNo)))
413         {
414             TRACE("Failed to retrieve names for dispIdMember %d\n", dispIdMember);
415         }
416         else
417         {
418             memset(szExceptionDescription, 0, sizeof(szExceptionDescription));
419             for (i=0; i<namesNo; i++)
420             {
421                 if (bFirst) bFirst = FALSE;
422                 else {
423                     lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], szComma);
424                 }
425                 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], bstrParamNames[i]);
426                 SysFreeString(bstrParamNames[i]);
427             }
428
429             memset(pExcepInfo, 0, sizeof(EXCEPINFO));
430             pExcepInfo->wCode = 1000;
431             pExcepInfo->bstrSource = SysAllocString(szExceptionSource);
432             pExcepInfo->bstrDescription = SysAllocString(szExceptionDescription);
433             hr = DISP_E_EXCEPTION;
434         }
435     }
436
437     /* Make sure we free the return variant if it is our dummy variant */
438     if (pVarResult == &varResultDummy) VariantClear(pVarResult);
439
440     /* Free function name if we retrieved it */
441     if (bstrName) SysFreeString(bstrName);
442
443     TRACE("Returning 0x%08x, %s\n", hr, SUCCEEDED(hr) ? "ok" : "not ok");
444
445     return hr;
446 }
447
448 static const struct IDispatchVtbl AutomationObject_Vtbl =
449 {
450     AutomationObject_QueryInterface,
451     AutomationObject_AddRef,
452     AutomationObject_Release,
453     AutomationObject_GetTypeInfoCount,
454     AutomationObject_GetTypeInfo,
455     AutomationObject_GetIDsOfNames,
456     AutomationObject_Invoke
457 };
458
459 /*
460  * IProvideMultipleClassInfo methods
461  */
462
463 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_QueryInterface(
464   IProvideMultipleClassInfo* iface,
465   REFIID     riid,
466   VOID**     ppvoid)
467 {
468     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
469     return AutomationObject_QueryInterface((IDispatch *)This, riid, ppvoid);
470 }
471
472 static ULONG WINAPI AutomationObject_IProvideMultipleClassInfo_AddRef(IProvideMultipleClassInfo* iface)
473 {
474     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
475     return AutomationObject_AddRef((IDispatch *)This);
476 }
477
478 static ULONG WINAPI AutomationObject_IProvideMultipleClassInfo_Release(IProvideMultipleClassInfo* iface)
479 {
480     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
481     return AutomationObject_Release((IDispatch *)This);
482 }
483
484 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_GetClassInfo(IProvideMultipleClassInfo* iface, ITypeInfo** ppTI)
485 {
486     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
487     TRACE("(%p/%p)->(%p)\n", iface, This, ppTI);
488     return load_type_info((IDispatch *)This, ppTI, This->clsid, 0);
489 }
490
491 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_GetGUID(IProvideMultipleClassInfo* iface, DWORD dwGuidKind, GUID* pGUID)
492 {
493     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
494     TRACE("(%p/%p)->(%d,%s)\n", iface, This, dwGuidKind, debugstr_guid(pGUID));
495
496     if (dwGuidKind != GUIDKIND_DEFAULT_SOURCE_DISP_IID)
497         return E_INVALIDARG;
498     else {
499         *pGUID = *This->clsid;
500         return S_OK;
501     }
502 }
503
504 static HRESULT WINAPI AutomationObject_GetMultiTypeInfoCount(IProvideMultipleClassInfo* iface, ULONG* pcti)
505 {
506     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
507
508     TRACE("(%p/%p)->(%p)\n", iface, This, pcti);
509     *pcti = 1;
510     return S_OK;
511 }
512
513 static HRESULT WINAPI AutomationObject_GetInfoOfIndex(IProvideMultipleClassInfo* iface,
514         ULONG iti,
515         DWORD dwFlags,
516         ITypeInfo** pptiCoClass,
517         DWORD* pdwTIFlags,
518         ULONG* pcdispidReserved,
519         IID* piidPrimary,
520         IID* piidSource)
521 {
522     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
523
524     TRACE("(%p/%p)->(%d,%d,%p,%p,%p,%p,%p)\n", iface, This, iti, dwFlags, pptiCoClass, pdwTIFlags, pcdispidReserved, piidPrimary, piidSource);
525
526     if (iti != 0)
527         return E_INVALIDARG;
528
529     if (dwFlags & MULTICLASSINFO_GETTYPEINFO)
530         load_type_info((IDispatch *)This, pptiCoClass, This->clsid, 0);
531
532     if (dwFlags & MULTICLASSINFO_GETNUMRESERVEDDISPIDS)
533     {
534         *pdwTIFlags = 0;
535         *pcdispidReserved = 0;
536     }
537
538     if (dwFlags & MULTICLASSINFO_GETIIDPRIMARY){
539         *piidPrimary = *This->clsid;
540     }
541
542     if (dwFlags & MULTICLASSINFO_GETIIDSOURCE){
543         *piidSource = *This->clsid;
544     }
545
546     return S_OK;
547 }
548
549 static const IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl =
550 {
551     AutomationObject_IProvideMultipleClassInfo_QueryInterface,
552     AutomationObject_IProvideMultipleClassInfo_AddRef,
553     AutomationObject_IProvideMultipleClassInfo_Release,
554     AutomationObject_IProvideMultipleClassInfo_GetClassInfo,
555     AutomationObject_IProvideMultipleClassInfo_GetGUID,
556     AutomationObject_GetMultiTypeInfoCount,
557     AutomationObject_GetInfoOfIndex
558 };
559
560 /*
561  * ListEnumerator methods
562  */
563
564 /*** IUnknown methods ***/
565 static HRESULT WINAPI ListEnumerator_QueryInterface(IEnumVARIANT* iface, REFIID riid, void** ppvObject)
566 {
567     ListEnumerator *This = (ListEnumerator *)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) || IsEqualGUID(riid, &IID_IEnumVARIANT))
577         *ppvObject = This;
578     else
579     {
580         TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid));
581         return E_NOINTERFACE;
582     }
583
584     IClassFactory_AddRef(iface);
585     return S_OK;
586 }
587
588 static ULONG WINAPI ListEnumerator_AddRef(IEnumVARIANT* iface)
589 {
590     ListEnumerator *This = (ListEnumerator *)iface;
591
592     TRACE("(%p/%p)\n", iface, This);
593
594     return InterlockedIncrement(&This->ref);
595 }
596
597 static ULONG WINAPI ListEnumerator_Release(IEnumVARIANT* iface)
598 {
599     ListEnumerator *This = (ListEnumerator *)iface;
600     ULONG ref = InterlockedDecrement(&This->ref);
601
602     TRACE("(%p/%p)\n", iface, This);
603
604     if (!ref)
605     {
606         if (This->pObj) IDispatch_Release((IDispatch *)This->pObj);
607         HeapFree(GetProcessHeap(), 0, This);
608     }
609
610     return ref;
611 }
612
613 /* IEnumVARIANT methods */
614
615 static HRESULT WINAPI ListEnumerator_Next(IEnumVARIANT* iface, ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched)
616 {
617     ListEnumerator *This = (ListEnumerator *)iface;
618     ListData *data = (ListData *)private_data(This->pObj);
619     ULONG idx, local;
620
621     TRACE("(%p,%uld,%p,%p)\n", iface, celt, rgVar, pCeltFetched);
622
623     if (pCeltFetched != NULL)
624         *pCeltFetched = 0;
625
626     if (rgVar == NULL)
627         return S_FALSE;
628
629     for (local = 0; local < celt; local++)
630         VariantInit(&rgVar[local]);
631
632     for (idx = This->ulPos, local = 0; idx < data->ulCount && local < celt; idx++, local++)
633         VariantCopy(&rgVar[local], &data->pVars[idx]);
634
635     if (pCeltFetched != NULL)
636         *pCeltFetched = local;
637     This->ulPos = idx;
638
639     return (local < celt) ? S_FALSE : S_OK;
640 }
641
642 static HRESULT WINAPI ListEnumerator_Skip(IEnumVARIANT* iface, ULONG celt)
643 {
644     ListEnumerator *This = (ListEnumerator *)iface;
645     ListData *data = (ListData *)private_data(This->pObj);
646
647     TRACE("(%p,%uld)\n", iface, celt);
648
649     This->ulPos += celt;
650     if (This->ulPos >= data->ulCount)
651     {
652         This->ulPos = data->ulCount;
653         return S_FALSE;
654     }
655     return S_OK;
656 }
657
658 static HRESULT WINAPI ListEnumerator_Reset(IEnumVARIANT* iface)
659 {
660     ListEnumerator *This = (ListEnumerator *)iface;
661
662     TRACE("(%p)\n", iface);
663
664     This->ulPos = 0;
665     return S_OK;
666 }
667
668 static HRESULT WINAPI ListEnumerator_Clone(IEnumVARIANT* iface, IEnumVARIANT **ppEnum)
669 {
670     ListEnumerator *This = (ListEnumerator *)iface;
671     HRESULT hr;
672
673     TRACE("(%p,%p)\n", iface, ppEnum);
674
675     if (ppEnum == NULL)
676         return S_FALSE;
677
678     *ppEnum = NULL;
679     hr = create_list_enumerator(NULL, (LPVOID *)ppEnum, This->pObj, 0);
680     if (FAILED(hr))
681     {
682         if (*ppEnum)
683             IUnknown_Release(*ppEnum);
684         return hr;
685     }
686
687     return S_OK;
688 }
689
690 static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl =
691 {
692     ListEnumerator_QueryInterface,
693     ListEnumerator_AddRef,
694     ListEnumerator_Release,
695     ListEnumerator_Next,
696     ListEnumerator_Skip,
697     ListEnumerator_Reset,
698     ListEnumerator_Clone
699 };
700
701 /*
702  * Individual Object Invocation Functions
703  */
704
705 /* Helper function that copies a passed parameter instead of using VariantChangeType like the actual DispGetParam.
706    This function is only for VARIANT type parameters that have several types that cannot be properly discriminated
707    using DispGetParam/VariantChangeType. */
708 HRESULT WINAPI DispGetParam_CopyOnly(
709         DISPPARAMS *pdispparams, /* [in] Parameter list */
710         UINT        *position,    /* [in] Position of parameter to copy in pdispparams; on return will contain calculated position */
711         VARIANT    *pvarResult)  /* [out] Destination for resulting variant */
712 {
713     /* position is counted backwards */
714     UINT pos;
715
716     TRACE("position=%d, cArgs=%d, cNamedArgs=%d\n",
717           *position, pdispparams->cArgs, pdispparams->cNamedArgs);
718     if (*position < pdispparams->cArgs) {
719       /* positional arg? */
720       pos = pdispparams->cArgs - *position - 1;
721     } else {
722       /* FIXME: is this how to handle named args? */
723       for (pos=0; pos<pdispparams->cNamedArgs; pos++)
724         if (pdispparams->rgdispidNamedArgs[pos] == *position) break;
725
726       if (pos==pdispparams->cNamedArgs)
727         return DISP_E_PARAMNOTFOUND;
728     }
729     *position = pos;
730     return VariantCopyInd(pvarResult,
731                         &pdispparams->rgvarg[pos]);
732 }
733
734 static HRESULT WINAPI SummaryInfoImpl_Invoke(
735         AutomationObject* This,
736         DISPID dispIdMember,
737         REFIID riid,
738         LCID lcid,
739         WORD wFlags,
740         DISPPARAMS* pDispParams,
741         VARIANT* pVarResult,
742         EXCEPINFO* pExcepInfo,
743         UINT* puArgErr)
744 {
745     UINT ret;
746     VARIANTARG varg0, varg1;
747     FILETIME ft, ftlocal;
748     SYSTEMTIME st;
749     HRESULT hr;
750
751     VariantInit(&varg0);
752     VariantInit(&varg1);
753
754     switch (dispIdMember)
755     {
756         case DISPID_SUMMARYINFO_PROPERTY:
757             if (wFlags & DISPATCH_PROPERTYGET)
758             {
759                 UINT type;
760                 INT value;
761                 DWORD size = 0;
762                 DATE date;
763                 LPWSTR str;
764
765                 static WCHAR szEmpty[] = {0};
766
767                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
768                 if (FAILED(hr)) return hr;
769                 ret = MsiSummaryInfoGetPropertyW(This->msiHandle, V_I4(&varg0), &type, &value,
770                                                  &ft, szEmpty, &size);
771                 if (ret != ERROR_SUCCESS &&
772                     ret != ERROR_MORE_DATA)
773                 {
774                     ERR("MsiSummaryInfoGetProperty returned %d\n", ret);
775                     return DISP_E_EXCEPTION;
776                 }
777
778                 switch (type)
779                 {
780                     case VT_EMPTY:
781                         break;
782
783                     case VT_I2:
784                     case VT_I4:
785                         V_VT(pVarResult) = VT_I4;
786                         V_I4(pVarResult) = value;
787                         break;
788
789                     case VT_LPSTR:
790                         if (!(str = msi_alloc(++size * sizeof(WCHAR))))
791                             ERR("Out of memory\n");
792                         else if ((ret = MsiSummaryInfoGetPropertyW(This->msiHandle, V_I4(&varg0), &type, NULL,
793                                                                    NULL, str, &size)) != ERROR_SUCCESS)
794                             ERR("MsiSummaryInfoGetProperty returned %d\n", ret);
795                         else
796                         {
797                             V_VT(pVarResult) = VT_BSTR;
798                             V_BSTR(pVarResult) = SysAllocString(str);
799                         }
800                         msi_free(str);
801                         break;
802
803                     case VT_FILETIME:
804                         FileTimeToLocalFileTime(&ft, &ftlocal);
805                         FileTimeToSystemTime(&ftlocal, &st);
806                         SystemTimeToVariantTime(&st, &date);
807
808                         V_VT(pVarResult) = VT_DATE;
809                         V_DATE(pVarResult) = date;
810                         break;
811
812                     default:
813                         ERR("Unhandled variant type %d\n", type);
814                 }
815             }
816             else if (wFlags & DISPATCH_PROPERTYPUT)
817             {
818                 UINT posValue = DISPID_PROPERTYPUT;
819
820                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
821                 if (FAILED(hr)) return hr;
822                 hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg1);
823                 if (FAILED(hr))
824                 {
825                     *puArgErr = posValue;
826                     return hr;
827                 }
828
829                 switch (V_VT(&varg1))
830                 {
831                     case VT_I2:
832                     case VT_I4:
833                         ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), V_VT(&varg1), V_I4(&varg1), NULL, NULL);
834                         break;
835
836                     case VT_DATE:
837                         VariantTimeToSystemTime(V_DATE(&varg1), &st);
838                         SystemTimeToFileTime(&st, &ftlocal);
839                         LocalFileTimeToFileTime(&ftlocal, &ft);
840                         ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), VT_FILETIME, 0, &ft, NULL);
841                         break;
842
843                     case VT_BSTR:
844                         ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), VT_LPSTR, 0, NULL, V_BSTR(&varg1));
845                         break;
846
847                     default:
848                         FIXME("Unhandled variant type %d\n", V_VT(&varg1));
849                         VariantClear(&varg1);
850                         return DISP_E_EXCEPTION;
851                 }
852
853                 if (ret != ERROR_SUCCESS)
854                 {
855                     ERR("MsiSummaryInfoSetPropertyW returned %d\n", ret);
856                     return DISP_E_EXCEPTION;
857                 }
858             }
859             else return DISP_E_MEMBERNOTFOUND;
860             break;
861
862         case DISPID_SUMMARYINFO_PROPERTYCOUNT:
863             if (wFlags & DISPATCH_PROPERTYGET) {
864                 UINT count;
865                 if ((ret = MsiSummaryInfoGetPropertyCount(This->msiHandle, &count)) != ERROR_SUCCESS)
866                     ERR("MsiSummaryInfoGetPropertyCount returned %d\n", ret);
867                 else
868                 {
869                     V_VT(pVarResult) = VT_I4;
870                     V_I4(pVarResult) = count;
871                 }
872             }
873             else return DISP_E_MEMBERNOTFOUND;
874             break;
875
876         default:
877             return DISP_E_MEMBERNOTFOUND;
878     }
879
880     VariantClear(&varg1);
881     VariantClear(&varg0);
882
883     return S_OK;
884 }
885
886 static HRESULT WINAPI RecordImpl_Invoke(
887         AutomationObject* This,
888         DISPID dispIdMember,
889         REFIID riid,
890         LCID lcid,
891         WORD wFlags,
892         DISPPARAMS* pDispParams,
893         VARIANT* pVarResult,
894         EXCEPINFO* pExcepInfo,
895         UINT* puArgErr)
896 {
897     WCHAR *szString;
898     DWORD dwLen;
899     UINT ret;
900     VARIANTARG varg0, varg1;
901     HRESULT hr;
902
903     VariantInit(&varg0);
904     VariantInit(&varg1);
905
906     switch (dispIdMember)
907     {
908         case DISPID_RECORD_FIELDCOUNT:
909             if (wFlags & DISPATCH_PROPERTYGET) {
910                 V_VT(pVarResult) = VT_I4;
911                 V_I4(pVarResult) = MsiRecordGetFieldCount(This->msiHandle);
912             }
913             else return DISP_E_MEMBERNOTFOUND;
914             break;
915
916         case DISPID_RECORD_STRINGDATA:
917             if (wFlags & DISPATCH_PROPERTYGET) {
918                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
919                 if (FAILED(hr)) return hr;
920                 V_VT(pVarResult) = VT_BSTR;
921                 V_BSTR(pVarResult) = NULL;
922                 if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
923                 {
924                     if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
925                         ERR("Out of memory\n");
926                     else if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
927                         V_BSTR(pVarResult) = SysAllocString(szString);
928                     msi_free(szString);
929                 }
930                 if (ret != ERROR_SUCCESS)
931                     ERR("MsiRecordGetString returned %d\n", ret);
932             } else if (wFlags & DISPATCH_PROPERTYPUT) {
933                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
934                 if (FAILED(hr)) return hr;
935                 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BSTR, &varg1, puArgErr);
936                 if (FAILED(hr)) return hr;
937                 if ((ret = MsiRecordSetStringW(This->msiHandle, V_I4(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
938                 {
939                     VariantClear(&varg1);
940                     ERR("MsiRecordSetString returned %d\n", ret);
941                     return DISP_E_EXCEPTION;
942                 }
943             }
944             else return DISP_E_MEMBERNOTFOUND;
945             break;
946
947         case DISPID_RECORD_INTEGERDATA:
948             if (wFlags & DISPATCH_PROPERTYGET) {
949                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
950                 if (FAILED(hr)) return hr;
951                 V_VT(pVarResult) = VT_I4;
952                 V_I4(pVarResult) = MsiRecordGetInteger(This->msiHandle, V_I4(&varg0));
953             } else if (wFlags & DISPATCH_PROPERTYPUT) {
954                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
955                 if (FAILED(hr)) return hr;
956                 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_I4, &varg1, puArgErr);
957                 if (FAILED(hr)) return hr;
958                 if ((ret = MsiRecordSetInteger(This->msiHandle, V_I4(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
959                 {
960                     ERR("MsiRecordSetInteger returned %d\n", ret);
961                     return DISP_E_EXCEPTION;
962                 }
963             }
964             else return DISP_E_MEMBERNOTFOUND;
965             break;
966
967          default:
968             return DISP_E_MEMBERNOTFOUND;
969     }
970
971     VariantClear(&varg1);
972     VariantClear(&varg0);
973
974     return S_OK;
975 }
976
977 static HRESULT WINAPI ListImpl_Invoke(
978         AutomationObject* This,
979         DISPID dispIdMember,
980         REFIID riid,
981         LCID lcid,
982         WORD wFlags,
983         DISPPARAMS* pDispParams,
984         VARIANT* pVarResult,
985         EXCEPINFO* pExcepInfo,
986         UINT* puArgErr)
987 {
988     ListData *data = (ListData *)private_data(This);
989     HRESULT hr;
990     VARIANTARG varg0;
991     IUnknown *pUnk = NULL;
992
993     VariantInit(&varg0);
994
995     switch (dispIdMember)
996     {
997          case DISPID_LIST__NEWENUM:
998              if (wFlags & DISPATCH_METHOD) {
999                  V_VT(pVarResult) = VT_UNKNOWN;
1000                  if (SUCCEEDED(hr = create_list_enumerator(NULL, (LPVOID *)&pUnk, This, 0)))
1001                      V_UNKNOWN(pVarResult) = pUnk;
1002                  else
1003                      ERR("Failed to create IEnumVARIANT object, hresult 0x%08x\n", hr);
1004              }
1005              else return DISP_E_MEMBERNOTFOUND;
1006              break;
1007
1008          case DISPID_LIST_ITEM:
1009              if (wFlags & DISPATCH_PROPERTYGET) {
1010                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1011                 if (FAILED(hr)) return hr;
1012                 if (V_I4(&varg0) < 0 || V_I4(&varg0) >= data->ulCount)
1013                     return DISP_E_BADINDEX;
1014                 VariantCopy(pVarResult, &data->pVars[V_I4(&varg0)]);
1015             }
1016             else return DISP_E_MEMBERNOTFOUND;
1017             break;
1018
1019          case DISPID_LIST_COUNT:
1020             if (wFlags & DISPATCH_PROPERTYGET) {
1021                 V_VT(pVarResult) = VT_I4;
1022                 V_I4(pVarResult) = data->ulCount;
1023             }
1024             else return DISP_E_MEMBERNOTFOUND;
1025             break;
1026
1027          default:
1028             return DISP_E_MEMBERNOTFOUND;
1029     }
1030
1031     VariantClear(&varg0);
1032
1033     return S_OK;
1034 }
1035
1036 static void WINAPI ListImpl_Free(AutomationObject *This)
1037 {
1038     ListData *data = private_data(This);
1039     ULONG idx;
1040
1041     for (idx=0; idx<data->ulCount; idx++)
1042         VariantClear(&data->pVars[idx]);
1043     HeapFree(GetProcessHeap(), 0, data->pVars);
1044 }
1045
1046 static HRESULT WINAPI ViewImpl_Invoke(
1047         AutomationObject* This,
1048         DISPID dispIdMember,
1049         REFIID riid,
1050         LCID lcid,
1051         WORD wFlags,
1052         DISPPARAMS* pDispParams,
1053         VARIANT* pVarResult,
1054         EXCEPINFO* pExcepInfo,
1055         UINT* puArgErr)
1056 {
1057     MSIHANDLE msiHandle;
1058     IDispatch *pDispatch = NULL;
1059     UINT ret;
1060     VARIANTARG varg0, varg1;
1061     HRESULT hr;
1062
1063     VariantInit(&varg0);
1064     VariantInit(&varg1);
1065
1066     switch (dispIdMember)
1067     {
1068         case DISPID_VIEW_EXECUTE:
1069             if (wFlags & DISPATCH_METHOD)
1070             {
1071                 hr = DispGetParam(pDispParams, 0, VT_DISPATCH, &varg0, puArgErr);
1072                 if (SUCCEEDED(hr) && V_DISPATCH(&varg0) != NULL)
1073                     MsiViewExecute(This->msiHandle, ((AutomationObject *)V_DISPATCH(&varg0))->msiHandle);
1074                 else
1075                     MsiViewExecute(This->msiHandle, 0);
1076             }
1077             else return DISP_E_MEMBERNOTFOUND;
1078             break;
1079
1080         case DISPID_VIEW_FETCH:
1081             if (wFlags & DISPATCH_METHOD)
1082             {
1083                 V_VT(pVarResult) = VT_DISPATCH;
1084                 if ((ret = MsiViewFetch(This->msiHandle, &msiHandle)) == ERROR_SUCCESS)
1085                 {
1086                     if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Record, RecordImpl_Invoke, NULL, 0)))
1087                         V_DISPATCH(pVarResult) = pDispatch;
1088                     else
1089                         ERR("Failed to create Record object, hresult 0x%08x\n", hr);
1090                 }
1091                 else if (ret == ERROR_NO_MORE_ITEMS)
1092                     V_DISPATCH(pVarResult) = NULL;
1093                 else
1094                 {
1095                     ERR("MsiViewFetch returned %d\n", ret);
1096                     return DISP_E_EXCEPTION;
1097                 }
1098             }
1099             else return DISP_E_MEMBERNOTFOUND;
1100             break;
1101
1102         case DISPID_VIEW_MODIFY:
1103             if (wFlags & DISPATCH_METHOD)
1104             {
1105                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1106                 if (FAILED(hr)) return hr;
1107                 hr = DispGetParam(pDispParams, 1, VT_DISPATCH, &varg1, puArgErr);
1108                 if (FAILED(hr)) return hr;
1109                 if (!V_DISPATCH(&varg1)) return DISP_E_EXCEPTION;
1110                 if ((ret = MsiViewModify(This->msiHandle, V_I4(&varg0), ((AutomationObject *)V_DISPATCH(&varg1))->msiHandle)) != ERROR_SUCCESS)
1111                 {
1112                     VariantClear(&varg1);
1113                     ERR("MsiViewModify returned %d\n", ret);
1114                     return DISP_E_EXCEPTION;
1115                 }
1116             }
1117             else return DISP_E_MEMBERNOTFOUND;
1118             break;
1119
1120         case DISPID_VIEW_CLOSE:
1121             if (wFlags & DISPATCH_METHOD)
1122             {
1123                 MsiViewClose(This->msiHandle);
1124             }
1125             else return DISP_E_MEMBERNOTFOUND;
1126             break;
1127
1128          default:
1129             return DISP_E_MEMBERNOTFOUND;
1130     }
1131
1132     VariantClear(&varg1);
1133     VariantClear(&varg0);
1134
1135     return S_OK;
1136 }
1137
1138 static HRESULT WINAPI DatabaseImpl_Invoke(
1139         AutomationObject* This,
1140         DISPID dispIdMember,
1141         REFIID riid,
1142         LCID lcid,
1143         WORD wFlags,
1144         DISPPARAMS* pDispParams,
1145         VARIANT* pVarResult,
1146         EXCEPINFO* pExcepInfo,
1147         UINT* puArgErr)
1148 {
1149     MSIHANDLE msiHandle;
1150     IDispatch *pDispatch = NULL;
1151     UINT ret;
1152     VARIANTARG varg0, varg1;
1153     HRESULT hr;
1154
1155     VariantInit(&varg0);
1156     VariantInit(&varg1);
1157
1158     switch (dispIdMember)
1159     {
1160         case DISPID_DATABASE_SUMMARYINFORMATION:
1161             if (wFlags & DISPATCH_PROPERTYGET)
1162             {
1163                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1164                 if (FAILED(hr))
1165                     V_I4(&varg0) = 0;
1166
1167                 V_VT(pVarResult) = VT_DISPATCH;
1168                 if ((ret = MsiGetSummaryInformationW(This->msiHandle, NULL, V_I4(&varg0), &msiHandle)) == ERROR_SUCCESS)
1169                 {
1170                     hr = create_automation_object(msiHandle, NULL, (LPVOID *)&pDispatch, &DIID_SummaryInfo, SummaryInfoImpl_Invoke, NULL, 0);
1171                     if (SUCCEEDED(hr))
1172                         V_DISPATCH(pVarResult) = pDispatch;
1173                     else
1174                         ERR("Failed to create SummaryInfo object: 0x%08x\n", hr);
1175                 }
1176                 else
1177                 {
1178                     ERR("MsiGetSummaryInformation returned %d\n", ret);
1179                     return DISP_E_EXCEPTION;
1180                 }
1181             }
1182             else return DISP_E_MEMBERNOTFOUND;
1183             break;
1184
1185         case DISPID_DATABASE_OPENVIEW:
1186             if (wFlags & DISPATCH_METHOD)
1187             {
1188                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1189                 if (FAILED(hr)) return hr;
1190                 V_VT(pVarResult) = VT_DISPATCH;
1191                 if ((ret = MsiDatabaseOpenViewW(This->msiHandle, V_BSTR(&varg0), &msiHandle)) == ERROR_SUCCESS)
1192                 {
1193                     if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_View, ViewImpl_Invoke, NULL, 0)))
1194                         V_DISPATCH(pVarResult) = pDispatch;
1195                     else
1196                         ERR("Failed to create View object, hresult 0x%08x\n", hr);
1197                 }
1198                 else
1199                 {
1200                     VariantClear(&varg0);
1201                     ERR("MsiDatabaseOpenView returned %d\n", ret);
1202                     return DISP_E_EXCEPTION;
1203                 }
1204             }
1205             else return DISP_E_MEMBERNOTFOUND;
1206             break;
1207
1208          default:
1209             return DISP_E_MEMBERNOTFOUND;
1210     }
1211
1212     VariantClear(&varg1);
1213     VariantClear(&varg0);
1214
1215     return S_OK;
1216 }
1217
1218 static HRESULT WINAPI SessionImpl_Invoke(
1219         AutomationObject* This,
1220         DISPID dispIdMember,
1221         REFIID riid,
1222         LCID lcid,
1223         WORD wFlags,
1224         DISPPARAMS* pDispParams,
1225         VARIANT* pVarResult,
1226         EXCEPINFO* pExcepInfo,
1227         UINT* puArgErr)
1228 {
1229     SessionData *data = private_data(This);
1230     WCHAR *szString;
1231     DWORD dwLen;
1232     IDispatch *pDispatch = NULL;
1233     MSIHANDLE msiHandle;
1234     LANGID langId;
1235     UINT ret;
1236     INSTALLSTATE iInstalled, iAction;
1237     VARIANTARG varg0, varg1;
1238     HRESULT hr;
1239
1240     VariantInit(&varg0);
1241     VariantInit(&varg1);
1242
1243     switch (dispIdMember)
1244     {
1245         case DISPID_SESSION_INSTALLER:
1246             if (wFlags & DISPATCH_PROPERTYGET) {
1247                 V_VT(pVarResult) = VT_DISPATCH;
1248                 IDispatch_AddRef(data->pInstaller);
1249                 V_DISPATCH(pVarResult) = data->pInstaller;
1250             }
1251             else return DISP_E_MEMBERNOTFOUND;
1252             break;
1253
1254         case DISPID_SESSION_PROPERTY:
1255             if (wFlags & DISPATCH_PROPERTYGET) {
1256                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1257                 if (FAILED(hr)) return hr;
1258                 V_VT(pVarResult) = VT_BSTR;
1259                 V_BSTR(pVarResult) = NULL;
1260                 if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
1261                 {
1262                     if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
1263                         ERR("Out of memory\n");
1264                     else if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
1265                         V_BSTR(pVarResult) = SysAllocString(szString);
1266                     msi_free(szString);
1267                 }
1268                 if (ret != ERROR_SUCCESS)
1269                     ERR("MsiGetProperty returned %d\n", ret);
1270             } else if (wFlags & DISPATCH_PROPERTYPUT) {
1271                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1272                 if (FAILED(hr)) return hr;
1273                 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BSTR, &varg1, puArgErr);
1274                 if (FAILED(hr)) {
1275                     VariantClear(&varg0);
1276                     return hr;
1277                 }
1278                 if ((ret = MsiSetPropertyW(This->msiHandle, V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
1279                 {
1280                     VariantClear(&varg0);
1281                     VariantClear(&varg1);
1282                     ERR("MsiSetProperty returned %d\n", ret);
1283                     return DISP_E_EXCEPTION;
1284                 }
1285             }
1286             else return DISP_E_MEMBERNOTFOUND;
1287             break;
1288
1289         case DISPID_SESSION_LANGUAGE:
1290             if (wFlags & DISPATCH_PROPERTYGET) {
1291                 langId = MsiGetLanguage(This->msiHandle);
1292                 V_VT(pVarResult) = VT_I4;
1293                 V_I4(pVarResult) = langId;
1294             }
1295             else return DISP_E_MEMBERNOTFOUND;
1296             break;
1297
1298         case DISPID_SESSION_MODE:
1299             if (wFlags & DISPATCH_PROPERTYGET) {
1300                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1301                 if (FAILED(hr)) return hr;
1302                 V_VT(pVarResult) = VT_BOOL;
1303                 V_BOOL(pVarResult) = MsiGetMode(This->msiHandle, V_I4(&varg0));
1304             } else if (wFlags & DISPATCH_PROPERTYPUT) {
1305                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1306                 if (FAILED(hr)) return hr;
1307                 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BOOL, &varg1, puArgErr);
1308                 if (FAILED(hr)) return hr;
1309                 if ((ret = MsiSetMode(This->msiHandle, V_I4(&varg0), V_BOOL(&varg1))) != ERROR_SUCCESS)
1310                 {
1311                     ERR("MsiSetMode returned %d\n", ret);
1312                     return DISP_E_EXCEPTION;
1313                 }
1314             }
1315             else return DISP_E_MEMBERNOTFOUND;
1316             break;
1317
1318         case DISPID_SESSION_DATABASE:
1319             if (wFlags & DISPATCH_PROPERTYGET) {
1320                 V_VT(pVarResult) = VT_DISPATCH;
1321                 if ((msiHandle = MsiGetActiveDatabase(This->msiHandle)))
1322                 {
1323                     if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Database, DatabaseImpl_Invoke, NULL, 0)))
1324                         V_DISPATCH(pVarResult) = pDispatch;
1325                     else
1326                         ERR("Failed to create Database object, hresult 0x%08x\n", hr);
1327                 }
1328                 else
1329                 {
1330                     ERR("MsiGetActiveDatabase failed\n");
1331                     return DISP_E_EXCEPTION;
1332                 }
1333             }
1334             else return DISP_E_MEMBERNOTFOUND;
1335             break;
1336
1337         case DISPID_SESSION_DOACTION:
1338             if (wFlags & DISPATCH_METHOD) {
1339                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1340                 if (FAILED(hr)) return hr;
1341                 ret = MsiDoActionW(This->msiHandle, V_BSTR(&varg0));
1342                 V_VT(pVarResult) = VT_I4;
1343                 switch (ret)
1344                 {
1345                     case ERROR_FUNCTION_NOT_CALLED:
1346                         V_I4(pVarResult) = msiDoActionStatusNoAction;
1347                         break;
1348                     case ERROR_SUCCESS:
1349                         V_I4(pVarResult) = msiDoActionStatusSuccess;
1350                         break;
1351                     case ERROR_INSTALL_USEREXIT:
1352                         V_I4(pVarResult) = msiDoActionStatusUserExit;
1353                         break;
1354                     case ERROR_INSTALL_FAILURE:
1355                         V_I4(pVarResult) = msiDoActionStatusFailure;
1356                         break;
1357                     case ERROR_INSTALL_SUSPEND:
1358                         V_I4(pVarResult) = msiDoActionStatusSuspend;
1359                         break;
1360                     case ERROR_MORE_DATA:
1361                         V_I4(pVarResult) = msiDoActionStatusFinished;
1362                         break;
1363                     case ERROR_INVALID_HANDLE_STATE:
1364                         V_I4(pVarResult) = msiDoActionStatusWrongState;
1365                         break;
1366                     case ERROR_INVALID_DATA:
1367                         V_I4(pVarResult) = msiDoActionStatusBadActionData;
1368                         break;
1369                     default:
1370                         VariantClear(&varg0);
1371                         FIXME("MsiDoAction returned unhandled value %d\n", ret);
1372                         return DISP_E_EXCEPTION;
1373                 }
1374             }
1375             else return DISP_E_MEMBERNOTFOUND;
1376             break;
1377
1378         case DISPID_SESSION_EVALUATECONDITION:
1379             if (wFlags & DISPATCH_METHOD) {
1380                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1381                 if (FAILED(hr)) return hr;
1382                 V_VT(pVarResult) = VT_I4;
1383                 V_I4(pVarResult) = MsiEvaluateConditionW(This->msiHandle, V_BSTR(&varg0));
1384             }
1385             else return DISP_E_MEMBERNOTFOUND;
1386             break;
1387
1388         case DISPID_SESSION_SETINSTALLLEVEL:
1389             if (wFlags & DISPATCH_METHOD) {
1390                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1391                 if (FAILED(hr)) return hr;
1392                 if ((ret = MsiSetInstallLevel(This->msiHandle, V_I4(&varg0))) != ERROR_SUCCESS)
1393                 {
1394                     ERR("MsiSetInstallLevel returned %d\n", ret);
1395                     return DISP_E_EXCEPTION;
1396                 }
1397             }
1398             else return DISP_E_MEMBERNOTFOUND;
1399             break;
1400
1401         case DISPID_SESSION_FEATURECURRENTSTATE:
1402             if (wFlags & DISPATCH_PROPERTYGET) {
1403                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1404                 if (FAILED(hr)) return hr;
1405                 V_VT(pVarResult) = VT_I4;
1406                 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1407                     V_I4(pVarResult) = iInstalled;
1408                 else
1409                 {
1410                     ERR("MsiGetFeatureState returned %d\n", ret);
1411                     V_I4(pVarResult) = msiInstallStateUnknown;
1412                 }
1413             }
1414             else return DISP_E_MEMBERNOTFOUND;
1415             break;
1416
1417         case DISPID_SESSION_FEATUREREQUESTSTATE:
1418             if (wFlags & DISPATCH_PROPERTYGET) {
1419                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1420                 if (FAILED(hr)) return hr;
1421                 V_VT(pVarResult) = VT_I4;
1422                 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1423                     V_I4(pVarResult) = iAction;
1424                 else
1425                 {
1426                     ERR("MsiGetFeatureState returned %d\n", ret);
1427                     V_I4(pVarResult) = msiInstallStateUnknown;
1428                 }
1429             } else if (wFlags & DISPATCH_PROPERTYPUT) {
1430                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1431                 if (FAILED(hr)) return hr;
1432                 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_I4, &varg1, puArgErr);
1433                 if (FAILED(hr)) {
1434                     VariantClear(&varg0);
1435                     return hr;
1436                 }
1437                 if ((ret = MsiSetFeatureStateW(This->msiHandle, V_BSTR(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
1438                 {
1439                     VariantClear(&varg0);
1440                     ERR("MsiSetFeatureState returned %d\n", ret);
1441                     return DISP_E_EXCEPTION;
1442                 }
1443             }
1444             else return DISP_E_MEMBERNOTFOUND;
1445             break;
1446
1447          default:
1448             return DISP_E_MEMBERNOTFOUND;
1449     }
1450
1451     VariantClear(&varg1);
1452     VariantClear(&varg0);
1453
1454     return S_OK;
1455 }
1456
1457 /* Fill the variant pointed to by pVarResult with the value & size returned by RegQueryValueEx as dictated by the
1458  * registry value type. Used by Installer::RegistryValue. */
1459 static void variant_from_registry_value(VARIANT *pVarResult, DWORD dwType, LPBYTE lpData, DWORD dwSize)
1460 {
1461     static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
1462     static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
1463     WCHAR *szString = (WCHAR *)lpData;
1464     LPWSTR szNewString = NULL;
1465     DWORD dwNewSize = 0;
1466     int idx;
1467
1468     switch (dwType)
1469     {
1470         /* Registry strings may not be null terminated so we must use SysAllocStringByteLen/Len */
1471         case REG_MULTI_SZ: /* Multi SZ change internal null characters to newlines */
1472             idx = (dwSize/sizeof(WCHAR))-1;
1473             while (idx >= 0 && !szString[idx]) idx--;
1474             for (; idx >= 0; idx--)
1475                 if (!szString[idx]) szString[idx] = '\n';
1476         case REG_SZ:
1477             V_VT(pVarResult) = VT_BSTR;
1478             V_BSTR(pVarResult) = SysAllocStringByteLen((LPCSTR)szString, dwSize);
1479             break;
1480
1481         case REG_EXPAND_SZ:
1482             if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1483                 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1484             else if (!(szNewString = msi_alloc(dwNewSize)))
1485                 ERR("Out of memory\n");
1486             else if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1487                 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1488             else
1489             {
1490                 V_VT(pVarResult) = VT_BSTR;
1491                 V_BSTR(pVarResult) = SysAllocStringLen(szNewString, dwNewSize);
1492             }
1493             msi_free(szNewString);
1494             break;
1495
1496         case REG_DWORD:
1497             V_VT(pVarResult) = VT_I4;
1498             V_I4(pVarResult) = *((DWORD *)lpData);
1499             break;
1500
1501         case REG_QWORD:
1502             V_VT(pVarResult) = VT_BSTR;
1503             V_BSTR(pVarResult) = SysAllocString(szREG_);   /* Weird string, don't know why native returns it */
1504             break;
1505
1506         case REG_BINARY:
1507             V_VT(pVarResult) = VT_BSTR;
1508             V_BSTR(pVarResult) = SysAllocString(szREG_BINARY);
1509             break;
1510
1511         case REG_NONE:
1512             V_VT(pVarResult) = VT_EMPTY;
1513             break;
1514
1515         default:
1516             FIXME("Unhandled registry value type %d\n", dwType);
1517     }
1518 }
1519
1520 static HRESULT WINAPI InstallerImpl_Invoke(
1521         AutomationObject* This,
1522         DISPID dispIdMember,
1523         REFIID riid,
1524         LCID lcid,
1525         WORD wFlags,
1526         DISPPARAMS* pDispParams,
1527         VARIANT* pVarResult,
1528         EXCEPINFO* pExcepInfo,
1529         UINT* puArgErr)
1530 {
1531     MSIHANDLE msiHandle;
1532     IDispatch *pDispatch = NULL;
1533     UINT ret;
1534     VARIANTARG varg0, varg1, varg2;
1535     HRESULT hr;
1536     LPWSTR szString = NULL;
1537     DWORD dwSize = 0;
1538
1539     VariantInit(&varg0);
1540     VariantInit(&varg1);
1541     VariantInit(&varg2);
1542
1543     switch (dispIdMember)
1544     {
1545         case DISPID_INSTALLER_CREATERECORD:
1546             if (wFlags & DISPATCH_METHOD)
1547             {
1548                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1549                 if (FAILED(hr)) return hr;
1550                 V_VT(pVarResult) = VT_DISPATCH;
1551                 if ((msiHandle = MsiCreateRecord(V_I4(&varg0))))
1552                 {
1553                     if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Record, RecordImpl_Invoke, NULL, 0)))
1554                         V_DISPATCH(pVarResult) = pDispatch;
1555                     else
1556                         ERR("Failed to create Record object, hresult 0x%08x\n", hr);
1557                 }
1558                 else
1559                 {
1560                     ERR("MsiCreateRecord failed\n");
1561                     return DISP_E_EXCEPTION;
1562                 }
1563             }
1564             else return DISP_E_MEMBERNOTFOUND;
1565             break;
1566
1567         case DISPID_INSTALLER_OPENPACKAGE:
1568             if (wFlags & DISPATCH_METHOD)
1569             {
1570                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1571                 if (FAILED(hr)) return hr;
1572                 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1573                 if (FAILED(hr))
1574                 {
1575                     VariantClear(&varg0);
1576                     return hr;
1577                 }
1578                 V_VT(pVarResult) = VT_DISPATCH;
1579                 if ((ret = MsiOpenPackageExW(V_BSTR(&varg0), V_I4(&varg1), &msiHandle)) == ERROR_SUCCESS)
1580                 {
1581                     if (SUCCEEDED(hr = create_session(msiHandle, (IDispatch *)This, &pDispatch)))
1582                         V_DISPATCH(pVarResult) = pDispatch;
1583                     else
1584                         ERR("Failed to create Session object, hresult 0x%08x\n", hr);
1585                 }
1586                 else
1587                 {
1588                     VariantClear(&varg0);
1589                     ERR("MsiOpenPackageEx returned %d\n", ret);
1590                     return DISP_E_EXCEPTION;
1591                 }
1592             }
1593             else return DISP_E_MEMBERNOTFOUND;
1594             break;
1595
1596         case DISPID_INSTALLER_OPENDATABASE:
1597             if (wFlags & DISPATCH_METHOD)
1598             {
1599                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1600                 if (FAILED(hr)) return hr;
1601
1602                 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1603                 if (FAILED(hr))
1604                 {
1605                     VariantClear(&varg0);
1606                     return hr;
1607                 }
1608
1609                 V_VT(pVarResult) = VT_DISPATCH;
1610                 if ((ret = MsiOpenDatabaseW(V_BSTR(&varg0), V_BSTR(&varg1), &msiHandle)) == ERROR_SUCCESS)
1611                 {
1612                     hr = create_automation_object(msiHandle, NULL, (LPVOID *)&pDispatch,
1613                                                   &DIID_Database, DatabaseImpl_Invoke, NULL, 0);
1614                     if (SUCCEEDED(hr))
1615                         V_DISPATCH(pVarResult) = pDispatch;
1616                     else
1617                         ERR("Failed to create Database object: 0x%08x\n", hr);
1618                 }
1619                 else
1620                 {
1621                     VariantClear(&varg0);
1622                     VariantClear(&varg1);
1623                     ERR("MsiOpenDatabase returned %d\n", ret);
1624                     return DISP_E_EXCEPTION;
1625                 }
1626             }
1627             else return DISP_E_MEMBERNOTFOUND;
1628             break;
1629
1630         case DISPID_INSTALLER_INSTALLPRODUCT:
1631             if (wFlags & DISPATCH_METHOD)
1632             {
1633                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1634                 if (FAILED(hr)) return hr;
1635                 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1636                 if (FAILED(hr))
1637                 {
1638                     VariantClear(&varg0);
1639                     return hr;
1640                 }
1641                 if ((ret = MsiInstallProductW(V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
1642                 {
1643                     VariantClear(&varg1);
1644                     VariantClear(&varg0);
1645                     ERR("MsiInstallProduct returned %d\n", ret);
1646                     return DISP_E_EXCEPTION;
1647                 }
1648             }
1649             else return DISP_E_MEMBERNOTFOUND;
1650             break;
1651
1652         case DISPID_INSTALLER_VERSION:
1653             if (wFlags & DISPATCH_PROPERTYGET) {
1654                 DLLVERSIONINFO verinfo;
1655                 WCHAR version[MAX_PATH];
1656
1657                 static const WCHAR format[] = {'%','d','.','%','d','.','%','d','.','%','d',0};
1658
1659                 verinfo.cbSize = sizeof(DLLVERSIONINFO);
1660                 hr = DllGetVersion(&verinfo);
1661                 if (FAILED(hr)) return hr;
1662
1663                 sprintfW(version, format, verinfo.dwMajorVersion, verinfo.dwMinorVersion,
1664                          verinfo.dwBuildNumber, verinfo.dwPlatformID);
1665
1666                 V_VT(pVarResult) = VT_BSTR;
1667                 V_BSTR(pVarResult) = SysAllocString(version);
1668             }
1669             else return DISP_E_MEMBERNOTFOUND;
1670             break;
1671
1672         case DISPID_INSTALLER_REGISTRYVALUE:
1673             if (wFlags & DISPATCH_METHOD) {
1674                 HKEY hkey;
1675                 DWORD dwType;
1676                 UINT posValue = 2;    /* Save valuePos so we can save puArgErr if we are unable to do our type conversions */
1677
1678                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1679                 if (FAILED(hr)) return hr;
1680                 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1681                 if (FAILED(hr)) return hr;
1682                 hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg2);
1683                 if (FAILED(hr))
1684                 {
1685                     VariantClear(&varg1);
1686                     return hr;
1687                 }
1688                 ret = RegOpenKeyW((HKEY)V_I4(&varg0), V_BSTR(&varg1), &hkey);
1689
1690                 /* Third parameter can be VT_EMPTY, VT_I4, or VT_BSTR */
1691                 switch (V_VT(&varg2))
1692                 {
1693                     case VT_EMPTY:  /* Return VT_BOOL as to whether or not registry key exists */
1694                         V_VT(pVarResult) = VT_BOOL;
1695                         V_BOOL(pVarResult) = (ret == ERROR_SUCCESS);
1696                         break;
1697
1698                     case VT_BSTR:   /* Return value of specified key if it exists */
1699                         if (ret == ERROR_SUCCESS &&
1700                             (ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL, NULL, NULL, &dwSize)) == ERROR_SUCCESS)
1701                         {
1702                             if (!(szString = msi_alloc(dwSize)))
1703                                 ERR("Out of memory\n");
1704                             else if ((ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL, &dwType, (LPBYTE)szString, &dwSize)) == ERROR_SUCCESS)
1705                                 variant_from_registry_value(pVarResult, dwType, (LPBYTE)szString, dwSize);
1706                         }
1707
1708                         if (ret != ERROR_SUCCESS)
1709                         {
1710                             msi_free(szString);
1711                             VariantClear(&varg2);
1712                             VariantClear(&varg1);
1713                             return DISP_E_BADINDEX;
1714                         }
1715                         break;
1716
1717                     default:     /* Try to make it into VT_I4, can use VariantChangeType for this */
1718                         hr = VariantChangeType(&varg2, &varg2, 0, VT_I4);
1719                         if (SUCCEEDED(hr) && ret != ERROR_SUCCESS) hr = DISP_E_BADINDEX; /* Conversion fine, but couldn't find key */
1720                         if (FAILED(hr))
1721                         {
1722                             if (hr == DISP_E_TYPEMISMATCH) *puArgErr = posValue;
1723                             VariantClear(&varg2);   /* Unknown type, so let's clear it */
1724                             VariantClear(&varg1);
1725                             return hr;
1726                         }
1727
1728                         /* Retrieve class name or maximum value name or subkey name size */
1729                         if (!V_I4(&varg2))
1730                             ret = RegQueryInfoKeyW(hkey, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1731                         else if (V_I4(&varg2) > 0)
1732                             ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL);
1733                         else /* V_I4(&varg2) < 0 */
1734                             ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
1735
1736                         if (ret == ERROR_SUCCESS)
1737                         {
1738                             if (!(szString = msi_alloc(++dwSize * sizeof(WCHAR))))
1739                                 ERR("Out of memory\n");
1740                             else if (!V_I4(&varg2))
1741                                 ret = RegQueryInfoKeyW(hkey, szString, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1742                             else if (V_I4(&varg2) > 0)
1743                                 ret = RegEnumValueW(hkey, V_I4(&varg2)-1, szString, &dwSize, 0, 0, NULL, NULL);
1744                             else /* V_I4(&varg2) < 0 */
1745                                 ret = RegEnumKeyW(hkey, -1 - V_I4(&varg2), szString, dwSize);
1746
1747                             if (szString && ret == ERROR_SUCCESS)
1748                             {
1749                                 V_VT(pVarResult) = VT_BSTR;
1750                                 V_BSTR(pVarResult) = SysAllocString(szString);
1751                             }
1752                         }
1753                 }
1754
1755                 msi_free(szString);
1756                 RegCloseKey(hkey);
1757             }
1758             else return DISP_E_MEMBERNOTFOUND;
1759             break;
1760
1761         case DISPID_INSTALLER_PRODUCTSTATE:
1762             if (wFlags & DISPATCH_PROPERTYGET) {
1763                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1764                 if (FAILED(hr)) return hr;
1765                 V_VT(pVarResult) = VT_I4;
1766                 V_I4(pVarResult) = MsiQueryProductStateW(V_BSTR(&varg0));
1767             }
1768             else return DISP_E_MEMBERNOTFOUND;
1769             break;
1770
1771         case DISPID_INSTALLER_PRODUCTINFO:
1772             if (wFlags & DISPATCH_PROPERTYGET) {
1773                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1774                 if (FAILED(hr)) return hr;
1775                 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1776                 if (FAILED(hr))
1777                 {
1778                     VariantClear(&varg0);
1779                     return hr;
1780                 }
1781                 V_VT(pVarResult) = VT_BSTR;
1782                 V_BSTR(pVarResult) = NULL;
1783                 if ((ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), NULL, &dwSize)) == ERROR_SUCCESS)
1784                 {
1785                     if (!(szString = msi_alloc((++dwSize)*sizeof(WCHAR))))
1786                         ERR("Out of memory\n");
1787                     else if ((ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), szString, &dwSize)) == ERROR_SUCCESS)
1788                         V_BSTR(pVarResult) = SysAllocString(szString);
1789                     msi_free(szString);
1790                 }
1791                 if (ret != ERROR_SUCCESS)
1792                 {
1793                     ERR("MsiGetProductInfo returned %d\n", ret);
1794                     VariantClear(&varg1);
1795                     VariantClear(&varg0);
1796                     return DISP_E_EXCEPTION;
1797                 }
1798             }
1799             else return DISP_E_MEMBERNOTFOUND;
1800             break;
1801
1802         case DISPID_INSTALLER_PRODUCTS:
1803             if (wFlags & DISPATCH_PROPERTYGET)
1804             {
1805                 ListData *ldata = NULL;
1806                 ULONG idx = 0;
1807                 WCHAR szProductBuf[GUID_SIZE];
1808
1809                 /* Find number of products */
1810                 while ((ret = MsiEnumProductsW(idx, szProductBuf)) == ERROR_SUCCESS) idx++;
1811                 if (ret != ERROR_NO_MORE_ITEMS)
1812                 {
1813                     ERR("MsiEnumProducts returned %d\n", ret);
1814                     return DISP_E_EXCEPTION;
1815                 }
1816
1817                 V_VT(pVarResult) = VT_DISPATCH;
1818                 if (SUCCEEDED(hr = create_automation_object(0, NULL, (LPVOID*)&pDispatch, &DIID_StringList, ListImpl_Invoke, ListImpl_Free, sizeof(ListData))))
1819                 {
1820                     V_DISPATCH(pVarResult) = pDispatch;
1821
1822                     /* Save product strings */
1823                     ldata = (ListData *)private_data((AutomationObject *)pDispatch);
1824                     if (!(ldata->pVars = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(VARIANT)*idx)))
1825                         ERR("Out of memory\n");
1826                     else
1827                     {
1828                         ldata->ulCount = idx;
1829                         for (idx = 0; idx < ldata->ulCount; idx++)
1830                         {
1831                             ret = MsiEnumProductsW(idx, szProductBuf);
1832                             VariantInit(&ldata->pVars[idx]);
1833                             V_VT(&ldata->pVars[idx]) = VT_BSTR;
1834                             V_BSTR(&ldata->pVars[idx]) = SysAllocString(szProductBuf);
1835                         }
1836                     }
1837                 }
1838                 else
1839                     ERR("Failed to create StringList object, hresult 0x%08x\n", hr);
1840             }
1841             else return DISP_E_MEMBERNOTFOUND;
1842             break;
1843
1844         case DISPID_INSTALLER_RELATEDPRODUCTS:
1845             if (wFlags & DISPATCH_PROPERTYGET)
1846             {
1847                 ListData *ldata = NULL;
1848                 ULONG idx = 0;
1849                 WCHAR szProductBuf[GUID_SIZE];
1850
1851                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1852                 if (FAILED(hr)) return hr;
1853
1854                 /* Find number of related products */
1855                 while ((ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, szProductBuf)) == ERROR_SUCCESS) idx++;
1856                 if (ret != ERROR_NO_MORE_ITEMS)
1857                 {
1858                     VariantClear(&varg0);
1859                     ERR("MsiEnumRelatedProducts returned %d\n", ret);
1860                     return DISP_E_EXCEPTION;
1861                 }
1862
1863                 V_VT(pVarResult) = VT_DISPATCH;
1864                 if (SUCCEEDED(hr = create_automation_object(0, NULL, (LPVOID*)&pDispatch, &DIID_StringList, ListImpl_Invoke, ListImpl_Free, sizeof(ListData))))
1865                 {
1866                     V_DISPATCH(pVarResult) = pDispatch;
1867
1868                     /* Save product strings */
1869                     ldata = (ListData *)private_data((AutomationObject *)pDispatch);
1870                     if (!(ldata->pVars = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(VARIANT)*idx)))
1871                         ERR("Out of memory\n");
1872                     else
1873                     {
1874                         ldata->ulCount = idx;
1875                         for (idx = 0; idx < ldata->ulCount; idx++)
1876                         {
1877                             ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, szProductBuf);
1878                             VariantInit(&ldata->pVars[idx]);
1879                             V_VT(&ldata->pVars[idx]) = VT_BSTR;
1880                             V_BSTR(&ldata->pVars[idx]) = SysAllocString(szProductBuf);
1881                         }
1882                     }
1883                 }
1884                 else
1885                     ERR("Failed to create StringList object, hresult 0x%08x\n", hr);
1886             }
1887             else return DISP_E_MEMBERNOTFOUND;
1888             break;
1889
1890          default:
1891             return DISP_E_MEMBERNOTFOUND;
1892     }
1893
1894     VariantClear(&varg2);
1895     VariantClear(&varg1);
1896     VariantClear(&varg0);
1897
1898     return S_OK;
1899 }
1900
1901 /* Wrapper around create_automation_object to create an installer object. */
1902 HRESULT create_msiserver(IUnknown *pOuter, LPVOID *ppObj)
1903 {
1904     return create_automation_object(0, pOuter, ppObj, &DIID_Installer, InstallerImpl_Invoke, NULL, 0);
1905 }
1906
1907 /* Wrapper around create_automation_object to create a session object. */
1908 HRESULT create_session(MSIHANDLE msiHandle, IDispatch *pInstaller, IDispatch **pDispatch)
1909 {
1910     HRESULT hr = create_automation_object(msiHandle, NULL, (LPVOID)pDispatch, &DIID_Session, SessionImpl_Invoke, NULL, sizeof(SessionData));
1911     if (SUCCEEDED(hr) && pDispatch && *pDispatch)
1912         ((SessionData *)private_data((AutomationObject *)*pDispatch))->pInstaller = pInstaller;
1913     return hr;
1914 }