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