msi: automation: Implement a few functions from the Session object.
[wine] / dlls / msi / automation.c
1 /*
2  * Implementation of OLE Automation for Microsoft Installer (msi.dll)
3  *
4  * Copyright 2007 Misha Koshelev
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #define COBJMACROS
22
23 #include <stdarg.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winerror.h"
27 #include "winuser.h"
28 #include "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
77 /* VTables */
78 static const struct IDispatchVtbl AutomationObject_Vtbl;
79 static const struct IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl;
80
81 /* Load type info so we don't have to process GetIDsOfNames */
82 HRESULT load_type_info(IDispatch *iface, ITypeInfo **pptinfo, REFIID clsid, LCID lcid)
83 {
84     HRESULT hr;
85     LPTYPELIB pLib = NULL;
86     LPTYPEINFO pInfo = NULL;
87     static const WCHAR szMsiServer[] = {'m','s','i','s','e','r','v','e','r','.','t','l','b'};
88
89     TRACE("(%p)->(%s,%d)\n", iface, debugstr_guid(clsid), lcid);
90
91     /* Load registered type library */
92     hr = LoadRegTypeLib(&LIBID_WindowsInstaller, 1, 0, lcid, &pLib);
93     if (FAILED(hr)) {
94         hr = LoadTypeLib(szMsiServer, &pLib);
95         if (FAILED(hr)) {
96             ERR("Could not load msiserver.tlb\n");
97             return hr;
98         }
99     }
100
101     /* Get type information for object */
102     hr = ITypeLib_GetTypeInfoOfGuid(pLib, clsid, &pInfo);
103     ITypeLib_Release(pLib);
104     if (FAILED(hr)) {
105         ERR("Could not load ITypeInfo for %s\n", debugstr_guid(clsid));
106         return hr;
107     }
108     *pptinfo = pInfo;
109     return S_OK;
110 }
111
112 /* Create the automation object, placing the result in the pointer ppObj. The automation object is created
113  * with the appropriate clsid and invocation function. */
114 HRESULT create_automation_object(MSIHANDLE msiHandle, IUnknown *pUnkOuter, LPVOID *ppObj, REFIID clsid,
115             HRESULT (STDMETHODCALLTYPE *funcInvoke)(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,
116                                                     VARIANT*,EXCEPINFO*,UINT*))
117 {
118     AutomationObject *object;
119     HRESULT hr;
120
121     TRACE("(%ld,%p,%p,%s,%p)\n", (unsigned long)msiHandle, pUnkOuter, ppObj, debugstr_guid(clsid), funcInvoke);
122
123     if( pUnkOuter )
124         return CLASS_E_NOAGGREGATION;
125
126     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AutomationObject));
127
128     /* Set all the VTable references */
129     object->lpVtbl = &AutomationObject_Vtbl;
130     object->lpvtblIProvideMultipleClassInfo = &AutomationObject_IProvideMultipleClassInfo_Vtbl;
131     object->ref = 1;
132
133     /* Store data that was passed */
134     object->msiHandle = msiHandle;
135     object->clsid = (LPCLSID)clsid;
136     object->funcInvoke = funcInvoke;
137
138     /* Load our TypeInfo so we don't have to process GetIDsOfNames */
139     object->iTypeInfo = NULL;
140     hr = load_type_info((IDispatch *)object, &object->iTypeInfo, clsid, 0x0);
141     if (FAILED(hr)) {
142         HeapFree(GetProcessHeap(), 0, object);
143         return hr;
144     }
145
146     *ppObj = object;
147
148     return S_OK;
149 }
150
151 /* Macros to get pointer to AutomationObject from the other VTables. */
152 static inline AutomationObject *obj_from_IProvideMultipleClassInfo( IProvideMultipleClassInfo *iface )
153 {
154     return (AutomationObject *)((char*)iface - FIELD_OFFSET(AutomationObject, lpvtblIProvideMultipleClassInfo));
155 }
156
157 /*
158  * AutomationObject methods
159  */
160
161 /*** IUnknown methods ***/
162 static HRESULT WINAPI AutomationObject_QueryInterface(IDispatch* iface, REFIID riid, void** ppvObject)
163 {
164     AutomationObject *This = (AutomationObject *)iface;
165
166     TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
167
168     if (ppvObject == NULL)
169       return E_INVALIDARG;
170
171     *ppvObject = 0;
172
173     if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDispatch) || IsEqualGUID(riid, This->clsid))
174         *ppvObject = This;
175     else if (IsEqualGUID(riid, &IID_IProvideClassInfo) ||
176              IsEqualGUID(riid, &IID_IProvideClassInfo2) ||
177              IsEqualGUID(riid, &IID_IProvideMultipleClassInfo))
178         *ppvObject = &This->lpvtblIProvideMultipleClassInfo;
179     else
180     {
181         TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid));
182         return E_NOINTERFACE;
183     }
184
185     /*
186      * Query Interface always increases the reference count by one when it is
187      * successful
188      */
189     IClassFactory_AddRef(iface);
190
191     return S_OK;
192 }
193
194 static ULONG WINAPI AutomationObject_AddRef(IDispatch* iface)
195 {
196     AutomationObject *This = (AutomationObject *)iface;
197
198     TRACE("(%p/%p)\n", iface, This);
199
200     return InterlockedIncrement(&This->ref);
201 }
202
203 static ULONG WINAPI AutomationObject_Release(IDispatch* iface)
204 {
205     AutomationObject *This = (AutomationObject *)iface;
206     ULONG ref = InterlockedDecrement(&This->ref);
207
208     TRACE("(%p/%p)\n", iface, This);
209
210     if (!ref)
211     {
212         MsiCloseHandle(This->msiHandle);
213         HeapFree(GetProcessHeap(), 0, This);
214     }
215
216     return ref;
217 }
218
219 /*** IDispatch methods ***/
220 static HRESULT WINAPI AutomationObject_GetTypeInfoCount(
221         IDispatch* iface,
222         UINT* pctinfo)
223 {
224     AutomationObject *This = (AutomationObject *)iface;
225
226     TRACE("(%p/%p)->(%p)\n", iface, This, pctinfo);
227     *pctinfo = 1;
228     return S_OK;
229 }
230
231 static HRESULT WINAPI AutomationObject_GetTypeInfo(
232         IDispatch* iface,
233         UINT iTInfo,
234         LCID lcid,
235         ITypeInfo** ppTInfo)
236 {
237     AutomationObject *This = (AutomationObject *)iface;
238     TRACE("(%p/%p)->(%d,%d,%p)\n", iface, This, iTInfo, lcid, ppTInfo);
239
240     ITypeInfo_AddRef(This->iTypeInfo);
241     *ppTInfo = This->iTypeInfo;
242     return S_OK;
243 }
244
245 static HRESULT WINAPI AutomationObject_GetIDsOfNames(
246         IDispatch* iface,
247         REFIID riid,
248         LPOLESTR* rgszNames,
249         UINT cNames,
250         LCID lcid,
251         DISPID* rgDispId)
252 {
253     AutomationObject *This = (AutomationObject *)iface;
254     TRACE("(%p/%p)->(%p,%p,%d,%d,%p)\n", iface, This, riid, rgszNames, cNames, lcid, rgDispId);
255
256     if (!IsEqualGUID(riid, &IID_NULL)) return E_INVALIDARG;
257     return ITypeInfo_GetIDsOfNames(This->iTypeInfo, rgszNames, cNames, rgDispId);
258 }
259
260 /* Maximum number of allowed function parameters+1 */
261 #define MAX_FUNC_PARAMS 20
262
263 /* Some error checking is done here to simplify individual object function invocation */
264 static HRESULT WINAPI AutomationObject_Invoke(
265         IDispatch* iface,
266         DISPID dispIdMember,
267         REFIID riid,
268         LCID lcid,
269         WORD wFlags,
270         DISPPARAMS* pDispParams,
271         VARIANT* pVarResult,
272         EXCEPINFO* pExcepInfo,
273         UINT* puArgErr)
274 {
275     AutomationObject *This = (AutomationObject *)iface;
276     HRESULT hr;
277     unsigned int uArgErr;
278     VARIANT varResultDummy;
279     BSTR bstrName = NULL;
280
281     TRACE("(%p/%p)->(%d,%p,%d,%d,%p,%p,%p,%p)\n", iface, This, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
282
283     if (!IsEqualIID(riid, &IID_NULL))
284     {
285         ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
286         return DISP_E_UNKNOWNNAME;
287     }
288
289     if (wFlags & DISPATCH_PROPERTYGET && !pVarResult)
290     {
291         ERR("NULL pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
292         return DISP_E_PARAMNOTOPTIONAL;
293     }
294
295     /* This simplifies our individual object invocation functions */
296     if (puArgErr == NULL) puArgErr = &uArgErr;
297     if (pVarResult == NULL) pVarResult = &varResultDummy;
298
299     /* Assume return type is void unless determined otherwise */
300     VariantInit(pVarResult);
301
302     /* If we are tracing, we want to see the name of the member we are invoking */
303     if (TRACE_ON(msi))
304     {
305         ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL);
306         TRACE("Method %d, %s\n", dispIdMember, debugstr_w(bstrName));
307     }
308
309     hr = This->funcInvoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
310
311     if (hr == DISP_E_MEMBERNOTFOUND) {
312         if (bstrName == NULL) ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL);
313         FIXME("Method %d, %s wflags %d not implemented, clsid %s\n", dispIdMember, debugstr_w(bstrName), wFlags, debugstr_guid(This->clsid));
314     }
315     else if (pExcepInfo &&
316              (hr == DISP_E_PARAMNOTFOUND ||
317               hr == DISP_E_EXCEPTION)) {
318         static const WCHAR szComma[] = { ',',0 };
319         static WCHAR szExceptionSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
320         WCHAR szExceptionDescription[MAX_PATH];
321         BSTR bstrParamNames[MAX_FUNC_PARAMS];
322         unsigned namesNo, i;
323         BOOL bFirst = TRUE;
324
325         if (FAILED(ITypeInfo_GetNames(This->iTypeInfo, dispIdMember, bstrParamNames,
326                                       MAX_FUNC_PARAMS, &namesNo)))
327         {
328             TRACE("Failed to retrieve names for dispIdMember %d\n", dispIdMember);
329         }
330         else
331         {
332             memset(szExceptionDescription, 0, sizeof(szExceptionDescription));
333             for (i=0; i<namesNo; i++)
334             {
335                 if (bFirst) bFirst = FALSE;
336                 else {
337                     lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], szComma);
338                 }
339                 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], bstrParamNames[i]);
340                 SysFreeString(bstrParamNames[i]);
341             }
342
343             memset(pExcepInfo, 0, sizeof(EXCEPINFO));
344             pExcepInfo->wCode = 1000;
345             pExcepInfo->bstrSource = szExceptionSource;
346             pExcepInfo->bstrDescription = szExceptionDescription;
347             hr = DISP_E_EXCEPTION;
348         }
349     }
350
351     /* Make sure we free the return variant if it is our dummy variant */
352     if (pVarResult == &varResultDummy) VariantClear(pVarResult);
353
354     /* Free function name if we retrieved it */
355     if (bstrName) SysFreeString(bstrName);
356
357     TRACE("Returning 0x%08x, %s\n", hr, SUCCEEDED(hr) ? "ok" : "not ok");
358
359     return hr;
360 }
361
362 static const struct IDispatchVtbl AutomationObject_Vtbl =
363 {
364     AutomationObject_QueryInterface,
365     AutomationObject_AddRef,
366     AutomationObject_Release,
367     AutomationObject_GetTypeInfoCount,
368     AutomationObject_GetTypeInfo,
369     AutomationObject_GetIDsOfNames,
370     AutomationObject_Invoke
371 };
372
373 /*
374  * IProvideMultipleClassInfo methods
375  */
376
377 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_QueryInterface(
378   IProvideMultipleClassInfo* iface,
379   REFIID     riid,
380   VOID**     ppvoid)
381 {
382     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
383     return AutomationObject_QueryInterface((IDispatch *)This, riid, ppvoid);
384 }
385
386 static ULONG WINAPI AutomationObject_IProvideMultipleClassInfo_AddRef(IProvideMultipleClassInfo* iface)
387 {
388     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
389     return AutomationObject_AddRef((IDispatch *)This);
390 }
391
392 static ULONG WINAPI AutomationObject_IProvideMultipleClassInfo_Release(IProvideMultipleClassInfo* iface)
393 {
394     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
395     return AutomationObject_Release((IDispatch *)This);
396 }
397
398 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_GetClassInfo(IProvideMultipleClassInfo* iface, ITypeInfo** ppTI)
399 {
400     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
401     TRACE("(%p/%p)->(%p)\n", iface, This, ppTI);
402     return load_type_info((IDispatch *)This, ppTI, This->clsid, 0);
403 }
404
405 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_GetGUID(IProvideMultipleClassInfo* iface, DWORD dwGuidKind, GUID* pGUID)
406 {
407     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
408     TRACE("(%p/%p)->(%d,%s)\n", iface, This, dwGuidKind, debugstr_guid(pGUID));
409
410     if (dwGuidKind != GUIDKIND_DEFAULT_SOURCE_DISP_IID)
411         return E_INVALIDARG;
412     else {
413         *pGUID = *This->clsid;
414         return S_OK;
415     }
416 }
417
418 static HRESULT WINAPI AutomationObject_GetMultiTypeInfoCount(IProvideMultipleClassInfo* iface, ULONG* pcti)
419 {
420     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
421
422     TRACE("(%p/%p)->(%p)\n", iface, This, pcti);
423     *pcti = 1;
424     return S_OK;
425 }
426
427 static HRESULT WINAPI AutomationObject_GetInfoOfIndex(IProvideMultipleClassInfo* iface,
428         ULONG iti,
429         DWORD dwFlags,
430         ITypeInfo** pptiCoClass,
431         DWORD* pdwTIFlags,
432         ULONG* pcdispidReserved,
433         IID* piidPrimary,
434         IID* piidSource)
435 {
436     AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
437
438     TRACE("(%p/%p)->(%d,%d,%p,%p,%p,%p,%p)\n", iface, This, iti, dwFlags, pptiCoClass, pdwTIFlags, pcdispidReserved, piidPrimary, piidSource);
439
440     if (iti != 0)
441         return E_INVALIDARG;
442
443     if (dwFlags & MULTICLASSINFO_GETTYPEINFO)
444         load_type_info((IDispatch *)This, pptiCoClass, This->clsid, 0);
445
446     if (dwFlags & MULTICLASSINFO_GETNUMRESERVEDDISPIDS)
447     {
448         *pdwTIFlags = 0;
449         *pcdispidReserved = 0;
450     }
451
452     if (dwFlags & MULTICLASSINFO_GETIIDPRIMARY){
453         *piidPrimary = *This->clsid;
454     }
455
456     if (dwFlags & MULTICLASSINFO_GETIIDSOURCE){
457         *piidSource = *This->clsid;
458     }
459
460     return S_OK;
461 }
462
463 static const IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl =
464 {
465     AutomationObject_IProvideMultipleClassInfo_QueryInterface,
466     AutomationObject_IProvideMultipleClassInfo_AddRef,
467     AutomationObject_IProvideMultipleClassInfo_Release,
468     AutomationObject_IProvideMultipleClassInfo_GetClassInfo,
469     AutomationObject_IProvideMultipleClassInfo_GetGUID,
470     AutomationObject_GetMultiTypeInfoCount,
471     AutomationObject_GetInfoOfIndex
472 };
473
474 /*
475  * Individual Object Invocation Functions
476  */
477
478 static HRESULT WINAPI RecordImpl_Invoke(
479         AutomationObject* This,
480         DISPID dispIdMember,
481         REFIID riid,
482         LCID lcid,
483         WORD wFlags,
484         DISPPARAMS* pDispParams,
485         VARIANT* pVarResult,
486         EXCEPINFO* pExcepInfo,
487         UINT* puArgErr)
488 {
489     WCHAR *szString;
490     DWORD dwLen;
491     UINT ret;
492     VARIANTARG varg0, varg1;
493     HRESULT hr;
494
495     VariantInit(&varg0);
496     VariantInit(&varg1);
497
498     switch (dispIdMember)
499     {
500         case DISPID_RECORD_STRINGDATA:
501             if (wFlags & DISPATCH_PROPERTYGET) {
502                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
503                 if (FAILED(hr)) return hr;
504                 V_VT(pVarResult) = VT_BSTR;
505                 V_BSTR(pVarResult) = NULL;
506                 ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), NULL, &dwLen);
507                 if (ret == ERROR_SUCCESS)
508                 {
509                     szString = msi_alloc((++dwLen)*sizeof(WCHAR));
510                     if (szString)
511                     {
512                         if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
513                             V_BSTR(pVarResult) = SysAllocString(szString);
514                         msi_free(szString);
515                     }
516                 }
517                 if (ret != ERROR_SUCCESS)
518                     ERR("MsiRecordGetString returned %d\n", ret);
519             } else if (wFlags & DISPATCH_PROPERTYPUT) {
520                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
521                 if (FAILED(hr)) return hr;
522                 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BSTR, &varg1, puArgErr);
523                 if (FAILED(hr)) return hr;
524                 if ((ret = MsiRecordSetStringW(This->msiHandle, V_I4(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
525                 {
526                     ERR("MsiRecordSetString returned %d\n", ret);
527                     return DISP_E_EXCEPTION;
528                 }
529             }
530             break;
531
532          default:
533             return DISP_E_MEMBERNOTFOUND;
534     }
535
536     return S_OK;
537 }
538
539 static HRESULT WINAPI ViewImpl_Invoke(
540         AutomationObject* This,
541         DISPID dispIdMember,
542         REFIID riid,
543         LCID lcid,
544         WORD wFlags,
545         DISPPARAMS* pDispParams,
546         VARIANT* pVarResult,
547         EXCEPINFO* pExcepInfo,
548         UINT* puArgErr)
549 {
550     MSIHANDLE msiHandle;
551     IDispatch *pDispatch = NULL;
552     UINT ret;
553     VARIANTARG varg0, varg1;
554     HRESULT hr;
555
556     VariantInit(&varg0);
557     VariantInit(&varg1);
558
559     switch (dispIdMember)
560     {
561         case DISPID_VIEW_EXECUTE:
562             if (wFlags & DISPATCH_METHOD)
563             {
564                 hr = DispGetParam(pDispParams, 0, VT_DISPATCH, &varg0, puArgErr);
565                 if (SUCCEEDED(hr) && V_DISPATCH(&varg0) != NULL)
566                     MsiViewExecute(This->msiHandle, ((AutomationObject *)V_DISPATCH(&varg0))->msiHandle);
567                 else
568                     MsiViewExecute(This->msiHandle, 0);
569             }
570             break;
571
572         case DISPID_VIEW_FETCH:
573             if (wFlags & DISPATCH_METHOD)
574             {
575                 V_VT(pVarResult) = VT_DISPATCH;
576                 if ((ret = MsiViewFetch(This->msiHandle, &msiHandle)) == ERROR_SUCCESS)
577                 {
578                     if (SUCCEEDED(create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Record, RecordImpl_Invoke)))
579                     {
580                         IDispatch_AddRef(pDispatch);
581                         V_DISPATCH(pVarResult) = pDispatch;
582                     }
583                 }
584                 else if (ret == ERROR_NO_MORE_ITEMS)
585                     V_DISPATCH(pVarResult) = NULL;
586                 else
587                 {
588                     ERR("MsiViewFetch returned %d\n", ret);
589                     return DISP_E_EXCEPTION;
590                 }
591             }
592             break;
593
594         case DISPID_VIEW_CLOSE:
595             if (wFlags & DISPATCH_METHOD)
596             {
597                 MsiViewClose(This->msiHandle);
598             }
599             break;
600
601          default:
602             return DISP_E_MEMBERNOTFOUND;
603     }
604
605     return S_OK;
606 }
607
608 static HRESULT WINAPI DatabaseImpl_Invoke(
609         AutomationObject* This,
610         DISPID dispIdMember,
611         REFIID riid,
612         LCID lcid,
613         WORD wFlags,
614         DISPPARAMS* pDispParams,
615         VARIANT* pVarResult,
616         EXCEPINFO* pExcepInfo,
617         UINT* puArgErr)
618 {
619     MSIHANDLE msiHandle;
620     IDispatch *pDispatch = NULL;
621     UINT ret;
622     VARIANTARG varg0, varg1;
623     HRESULT hr;
624
625     VariantInit(&varg0);
626     VariantInit(&varg1);
627
628     switch (dispIdMember)
629     {
630         case DISPID_DATABASE_OPENVIEW:
631             if (wFlags & DISPATCH_METHOD)
632             {
633                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
634                 if (FAILED(hr)) return hr;
635                 V_VT(pVarResult) = VT_DISPATCH;
636                 if ((ret = MsiDatabaseOpenViewW(This->msiHandle, V_BSTR(&varg0), &msiHandle)) == ERROR_SUCCESS)
637                 {
638                     if (SUCCEEDED(create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_View, ViewImpl_Invoke)))
639                     {
640                         IDispatch_AddRef(pDispatch);
641                         V_DISPATCH(pVarResult) = pDispatch;
642                     }
643                 }
644                 else
645                 {
646                     ERR("MsiDatabaseOpenView returned %d\n", ret);
647                     return DISP_E_EXCEPTION;
648                 }
649             }
650             break;
651
652          default:
653             return DISP_E_MEMBERNOTFOUND;
654     }
655
656     return S_OK;
657 }
658
659 static HRESULT WINAPI SessionImpl_Invoke(
660         AutomationObject* This,
661         DISPID dispIdMember,
662         REFIID riid,
663         LCID lcid,
664         WORD wFlags,
665         DISPPARAMS* pDispParams,
666         VARIANT* pVarResult,
667         EXCEPINFO* pExcepInfo,
668         UINT* puArgErr)
669 {
670     WCHAR *szString;
671     DWORD dwLen;
672     IDispatch *pDispatch = NULL;
673     MSIHANDLE msiHandle;
674     LANGID langId;
675     UINT ret;
676     INSTALLSTATE iInstalled, iAction;
677     VARIANTARG varg0, varg1;
678     HRESULT hr;
679
680     VariantInit(&varg0);
681     VariantInit(&varg1);
682
683     switch (dispIdMember)
684     {
685         case DISPID_SESSION_PROPERTY:
686             if (wFlags & DISPATCH_PROPERTYGET) {
687                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
688                 if (FAILED(hr)) return hr;
689                 V_VT(pVarResult) = VT_BSTR;
690                 V_BSTR(pVarResult) = NULL;
691                 ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), NULL, &dwLen);
692                 if (ret == ERROR_SUCCESS)
693                 {
694                     szString = msi_alloc((++dwLen)*sizeof(WCHAR));
695                     if (szString)
696                     {
697                         if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
698                             V_BSTR(pVarResult) = SysAllocString(szString);
699                         msi_free(szString);
700                     }
701                 }
702                 if (ret != ERROR_SUCCESS)
703                     ERR("MsiGetProperty returned %d\n", ret);
704             } else if (wFlags & DISPATCH_PROPERTYPUT) {
705                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
706                 if (FAILED(hr)) return hr;
707                 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BSTR, &varg1, puArgErr);
708                 if (FAILED(hr)) {
709                     VariantClear(&varg0);
710                     return hr;
711                 }
712                 if ((ret = MsiSetPropertyW(This->msiHandle, V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
713                 {
714                     ERR("MsiSetProperty returned %d\n", ret);
715                     return DISP_E_EXCEPTION;
716                 }
717             }
718             break;
719
720         case DISPID_SESSION_LANGUAGE:
721             if (wFlags & DISPATCH_PROPERTYGET) {
722                 langId = MsiGetLanguage(This->msiHandle);
723                 V_VT(pVarResult) = VT_I4;
724                 V_I4(pVarResult) = langId;
725             }
726             break;
727
728         case DISPID_SESSION_MODE:
729             if (wFlags & DISPATCH_PROPERTYGET) {
730                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
731                 if (FAILED(hr)) return hr;
732                 V_VT(pVarResult) = VT_BOOL;
733                 V_BOOL(pVarResult) = MsiGetMode(This->msiHandle, V_I4(&varg0));
734             } else if (wFlags & DISPATCH_PROPERTYPUT) {
735                 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
736                 if (FAILED(hr)) return hr;
737                 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BOOL, &varg1, puArgErr);
738                 if (FAILED(hr)) return hr;
739                 if ((ret = MsiSetMode(This->msiHandle, V_I4(&varg0), V_BOOL(&varg1))) != ERROR_SUCCESS)
740                 {
741                     ERR("MsiSetMode returned %d\n", ret);
742                     return DISP_E_EXCEPTION;
743                 }
744             }
745             break;
746
747         case DISPID_SESSION_DATABASE:
748             if (wFlags & DISPATCH_PROPERTYGET) {
749                 V_VT(pVarResult) = VT_DISPATCH;
750                 if ((msiHandle = MsiGetActiveDatabase(This->msiHandle)))
751                 {
752                     if (SUCCEEDED(create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Database, DatabaseImpl_Invoke)))
753                     {
754                         IDispatch_AddRef(pDispatch);
755                         V_DISPATCH(pVarResult) = pDispatch;
756                     }
757                 }
758                 else
759                 {
760                     ERR("MsiGetActiveDatabase failed\n");
761                     return DISP_E_EXCEPTION;
762                 }
763             }
764             break;
765
766         case DISPID_SESSION_DOACTION:
767             if (wFlags & DISPATCH_METHOD) {
768                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
769                 if (FAILED(hr)) return hr;
770                 ret = MsiDoActionW(This->msiHandle, V_BSTR(&varg0));
771                 V_VT(pVarResult) = VT_I4;
772                 switch (ret)
773                 {
774                     case ERROR_FUNCTION_NOT_CALLED:
775                         V_I4(pVarResult) = msiDoActionStatusNoAction;
776                         break;
777                     case ERROR_SUCCESS:
778                         V_I4(pVarResult) = msiDoActionStatusSuccess;
779                         break;
780                     case ERROR_INSTALL_USEREXIT:
781                         V_I4(pVarResult) = msiDoActionStatusUserExit;
782                         break;
783                     case ERROR_INSTALL_FAILURE:
784                         V_I4(pVarResult) = msiDoActionStatusFailure;
785                         break;
786                     case ERROR_INSTALL_SUSPEND:
787                         V_I4(pVarResult) = msiDoActionStatusSuspend;
788                         break;
789                     case ERROR_MORE_DATA:
790                         V_I4(pVarResult) = msiDoActionStatusFinished;
791                         break;
792                     case ERROR_INVALID_HANDLE_STATE:
793                         V_I4(pVarResult) = msiDoActionStatusWrongState;
794                         break;
795                     case ERROR_INVALID_DATA:
796                         V_I4(pVarResult) = msiDoActionStatusBadActionData;
797                         break;
798                     default:
799                         FIXME("MsiDoAction returned unhandled value %d\n", ret);
800                         return DISP_E_EXCEPTION;
801                 }
802             }
803             break;
804
805         case DISPID_SESSION_SETINSTALLLEVEL:
806             hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
807             if (FAILED(hr)) return hr;
808             if ((ret = MsiSetInstallLevel(This->msiHandle, V_I4(&varg0))) != ERROR_SUCCESS)
809             {
810                 ERR("MsiSetInstallLevel returned %d\n", ret);
811                 return DISP_E_EXCEPTION;
812             }
813             break;
814
815         case DISPID_SESSION_FEATURECURRENTSTATE:
816             if (wFlags & DISPATCH_PROPERTYGET) {
817                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
818                 if (FAILED(hr)) return hr;
819                 V_VT(pVarResult) = VT_I4;
820                 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
821                     V_I4(pVarResult) = iInstalled;
822                 else
823                 {
824                     ERR("MsiGetFeatureState returned %d\n", ret);
825                     V_I4(pVarResult) = msiInstallStateUnknown;
826                 }
827             }
828             break;
829
830         case DISPID_SESSION_FEATUREREQUESTSTATE:
831             if (wFlags & DISPATCH_PROPERTYGET) {
832                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
833                 if (FAILED(hr)) return hr;
834                 V_VT(pVarResult) = VT_I4;
835                 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
836                     V_I4(pVarResult) = iAction;
837                 else
838                 {
839                     ERR("MsiGetFeatureState returned %d\n", ret);
840                     V_I4(pVarResult) = msiInstallStateUnknown;
841                 }
842             } else if (wFlags & DISPATCH_PROPERTYPUT) {
843                 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
844                 if (FAILED(hr)) return hr;
845                 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_I4, &varg1, puArgErr);
846                 if (FAILED(hr)) {
847                     VariantClear(&varg0);
848                     return hr;
849                 }
850                 if ((ret = MsiSetFeatureStateW(This->msiHandle, V_BSTR(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
851                 {
852                     ERR("MsiSetFeatureState returned %d\n", ret);
853                     return DISP_E_EXCEPTION;
854                 }
855             }
856             break;
857
858          default:
859             return DISP_E_MEMBERNOTFOUND;
860     }
861
862     return S_OK;
863 }