mcicda: Exclude unused headers.
[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 "msidefs.h"
29 #include "msipriv.h"
30 #include "activscp.h"
31 #include "oleauto.h"
32 #include "wine/debug.h"
33 #include "wine/unicode.h"
34
35 #include "msiserver.h"
36 #include "msiserver_dispids.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(msi);
39
40 /*
41  * AutomationObject - "base" class for all automation objects. For each interface, we implement Invoke function
42  *                    called from AutomationObject::Invoke, and pass this function to create_automation_object.
43  */
44
45 typedef interface AutomationObject AutomationObject;
46
47 interface AutomationObject {
48     /*
49      * VTables - We provide IDispatch, IProvideClassInfo, IProvideClassInfo2, IProvideMultipleClassInfo
50      */
51     const IDispatchVtbl *lpVtbl;
52     const IProvideMultipleClassInfoVtbl *lpvtblIProvideMultipleClassInfo;
53
54     /* Object reference count */
55     LONG ref;
56
57     /* Clsid for this class and it's appropriate ITypeInfo object */
58     LPCLSID clsid;
59     ITypeInfo *iTypeInfo;
60
61     /* The MSI handle of the current object */
62     MSIHANDLE msiHandle;
63
64     /* A function that is called from AutomationObject::Invoke, specific to this type of object. */
65     HRESULT (STDMETHODCALLTYPE *funcInvoke)(
66         AutomationObject* This,
67         DISPID dispIdMember,
68         REFIID riid,
69         LCID lcid,
70         WORD wFlags,
71         DISPPARAMS* pDispParams,
72         VARIANT* pVarResult,
73         EXCEPINFO* pExcepInfo,
74         UINT* puArgErr);
75
76     /* A function that is called from AutomationObject::Release when the object is being freed to free any private
77      * data structures (or NULL) */
78     void (STDMETHODCALLTYPE *funcFree)(AutomationObject* This);
79 };
80
81 /*
82  * Structures for additional data required by specific automation objects
83  */
84
85 typedef struct {
86     int iCount;
87     LPWSTR *pszStrings;
88 } StringListData;
89
90 typedef struct {
91     /* The parent Installer object */
92     IDispatch *pInstaller;
93 } SessionData;
94
95 /* VTables */
96 static const struct IDispatchVtbl AutomationObject_Vtbl;
97 static const struct IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl;
98
99 /* Load type info so we don't have to process GetIDsOfNames */
100 HRESULT load_type_info(IDispatch *iface, ITypeInfo **pptinfo, REFIID clsid, LCID lcid)
101 {
102     HRESULT hr;
103     LPTYPELIB pLib = NULL;
104     LPTYPEINFO pInfo = NULL;
105     static const WCHAR szMsiServer[] = {'m','s','i','s','e','r','v','e','r','.','t','l','b'};
106
107     TRACE("(%p)->(%s,%d)\n", iface, debugstr_guid(clsid), lcid);
108
109     /* Load registered type library */
110     hr = LoadRegTypeLib(&LIBID_WindowsInstaller, 1, 0, lcid, &pLib);
111     if (FAILED(hr)) {
112         hr = LoadTypeLib(szMsiServer, &pLib);
113         if (FAILED(hr)) {
114             ERR("Could not load msiserver.tlb\n");
115             return hr;
116         }
117     }
118
119     /* Get type information for object */
120     hr = ITypeLib_GetTypeInfoOfGuid(pLib, clsid, &pInfo);
121     ITypeLib_Release(pLib);
122     if (FAILED(hr)) {
123         ERR("Could not load ITypeInfo for %s\n", debugstr_guid(clsid));
124         return hr;
125     }
126     *pptinfo = pInfo;
127     return S_OK;
128 }
129
130 /* Create the automation object, placing the result in the pointer ppObj. The automation object is created
131  * with the appropriate clsid and invocation function. */
132 HRESULT create_automation_object(MSIHANDLE msiHandle, IUnknown *pUnkOuter, LPVOID *ppObj, REFIID clsid,
133             HRESULT (STDMETHODCALLTYPE *funcInvoke)(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,
134                                                     VARIANT*,EXCEPINFO*,UINT*),
135                                  void (STDMETHODCALLTYPE *funcFree)(AutomationObject*),
136                                  SIZE_T sizetPrivateData)
137 {
138     AutomationObject *object;
139     HRESULT hr;
140
141     TRACE("(%ld,%p,%p,%s,%p,%p,%ld)\n", (unsigned long)msiHandle, pUnkOuter, ppObj, debugstr_guid(clsid), funcInvoke, funcFree, sizetPrivateData);
142
143     if( pUnkOuter )
144         return CLASS_E_NOAGGREGATION;
145
146     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AutomationObject)+sizetPrivateData);
147
148     /* Set all the VTable references */
149     object->lpVtbl = &AutomationObject_Vtbl;
150     object->lpvtblIProvideMultipleClassInfo = &AutomationObject_IProvideMultipleClassInfo_Vtbl;
151     object->ref = 1;
152
153     /* Store data that was passed */
154     object->msiHandle = msiHandle;
155     object->clsid = (LPCLSID)clsid;
156     object->funcInvoke = funcInvoke;
157     object->funcFree = funcFree;
158
159     /* Load our TypeInfo so we don't have to process GetIDsOfNames */
160     object->iTypeInfo = NULL;
161     hr = load_type_info((IDispatch *)object, &object->iTypeInfo, clsid, 0x0);
162     if (FAILED(hr)) {
163         HeapFree(GetProcessHeap(), 0, object);
164         return hr;
165     }
166
167     *ppObj = object;
168
169     return S_OK;
170 }
171
172 /* Macros to get pointer to AutomationObject from the other VTables. */
173 static inline AutomationObject *obj_from_IProvideMultipleClassInfo( IProvideMultipleClassInfo *iface )
174 {
175     return (AutomationObject *)((char*)iface - FIELD_OFFSET(AutomationObject, lpvtblIProvideMultipleClassInfo));
176 }
177
178 /* Macro to get pointer to private object data */
179 static inline void *private_data( AutomationObject *This )
180 {
181     return This + 1;
182 }
183
184 /*
185  * AutomationObject methods
186  */
187
188 /*** IUnknown methods ***/
189 static HRESULT WINAPI AutomationObject_QueryInterface(IDispatch* iface, REFIID riid, void** ppvObject)
190 {
191     AutomationObject *This = (AutomationObject *)iface;
192
193     TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
194
195     if (ppvObject == NULL)
196       return E_INVALIDARG;
197
198     *ppvObject = 0;
199
200     if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDispatch) || IsEqualGUID(riid, This->clsid))
201         *ppvObject = This;
202     else if (IsEqualGUID(riid, &IID_IProvideClassInfo) ||
203              IsEqualGUID(riid, &IID_IProvideClassInfo2) ||
204              IsEqualGUID(riid, &IID_IProvideMultipleClassInfo))
205         *ppvObject = &This->lpvtblIProvideMultipleClassInfo;
206     else
207     {
208         TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid));
209         return E_NOINTERFACE;
210     }
211
212     /*
213      * Query Interface always increases the reference count by one when it is
214      * successful
215      */
216     IClassFactory_AddRef(iface);
217
218     return S_OK;
219 }
220
221 static ULONG WINAPI AutomationObject_AddRef(IDispatch* iface)
222 {
223     AutomationObject *This = (AutomationObject *)iface;
224
225     TRACE("(%p/%p)\n", iface, This);
226
227     return InterlockedIncrement(&This->ref);
228 }
229
230 static ULONG WINAPI AutomationObject_Release(IDispatch* iface)
231 {
232     AutomationObject *This = (AutomationObject *)iface;
233     ULONG ref = InterlockedDecrement(&This->ref);
234
235     TRACE("(%p/%p)\n", iface, This);
236
237     if (!ref)
238     {
239         if (This->funcFree) This->funcFree(This);
240         MsiCloseHandle(This->msiHandle);
241         HeapFree(GetProcessHeap(), 0, This);
242     }
243
244     return ref;
245 }
246
247 /*** IDispatch methods ***/
248 static HRESULT WINAPI AutomationObject_GetTypeInfoCount(
249         IDispatch* iface,
250         UINT* pctinfo)
251 {
252     AutomationObject *This = (AutomationObject *)iface;
253
254     TRACE("(%p/%p)->(%p)\n", iface, This, pctinfo);
255     *pctinfo = 1;
256     return S_OK;
257 }
258
259 static HRESULT WINAPI AutomationObject_GetTypeInfo(
260         IDispatch* iface,
261         UINT iTInfo,
262         LCID lcid,
263         ITypeInfo** ppTInfo)
264 {
265     AutomationObject *This = (AutomationObject *)iface;
266     TRACE("(%p/%p)->(%d,%d,%p)\n", iface, This, iTInfo, lcid, ppTInfo);
267
268     ITypeInfo_AddRef(This->iTypeInfo);
269     *ppTInfo = This->iTypeInfo;
270     return S_OK;
271 }
272
273 static HRESULT WINAPI AutomationObject_GetIDsOfNames(
274         IDispatch* iface,
275         REFIID riid,
276         LPOLESTR* rgszNames,
277         UINT cNames,
278         LCID lcid,
279         DISPID* rgDispId)
280 {
281     AutomationObject *This = (AutomationObject *)iface;
282     HRESULT hr;
283     TRACE("(%p/%p)->(%p,%p,%d,%d,%p)\n", iface, This, riid, rgszNames, cNames, lcid, rgDispId);
284
285     if (!IsEqualGUID(riid, &IID_NULL)) return E_INVALIDARG;
286     hr = ITypeInfo_GetIDsOfNames(This->iTypeInfo, rgszNames, cNames, rgDispId);
287     if (hr == DISP_E_UNKNOWNNAME)
288     {
289         int idx;
290         for (idx=0; idx<cNames; idx++)
291         {
292             if (rgDispId[idx] == DISPID_UNKNOWN)
293                 FIXME("Unknown member %s, clsid %s\n", debugstr_w(rgszNames[idx]), debugstr_guid(This->clsid));
294         }
295     }
296     return hr;
297 }
298
299 /* Maximum number of allowed function parameters+1 */
300 #define MAX_FUNC_PARAMS 20
301
302 /* Some error checking is done here to simplify individual object function invocation */
303 static HRESULT WINAPI AutomationObject_Invoke(
304         IDispatch* iface,
305         DISPID dispIdMember,
306         REFIID riid,
307         LCID lcid,
308         WORD wFlags,
309         DISPPARAMS* pDispParams,
310         VARIANT* pVarResult,
311         EXCEPINFO* pExcepInfo,
312         UINT* puArgErr)
313 {
314     AutomationObject *This = (AutomationObject *)iface;
315     HRESULT hr;
316     unsigned int uArgErr;
317     VARIANT varResultDummy;
318     BSTR bstrName = NULL;
319
320     TRACE("(%p/%p)->(%d,%p,%d,%d,%p,%p,%p,%p)\n", iface, This, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
321
322     if (!IsEqualIID(riid, &IID_NULL))
323     {
324         ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
325         return DISP_E_UNKNOWNNAME;
326     }
327
328     if (wFlags & DISPATCH_PROPERTYGET && !pVarResult)
329     {
330         ERR("NULL pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
331         return DISP_E_PARAMNOTOPTIONAL;
332     }
333
334     /* This simplifies our individual object invocation functions */
335     if (puArgErr == NULL) puArgErr = &uArgErr;
336     if (pVarResult == NULL) pVarResult = &varResultDummy;
337
338     /* Assume return type is void unless determined otherwise */
339     VariantInit(pVarResult);
340
341     /* If we are tracing, we want to see the name of the member we are invoking */
342     if (TRACE_ON(msi))
343     {
344         ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL);
345         TRACE("Method %d, %s\n", dispIdMember, debugstr_w(bstrName));
346     }
347
348     hr = This->funcInvoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
349
350     if (hr == DISP_E_MEMBERNOTFOUND) {
351         if (bstrName == NULL) ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL);
352         FIXME("Method %d, %s wflags %d not implemented, clsid %s\n", dispIdMember, debugstr_w(bstrName), wFlags, debugstr_guid(This->clsid));
353     }
354     else if (pExcepInfo &&
355              (hr == DISP_E_PARAMNOTFOUND ||
356               hr == DISP_E_EXCEPTION)) {
357         static const WCHAR szComma[] = { ',',0 };
358         static WCHAR szExceptionSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
359         WCHAR szExceptionDescription[MAX_PATH];
360         BSTR bstrParamNames[MAX_FUNC_PARAMS];
361         unsigned namesNo, i;
362         BOOL bFirst = TRUE;
363
364         if (FAILED(ITypeInfo_GetNames(This->iTypeInfo, dispIdMember, bstrParamNames,
365                                       MAX_FUNC_PARAMS, &namesNo)))
366         {
367             TRACE("Failed to retrieve names for dispIdMember %d\n", dispIdMember);
368         }
369         else
370         {
371             memset(szExceptionDescription, 0, sizeof(szExceptionDescription));
372             for (i=0; i<namesNo; i++)
373             {
374                 if (bFirst) bFirst = FALSE;
375                 else {
376                     lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], szComma);
377                 }
378                 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], bstrParamNames[i]);
379                 SysFreeString(bstrParamNames[i]);
380             }
381
382             memset(pExcepInfo, 0, sizeof(EXCEPINFO));
383             pExcepInfo->wCode = 1000;
384             pExcepInfo->bstrSource = szExceptionSource;
385             pExcepInfo->bstrDescription = szExceptionDescription;
386             hr = DISP_E_EXCEPTION;
387         }
388     }
389
390     /* Make sure we free the return variant if it is our dummy variant */
391     if (pVarResult == &varResultDummy) VariantClear(pVarResult);
392
393     /* Free function name if we retrieved it */
394     if (bstrName) SysFreeString(bstrName);
395
396     TRACE("Returning 0x%08x, %s\n", hr, SUCCEEDED(hr) ? "ok" : "not ok");
397
398     return hr;
399 }
400
401 static const struct IDispatchVtbl AutomationObject_Vtbl =
402 {
403     AutomationObject_QueryInterface,
404     AutomationObject_AddRef,
405     AutomationObject_Release,
406     AutomationObject_GetTypeInfoCount,
407     AutomationObject_GetTypeInfo,
408     AutomationObject_GetIDsOfNames,
409     AutomationObject_Invoke
410 };
411
412 /*
413  * IProvideMultipleClassInfo methods
414  */
415
416 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_QueryInterface(
417   IProvideMultipleClassInfo* iface,
418   REFIID     riid,
419   VOID**     ppvoid)
420 {
421     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
422     return AutomationObject_QueryInterface((IDispatch *)This, riid, ppvoid);
423 }
424
425 static ULONG WINAPI AutomationObject_IProvideMultipleClassInfo_AddRef(IProvideMultipleClassInfo* iface)
426 {
427     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
428     return AutomationObject_AddRef((IDispatch *)This);
429 }
430
431 static ULONG WINAPI AutomationObject_IProvideMultipleClassInfo_Release(IProvideMultipleClassInfo* iface)
432 {
433     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
434     return AutomationObject_Release((IDispatch *)This);
435 }
436
437 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_GetClassInfo(IProvideMultipleClassInfo* iface, ITypeInfo** ppTI)
438 {
439     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
440     TRACE("(%p/%p)->(%p)\n", iface, This, ppTI);
441     return load_type_info((IDispatch *)This, ppTI, This->clsid, 0);
442 }
443
444 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_GetGUID(IProvideMultipleClassInfo* iface, DWORD dwGuidKind, GUID* pGUID)
445 {
446     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
447     TRACE("(%p/%p)->(%d,%s)\n", iface, This, dwGuidKind, debugstr_guid(pGUID));
448
449     if (dwGuidKind != GUIDKIND_DEFAULT_SOURCE_DISP_IID)
450         return E_INVALIDARG;
451     else {
452         *pGUID = *This->clsid;
453         return S_OK;
454     }
455 }
456
457 static HRESULT WINAPI AutomationObject_GetMultiTypeInfoCount(IProvideMultipleClassInfo* iface, ULONG* pcti)
458 {
459     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
460
461     TRACE("(%p/%p)->(%p)\n", iface, This, pcti);
462     *pcti = 1;
463     return S_OK;
464 }
465
466 static HRESULT WINAPI AutomationObject_GetInfoOfIndex(IProvideMultipleClassInfo* iface,
467         ULONG iti,
468         DWORD dwFlags,
469         ITypeInfo** pptiCoClass,
470         DWORD* pdwTIFlags,
471         ULONG* pcdispidReserved,
472         IID* piidPrimary,
473         IID* piidSource)
474 {
475     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
476
477     TRACE("(%p/%p)->(%d,%d,%p,%p,%p,%p,%p)\n", iface, This, iti, dwFlags, pptiCoClass, pdwTIFlags, pcdispidReserved, piidPrimary, piidSource);
478
479     if (iti != 0)
480         return E_INVALIDARG;
481
482     if (dwFlags & MULTICLASSINFO_GETTYPEINFO)
483         load_type_info((IDispatch *)This, pptiCoClass, This->clsid, 0);
484
485     if (dwFlags & MULTICLASSINFO_GETNUMRESERVEDDISPIDS)
486     {
487         *pdwTIFlags = 0;
488         *pcdispidReserved = 0;
489     }
490
491     if (dwFlags & MULTICLASSINFO_GETIIDPRIMARY){
492         *piidPrimary = *This->clsid;
493     }
494
495     if (dwFlags & MULTICLASSINFO_GETIIDSOURCE){
496         *piidSource = *This->clsid;
497     }
498
499     return S_OK;
500 }
501
502 static const IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl =
503 {
504     AutomationObject_IProvideMultipleClassInfo_QueryInterface,
505     AutomationObject_IProvideMultipleClassInfo_AddRef,
506     AutomationObject_IProvideMultipleClassInfo_Release,
507     AutomationObject_IProvideMultipleClassInfo_GetClassInfo,
508     AutomationObject_IProvideMultipleClassInfo_GetGUID,
509     AutomationObject_GetMultiTypeInfoCount,
510     AutomationObject_GetInfoOfIndex
511 };
512
513 /*
514  * Individual Object Invocation Functions
515  */
516
517 static HRESULT WINAPI RecordImpl_Invoke(
518         AutomationObject* This,
519         DISPID dispIdMember,
520         REFIID riid,
521         LCID lcid,
522         WORD wFlags,
523         DISPPARAMS* pDispParams,
524         VARIANT* pVarResult,
525         EXCEPINFO* pExcepInfo,
526         UINT* puArgErr)
527 {
528     WCHAR *szString;
529     DWORD dwLen;
530     UINT ret;
531     VARIANTARG varg0, varg1;
532     HRESULT hr;
533
534     VariantInit(&varg0);
535     VariantInit(&varg1);
536
537     switch (dispIdMember)
538     {
539         case DISPID_RECORD_STRINGDATA:
540             if (wFlags & DISPATCH_PROPERTYGET) {
541                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
542                 if (FAILED(hr)) return hr;
543                 V_VT(pVarResult) = VT_BSTR;
544                 V_BSTR(pVarResult) = NULL;
545                 ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), NULL, &dwLen);
546                 if (ret == ERROR_SUCCESS)
547                 {
548                     szString = msi_alloc((++dwLen)*sizeof(WCHAR));
549                     if (szString)
550                     {
551                         if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
552                             V_BSTR(pVarResult) = SysAllocString(szString);
553                         msi_free(szString);
554                     }
555                 }
556                 if (ret != ERROR_SUCCESS)
557                     ERR("MsiRecordGetString returned %d\n", ret);
558             } else if (wFlags & DISPATCH_PROPERTYPUT) {
559                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
560                 if (FAILED(hr)) return hr;
561                 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BSTR, &varg1, puArgErr);
562                 if (FAILED(hr)) return hr;
563                 if ((ret = MsiRecordSetStringW(This->msiHandle, V_I4(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
564                 {
565                     VariantClear(&varg1);
566                     ERR("MsiRecordSetString returned %d\n", ret);
567                     return DISP_E_EXCEPTION;
568                 }
569             }
570             break;
571
572          default:
573             return DISP_E_MEMBERNOTFOUND;
574     }
575
576     VariantClear(&varg1);
577     VariantClear(&varg0);
578
579     return S_OK;
580 }
581
582 static HRESULT WINAPI StringListImpl_Invoke(
583         AutomationObject* This,
584         DISPID dispIdMember,
585         REFIID riid,
586         LCID lcid,
587         WORD wFlags,
588         DISPPARAMS* pDispParams,
589         VARIANT* pVarResult,
590         EXCEPINFO* pExcepInfo,
591         UINT* puArgErr)
592 {
593     StringListData *data = (StringListData *)private_data(This);
594     HRESULT hr;
595     VARIANTARG varg0;
596
597     VariantInit(&varg0);
598
599     switch (dispIdMember)
600     {
601          case DISPID_STRINGLIST_ITEM:
602             if (wFlags & DISPATCH_PROPERTYGET) {
603                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
604                 if (FAILED(hr)) return hr;
605                 if (V_I4(&varg0) < 0 || V_I4(&varg0) >= data->iCount)
606                     return DISP_E_BADINDEX;
607                 V_VT(pVarResult) = VT_BSTR;
608                 V_BSTR(pVarResult) = SysAllocString(data->pszStrings[V_I4(&varg0)]);
609             }
610             break;
611
612          case DISPID_STRINGLIST_COUNT:
613             if (wFlags & DISPATCH_PROPERTYGET) {
614                 V_VT(pVarResult) = VT_I4;
615                 V_I4(pVarResult) = data->iCount;
616             }
617             break;
618
619          default:
620             return DISP_E_MEMBERNOTFOUND;
621     }
622
623     VariantClear(&varg0);
624
625     return S_OK;
626 }
627
628 static void WINAPI StringListImpl_Free(AutomationObject *This)
629 {
630     StringListData *data = private_data(This);
631     int idx;
632
633     for (idx=0; idx<data->iCount; idx++)
634         SysFreeString(data->pszStrings[idx]);
635     HeapFree(GetProcessHeap(), 0, data->pszStrings);
636 }
637
638 static HRESULT WINAPI ViewImpl_Invoke(
639         AutomationObject* This,
640         DISPID dispIdMember,
641         REFIID riid,
642         LCID lcid,
643         WORD wFlags,
644         DISPPARAMS* pDispParams,
645         VARIANT* pVarResult,
646         EXCEPINFO* pExcepInfo,
647         UINT* puArgErr)
648 {
649     MSIHANDLE msiHandle;
650     IDispatch *pDispatch = NULL;
651     UINT ret;
652     VARIANTARG varg0, varg1;
653     HRESULT hr;
654
655     VariantInit(&varg0);
656     VariantInit(&varg1);
657
658     switch (dispIdMember)
659     {
660         case DISPID_VIEW_EXECUTE:
661             if (wFlags & DISPATCH_METHOD)
662             {
663                 hr = DispGetParam(pDispParams, 0, VT_DISPATCH, &varg0, puArgErr);
664                 if (SUCCEEDED(hr) && V_DISPATCH(&varg0) != NULL)
665                     MsiViewExecute(This->msiHandle, ((AutomationObject *)V_DISPATCH(&varg0))->msiHandle);
666                 else
667                     MsiViewExecute(This->msiHandle, 0);
668             }
669             break;
670
671         case DISPID_VIEW_FETCH:
672             if (wFlags & DISPATCH_METHOD)
673             {
674                 V_VT(pVarResult) = VT_DISPATCH;
675                 if ((ret = MsiViewFetch(This->msiHandle, &msiHandle)) == ERROR_SUCCESS)
676                 {
677                     if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Record, RecordImpl_Invoke, NULL, 0)))
678                     {
679                         IDispatch_AddRef(pDispatch);
680                         V_DISPATCH(pVarResult) = pDispatch;
681                     }
682                     else
683                         ERR("Failed to create Record object, hresult 0x%08x\n", hr);
684                 }
685                 else if (ret == ERROR_NO_MORE_ITEMS)
686                     V_DISPATCH(pVarResult) = NULL;
687                 else
688                 {
689                     ERR("MsiViewFetch returned %d\n", ret);
690                     return DISP_E_EXCEPTION;
691                 }
692             }
693             break;
694
695         case DISPID_VIEW_CLOSE:
696             if (wFlags & DISPATCH_METHOD)
697             {
698                 MsiViewClose(This->msiHandle);
699             }
700             break;
701
702          default:
703             return DISP_E_MEMBERNOTFOUND;
704     }
705
706     VariantClear(&varg1);
707     VariantClear(&varg0);
708
709     return S_OK;
710 }
711
712 static HRESULT WINAPI DatabaseImpl_Invoke(
713         AutomationObject* This,
714         DISPID dispIdMember,
715         REFIID riid,
716         LCID lcid,
717         WORD wFlags,
718         DISPPARAMS* pDispParams,
719         VARIANT* pVarResult,
720         EXCEPINFO* pExcepInfo,
721         UINT* puArgErr)
722 {
723     MSIHANDLE msiHandle;
724     IDispatch *pDispatch = NULL;
725     UINT ret;
726     VARIANTARG varg0, varg1;
727     HRESULT hr;
728
729     VariantInit(&varg0);
730     VariantInit(&varg1);
731
732     switch (dispIdMember)
733     {
734         case DISPID_DATABASE_OPENVIEW:
735             if (wFlags & DISPATCH_METHOD)
736             {
737                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
738                 if (FAILED(hr)) return hr;
739                 V_VT(pVarResult) = VT_DISPATCH;
740                 if ((ret = MsiDatabaseOpenViewW(This->msiHandle, V_BSTR(&varg0), &msiHandle)) == ERROR_SUCCESS)
741                 {
742                     if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_View, ViewImpl_Invoke, NULL, 0)))
743                     {
744                         IDispatch_AddRef(pDispatch);
745                         V_DISPATCH(pVarResult) = pDispatch;
746                     }
747                     else
748                         ERR("Failed to create View object, hresult 0x%08x\n", hr);
749                 }
750                 else
751                 {
752                     VariantClear(&varg0);
753                     ERR("MsiDatabaseOpenView returned %d\n", ret);
754                     return DISP_E_EXCEPTION;
755                 }
756             }
757             break;
758
759          default:
760             return DISP_E_MEMBERNOTFOUND;
761     }
762
763     VariantClear(&varg1);
764     VariantClear(&varg0);
765
766     return S_OK;
767 }
768
769 static HRESULT WINAPI SessionImpl_Invoke(
770         AutomationObject* This,
771         DISPID dispIdMember,
772         REFIID riid,
773         LCID lcid,
774         WORD wFlags,
775         DISPPARAMS* pDispParams,
776         VARIANT* pVarResult,
777         EXCEPINFO* pExcepInfo,
778         UINT* puArgErr)
779 {
780     SessionData *data = private_data(This);
781     WCHAR *szString;
782     DWORD dwLen;
783     IDispatch *pDispatch = NULL;
784     MSIHANDLE msiHandle;
785     LANGID langId;
786     UINT ret;
787     INSTALLSTATE iInstalled, iAction;
788     VARIANTARG varg0, varg1;
789     HRESULT hr;
790
791     VariantInit(&varg0);
792     VariantInit(&varg1);
793
794     switch (dispIdMember)
795     {
796         case DISPID_SESSION_INSTALLER:
797             if (wFlags & DISPATCH_PROPERTYGET) {
798                 V_VT(pVarResult) = VT_DISPATCH;
799                 IDispatch_AddRef(data->pInstaller);
800                 V_DISPATCH(pVarResult) = data->pInstaller;
801             }
802             break;
803
804         case DISPID_SESSION_PROPERTY:
805             if (wFlags & DISPATCH_PROPERTYGET) {
806                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
807                 if (FAILED(hr)) return hr;
808                 V_VT(pVarResult) = VT_BSTR;
809                 V_BSTR(pVarResult) = NULL;
810                 ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), NULL, &dwLen);
811                 if (ret == ERROR_SUCCESS)
812                 {
813                     szString = msi_alloc((++dwLen)*sizeof(WCHAR));
814                     if (szString)
815                     {
816                         if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
817                             V_BSTR(pVarResult) = SysAllocString(szString);
818                         msi_free(szString);
819                     }
820                 }
821                 if (ret != ERROR_SUCCESS)
822                     ERR("MsiGetProperty returned %d\n", ret);
823             } else if (wFlags & DISPATCH_PROPERTYPUT) {
824                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
825                 if (FAILED(hr)) return hr;
826                 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BSTR, &varg1, puArgErr);
827                 if (FAILED(hr)) {
828                     VariantClear(&varg0);
829                     return hr;
830                 }
831                 if ((ret = MsiSetPropertyW(This->msiHandle, V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
832                 {
833                     VariantClear(&varg0);
834                     VariantClear(&varg1);
835                     ERR("MsiSetProperty returned %d\n", ret);
836                     return DISP_E_EXCEPTION;
837                 }
838             }
839             break;
840
841         case DISPID_SESSION_LANGUAGE:
842             if (wFlags & DISPATCH_PROPERTYGET) {
843                 langId = MsiGetLanguage(This->msiHandle);
844                 V_VT(pVarResult) = VT_I4;
845                 V_I4(pVarResult) = langId;
846             }
847             break;
848
849         case DISPID_SESSION_MODE:
850             if (wFlags & DISPATCH_PROPERTYGET) {
851                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
852                 if (FAILED(hr)) return hr;
853                 V_VT(pVarResult) = VT_BOOL;
854                 V_BOOL(pVarResult) = MsiGetMode(This->msiHandle, V_I4(&varg0));
855             } else if (wFlags & DISPATCH_PROPERTYPUT) {
856                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
857                 if (FAILED(hr)) return hr;
858                 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BOOL, &varg1, puArgErr);
859                 if (FAILED(hr)) return hr;
860                 if ((ret = MsiSetMode(This->msiHandle, V_I4(&varg0), V_BOOL(&varg1))) != ERROR_SUCCESS)
861                 {
862                     ERR("MsiSetMode returned %d\n", ret);
863                     return DISP_E_EXCEPTION;
864                 }
865             }
866             break;
867
868         case DISPID_SESSION_DATABASE:
869             if (wFlags & DISPATCH_PROPERTYGET) {
870                 V_VT(pVarResult) = VT_DISPATCH;
871                 if ((msiHandle = MsiGetActiveDatabase(This->msiHandle)))
872                 {
873                     if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Database, DatabaseImpl_Invoke, NULL, 0)))
874                     {
875                         IDispatch_AddRef(pDispatch);
876                         V_DISPATCH(pVarResult) = pDispatch;
877                     }
878                     else
879                         ERR("Failed to create Database object, hresult 0x%08x\n", hr);
880                 }
881                 else
882                 {
883                     ERR("MsiGetActiveDatabase failed\n");
884                     return DISP_E_EXCEPTION;
885                 }
886             }
887             break;
888
889         case DISPID_SESSION_DOACTION:
890             if (wFlags & DISPATCH_METHOD) {
891                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
892                 if (FAILED(hr)) return hr;
893                 ret = MsiDoActionW(This->msiHandle, V_BSTR(&varg0));
894                 V_VT(pVarResult) = VT_I4;
895                 switch (ret)
896                 {
897                     case ERROR_FUNCTION_NOT_CALLED:
898                         V_I4(pVarResult) = msiDoActionStatusNoAction;
899                         break;
900                     case ERROR_SUCCESS:
901                         V_I4(pVarResult) = msiDoActionStatusSuccess;
902                         break;
903                     case ERROR_INSTALL_USEREXIT:
904                         V_I4(pVarResult) = msiDoActionStatusUserExit;
905                         break;
906                     case ERROR_INSTALL_FAILURE:
907                         V_I4(pVarResult) = msiDoActionStatusFailure;
908                         break;
909                     case ERROR_INSTALL_SUSPEND:
910                         V_I4(pVarResult) = msiDoActionStatusSuspend;
911                         break;
912                     case ERROR_MORE_DATA:
913                         V_I4(pVarResult) = msiDoActionStatusFinished;
914                         break;
915                     case ERROR_INVALID_HANDLE_STATE:
916                         V_I4(pVarResult) = msiDoActionStatusWrongState;
917                         break;
918                     case ERROR_INVALID_DATA:
919                         V_I4(pVarResult) = msiDoActionStatusBadActionData;
920                         break;
921                     default:
922                         VariantClear(&varg0);
923                         FIXME("MsiDoAction returned unhandled value %d\n", ret);
924                         return DISP_E_EXCEPTION;
925                 }
926             }
927             break;
928
929         case DISPID_SESSION_SETINSTALLLEVEL:
930             hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
931             if (FAILED(hr)) return hr;
932             if ((ret = MsiSetInstallLevel(This->msiHandle, V_I4(&varg0))) != ERROR_SUCCESS)
933             {
934                 ERR("MsiSetInstallLevel returned %d\n", ret);
935                 return DISP_E_EXCEPTION;
936             }
937             break;
938
939         case DISPID_SESSION_FEATURECURRENTSTATE:
940             if (wFlags & DISPATCH_PROPERTYGET) {
941                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
942                 if (FAILED(hr)) return hr;
943                 V_VT(pVarResult) = VT_I4;
944                 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
945                     V_I4(pVarResult) = iInstalled;
946                 else
947                 {
948                     ERR("MsiGetFeatureState returned %d\n", ret);
949                     V_I4(pVarResult) = msiInstallStateUnknown;
950                 }
951             }
952             break;
953
954         case DISPID_SESSION_FEATUREREQUESTSTATE:
955             if (wFlags & DISPATCH_PROPERTYGET) {
956                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
957                 if (FAILED(hr)) return hr;
958                 V_VT(pVarResult) = VT_I4;
959                 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
960                     V_I4(pVarResult) = iAction;
961                 else
962                 {
963                     ERR("MsiGetFeatureState returned %d\n", ret);
964                     V_I4(pVarResult) = msiInstallStateUnknown;
965                 }
966             } else if (wFlags & DISPATCH_PROPERTYPUT) {
967                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
968                 if (FAILED(hr)) return hr;
969                 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_I4, &varg1, puArgErr);
970                 if (FAILED(hr)) {
971                     VariantClear(&varg0);
972                     return hr;
973                 }
974                 if ((ret = MsiSetFeatureStateW(This->msiHandle, V_BSTR(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
975                 {
976                     VariantClear(&varg0);
977                     ERR("MsiSetFeatureState returned %d\n", ret);
978                     return DISP_E_EXCEPTION;
979                 }
980             }
981             break;
982
983          default:
984             return DISP_E_MEMBERNOTFOUND;
985     }
986
987     VariantClear(&varg1);
988     VariantClear(&varg0);
989
990     return S_OK;
991 }
992
993 static HRESULT WINAPI InstallerImpl_Invoke(
994         AutomationObject* This,
995         DISPID dispIdMember,
996         REFIID riid,
997         LCID lcid,
998         WORD wFlags,
999         DISPPARAMS* pDispParams,
1000         VARIANT* pVarResult,
1001         EXCEPINFO* pExcepInfo,
1002         UINT* puArgErr)
1003 {
1004     MSIHANDLE msiHandle;
1005     IDispatch *pDispatch = NULL;
1006     UINT ret;
1007     VARIANTARG varg0, varg1;
1008     HRESULT hr;
1009
1010     VariantInit(&varg0);
1011     VariantInit(&varg1);
1012
1013     switch (dispIdMember)
1014     {
1015         case DISPID_INSTALLER_OPENPACKAGE:
1016             if (wFlags & DISPATCH_METHOD)
1017             {
1018                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1019                 if (FAILED(hr)) return hr;
1020                 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1021                 if (FAILED(hr))
1022                 {
1023                     VariantClear(&varg0);
1024                     return hr;
1025                 }
1026                 V_VT(pVarResult) = VT_DISPATCH;
1027                 if ((ret = MsiOpenPackageExW(V_BSTR(&varg0), V_I4(&varg1), &msiHandle)) == ERROR_SUCCESS)
1028                 {
1029                     if (SUCCEEDED(hr = create_session(msiHandle, (IDispatch *)This, &pDispatch)))
1030                     {
1031                         IDispatch_AddRef(pDispatch);
1032                         V_DISPATCH(pVarResult) = pDispatch;
1033                     }
1034                     else
1035                         ERR("Failed to create Session object, hresult 0x%08x\n", hr);
1036                 }
1037                 else
1038                 {
1039                     VariantClear(&varg0);
1040                     ERR("MsiOpenPackageEx returned %d\n", ret);
1041                     return DISP_E_EXCEPTION;
1042                 }
1043             }
1044             break;
1045
1046         case DISPID_INSTALLER_PRODUCTSTATE:
1047             if (wFlags & DISPATCH_PROPERTYGET) {
1048                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1049                 if (FAILED(hr)) return hr;
1050                 V_VT(pVarResult) = VT_I4;
1051                 V_I4(pVarResult) = MsiQueryProductStateW(V_BSTR(&varg0));
1052             }
1053             break;
1054
1055         case DISPID_INSTALLER_PRODUCTS:
1056             if (wFlags & DISPATCH_PROPERTYGET)
1057             {
1058                 StringListData *sldata = NULL;
1059                 int idx = 0;
1060                 WCHAR szProductBuf[GUID_SIZE];
1061
1062                 /* Find number of products */
1063                 do {
1064                     ret = MsiEnumProductsW(idx, szProductBuf);
1065                     if (ret == ERROR_SUCCESS) idx++;
1066                 } while (ret == ERROR_SUCCESS && ret != ERROR_NO_MORE_ITEMS);
1067
1068                 if (ret != ERROR_SUCCESS && ret != ERROR_NO_MORE_ITEMS)
1069                 {
1070                     ERR("MsiEnumProducts returned %d\n", ret);
1071                     return DISP_E_EXCEPTION;
1072                 }
1073
1074                 V_VT(pVarResult) = VT_DISPATCH;
1075                 if (SUCCEEDED(hr = create_automation_object(0, NULL, (LPVOID*)&pDispatch, &DIID_StringList, StringListImpl_Invoke, StringListImpl_Free, sizeof(StringListData))))
1076                 {
1077                     IDispatch_AddRef(pDispatch);
1078                     V_DISPATCH(pVarResult) = pDispatch;
1079
1080                     /* Save product strings */
1081                     sldata = (StringListData *)private_data((AutomationObject *)pDispatch);
1082                     sldata->iCount = idx;
1083                     sldata->pszStrings = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LPWSTR)*sldata->iCount);
1084                     for (idx = 0; idx < sldata->iCount; idx++)
1085                     {
1086                         ret = MsiEnumProductsW(idx, szProductBuf);
1087                         sldata->pszStrings[idx] = SysAllocString(szProductBuf);
1088                     }
1089                 }
1090                 else
1091                     ERR("Failed to create StringList object, hresult 0x%08x\n", hr);
1092             }
1093             break;
1094
1095          default:
1096             return DISP_E_MEMBERNOTFOUND;
1097     }
1098
1099     VariantClear(&varg1);
1100     VariantClear(&varg0);
1101
1102     return S_OK;
1103 }
1104
1105 /* Wrapper around create_automation_object to create an installer object. */
1106 HRESULT create_msiserver(IUnknown *pOuter, LPVOID *ppObj)
1107 {
1108     return create_automation_object(0, pOuter, ppObj, &DIID_Installer, InstallerImpl_Invoke, NULL, 0);
1109 }
1110
1111 /* Wrapper around create_automation_object to create a session object. */
1112 HRESULT create_session(MSIHANDLE msiHandle, IDispatch *pInstaller, IDispatch **pDispatch)
1113 {
1114     HRESULT hr = create_automation_object(msiHandle, NULL, (LPVOID)pDispatch, &DIID_Session, SessionImpl_Invoke, NULL, sizeof(SessionData));
1115     if (SUCCEEDED(hr) && pDispatch && *pDispatch)
1116         ((SessionData *)private_data((AutomationObject *)*pDispatch))->pInstaller = pInstaller;
1117     return hr;
1118 }