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