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
,
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
);
82 * Structures for additional data required by specific automation objects
91 /* The parent Installer object */
92 IDispatch
*pInstaller
;
96 static const struct IDispatchVtbl AutomationObject_Vtbl
;
97 static const struct IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl
;
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
)
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'};
107 TRACE("(%p)->(%s,%d)\n", iface
, debugstr_guid(clsid
), lcid
);
109 /* Load registered type library */
110 hr
= LoadRegTypeLib(&LIBID_WindowsInstaller
, 1, 0, lcid
, &pLib
);
112 hr
= LoadTypeLib(szMsiServer
, &pLib
);
114 ERR("Could not load msiserver.tlb\n");
119 /* Get type information for object */
120 hr
= ITypeLib_GetTypeInfoOfGuid(pLib
, clsid
, &pInfo
);
121 ITypeLib_Release(pLib
);
123 ERR("Could not load ITypeInfo for %s\n", debugstr_guid(clsid
));
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
)
138 AutomationObject
*object
;
141 TRACE("(%ld,%p,%p,%s,%p,%p,%ld)\n", (unsigned long)msiHandle
, pUnkOuter
, ppObj
, debugstr_guid(clsid
), funcInvoke
, funcFree
, sizetPrivateData
);
144 return CLASS_E_NOAGGREGATION
;
146 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(AutomationObject
)+sizetPrivateData
);
148 /* Set all the VTable references */
149 object
->lpVtbl
= &AutomationObject_Vtbl
;
150 object
->lpvtblIProvideMultipleClassInfo
= &AutomationObject_IProvideMultipleClassInfo_Vtbl
;
153 /* Store data that was passed */
154 object
->msiHandle
= msiHandle
;
155 object
->clsid
= (LPCLSID
)clsid
;
156 object
->funcInvoke
= funcInvoke
;
157 object
->funcFree
= funcFree
;
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);
163 HeapFree(GetProcessHeap(), 0, object
);
172 /* Macros to get pointer to AutomationObject from the other VTables. */
173 static inline AutomationObject
*obj_from_IProvideMultipleClassInfo( IProvideMultipleClassInfo
*iface
)
175 return (AutomationObject
*)((char*)iface
- FIELD_OFFSET(AutomationObject
, lpvtblIProvideMultipleClassInfo
));
178 /* Macro to get pointer to private object data */
179 static inline void *private_data( AutomationObject
*This
)
185 * AutomationObject methods
188 /*** IUnknown methods ***/
189 static HRESULT WINAPI
AutomationObject_QueryInterface(IDispatch
* iface
, REFIID riid
, void** ppvObject
)
191 AutomationObject
*This
= (AutomationObject
*)iface
;
193 TRACE("(%p/%p)->(%s,%p)\n", iface
, This
, debugstr_guid(riid
), ppvObject
);
195 if (ppvObject
== NULL
)
200 if (IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_IDispatch
) || IsEqualGUID(riid
, This
->clsid
))
202 else if (IsEqualGUID(riid
, &IID_IProvideClassInfo
) ||
203 IsEqualGUID(riid
, &IID_IProvideClassInfo2
) ||
204 IsEqualGUID(riid
, &IID_IProvideMultipleClassInfo
))
205 *ppvObject
= &This
->lpvtblIProvideMultipleClassInfo
;
208 TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid
));
209 return E_NOINTERFACE
;
213 * Query Interface always increases the reference count by one when it is
216 IClassFactory_AddRef(iface
);
221 static ULONG WINAPI
AutomationObject_AddRef(IDispatch
* iface
)
223 AutomationObject
*This
= (AutomationObject
*)iface
;
225 TRACE("(%p/%p)\n", iface
, This
);
227 return InterlockedIncrement(&This
->ref
);
230 static ULONG WINAPI
AutomationObject_Release(IDispatch
* iface
)
232 AutomationObject
*This
= (AutomationObject
*)iface
;
233 ULONG ref
= InterlockedDecrement(&This
->ref
);
235 TRACE("(%p/%p)\n", iface
, This
);
239 if (This
->funcFree
) This
->funcFree(This
);
240 MsiCloseHandle(This
->msiHandle
);
241 HeapFree(GetProcessHeap(), 0, This
);
247 /*** IDispatch methods ***/
248 static HRESULT WINAPI
AutomationObject_GetTypeInfoCount(
252 AutomationObject
*This
= (AutomationObject
*)iface
;
254 TRACE("(%p/%p)->(%p)\n", iface
, This
, pctinfo
);
259 static HRESULT WINAPI
AutomationObject_GetTypeInfo(
265 AutomationObject
*This
= (AutomationObject
*)iface
;
266 TRACE("(%p/%p)->(%d,%d,%p)\n", iface
, This
, iTInfo
, lcid
, ppTInfo
);
268 ITypeInfo_AddRef(This
->iTypeInfo
);
269 *ppTInfo
= This
->iTypeInfo
;
273 static HRESULT WINAPI
AutomationObject_GetIDsOfNames(
281 AutomationObject
*This
= (AutomationObject
*)iface
;
283 TRACE("(%p/%p)->(%p,%p,%d,%d,%p)\n", iface
, This
, riid
, rgszNames
, cNames
, lcid
, rgDispId
);
285 if (!IsEqualGUID(riid
, &IID_NULL
)) return E_INVALIDARG
;
286 hr
= ITypeInfo_GetIDsOfNames(This
->iTypeInfo
, rgszNames
, cNames
, rgDispId
);
287 if (hr
== DISP_E_UNKNOWNNAME
)
290 for (idx
=0; idx
<cNames
; idx
++)
292 if (rgDispId
[idx
] == DISPID_UNKNOWN
)
293 FIXME("Unknown member %s, clsid %s\n", debugstr_w(rgszNames
[idx
]), debugstr_guid(This
->clsid
));
299 /* Maximum number of allowed function parameters+1 */
300 #define MAX_FUNC_PARAMS 20
302 /* Some error checking is done here to simplify individual object function invocation */
303 static HRESULT WINAPI
AutomationObject_Invoke(
309 DISPPARAMS
* pDispParams
,
311 EXCEPINFO
* pExcepInfo
,
314 AutomationObject
*This
= (AutomationObject
*)iface
;
316 unsigned int uArgErr
;
317 VARIANT varResultDummy
;
318 BSTR bstrName
= NULL
;
320 TRACE("(%p/%p)->(%d,%p,%d,%d,%p,%p,%p,%p)\n", iface
, This
, dispIdMember
, riid
, lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
322 if (!IsEqualIID(riid
, &IID_NULL
))
324 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid
));
325 return DISP_E_UNKNOWNNAME
;
328 if (wFlags
& DISPATCH_PROPERTYGET
&& !pVarResult
)
330 ERR("NULL pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
331 return DISP_E_PARAMNOTOPTIONAL
;
334 /* This simplifies our individual object invocation functions */
335 if (puArgErr
== NULL
) puArgErr
= &uArgErr
;
336 if (pVarResult
== NULL
) pVarResult
= &varResultDummy
;
338 /* Assume return type is void unless determined otherwise */
339 VariantInit(pVarResult
);
341 /* If we are tracing, we want to see the name of the member we are invoking */
344 ITypeInfo_GetDocumentation(This
->iTypeInfo
, dispIdMember
, &bstrName
, NULL
, NULL
, NULL
);
345 TRACE("Method %d, %s\n", dispIdMember
, debugstr_w(bstrName
));
348 hr
= This
->funcInvoke(This
,dispIdMember
,riid
,lcid
,wFlags
,pDispParams
,pVarResult
,pExcepInfo
,puArgErr
);
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
));
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
];
364 if (FAILED(ITypeInfo_GetNames(This
->iTypeInfo
, dispIdMember
, bstrParamNames
,
365 MAX_FUNC_PARAMS
, &namesNo
)))
367 TRACE("Failed to retrieve names for dispIdMember %d\n", dispIdMember
);
371 memset(szExceptionDescription
, 0, sizeof(szExceptionDescription
));
372 for (i
=0; i
<namesNo
; i
++)
374 if (bFirst
) bFirst
= FALSE
;
376 lstrcpyW(&szExceptionDescription
[lstrlenW(szExceptionDescription
)], szComma
);
378 lstrcpyW(&szExceptionDescription
[lstrlenW(szExceptionDescription
)], bstrParamNames
[i
]);
379 SysFreeString(bstrParamNames
[i
]);
382 memset(pExcepInfo
, 0, sizeof(EXCEPINFO
));
383 pExcepInfo
->wCode
= 1000;
384 pExcepInfo
->bstrSource
= szExceptionSource
;
385 pExcepInfo
->bstrDescription
= szExceptionDescription
;
386 hr
= DISP_E_EXCEPTION
;
390 /* Make sure we free the return variant if it is our dummy variant */
391 if (pVarResult
== &varResultDummy
) VariantClear(pVarResult
);
393 /* Free function name if we retrieved it */
394 if (bstrName
) SysFreeString(bstrName
);
396 TRACE("Returning 0x%08x, %s\n", hr
, SUCCEEDED(hr
) ? "ok" : "not ok");
401 static const struct IDispatchVtbl AutomationObject_Vtbl
=
403 AutomationObject_QueryInterface
,
404 AutomationObject_AddRef
,
405 AutomationObject_Release
,
406 AutomationObject_GetTypeInfoCount
,
407 AutomationObject_GetTypeInfo
,
408 AutomationObject_GetIDsOfNames
,
409 AutomationObject_Invoke
413 * IProvideMultipleClassInfo methods
416 static HRESULT WINAPI
AutomationObject_IProvideMultipleClassInfo_QueryInterface(
417 IProvideMultipleClassInfo
* iface
,
421 AutomationObject
*This
= obj_from_IProvideMultipleClassInfo(iface
);
422 return AutomationObject_QueryInterface((IDispatch
*)This
, riid
, ppvoid
);
425 static ULONG WINAPI
AutomationObject_IProvideMultipleClassInfo_AddRef(IProvideMultipleClassInfo
* iface
)
427 AutomationObject
*This
= obj_from_IProvideMultipleClassInfo(iface
);
428 return AutomationObject_AddRef((IDispatch
*)This
);
431 static ULONG WINAPI
AutomationObject_IProvideMultipleClassInfo_Release(IProvideMultipleClassInfo
* iface
)
433 AutomationObject
*This
= obj_from_IProvideMultipleClassInfo(iface
);
434 return AutomationObject_Release((IDispatch
*)This
);
437 static HRESULT WINAPI
AutomationObject_IProvideMultipleClassInfo_GetClassInfo(IProvideMultipleClassInfo
* iface
, ITypeInfo
** ppTI
)
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);
444 static HRESULT WINAPI
AutomationObject_IProvideMultipleClassInfo_GetGUID(IProvideMultipleClassInfo
* iface
, DWORD dwGuidKind
, GUID
* pGUID
)
446 AutomationObject
*This
= obj_from_IProvideMultipleClassInfo(iface
);
447 TRACE("(%p/%p)->(%d,%s)\n", iface
, This
, dwGuidKind
, debugstr_guid(pGUID
));
449 if (dwGuidKind
!= GUIDKIND_DEFAULT_SOURCE_DISP_IID
)
452 *pGUID
= *This
->clsid
;
457 static HRESULT WINAPI
AutomationObject_GetMultiTypeInfoCount(IProvideMultipleClassInfo
* iface
, ULONG
* pcti
)
459 AutomationObject
*This
= obj_from_IProvideMultipleClassInfo(iface
);
461 TRACE("(%p/%p)->(%p)\n", iface
, This
, pcti
);
466 static HRESULT WINAPI
AutomationObject_GetInfoOfIndex(IProvideMultipleClassInfo
* iface
,
469 ITypeInfo
** pptiCoClass
,
471 ULONG
* pcdispidReserved
,
475 AutomationObject
*This
= obj_from_IProvideMultipleClassInfo(iface
);
477 TRACE("(%p/%p)->(%d,%d,%p,%p,%p,%p,%p)\n", iface
, This
, iti
, dwFlags
, pptiCoClass
, pdwTIFlags
, pcdispidReserved
, piidPrimary
, piidSource
);
482 if (dwFlags
& MULTICLASSINFO_GETTYPEINFO
)
483 load_type_info((IDispatch
*)This
, pptiCoClass
, This
->clsid
, 0);
485 if (dwFlags
& MULTICLASSINFO_GETNUMRESERVEDDISPIDS
)
488 *pcdispidReserved
= 0;
491 if (dwFlags
& MULTICLASSINFO_GETIIDPRIMARY
){
492 *piidPrimary
= *This
->clsid
;
495 if (dwFlags
& MULTICLASSINFO_GETIIDSOURCE
){
496 *piidSource
= *This
->clsid
;
502 static const IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl
=
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
514 * Individual Object Invocation Functions
517 static HRESULT WINAPI
RecordImpl_Invoke(
518 AutomationObject
* This
,
523 DISPPARAMS
* pDispParams
,
525 EXCEPINFO
* pExcepInfo
,
531 VARIANTARG varg0
, varg1
;
537 switch (dispIdMember
)
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
)
548 szString
= msi_alloc((++dwLen
)*sizeof(WCHAR
));
551 if ((ret
= MsiRecordGetStringW(This
->msiHandle
, V_I4(&varg0
), szString
, &dwLen
)) == ERROR_SUCCESS
)
552 V_BSTR(pVarResult
) = SysAllocString(szString
);
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
)
565 VariantClear(&varg1
);
566 ERR("MsiRecordSetString returned %d\n", ret
);
567 return DISP_E_EXCEPTION
;
573 return DISP_E_MEMBERNOTFOUND
;
576 VariantClear(&varg1
);
577 VariantClear(&varg0
);
582 static HRESULT WINAPI
StringListImpl_Invoke(
583 AutomationObject
* This
,
588 DISPPARAMS
* pDispParams
,
590 EXCEPINFO
* pExcepInfo
,
593 StringListData
*data
= (StringListData
*)private_data(This
);
599 switch (dispIdMember
)
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
)]);
612 case DISPID_STRINGLIST_COUNT
:
613 if (wFlags
& DISPATCH_PROPERTYGET
) {
614 V_VT(pVarResult
) = VT_I4
;
615 V_I4(pVarResult
) = data
->iCount
;
620 return DISP_E_MEMBERNOTFOUND
;
623 VariantClear(&varg0
);
628 static void WINAPI
StringListImpl_Free(AutomationObject
*This
)
630 StringListData
*data
= private_data(This
);
633 for (idx
=0; idx
<data
->iCount
; idx
++)
634 SysFreeString(data
->pszStrings
[idx
]);
635 HeapFree(GetProcessHeap(), 0, data
->pszStrings
);
638 static HRESULT WINAPI
ViewImpl_Invoke(
639 AutomationObject
* This
,
644 DISPPARAMS
* pDispParams
,
646 EXCEPINFO
* pExcepInfo
,
650 IDispatch
*pDispatch
= NULL
;
652 VARIANTARG varg0
, varg1
;
658 switch (dispIdMember
)
660 case DISPID_VIEW_EXECUTE
:
661 if (wFlags
& DISPATCH_METHOD
)
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
);
667 MsiViewExecute(This
->msiHandle
, 0);
671 case DISPID_VIEW_FETCH
:
672 if (wFlags
& DISPATCH_METHOD
)
674 V_VT(pVarResult
) = VT_DISPATCH
;
675 if ((ret
= MsiViewFetch(This
->msiHandle
, &msiHandle
)) == ERROR_SUCCESS
)
677 if (SUCCEEDED(hr
= create_automation_object(msiHandle
, NULL
, (LPVOID
*)&pDispatch
, &DIID_Record
, RecordImpl_Invoke
, NULL
, 0)))
679 IDispatch_AddRef(pDispatch
);
680 V_DISPATCH(pVarResult
) = pDispatch
;
683 ERR("Failed to create Record object, hresult 0x%08x\n", hr
);
685 else if (ret
== ERROR_NO_MORE_ITEMS
)
686 V_DISPATCH(pVarResult
) = NULL
;
689 ERR("MsiViewFetch returned %d\n", ret
);
690 return DISP_E_EXCEPTION
;
695 case DISPID_VIEW_CLOSE
:
696 if (wFlags
& DISPATCH_METHOD
)
698 MsiViewClose(This
->msiHandle
);
703 return DISP_E_MEMBERNOTFOUND
;
706 VariantClear(&varg1
);
707 VariantClear(&varg0
);
712 static HRESULT WINAPI
DatabaseImpl_Invoke(
713 AutomationObject
* This
,
718 DISPPARAMS
* pDispParams
,
720 EXCEPINFO
* pExcepInfo
,
724 IDispatch
*pDispatch
= NULL
;
726 VARIANTARG varg0
, varg1
;
732 switch (dispIdMember
)
734 case DISPID_DATABASE_OPENVIEW
:
735 if (wFlags
& DISPATCH_METHOD
)
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
)
742 if (SUCCEEDED(hr
= create_automation_object(msiHandle
, NULL
, (LPVOID
*)&pDispatch
, &DIID_View
, ViewImpl_Invoke
, NULL
, 0)))
744 IDispatch_AddRef(pDispatch
);
745 V_DISPATCH(pVarResult
) = pDispatch
;
748 ERR("Failed to create View object, hresult 0x%08x\n", hr
);
752 VariantClear(&varg0
);
753 ERR("MsiDatabaseOpenView returned %d\n", ret
);
754 return DISP_E_EXCEPTION
;
760 return DISP_E_MEMBERNOTFOUND
;
763 VariantClear(&varg1
);
764 VariantClear(&varg0
);
769 static HRESULT WINAPI
SessionImpl_Invoke(
770 AutomationObject
* This
,
775 DISPPARAMS
* pDispParams
,
777 EXCEPINFO
* pExcepInfo
,
780 SessionData
*data
= private_data(This
);
783 IDispatch
*pDispatch
= NULL
;
787 INSTALLSTATE iInstalled
, iAction
;
788 VARIANTARG varg0
, varg1
;
794 switch (dispIdMember
)
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
;
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
)
813 szString
= msi_alloc((++dwLen
)*sizeof(WCHAR
));
816 if ((ret
= MsiGetPropertyW(This
->msiHandle
, V_BSTR(&varg0
), szString
, &dwLen
)) == ERROR_SUCCESS
)
817 V_BSTR(pVarResult
) = SysAllocString(szString
);
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
);
828 VariantClear(&varg0
);
831 if ((ret
= MsiSetPropertyW(This
->msiHandle
, V_BSTR(&varg0
), V_BSTR(&varg1
))) != ERROR_SUCCESS
)
833 VariantClear(&varg0
);
834 VariantClear(&varg1
);
835 ERR("MsiSetProperty returned %d\n", ret
);
836 return DISP_E_EXCEPTION
;
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
;
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
)
862 ERR("MsiSetMode returned %d\n", ret
);
863 return DISP_E_EXCEPTION
;
868 case DISPID_SESSION_DATABASE
:
869 if (wFlags
& DISPATCH_PROPERTYGET
) {
870 V_VT(pVarResult
) = VT_DISPATCH
;
871 if ((msiHandle
= MsiGetActiveDatabase(This
->msiHandle
)))
873 if (SUCCEEDED(hr
= create_automation_object(msiHandle
, NULL
, (LPVOID
*)&pDispatch
, &DIID_Database
, DatabaseImpl_Invoke
, NULL
, 0)))
875 IDispatch_AddRef(pDispatch
);
876 V_DISPATCH(pVarResult
) = pDispatch
;
879 ERR("Failed to create Database object, hresult 0x%08x\n", hr
);
883 ERR("MsiGetActiveDatabase failed\n");
884 return DISP_E_EXCEPTION
;
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
;
897 case ERROR_FUNCTION_NOT_CALLED
:
898 V_I4(pVarResult
) = msiDoActionStatusNoAction
;
901 V_I4(pVarResult
) = msiDoActionStatusSuccess
;
903 case ERROR_INSTALL_USEREXIT
:
904 V_I4(pVarResult
) = msiDoActionStatusUserExit
;
906 case ERROR_INSTALL_FAILURE
:
907 V_I4(pVarResult
) = msiDoActionStatusFailure
;
909 case ERROR_INSTALL_SUSPEND
:
910 V_I4(pVarResult
) = msiDoActionStatusSuspend
;
912 case ERROR_MORE_DATA
:
913 V_I4(pVarResult
) = msiDoActionStatusFinished
;
915 case ERROR_INVALID_HANDLE_STATE
:
916 V_I4(pVarResult
) = msiDoActionStatusWrongState
;
918 case ERROR_INVALID_DATA
:
919 V_I4(pVarResult
) = msiDoActionStatusBadActionData
;
922 VariantClear(&varg0
);
923 FIXME("MsiDoAction returned unhandled value %d\n", ret
);
924 return DISP_E_EXCEPTION
;
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
)
934 ERR("MsiSetInstallLevel returned %d\n", ret
);
935 return DISP_E_EXCEPTION
;
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
;
948 ERR("MsiGetFeatureState returned %d\n", ret
);
949 V_I4(pVarResult
) = msiInstallStateUnknown
;
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
;
963 ERR("MsiGetFeatureState returned %d\n", ret
);
964 V_I4(pVarResult
) = msiInstallStateUnknown
;
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
);
971 VariantClear(&varg0
);
974 if ((ret
= MsiSetFeatureStateW(This
->msiHandle
, V_BSTR(&varg0
), V_I4(&varg1
))) != ERROR_SUCCESS
)
976 VariantClear(&varg0
);
977 ERR("MsiSetFeatureState returned %d\n", ret
);
978 return DISP_E_EXCEPTION
;
984 return DISP_E_MEMBERNOTFOUND
;
987 VariantClear(&varg1
);
988 VariantClear(&varg0
);
993 static HRESULT WINAPI
InstallerImpl_Invoke(
994 AutomationObject
* This
,
999 DISPPARAMS
* pDispParams
,
1000 VARIANT
* pVarResult
,
1001 EXCEPINFO
* pExcepInfo
,
1004 MSIHANDLE msiHandle
;
1005 IDispatch
*pDispatch
= NULL
;
1007 VARIANTARG varg0
, varg1
;
1010 VariantInit(&varg0
);
1011 VariantInit(&varg1
);
1013 switch (dispIdMember
)
1015 case DISPID_INSTALLER_OPENPACKAGE
:
1016 if (wFlags
& DISPATCH_METHOD
)
1018 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1019 if (FAILED(hr
)) return hr
;
1020 hr
= DispGetParam(pDispParams
, 1, VT_I4
, &varg1
, puArgErr
);
1023 VariantClear(&varg0
);
1026 V_VT(pVarResult
) = VT_DISPATCH
;
1027 if ((ret
= MsiOpenPackageExW(V_BSTR(&varg0
), V_I4(&varg1
), &msiHandle
)) == ERROR_SUCCESS
)
1029 if (SUCCEEDED(create_session(msiHandle
, (IDispatch
*)This
, &pDispatch
)))
1031 IDispatch_AddRef(pDispatch
);
1032 V_DISPATCH(pVarResult
) = pDispatch
;
1037 VariantClear(&varg0
);
1038 ERR("MsiOpenPackageEx returned %d\n", ret
);
1039 return DISP_E_EXCEPTION
;
1044 case DISPID_INSTALLER_PRODUCTSTATE
:
1045 if (wFlags
& DISPATCH_PROPERTYGET
) {
1046 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1047 if (FAILED(hr
)) return hr
;
1048 V_VT(pVarResult
) = VT_I4
;
1049 V_I4(pVarResult
) = MsiQueryProductStateW(V_BSTR(&varg0
));
1053 case DISPID_INSTALLER_PRODUCTS
:
1054 if (wFlags
& DISPATCH_PROPERTYGET
)
1056 StringListData
*sldata
= NULL
;
1058 WCHAR szProductBuf
[GUID_SIZE
];
1060 /* Find number of products */
1062 ret
= MsiEnumProductsW(idx
, szProductBuf
);
1063 if (ret
== ERROR_SUCCESS
) idx
++;
1064 } while (ret
== ERROR_SUCCESS
&& ret
!= ERROR_NO_MORE_ITEMS
);
1066 if (ret
!= ERROR_SUCCESS
&& ret
!= ERROR_NO_MORE_ITEMS
)
1068 ERR("MsiEnumProducts returned %d\n", ret
);
1069 return DISP_E_EXCEPTION
;
1072 V_VT(pVarResult
) = VT_DISPATCH
;
1073 if (SUCCEEDED(hr
= create_automation_object(0, NULL
, (LPVOID
*)&pDispatch
, &DIID_StringList
, StringListImpl_Invoke
, StringListImpl_Free
, sizeof(StringListData
))))
1075 IDispatch_AddRef(pDispatch
);
1076 V_DISPATCH(pVarResult
) = pDispatch
;
1078 /* Save product strings */
1079 sldata
= (StringListData
*)private_data((AutomationObject
*)pDispatch
);
1080 sldata
->iCount
= idx
;
1081 sldata
->pszStrings
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(LPWSTR
)*sldata
->iCount
);
1082 for (idx
= 0; idx
< sldata
->iCount
; idx
++)
1084 ret
= MsiEnumProductsW(idx
, szProductBuf
);
1085 sldata
->pszStrings
[idx
] = SysAllocString(szProductBuf
);
1089 ERR("Failed to create StringList object, hresult 0x%08x\n", hr
);
1094 return DISP_E_MEMBERNOTFOUND
;
1097 VariantClear(&varg1
);
1098 VariantClear(&varg0
);
1103 /* Wrapper around create_automation_object to create an installer object. */
1104 HRESULT
create_msiserver(IUnknown
*pOuter
, LPVOID
*ppObj
)
1106 return create_automation_object(0, pOuter
, ppObj
, &DIID_Installer
, InstallerImpl_Invoke
, NULL
, 0);
1109 /* Wrapper around create_automation_object to create a session object. */
1110 HRESULT
create_session(MSIHANDLE msiHandle
, IDispatch
*pInstaller
, IDispatch
**pDispatch
)
1112 HRESULT hr
= create_automation_object(msiHandle
, NULL
, (LPVOID
)pDispatch
, &DIID_Session
, SessionImpl_Invoke
, NULL
, sizeof(SessionData
));
1113 if (SUCCEEDED(hr
) && pDispatch
&& *pDispatch
)
1114 ((SessionData
*)private_data((AutomationObject
*)*pDispatch
))->pInstaller
= pInstaller
;