2 * Implementation of OLE Automation for Microsoft Installer (msi.dll)
4 * Copyright 2007 Misha Koshelev
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.
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.
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
32 #include "wine/debug.h"
33 #include "wine/unicode.h"
35 #include "msiserver.h"
36 #include "msiserver_dispids.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(msi);
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.
45 typedef interface AutomationObject AutomationObject;
47 interface AutomationObject {
49 * VTables - We provide IDispatch, IProvideClassInfo, IProvideClassInfo2, IProvideMultipleClassInfo
51 const IDispatchVtbl *lpVtbl;
52 const IProvideMultipleClassInfoVtbl *lpvtblIProvideMultipleClassInfo;
54 /* Object reference count */
57 /* Clsid for this class and it's appropriate ITypeInfo object */
61 /* The MSI handle of the current object */
64 /* A function that is called from AutomationObject::Invoke, specific to this type of object. */
65 HRESULT (STDMETHODCALLTYPE *funcInvoke)(
66 AutomationObject* This,
71 DISPPARAMS* pDispParams,
73 EXCEPINFO* pExcepInfo,
78 static const struct IDispatchVtbl AutomationObject_Vtbl;
79 static const struct IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl;
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)
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'};
89 TRACE("(%p)->(%s,%d)\n", iface, debugstr_guid(clsid), lcid);
91 /* Load registered type library */
92 hr = LoadRegTypeLib(&LIBID_WindowsInstaller, 1, 0, lcid, &pLib);
94 hr = LoadTypeLib(szMsiServer, &pLib);
96 ERR("Could not load msiserver.tlb\n");
101 /* Get type information for object */
102 hr = ITypeLib_GetTypeInfoOfGuid(pLib, clsid, &pInfo);
103 ITypeLib_Release(pLib);
105 ERR("Could not load ITypeInfo for %s\n", debugstr_guid(clsid));
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*))
118 AutomationObject *object;
121 TRACE("(%ld,%p,%p,%s,%p)\n", (unsigned long)msiHandle, pUnkOuter, ppObj, debugstr_guid(clsid), funcInvoke);
124 return CLASS_E_NOAGGREGATION;
126 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AutomationObject));
128 /* Set all the VTable references */
129 object->lpVtbl = &AutomationObject_Vtbl;
130 object->lpvtblIProvideMultipleClassInfo = &AutomationObject_IProvideMultipleClassInfo_Vtbl;
133 /* Store data that was passed */
134 object->msiHandle = msiHandle;
135 object->clsid = (LPCLSID)clsid;
136 object->funcInvoke = funcInvoke;
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);
142 HeapFree(GetProcessHeap(), 0, object);
151 /* Macros to get pointer to AutomationObject from the other VTables. */
152 static inline AutomationObject *obj_from_IProvideMultipleClassInfo( IProvideMultipleClassInfo *iface )
154 return (AutomationObject *)((char*)iface - FIELD_OFFSET(AutomationObject, lpvtblIProvideMultipleClassInfo));
158 * AutomationObject methods
161 /*** IUnknown methods ***/
162 static HRESULT WINAPI AutomationObject_QueryInterface(IDispatch* iface, REFIID riid, void** ppvObject)
164 AutomationObject *This = (AutomationObject *)iface;
166 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
168 if (ppvObject == NULL)
173 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDispatch) || IsEqualGUID(riid, This->clsid))
175 else if (IsEqualGUID(riid, &IID_IProvideClassInfo) ||
176 IsEqualGUID(riid, &IID_IProvideClassInfo2) ||
177 IsEqualGUID(riid, &IID_IProvideMultipleClassInfo))
178 *ppvObject = &This->lpvtblIProvideMultipleClassInfo;
181 TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid));
182 return E_NOINTERFACE;
186 * Query Interface always increases the reference count by one when it is
189 IClassFactory_AddRef(iface);
194 static ULONG WINAPI AutomationObject_AddRef(IDispatch* iface)
196 AutomationObject *This = (AutomationObject *)iface;
198 TRACE("(%p/%p)\n", iface, This);
200 return InterlockedIncrement(&This->ref);
203 static ULONG WINAPI AutomationObject_Release(IDispatch* iface)
205 AutomationObject *This = (AutomationObject *)iface;
206 ULONG ref = InterlockedDecrement(&This->ref);
208 TRACE("(%p/%p)\n", iface, This);
212 MsiCloseHandle(This->msiHandle);
213 HeapFree(GetProcessHeap(), 0, This);
219 /*** IDispatch methods ***/
220 static HRESULT WINAPI AutomationObject_GetTypeInfoCount(
224 AutomationObject *This = (AutomationObject *)iface;
226 TRACE("(%p/%p)->(%p)\n", iface, This, pctinfo);
231 static HRESULT WINAPI AutomationObject_GetTypeInfo(
237 AutomationObject *This = (AutomationObject *)iface;
238 TRACE("(%p/%p)->(%d,%d,%p)\n", iface, This, iTInfo, lcid, ppTInfo);
240 ITypeInfo_AddRef(This->iTypeInfo);
241 *ppTInfo = This->iTypeInfo;
245 static HRESULT WINAPI AutomationObject_GetIDsOfNames(
253 AutomationObject *This = (AutomationObject *)iface;
254 TRACE("(%p/%p)->(%p,%p,%d,%d,%p)\n", iface, This, riid, rgszNames, cNames, lcid, rgDispId);
256 if (!IsEqualGUID(riid, &IID_NULL)) return E_INVALIDARG;
257 return ITypeInfo_GetIDsOfNames(This->iTypeInfo, rgszNames, cNames, rgDispId);
260 /* Maximum number of allowed function parameters+1 */
261 #define MAX_FUNC_PARAMS 20
263 /* Some error checking is done here to simplify individual object function invocation */
264 static HRESULT WINAPI AutomationObject_Invoke(
270 DISPPARAMS* pDispParams,
272 EXCEPINFO* pExcepInfo,
275 AutomationObject *This = (AutomationObject *)iface;
277 unsigned int uArgErr;
278 VARIANT varResultDummy;
279 BSTR bstrName = NULL;
281 TRACE("(%p/%p)->(%d,%p,%d,%d,%p,%p,%p,%p)\n", iface, This, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
283 if (!IsEqualIID(riid, &IID_NULL))
285 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
286 return DISP_E_UNKNOWNNAME;
289 if (wFlags & DISPATCH_PROPERTYGET && !pVarResult)
291 ERR("NULL pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
292 return DISP_E_PARAMNOTOPTIONAL;
295 /* This simplifies our individual object invocation functions */
296 if (puArgErr == NULL) puArgErr = &uArgErr;
297 if (pVarResult == NULL) pVarResult = &varResultDummy;
299 /* Assume return type is void unless determined otherwise */
300 VariantInit(pVarResult);
302 /* If we are tracing, we want to see the name of the member we are invoking */
305 ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL);
306 TRACE("Method %d, %s\n", dispIdMember, debugstr_w(bstrName));
309 hr = This->funcInvoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
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));
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];
325 if (FAILED(ITypeInfo_GetNames(This->iTypeInfo, dispIdMember, bstrParamNames,
326 MAX_FUNC_PARAMS, &namesNo)))
328 TRACE("Failed to retrieve names for dispIdMember %d\n", dispIdMember);
332 memset(szExceptionDescription, 0, sizeof(szExceptionDescription));
333 for (i=0; i<namesNo; i++)
335 if (bFirst) bFirst = FALSE;
337 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], szComma);
339 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], bstrParamNames[i]);
340 SysFreeString(bstrParamNames[i]);
343 memset(pExcepInfo, 0, sizeof(EXCEPINFO));
344 pExcepInfo->wCode = 1000;
345 pExcepInfo->bstrSource = szExceptionSource;
346 pExcepInfo->bstrDescription = szExceptionDescription;
347 hr = DISP_E_EXCEPTION;
351 /* Make sure we free the return variant if it is our dummy variant */
352 if (pVarResult == &varResultDummy) VariantClear(pVarResult);
354 /* Free function name if we retrieved it */
355 if (bstrName) SysFreeString(bstrName);
357 TRACE("Returning 0x%08x, %s\n", hr, SUCCEEDED(hr) ? "ok" : "not ok");
362 static const struct IDispatchVtbl AutomationObject_Vtbl =
364 AutomationObject_QueryInterface,
365 AutomationObject_AddRef,
366 AutomationObject_Release,
367 AutomationObject_GetTypeInfoCount,
368 AutomationObject_GetTypeInfo,
369 AutomationObject_GetIDsOfNames,
370 AutomationObject_Invoke
374 * IProvideMultipleClassInfo methods
377 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_QueryInterface(
378 IProvideMultipleClassInfo* iface,
382 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
383 return AutomationObject_QueryInterface((IDispatch *)This, riid, ppvoid);
386 static ULONG WINAPI AutomationObject_IProvideMultipleClassInfo_AddRef(IProvideMultipleClassInfo* iface)
388 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
389 return AutomationObject_AddRef((IDispatch *)This);
392 static ULONG WINAPI AutomationObject_IProvideMultipleClassInfo_Release(IProvideMultipleClassInfo* iface)
394 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
395 return AutomationObject_Release((IDispatch *)This);
398 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_GetClassInfo(IProvideMultipleClassInfo* iface, ITypeInfo** ppTI)
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);
405 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_GetGUID(IProvideMultipleClassInfo* iface, DWORD dwGuidKind, GUID* pGUID)
407 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
408 TRACE("(%p/%p)->(%d,%s)\n", iface, This, dwGuidKind, debugstr_guid(pGUID));
410 if (dwGuidKind != GUIDKIND_DEFAULT_SOURCE_DISP_IID)
413 *pGUID = *This->clsid;
418 static HRESULT WINAPI AutomationObject_GetMultiTypeInfoCount(IProvideMultipleClassInfo* iface, ULONG* pcti)
420 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
422 TRACE("(%p/%p)->(%p)\n", iface, This, pcti);
427 static HRESULT WINAPI AutomationObject_GetInfoOfIndex(IProvideMultipleClassInfo* iface,
430 ITypeInfo** pptiCoClass,
432 ULONG* pcdispidReserved,
436 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
438 TRACE("(%p/%p)->(%d,%d,%p,%p,%p,%p,%p)\n", iface, This, iti, dwFlags, pptiCoClass, pdwTIFlags, pcdispidReserved, piidPrimary, piidSource);
443 if (dwFlags & MULTICLASSINFO_GETTYPEINFO)
444 load_type_info((IDispatch *)This, pptiCoClass, This->clsid, 0);
446 if (dwFlags & MULTICLASSINFO_GETNUMRESERVEDDISPIDS)
449 *pcdispidReserved = 0;
452 if (dwFlags & MULTICLASSINFO_GETIIDPRIMARY){
453 *piidPrimary = *This->clsid;
456 if (dwFlags & MULTICLASSINFO_GETIIDSOURCE){
457 *piidSource = *This->clsid;
463 static const IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl =
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
475 * Individual Object Invocation Functions
478 static HRESULT WINAPI RecordImpl_Invoke(
479 AutomationObject* This,
484 DISPPARAMS* pDispParams,
486 EXCEPINFO* pExcepInfo,
492 VARIANTARG varg0, varg1;
498 switch (dispIdMember)
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)
509 szString = msi_alloc((++dwLen)*sizeof(WCHAR));
512 if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
513 V_BSTR(pVarResult) = SysAllocString(szString);
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)
526 ERR("MsiRecordSetString returned %d\n", ret);
527 return DISP_E_EXCEPTION;
533 return DISP_E_MEMBERNOTFOUND;
539 static HRESULT WINAPI ViewImpl_Invoke(
540 AutomationObject* This,
545 DISPPARAMS* pDispParams,
547 EXCEPINFO* pExcepInfo,
551 IDispatch *pDispatch = NULL;
553 VARIANTARG varg0, varg1;
559 switch (dispIdMember)
561 case DISPID_VIEW_EXECUTE:
562 if (wFlags & DISPATCH_METHOD)
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);
568 MsiViewExecute(This->msiHandle, 0);
572 case DISPID_VIEW_FETCH:
573 if (wFlags & DISPATCH_METHOD)
575 V_VT(pVarResult) = VT_DISPATCH;
576 if ((ret = MsiViewFetch(This->msiHandle, &msiHandle)) == ERROR_SUCCESS)
578 if (SUCCEEDED(create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Record, RecordImpl_Invoke)))
580 IDispatch_AddRef(pDispatch);
581 V_DISPATCH(pVarResult) = pDispatch;
584 else if (ret == ERROR_NO_MORE_ITEMS)
585 V_DISPATCH(pVarResult) = NULL;
588 ERR("MsiViewFetch returned %d\n", ret);
589 return DISP_E_EXCEPTION;
594 case DISPID_VIEW_CLOSE:
595 if (wFlags & DISPATCH_METHOD)
597 MsiViewClose(This->msiHandle);
602 return DISP_E_MEMBERNOTFOUND;
608 static HRESULT WINAPI DatabaseImpl_Invoke(
609 AutomationObject* This,
614 DISPPARAMS* pDispParams,
616 EXCEPINFO* pExcepInfo,
620 IDispatch *pDispatch = NULL;
622 VARIANTARG varg0, varg1;
628 switch (dispIdMember)
630 case DISPID_DATABASE_OPENVIEW:
631 if (wFlags & DISPATCH_METHOD)
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)
638 if (SUCCEEDED(create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_View, ViewImpl_Invoke)))
640 IDispatch_AddRef(pDispatch);
641 V_DISPATCH(pVarResult) = pDispatch;
646 ERR("MsiDatabaseOpenView returned %d\n", ret);
647 return DISP_E_EXCEPTION;
653 return DISP_E_MEMBERNOTFOUND;
659 static HRESULT WINAPI SessionImpl_Invoke(
660 AutomationObject* This,
665 DISPPARAMS* pDispParams,
667 EXCEPINFO* pExcepInfo,
672 IDispatch *pDispatch = NULL;
676 INSTALLSTATE iInstalled, iAction;
677 VARIANTARG varg0, varg1;
683 switch (dispIdMember)
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)
694 szString = msi_alloc((++dwLen)*sizeof(WCHAR));
697 if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
698 V_BSTR(pVarResult) = SysAllocString(szString);
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);
709 VariantClear(&varg0);
712 if ((ret = MsiSetPropertyW(This->msiHandle, V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
714 ERR("MsiSetProperty returned %d\n", ret);
715 return DISP_E_EXCEPTION;
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;
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)
741 ERR("MsiSetMode returned %d\n", ret);
742 return DISP_E_EXCEPTION;
747 case DISPID_SESSION_DATABASE:
748 if (wFlags & DISPATCH_PROPERTYGET) {
749 V_VT(pVarResult) = VT_DISPATCH;
750 if ((msiHandle = MsiGetActiveDatabase(This->msiHandle)))
752 if (SUCCEEDED(create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Database, DatabaseImpl_Invoke)))
754 IDispatch_AddRef(pDispatch);
755 V_DISPATCH(pVarResult) = pDispatch;
760 ERR("MsiGetActiveDatabase failed\n");
761 return DISP_E_EXCEPTION;
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;
774 case ERROR_FUNCTION_NOT_CALLED:
775 V_I4(pVarResult) = msiDoActionStatusNoAction;
778 V_I4(pVarResult) = msiDoActionStatusSuccess;
780 case ERROR_INSTALL_USEREXIT:
781 V_I4(pVarResult) = msiDoActionStatusUserExit;
783 case ERROR_INSTALL_FAILURE:
784 V_I4(pVarResult) = msiDoActionStatusFailure;
786 case ERROR_INSTALL_SUSPEND:
787 V_I4(pVarResult) = msiDoActionStatusSuspend;
789 case ERROR_MORE_DATA:
790 V_I4(pVarResult) = msiDoActionStatusFinished;
792 case ERROR_INVALID_HANDLE_STATE:
793 V_I4(pVarResult) = msiDoActionStatusWrongState;
795 case ERROR_INVALID_DATA:
796 V_I4(pVarResult) = msiDoActionStatusBadActionData;
799 FIXME("MsiDoAction returned unhandled value %d\n", ret);
800 return DISP_E_EXCEPTION;
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)
810 ERR("MsiSetInstallLevel returned %d\n", ret);
811 return DISP_E_EXCEPTION;
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;
824 ERR("MsiGetFeatureState returned %d\n", ret);
825 V_I4(pVarResult) = msiInstallStateUnknown;
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;
839 ERR("MsiGetFeatureState returned %d\n", ret);
840 V_I4(pVarResult) = msiInstallStateUnknown;
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);
847 VariantClear(&varg0);
850 if ((ret = MsiSetFeatureStateW(This->msiHandle, V_BSTR(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
852 ERR("MsiSetFeatureState returned %d\n", ret);
853 return DISP_E_EXCEPTION;
859 return DISP_E_MEMBERNOTFOUND;