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
33 #include "wine/debug.h"
34 #include "wine/unicode.h"
36 #include "msiserver.h"
37 #include "msiserver_dispids.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(msi
);
42 * AutomationObject - "base" class for all automation objects. For each interface, we implement Invoke function
43 * called from AutomationObject::Invoke, and pass this function to create_automation_object.
46 typedef interface AutomationObject AutomationObject
;
48 interface AutomationObject
{
50 * VTables - We provide IDispatch, IProvideClassInfo, IProvideClassInfo2, IProvideMultipleClassInfo
52 const IDispatchVtbl
*lpVtbl
;
53 const IProvideMultipleClassInfoVtbl
*lpvtblIProvideMultipleClassInfo
;
55 /* Object reference count */
58 /* Clsid for this class and it's appropriate ITypeInfo object */
62 /* The MSI handle of the current object */
65 /* A function that is called from AutomationObject::Invoke, specific to this type of object. */
66 HRESULT (STDMETHODCALLTYPE
*funcInvoke
)(
67 AutomationObject
* This
,
72 DISPPARAMS
* pDispParams
,
74 EXCEPINFO
* pExcepInfo
,
77 /* A function that is called from AutomationObject::Release when the object is being freed to free any private
78 * data structures (or NULL) */
79 void (STDMETHODCALLTYPE
*funcFree
)(AutomationObject
* This
);
83 * ListEnumerator - IEnumVARIANT implementation for MSI automation lists.
86 typedef interface ListEnumerator ListEnumerator
;
88 interface ListEnumerator
{
90 const IEnumVARIANTVtbl
*lpVtbl
;
92 /* Object reference count */
95 /* Current position and pointer to AutomationObject that stores actual data */
97 AutomationObject
*pObj
;
101 * Structures for additional data required by specific automation objects
110 /* The parent Installer object */
111 IDispatch
*pInstaller
;
115 static const struct IDispatchVtbl AutomationObject_Vtbl
;
116 static const struct IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl
;
117 static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl
;
119 /* Load type info so we don't have to process GetIDsOfNames */
120 HRESULT
load_type_info(IDispatch
*iface
, ITypeInfo
**pptinfo
, REFIID clsid
, LCID lcid
)
123 LPTYPELIB pLib
= NULL
;
124 LPTYPEINFO pInfo
= NULL
;
125 static const WCHAR szMsiServer
[] = {'m','s','i','s','e','r','v','e','r','.','t','l','b'};
127 TRACE("(%p)->(%s,%d)\n", iface
, debugstr_guid(clsid
), lcid
);
129 /* Load registered type library */
130 hr
= LoadRegTypeLib(&LIBID_WindowsInstaller
, 1, 0, lcid
, &pLib
);
132 hr
= LoadTypeLib(szMsiServer
, &pLib
);
134 ERR("Could not load msiserver.tlb\n");
139 /* Get type information for object */
140 hr
= ITypeLib_GetTypeInfoOfGuid(pLib
, clsid
, &pInfo
);
141 ITypeLib_Release(pLib
);
143 ERR("Could not load ITypeInfo for %s\n", debugstr_guid(clsid
));
150 /* Create the automation object, placing the result in the pointer ppObj. The automation object is created
151 * with the appropriate clsid and invocation function. */
152 HRESULT
create_automation_object(MSIHANDLE msiHandle
, IUnknown
*pUnkOuter
, LPVOID
*ppObj
, REFIID clsid
,
153 HRESULT (STDMETHODCALLTYPE
*funcInvoke
)(AutomationObject
*,DISPID
,REFIID
,LCID
,WORD
,DISPPARAMS
*,
154 VARIANT
*,EXCEPINFO
*,UINT
*),
155 void (STDMETHODCALLTYPE
*funcFree
)(AutomationObject
*),
156 SIZE_T sizetPrivateData
)
158 AutomationObject
*object
;
161 TRACE("(%ld,%p,%p,%s,%p,%p,%ld)\n", (unsigned long)msiHandle
, pUnkOuter
, ppObj
, debugstr_guid(clsid
), funcInvoke
, funcFree
, sizetPrivateData
);
164 return CLASS_E_NOAGGREGATION
;
166 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(AutomationObject
)+sizetPrivateData
);
168 /* Set all the VTable references */
169 object
->lpVtbl
= &AutomationObject_Vtbl
;
170 object
->lpvtblIProvideMultipleClassInfo
= &AutomationObject_IProvideMultipleClassInfo_Vtbl
;
173 /* Store data that was passed */
174 object
->msiHandle
= msiHandle
;
175 object
->clsid
= (LPCLSID
)clsid
;
176 object
->funcInvoke
= funcInvoke
;
177 object
->funcFree
= funcFree
;
179 /* Load our TypeInfo so we don't have to process GetIDsOfNames */
180 object
->iTypeInfo
= NULL
;
181 hr
= load_type_info((IDispatch
*)object
, &object
->iTypeInfo
, clsid
, 0x0);
183 HeapFree(GetProcessHeap(), 0, object
);
192 /* Create a list enumerator, placing the result in the pointer ppObj. */
193 HRESULT
create_list_enumerator(IUnknown
*pUnkOuter
, LPVOID
*ppObj
, AutomationObject
*pObj
, ULONG ulPos
)
195 ListEnumerator
*object
;
197 TRACE("(%p,%p,%p,%uld)\n", pUnkOuter
, ppObj
, pObj
, ulPos
);
200 return CLASS_E_NOAGGREGATION
;
202 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(ListEnumerator
));
204 /* Set all the VTable references */
205 object
->lpVtbl
= &ListEnumerator_Vtbl
;
208 /* Store data that was passed */
209 object
->ulPos
= ulPos
;
211 if (pObj
) IDispatch_AddRef((IDispatch
*)pObj
);
217 /* Macros to get pointer to AutomationObject from the other VTables. */
218 static inline AutomationObject
*obj_from_IProvideMultipleClassInfo( IProvideMultipleClassInfo
*iface
)
220 return (AutomationObject
*)((char*)iface
- FIELD_OFFSET(AutomationObject
, lpvtblIProvideMultipleClassInfo
));
223 /* Macro to get pointer to private object data */
224 static inline void *private_data( AutomationObject
*This
)
230 * AutomationObject methods
233 /*** IUnknown methods ***/
234 static HRESULT WINAPI
AutomationObject_QueryInterface(IDispatch
* iface
, REFIID riid
, void** ppvObject
)
236 AutomationObject
*This
= (AutomationObject
*)iface
;
238 TRACE("(%p/%p)->(%s,%p)\n", iface
, This
, debugstr_guid(riid
), ppvObject
);
240 if (ppvObject
== NULL
)
245 if (IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_IDispatch
) || IsEqualGUID(riid
, This
->clsid
))
247 else if (IsEqualGUID(riid
, &IID_IProvideClassInfo
) ||
248 IsEqualGUID(riid
, &IID_IProvideClassInfo2
) ||
249 IsEqualGUID(riid
, &IID_IProvideMultipleClassInfo
))
250 *ppvObject
= &This
->lpvtblIProvideMultipleClassInfo
;
253 TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid
));
254 return E_NOINTERFACE
;
258 * Query Interface always increases the reference count by one when it is
261 IClassFactory_AddRef(iface
);
266 static ULONG WINAPI
AutomationObject_AddRef(IDispatch
* iface
)
268 AutomationObject
*This
= (AutomationObject
*)iface
;
270 TRACE("(%p/%p)\n", iface
, This
);
272 return InterlockedIncrement(&This
->ref
);
275 static ULONG WINAPI
AutomationObject_Release(IDispatch
* iface
)
277 AutomationObject
*This
= (AutomationObject
*)iface
;
278 ULONG ref
= InterlockedDecrement(&This
->ref
);
280 TRACE("(%p/%p)\n", iface
, This
);
284 if (This
->funcFree
) This
->funcFree(This
);
285 ITypeInfo_Release(This
->iTypeInfo
);
286 MsiCloseHandle(This
->msiHandle
);
287 HeapFree(GetProcessHeap(), 0, This
);
293 /*** IDispatch methods ***/
294 static HRESULT WINAPI
AutomationObject_GetTypeInfoCount(
298 AutomationObject
*This
= (AutomationObject
*)iface
;
300 TRACE("(%p/%p)->(%p)\n", iface
, This
, pctinfo
);
305 static HRESULT WINAPI
AutomationObject_GetTypeInfo(
311 AutomationObject
*This
= (AutomationObject
*)iface
;
312 TRACE("(%p/%p)->(%d,%d,%p)\n", iface
, This
, iTInfo
, lcid
, ppTInfo
);
314 ITypeInfo_AddRef(This
->iTypeInfo
);
315 *ppTInfo
= This
->iTypeInfo
;
319 static HRESULT WINAPI
AutomationObject_GetIDsOfNames(
327 AutomationObject
*This
= (AutomationObject
*)iface
;
329 TRACE("(%p/%p)->(%p,%p,%d,%d,%p)\n", iface
, This
, riid
, rgszNames
, cNames
, lcid
, rgDispId
);
331 if (!IsEqualGUID(riid
, &IID_NULL
)) return E_INVALIDARG
;
332 hr
= ITypeInfo_GetIDsOfNames(This
->iTypeInfo
, rgszNames
, cNames
, rgDispId
);
333 if (hr
== DISP_E_UNKNOWNNAME
)
336 for (idx
=0; idx
<cNames
; idx
++)
338 if (rgDispId
[idx
] == DISPID_UNKNOWN
)
339 FIXME("Unknown member %s, clsid %s\n", debugstr_w(rgszNames
[idx
]), debugstr_guid(This
->clsid
));
345 /* Maximum number of allowed function parameters+1 */
346 #define MAX_FUNC_PARAMS 20
348 /* Some error checking is done here to simplify individual object function invocation */
349 static HRESULT WINAPI
AutomationObject_Invoke(
355 DISPPARAMS
* pDispParams
,
357 EXCEPINFO
* pExcepInfo
,
360 AutomationObject
*This
= (AutomationObject
*)iface
;
362 unsigned int uArgErr
;
363 VARIANT varResultDummy
;
364 BSTR bstrName
= NULL
;
366 TRACE("(%p/%p)->(%d,%p,%d,%d,%p,%p,%p,%p)\n", iface
, This
, dispIdMember
, riid
, lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
368 if (!IsEqualIID(riid
, &IID_NULL
))
370 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid
));
371 return DISP_E_UNKNOWNNAME
;
374 if (wFlags
& DISPATCH_PROPERTYGET
&& !pVarResult
)
376 ERR("NULL pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
377 return DISP_E_PARAMNOTOPTIONAL
;
380 /* This simplifies our individual object invocation functions */
381 if (puArgErr
== NULL
) puArgErr
= &uArgErr
;
382 if (pVarResult
== NULL
) pVarResult
= &varResultDummy
;
384 /* Assume return type is void unless determined otherwise */
385 VariantInit(pVarResult
);
387 /* If we are tracing, we want to see the name of the member we are invoking */
390 ITypeInfo_GetDocumentation(This
->iTypeInfo
, dispIdMember
, &bstrName
, NULL
, NULL
, NULL
);
391 TRACE("Method %d, %s\n", dispIdMember
, debugstr_w(bstrName
));
394 hr
= This
->funcInvoke(This
,dispIdMember
,riid
,lcid
,wFlags
,pDispParams
,pVarResult
,pExcepInfo
,puArgErr
);
396 if (hr
== DISP_E_MEMBERNOTFOUND
) {
397 if (bstrName
== NULL
) ITypeInfo_GetDocumentation(This
->iTypeInfo
, dispIdMember
, &bstrName
, NULL
, NULL
, NULL
);
398 FIXME("Method %d, %s wflags %d not implemented, clsid %s\n", dispIdMember
, debugstr_w(bstrName
), wFlags
, debugstr_guid(This
->clsid
));
400 else if (pExcepInfo
&&
401 (hr
== DISP_E_PARAMNOTFOUND
||
402 hr
== DISP_E_EXCEPTION
)) {
403 static const WCHAR szComma
[] = { ',',0 };
404 static WCHAR szExceptionSource
[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
405 WCHAR szExceptionDescription
[MAX_PATH
];
406 BSTR bstrParamNames
[MAX_FUNC_PARAMS
];
410 if (FAILED(ITypeInfo_GetNames(This
->iTypeInfo
, dispIdMember
, bstrParamNames
,
411 MAX_FUNC_PARAMS
, &namesNo
)))
413 TRACE("Failed to retrieve names for dispIdMember %d\n", dispIdMember
);
417 memset(szExceptionDescription
, 0, sizeof(szExceptionDescription
));
418 for (i
=0; i
<namesNo
; i
++)
420 if (bFirst
) bFirst
= FALSE
;
422 lstrcpyW(&szExceptionDescription
[lstrlenW(szExceptionDescription
)], szComma
);
424 lstrcpyW(&szExceptionDescription
[lstrlenW(szExceptionDescription
)], bstrParamNames
[i
]);
425 SysFreeString(bstrParamNames
[i
]);
428 memset(pExcepInfo
, 0, sizeof(EXCEPINFO
));
429 pExcepInfo
->wCode
= 1000;
430 pExcepInfo
->bstrSource
= SysAllocString(szExceptionSource
);
431 pExcepInfo
->bstrDescription
= SysAllocString(szExceptionDescription
);
432 hr
= DISP_E_EXCEPTION
;
436 /* Make sure we free the return variant if it is our dummy variant */
437 if (pVarResult
== &varResultDummy
) VariantClear(pVarResult
);
439 /* Free function name if we retrieved it */
440 if (bstrName
) SysFreeString(bstrName
);
442 TRACE("Returning 0x%08x, %s\n", hr
, SUCCEEDED(hr
) ? "ok" : "not ok");
447 static const struct IDispatchVtbl AutomationObject_Vtbl
=
449 AutomationObject_QueryInterface
,
450 AutomationObject_AddRef
,
451 AutomationObject_Release
,
452 AutomationObject_GetTypeInfoCount
,
453 AutomationObject_GetTypeInfo
,
454 AutomationObject_GetIDsOfNames
,
455 AutomationObject_Invoke
459 * IProvideMultipleClassInfo methods
462 static HRESULT WINAPI
AutomationObject_IProvideMultipleClassInfo_QueryInterface(
463 IProvideMultipleClassInfo
* iface
,
467 AutomationObject
*This
= obj_from_IProvideMultipleClassInfo(iface
);
468 return AutomationObject_QueryInterface((IDispatch
*)This
, riid
, ppvoid
);
471 static ULONG WINAPI
AutomationObject_IProvideMultipleClassInfo_AddRef(IProvideMultipleClassInfo
* iface
)
473 AutomationObject
*This
= obj_from_IProvideMultipleClassInfo(iface
);
474 return AutomationObject_AddRef((IDispatch
*)This
);
477 static ULONG WINAPI
AutomationObject_IProvideMultipleClassInfo_Release(IProvideMultipleClassInfo
* iface
)
479 AutomationObject
*This
= obj_from_IProvideMultipleClassInfo(iface
);
480 return AutomationObject_Release((IDispatch
*)This
);
483 static HRESULT WINAPI
AutomationObject_IProvideMultipleClassInfo_GetClassInfo(IProvideMultipleClassInfo
* iface
, ITypeInfo
** ppTI
)
485 AutomationObject
*This
= obj_from_IProvideMultipleClassInfo(iface
);
486 TRACE("(%p/%p)->(%p)\n", iface
, This
, ppTI
);
487 return load_type_info((IDispatch
*)This
, ppTI
, This
->clsid
, 0);
490 static HRESULT WINAPI
AutomationObject_IProvideMultipleClassInfo_GetGUID(IProvideMultipleClassInfo
* iface
, DWORD dwGuidKind
, GUID
* pGUID
)
492 AutomationObject
*This
= obj_from_IProvideMultipleClassInfo(iface
);
493 TRACE("(%p/%p)->(%d,%s)\n", iface
, This
, dwGuidKind
, debugstr_guid(pGUID
));
495 if (dwGuidKind
!= GUIDKIND_DEFAULT_SOURCE_DISP_IID
)
498 *pGUID
= *This
->clsid
;
503 static HRESULT WINAPI
AutomationObject_GetMultiTypeInfoCount(IProvideMultipleClassInfo
* iface
, ULONG
* pcti
)
505 AutomationObject
*This
= obj_from_IProvideMultipleClassInfo(iface
);
507 TRACE("(%p/%p)->(%p)\n", iface
, This
, pcti
);
512 static HRESULT WINAPI
AutomationObject_GetInfoOfIndex(IProvideMultipleClassInfo
* iface
,
515 ITypeInfo
** pptiCoClass
,
517 ULONG
* pcdispidReserved
,
521 AutomationObject
*This
= obj_from_IProvideMultipleClassInfo(iface
);
523 TRACE("(%p/%p)->(%d,%d,%p,%p,%p,%p,%p)\n", iface
, This
, iti
, dwFlags
, pptiCoClass
, pdwTIFlags
, pcdispidReserved
, piidPrimary
, piidSource
);
528 if (dwFlags
& MULTICLASSINFO_GETTYPEINFO
)
529 load_type_info((IDispatch
*)This
, pptiCoClass
, This
->clsid
, 0);
531 if (dwFlags
& MULTICLASSINFO_GETNUMRESERVEDDISPIDS
)
534 *pcdispidReserved
= 0;
537 if (dwFlags
& MULTICLASSINFO_GETIIDPRIMARY
){
538 *piidPrimary
= *This
->clsid
;
541 if (dwFlags
& MULTICLASSINFO_GETIIDSOURCE
){
542 *piidSource
= *This
->clsid
;
548 static const IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl
=
550 AutomationObject_IProvideMultipleClassInfo_QueryInterface
,
551 AutomationObject_IProvideMultipleClassInfo_AddRef
,
552 AutomationObject_IProvideMultipleClassInfo_Release
,
553 AutomationObject_IProvideMultipleClassInfo_GetClassInfo
,
554 AutomationObject_IProvideMultipleClassInfo_GetGUID
,
555 AutomationObject_GetMultiTypeInfoCount
,
556 AutomationObject_GetInfoOfIndex
560 * ListEnumerator methods
563 /*** IUnknown methods ***/
564 static HRESULT WINAPI
ListEnumerator_QueryInterface(IEnumVARIANT
* iface
, REFIID riid
, void** ppvObject
)
566 ListEnumerator
*This
= (ListEnumerator
*)iface
;
568 TRACE("(%p/%p)->(%s,%p)\n", iface
, This
, debugstr_guid(riid
), ppvObject
);
570 if (ppvObject
== NULL
)
575 if (IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_IEnumVARIANT
))
579 TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid
));
580 return E_NOINTERFACE
;
583 IClassFactory_AddRef(iface
);
587 static ULONG WINAPI
ListEnumerator_AddRef(IEnumVARIANT
* iface
)
589 ListEnumerator
*This
= (ListEnumerator
*)iface
;
591 TRACE("(%p/%p)\n", iface
, This
);
593 return InterlockedIncrement(&This
->ref
);
596 static ULONG WINAPI
ListEnumerator_Release(IEnumVARIANT
* iface
)
598 ListEnumerator
*This
= (ListEnumerator
*)iface
;
599 ULONG ref
= InterlockedDecrement(&This
->ref
);
601 TRACE("(%p/%p)\n", iface
, This
);
605 if (This
->pObj
) IDispatch_Release((IDispatch
*)This
->pObj
);
606 HeapFree(GetProcessHeap(), 0, This
);
612 /* IEnumVARIANT methods */
614 static HRESULT WINAPI
ListEnumerator_Next(IEnumVARIANT
* iface
, ULONG celt
, VARIANT
*rgVar
, ULONG
*pCeltFetched
)
616 ListEnumerator
*This
= (ListEnumerator
*)iface
;
617 ListData
*data
= (ListData
*)private_data(This
->pObj
);
620 TRACE("(%p,%uld,%p,%p)\n", iface
, celt
, rgVar
, pCeltFetched
);
622 if (pCeltFetched
!= NULL
)
628 for (local
= 0; local
< celt
; local
++)
629 VariantInit(&rgVar
[local
]);
631 for (idx
= This
->ulPos
, local
= 0; idx
< data
->ulCount
&& local
< celt
; idx
++, local
++)
632 VariantCopy(&rgVar
[local
], &data
->pVars
[idx
]);
634 if (pCeltFetched
!= NULL
)
635 *pCeltFetched
= local
;
638 return (local
< celt
) ? S_FALSE
: S_OK
;
641 static HRESULT WINAPI
ListEnumerator_Skip(IEnumVARIANT
* iface
, ULONG celt
)
643 ListEnumerator
*This
= (ListEnumerator
*)iface
;
644 ListData
*data
= (ListData
*)private_data(This
->pObj
);
646 TRACE("(%p,%uld)\n", iface
, celt
);
649 if (This
->ulPos
>= data
->ulCount
)
651 This
->ulPos
= data
->ulCount
;
657 static HRESULT WINAPI
ListEnumerator_Reset(IEnumVARIANT
* iface
)
659 ListEnumerator
*This
= (ListEnumerator
*)iface
;
661 TRACE("(%p)\n", iface
);
667 static HRESULT WINAPI
ListEnumerator_Clone(IEnumVARIANT
* iface
, IEnumVARIANT
**ppEnum
)
669 ListEnumerator
*This
= (ListEnumerator
*)iface
;
672 TRACE("(%p,%p)\n", iface
, ppEnum
);
678 hr
= create_list_enumerator(NULL
, (LPVOID
*)ppEnum
, This
->pObj
, 0);
682 IUnknown_Release(*ppEnum
);
689 static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl
=
691 ListEnumerator_QueryInterface
,
692 ListEnumerator_AddRef
,
693 ListEnumerator_Release
,
696 ListEnumerator_Reset
,
701 * Individual Object Invocation Functions
704 /* Helper function that copies a passed parameter instead of using VariantChangeType like the actual DispGetParam.
705 This function is only for VARIANT type parameters that have several types that cannot be properly discriminated
706 using DispGetParam/VariantChangeType. */
707 HRESULT WINAPI
DispGetParam_CopyOnly(
708 DISPPARAMS
*pdispparams
, /* [in] Parameter list */
709 UINT
*position
, /* [in] Position of parameter to copy in pdispparams; on return will contain calculated position */
710 VARIANT
*pvarResult
) /* [out] Destination for resulting variant */
712 /* position is counted backwards */
715 TRACE("position=%d, cArgs=%d, cNamedArgs=%d\n",
716 *position
, pdispparams
->cArgs
, pdispparams
->cNamedArgs
);
717 if (*position
< pdispparams
->cArgs
) {
718 /* positional arg? */
719 pos
= pdispparams
->cArgs
- *position
- 1;
721 /* FIXME: is this how to handle named args? */
722 for (pos
=0; pos
<pdispparams
->cNamedArgs
; pos
++)
723 if (pdispparams
->rgdispidNamedArgs
[pos
] == *position
) break;
725 if (pos
==pdispparams
->cNamedArgs
)
726 return DISP_E_PARAMNOTFOUND
;
729 return VariantCopyInd(pvarResult
,
730 &pdispparams
->rgvarg
[pos
]);
733 static HRESULT WINAPI
SummaryInfoImpl_Invoke(
734 AutomationObject
* This
,
739 DISPPARAMS
* pDispParams
,
741 EXCEPINFO
* pExcepInfo
,
745 VARIANTARG varg0
, varg1
;
746 FILETIME ft
, ftlocal
;
753 switch (dispIdMember
)
755 case DISPID_SUMMARYINFO_PROPERTY
:
756 if (wFlags
& DISPATCH_PROPERTYGET
)
764 static WCHAR szEmpty
[] = {0};
766 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
767 if (FAILED(hr
)) return hr
;
768 ret
= MsiSummaryInfoGetPropertyW(This
->msiHandle
, V_I4(&varg0
), &type
, &value
,
769 &ft
, szEmpty
, &size
);
770 if (ret
!= ERROR_SUCCESS
&&
771 ret
!= ERROR_MORE_DATA
)
773 ERR("MsiSummaryInfoGetProperty returned %d\n", ret
);
774 return DISP_E_EXCEPTION
;
784 V_VT(pVarResult
) = VT_I4
;
785 V_I4(pVarResult
) = value
;
789 if (!(str
= msi_alloc(++size
* sizeof(WCHAR
))))
790 ERR("Out of memory\n");
791 else if ((ret
= MsiSummaryInfoGetPropertyW(This
->msiHandle
, V_I4(&varg0
), &type
, NULL
,
792 NULL
, str
, &size
)) != ERROR_SUCCESS
)
793 ERR("MsiSummaryInfoGetProperty returned %d\n", ret
);
796 V_VT(pVarResult
) = VT_BSTR
;
797 V_BSTR(pVarResult
) = SysAllocString(str
);
803 FileTimeToLocalFileTime(&ft
, &ftlocal
);
804 FileTimeToSystemTime(&ftlocal
, &st
);
805 SystemTimeToVariantTime(&st
, &date
);
807 V_VT(pVarResult
) = VT_DATE
;
808 V_DATE(pVarResult
) = date
;
812 ERR("Unhandled variant type %d\n", type
);
815 else if (wFlags
& DISPATCH_PROPERTYPUT
)
817 UINT posValue
= DISPID_PROPERTYPUT
;
819 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
820 if (FAILED(hr
)) return hr
;
821 hr
= DispGetParam_CopyOnly(pDispParams
, &posValue
, &varg1
);
824 *puArgErr
= posValue
;
828 switch (V_VT(&varg1
))
832 ret
= MsiSummaryInfoSetPropertyW(This
->msiHandle
, V_I4(&varg0
), V_VT(&varg1
), V_I4(&varg1
), NULL
, NULL
);
836 VariantTimeToSystemTime(V_DATE(&varg1
), &st
);
837 SystemTimeToFileTime(&st
, &ftlocal
);
838 LocalFileTimeToFileTime(&ftlocal
, &ft
);
839 ret
= MsiSummaryInfoSetPropertyW(This
->msiHandle
, V_I4(&varg0
), VT_FILETIME
, 0, &ft
, NULL
);
843 ret
= MsiSummaryInfoSetPropertyW(This
->msiHandle
, V_I4(&varg0
), VT_LPSTR
, 0, NULL
, V_BSTR(&varg1
));
847 FIXME("Unhandled variant type %d\n", V_VT(&varg1
));
848 VariantClear(&varg1
);
849 return DISP_E_EXCEPTION
;
852 if (ret
!= ERROR_SUCCESS
)
854 ERR("MsiSummaryInfoSetPropertyW returned %d\n", ret
);
855 return DISP_E_EXCEPTION
;
858 else return DISP_E_MEMBERNOTFOUND
;
861 case DISPID_SUMMARYINFO_PROPERTYCOUNT
:
862 if (wFlags
& DISPATCH_PROPERTYGET
) {
864 if ((ret
= MsiSummaryInfoGetPropertyCount(This
->msiHandle
, &count
)) != ERROR_SUCCESS
)
865 ERR("MsiSummaryInfoGetPropertyCount returned %d\n", ret
);
868 V_VT(pVarResult
) = VT_I4
;
869 V_I4(pVarResult
) = count
;
872 else return DISP_E_MEMBERNOTFOUND
;
876 return DISP_E_MEMBERNOTFOUND
;
879 VariantClear(&varg1
);
880 VariantClear(&varg0
);
885 static HRESULT WINAPI
RecordImpl_Invoke(
886 AutomationObject
* This
,
891 DISPPARAMS
* pDispParams
,
893 EXCEPINFO
* pExcepInfo
,
899 VARIANTARG varg0
, varg1
;
905 switch (dispIdMember
)
907 case DISPID_RECORD_FIELDCOUNT
:
908 if (wFlags
& DISPATCH_PROPERTYGET
) {
909 V_VT(pVarResult
) = VT_I4
;
910 V_I4(pVarResult
) = MsiRecordGetFieldCount(This
->msiHandle
);
912 else return DISP_E_MEMBERNOTFOUND
;
915 case DISPID_RECORD_STRINGDATA
:
916 if (wFlags
& DISPATCH_PROPERTYGET
) {
917 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
918 if (FAILED(hr
)) return hr
;
919 V_VT(pVarResult
) = VT_BSTR
;
920 V_BSTR(pVarResult
) = NULL
;
921 if ((ret
= MsiRecordGetStringW(This
->msiHandle
, V_I4(&varg0
), NULL
, &dwLen
)) == ERROR_SUCCESS
)
923 if (!(szString
= msi_alloc((++dwLen
)*sizeof(WCHAR
))))
924 ERR("Out of memory\n");
925 else if ((ret
= MsiRecordGetStringW(This
->msiHandle
, V_I4(&varg0
), szString
, &dwLen
)) == ERROR_SUCCESS
)
926 V_BSTR(pVarResult
) = SysAllocString(szString
);
929 if (ret
!= ERROR_SUCCESS
)
930 ERR("MsiRecordGetString returned %d\n", ret
);
931 } else if (wFlags
& DISPATCH_PROPERTYPUT
) {
932 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
933 if (FAILED(hr
)) return hr
;
934 hr
= DispGetParam(pDispParams
, DISPID_PROPERTYPUT
, VT_BSTR
, &varg1
, puArgErr
);
935 if (FAILED(hr
)) return hr
;
936 if ((ret
= MsiRecordSetStringW(This
->msiHandle
, V_I4(&varg0
), V_BSTR(&varg1
))) != ERROR_SUCCESS
)
938 VariantClear(&varg1
);
939 ERR("MsiRecordSetString returned %d\n", ret
);
940 return DISP_E_EXCEPTION
;
943 else return DISP_E_MEMBERNOTFOUND
;
946 case DISPID_RECORD_INTEGERDATA
:
947 if (wFlags
& DISPATCH_PROPERTYGET
) {
948 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
949 if (FAILED(hr
)) return hr
;
950 V_VT(pVarResult
) = VT_I4
;
951 V_I4(pVarResult
) = MsiRecordGetInteger(This
->msiHandle
, V_I4(&varg0
));
952 } else if (wFlags
& DISPATCH_PROPERTYPUT
) {
953 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
954 if (FAILED(hr
)) return hr
;
955 hr
= DispGetParam(pDispParams
, DISPID_PROPERTYPUT
, VT_I4
, &varg1
, puArgErr
);
956 if (FAILED(hr
)) return hr
;
957 if ((ret
= MsiRecordSetInteger(This
->msiHandle
, V_I4(&varg0
), V_I4(&varg1
))) != ERROR_SUCCESS
)
959 ERR("MsiRecordSetInteger returned %d\n", ret
);
960 return DISP_E_EXCEPTION
;
963 else return DISP_E_MEMBERNOTFOUND
;
967 return DISP_E_MEMBERNOTFOUND
;
970 VariantClear(&varg1
);
971 VariantClear(&varg0
);
976 static HRESULT WINAPI
ListImpl_Invoke(
977 AutomationObject
* This
,
982 DISPPARAMS
* pDispParams
,
984 EXCEPINFO
* pExcepInfo
,
987 ListData
*data
= (ListData
*)private_data(This
);
990 IUnknown
*pUnk
= NULL
;
994 switch (dispIdMember
)
996 case DISPID_LIST__NEWENUM
:
997 if (wFlags
& DISPATCH_METHOD
) {
998 V_VT(pVarResult
) = VT_UNKNOWN
;
999 if (SUCCEEDED(hr
= create_list_enumerator(NULL
, (LPVOID
*)&pUnk
, This
, 0)))
1000 V_UNKNOWN(pVarResult
) = pUnk
;
1002 ERR("Failed to create IEnumVARIANT object, hresult 0x%08x\n", hr
);
1004 else return DISP_E_MEMBERNOTFOUND
;
1007 case DISPID_LIST_ITEM
:
1008 if (wFlags
& DISPATCH_PROPERTYGET
) {
1009 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
1010 if (FAILED(hr
)) return hr
;
1011 if (V_I4(&varg0
) < 0 || V_I4(&varg0
) >= data
->ulCount
)
1012 return DISP_E_BADINDEX
;
1013 VariantCopy(pVarResult
, &data
->pVars
[V_I4(&varg0
)]);
1015 else return DISP_E_MEMBERNOTFOUND
;
1018 case DISPID_LIST_COUNT
:
1019 if (wFlags
& DISPATCH_PROPERTYGET
) {
1020 V_VT(pVarResult
) = VT_I4
;
1021 V_I4(pVarResult
) = data
->ulCount
;
1023 else return DISP_E_MEMBERNOTFOUND
;
1027 return DISP_E_MEMBERNOTFOUND
;
1030 VariantClear(&varg0
);
1035 static void WINAPI
ListImpl_Free(AutomationObject
*This
)
1037 ListData
*data
= private_data(This
);
1040 for (idx
=0; idx
<data
->ulCount
; idx
++)
1041 VariantClear(&data
->pVars
[idx
]);
1042 HeapFree(GetProcessHeap(), 0, data
->pVars
);
1045 static HRESULT WINAPI
ViewImpl_Invoke(
1046 AutomationObject
* This
,
1047 DISPID dispIdMember
,
1051 DISPPARAMS
* pDispParams
,
1052 VARIANT
* pVarResult
,
1053 EXCEPINFO
* pExcepInfo
,
1056 MSIHANDLE msiHandle
;
1057 IDispatch
*pDispatch
= NULL
;
1059 VARIANTARG varg0
, varg1
;
1062 VariantInit(&varg0
);
1063 VariantInit(&varg1
);
1065 switch (dispIdMember
)
1067 case DISPID_VIEW_EXECUTE
:
1068 if (wFlags
& DISPATCH_METHOD
)
1070 hr
= DispGetParam(pDispParams
, 0, VT_DISPATCH
, &varg0
, puArgErr
);
1071 if (SUCCEEDED(hr
) && V_DISPATCH(&varg0
) != NULL
)
1072 MsiViewExecute(This
->msiHandle
, ((AutomationObject
*)V_DISPATCH(&varg0
))->msiHandle
);
1074 MsiViewExecute(This
->msiHandle
, 0);
1076 else return DISP_E_MEMBERNOTFOUND
;
1079 case DISPID_VIEW_FETCH
:
1080 if (wFlags
& DISPATCH_METHOD
)
1082 V_VT(pVarResult
) = VT_DISPATCH
;
1083 if ((ret
= MsiViewFetch(This
->msiHandle
, &msiHandle
)) == ERROR_SUCCESS
)
1085 if (SUCCEEDED(hr
= create_automation_object(msiHandle
, NULL
, (LPVOID
*)&pDispatch
, &DIID_Record
, RecordImpl_Invoke
, NULL
, 0)))
1086 V_DISPATCH(pVarResult
) = pDispatch
;
1088 ERR("Failed to create Record object, hresult 0x%08x\n", hr
);
1090 else if (ret
== ERROR_NO_MORE_ITEMS
)
1091 V_DISPATCH(pVarResult
) = NULL
;
1094 ERR("MsiViewFetch returned %d\n", ret
);
1095 return DISP_E_EXCEPTION
;
1098 else return DISP_E_MEMBERNOTFOUND
;
1101 case DISPID_VIEW_MODIFY
:
1102 if (wFlags
& DISPATCH_METHOD
)
1104 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
1105 if (FAILED(hr
)) return hr
;
1106 hr
= DispGetParam(pDispParams
, 1, VT_DISPATCH
, &varg1
, puArgErr
);
1107 if (FAILED(hr
)) return hr
;
1108 if (!V_DISPATCH(&varg1
)) return DISP_E_EXCEPTION
;
1109 if ((ret
= MsiViewModify(This
->msiHandle
, V_I4(&varg0
), ((AutomationObject
*)V_DISPATCH(&varg1
))->msiHandle
)) != ERROR_SUCCESS
)
1111 VariantClear(&varg1
);
1112 ERR("MsiViewModify returned %d\n", ret
);
1113 return DISP_E_EXCEPTION
;
1116 else return DISP_E_MEMBERNOTFOUND
;
1119 case DISPID_VIEW_CLOSE
:
1120 if (wFlags
& DISPATCH_METHOD
)
1122 MsiViewClose(This
->msiHandle
);
1124 else return DISP_E_MEMBERNOTFOUND
;
1128 return DISP_E_MEMBERNOTFOUND
;
1131 VariantClear(&varg1
);
1132 VariantClear(&varg0
);
1137 static HRESULT WINAPI
DatabaseImpl_Invoke(
1138 AutomationObject
* This
,
1139 DISPID dispIdMember
,
1143 DISPPARAMS
* pDispParams
,
1144 VARIANT
* pVarResult
,
1145 EXCEPINFO
* pExcepInfo
,
1148 MSIHANDLE msiHandle
;
1149 IDispatch
*pDispatch
= NULL
;
1151 VARIANTARG varg0
, varg1
;
1154 VariantInit(&varg0
);
1155 VariantInit(&varg1
);
1157 switch (dispIdMember
)
1159 case DISPID_DATABASE_SUMMARYINFORMATION
:
1160 if (wFlags
& DISPATCH_PROPERTYGET
)
1162 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
1166 V_VT(pVarResult
) = VT_DISPATCH
;
1167 if ((ret
= MsiGetSummaryInformationW(This
->msiHandle
, NULL
, V_I4(&varg0
), &msiHandle
)) == ERROR_SUCCESS
)
1169 hr
= create_automation_object(msiHandle
, NULL
, (LPVOID
*)&pDispatch
, &DIID_SummaryInfo
, SummaryInfoImpl_Invoke
, NULL
, 0);
1171 V_DISPATCH(pVarResult
) = pDispatch
;
1173 ERR("Failed to create SummaryInfo object: 0x%08x\n", hr
);
1177 ERR("MsiGetSummaryInformation returned %d\n", ret
);
1178 return DISP_E_EXCEPTION
;
1181 else return DISP_E_MEMBERNOTFOUND
;
1184 case DISPID_DATABASE_OPENVIEW
:
1185 if (wFlags
& DISPATCH_METHOD
)
1187 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1188 if (FAILED(hr
)) return hr
;
1189 V_VT(pVarResult
) = VT_DISPATCH
;
1190 if ((ret
= MsiDatabaseOpenViewW(This
->msiHandle
, V_BSTR(&varg0
), &msiHandle
)) == ERROR_SUCCESS
)
1192 if (SUCCEEDED(hr
= create_automation_object(msiHandle
, NULL
, (LPVOID
*)&pDispatch
, &DIID_View
, ViewImpl_Invoke
, NULL
, 0)))
1193 V_DISPATCH(pVarResult
) = pDispatch
;
1195 ERR("Failed to create View object, hresult 0x%08x\n", hr
);
1199 VariantClear(&varg0
);
1200 ERR("MsiDatabaseOpenView returned %d\n", ret
);
1201 return DISP_E_EXCEPTION
;
1204 else return DISP_E_MEMBERNOTFOUND
;
1208 return DISP_E_MEMBERNOTFOUND
;
1211 VariantClear(&varg1
);
1212 VariantClear(&varg0
);
1217 static HRESULT WINAPI
SessionImpl_Invoke(
1218 AutomationObject
* This
,
1219 DISPID dispIdMember
,
1223 DISPPARAMS
* pDispParams
,
1224 VARIANT
* pVarResult
,
1225 EXCEPINFO
* pExcepInfo
,
1228 SessionData
*data
= private_data(This
);
1231 IDispatch
*pDispatch
= NULL
;
1232 MSIHANDLE msiHandle
;
1235 INSTALLSTATE iInstalled
, iAction
;
1236 VARIANTARG varg0
, varg1
;
1239 VariantInit(&varg0
);
1240 VariantInit(&varg1
);
1242 switch (dispIdMember
)
1244 case DISPID_SESSION_INSTALLER
:
1245 if (wFlags
& DISPATCH_PROPERTYGET
) {
1246 V_VT(pVarResult
) = VT_DISPATCH
;
1247 IDispatch_AddRef(data
->pInstaller
);
1248 V_DISPATCH(pVarResult
) = data
->pInstaller
;
1250 else return DISP_E_MEMBERNOTFOUND
;
1253 case DISPID_SESSION_PROPERTY
:
1254 if (wFlags
& DISPATCH_PROPERTYGET
) {
1255 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1256 if (FAILED(hr
)) return hr
;
1257 V_VT(pVarResult
) = VT_BSTR
;
1258 V_BSTR(pVarResult
) = NULL
;
1259 if ((ret
= MsiGetPropertyW(This
->msiHandle
, V_BSTR(&varg0
), NULL
, &dwLen
)) == ERROR_SUCCESS
)
1261 if (!(szString
= msi_alloc((++dwLen
)*sizeof(WCHAR
))))
1262 ERR("Out of memory\n");
1263 else if ((ret
= MsiGetPropertyW(This
->msiHandle
, V_BSTR(&varg0
), szString
, &dwLen
)) == ERROR_SUCCESS
)
1264 V_BSTR(pVarResult
) = SysAllocString(szString
);
1267 if (ret
!= ERROR_SUCCESS
)
1268 ERR("MsiGetProperty returned %d\n", ret
);
1269 } else if (wFlags
& DISPATCH_PROPERTYPUT
) {
1270 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1271 if (FAILED(hr
)) return hr
;
1272 hr
= DispGetParam(pDispParams
, DISPID_PROPERTYPUT
, VT_BSTR
, &varg1
, puArgErr
);
1274 VariantClear(&varg0
);
1277 if ((ret
= MsiSetPropertyW(This
->msiHandle
, V_BSTR(&varg0
), V_BSTR(&varg1
))) != ERROR_SUCCESS
)
1279 VariantClear(&varg0
);
1280 VariantClear(&varg1
);
1281 ERR("MsiSetProperty returned %d\n", ret
);
1282 return DISP_E_EXCEPTION
;
1285 else return DISP_E_MEMBERNOTFOUND
;
1288 case DISPID_SESSION_LANGUAGE
:
1289 if (wFlags
& DISPATCH_PROPERTYGET
) {
1290 langId
= MsiGetLanguage(This
->msiHandle
);
1291 V_VT(pVarResult
) = VT_I4
;
1292 V_I4(pVarResult
) = langId
;
1294 else return DISP_E_MEMBERNOTFOUND
;
1297 case DISPID_SESSION_MODE
:
1298 if (wFlags
& DISPATCH_PROPERTYGET
) {
1299 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
1300 if (FAILED(hr
)) return hr
;
1301 V_VT(pVarResult
) = VT_BOOL
;
1302 V_BOOL(pVarResult
) = MsiGetMode(This
->msiHandle
, V_I4(&varg0
));
1303 } else if (wFlags
& DISPATCH_PROPERTYPUT
) {
1304 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
1305 if (FAILED(hr
)) return hr
;
1306 hr
= DispGetParam(pDispParams
, DISPID_PROPERTYPUT
, VT_BOOL
, &varg1
, puArgErr
);
1307 if (FAILED(hr
)) return hr
;
1308 if ((ret
= MsiSetMode(This
->msiHandle
, V_I4(&varg0
), V_BOOL(&varg1
))) != ERROR_SUCCESS
)
1310 ERR("MsiSetMode returned %d\n", ret
);
1311 return DISP_E_EXCEPTION
;
1314 else return DISP_E_MEMBERNOTFOUND
;
1317 case DISPID_SESSION_DATABASE
:
1318 if (wFlags
& DISPATCH_PROPERTYGET
) {
1319 V_VT(pVarResult
) = VT_DISPATCH
;
1320 if ((msiHandle
= MsiGetActiveDatabase(This
->msiHandle
)))
1322 if (SUCCEEDED(hr
= create_automation_object(msiHandle
, NULL
, (LPVOID
*)&pDispatch
, &DIID_Database
, DatabaseImpl_Invoke
, NULL
, 0)))
1323 V_DISPATCH(pVarResult
) = pDispatch
;
1325 ERR("Failed to create Database object, hresult 0x%08x\n", hr
);
1329 ERR("MsiGetActiveDatabase failed\n");
1330 return DISP_E_EXCEPTION
;
1333 else return DISP_E_MEMBERNOTFOUND
;
1336 case DISPID_SESSION_DOACTION
:
1337 if (wFlags
& DISPATCH_METHOD
) {
1338 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1339 if (FAILED(hr
)) return hr
;
1340 ret
= MsiDoActionW(This
->msiHandle
, V_BSTR(&varg0
));
1341 V_VT(pVarResult
) = VT_I4
;
1344 case ERROR_FUNCTION_NOT_CALLED
:
1345 V_I4(pVarResult
) = msiDoActionStatusNoAction
;
1348 V_I4(pVarResult
) = msiDoActionStatusSuccess
;
1350 case ERROR_INSTALL_USEREXIT
:
1351 V_I4(pVarResult
) = msiDoActionStatusUserExit
;
1353 case ERROR_INSTALL_FAILURE
:
1354 V_I4(pVarResult
) = msiDoActionStatusFailure
;
1356 case ERROR_INSTALL_SUSPEND
:
1357 V_I4(pVarResult
) = msiDoActionStatusSuspend
;
1359 case ERROR_MORE_DATA
:
1360 V_I4(pVarResult
) = msiDoActionStatusFinished
;
1362 case ERROR_INVALID_HANDLE_STATE
:
1363 V_I4(pVarResult
) = msiDoActionStatusWrongState
;
1365 case ERROR_INVALID_DATA
:
1366 V_I4(pVarResult
) = msiDoActionStatusBadActionData
;
1369 VariantClear(&varg0
);
1370 FIXME("MsiDoAction returned unhandled value %d\n", ret
);
1371 return DISP_E_EXCEPTION
;
1374 else return DISP_E_MEMBERNOTFOUND
;
1377 case DISPID_SESSION_EVALUATECONDITION
:
1378 if (wFlags
& DISPATCH_METHOD
) {
1379 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1380 if (FAILED(hr
)) return hr
;
1381 V_VT(pVarResult
) = VT_I4
;
1382 V_I4(pVarResult
) = MsiEvaluateConditionW(This
->msiHandle
, V_BSTR(&varg0
));
1384 else return DISP_E_MEMBERNOTFOUND
;
1387 case DISPID_SESSION_SETINSTALLLEVEL
:
1388 if (wFlags
& DISPATCH_METHOD
) {
1389 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
1390 if (FAILED(hr
)) return hr
;
1391 if ((ret
= MsiSetInstallLevel(This
->msiHandle
, V_I4(&varg0
))) != ERROR_SUCCESS
)
1393 ERR("MsiSetInstallLevel returned %d\n", ret
);
1394 return DISP_E_EXCEPTION
;
1397 else return DISP_E_MEMBERNOTFOUND
;
1400 case DISPID_SESSION_FEATURECURRENTSTATE
:
1401 if (wFlags
& DISPATCH_PROPERTYGET
) {
1402 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1403 if (FAILED(hr
)) return hr
;
1404 V_VT(pVarResult
) = VT_I4
;
1405 if ((ret
= MsiGetFeatureStateW(This
->msiHandle
, V_BSTR(&varg0
), &iInstalled
, &iAction
)) == ERROR_SUCCESS
)
1406 V_I4(pVarResult
) = iInstalled
;
1409 ERR("MsiGetFeatureState returned %d\n", ret
);
1410 V_I4(pVarResult
) = msiInstallStateUnknown
;
1413 else return DISP_E_MEMBERNOTFOUND
;
1416 case DISPID_SESSION_FEATUREREQUESTSTATE
:
1417 if (wFlags
& DISPATCH_PROPERTYGET
) {
1418 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1419 if (FAILED(hr
)) return hr
;
1420 V_VT(pVarResult
) = VT_I4
;
1421 if ((ret
= MsiGetFeatureStateW(This
->msiHandle
, V_BSTR(&varg0
), &iInstalled
, &iAction
)) == ERROR_SUCCESS
)
1422 V_I4(pVarResult
) = iAction
;
1425 ERR("MsiGetFeatureState returned %d\n", ret
);
1426 V_I4(pVarResult
) = msiInstallStateUnknown
;
1428 } else if (wFlags
& DISPATCH_PROPERTYPUT
) {
1429 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1430 if (FAILED(hr
)) return hr
;
1431 hr
= DispGetParam(pDispParams
, DISPID_PROPERTYPUT
, VT_I4
, &varg1
, puArgErr
);
1433 VariantClear(&varg0
);
1436 if ((ret
= MsiSetFeatureStateW(This
->msiHandle
, V_BSTR(&varg0
), V_I4(&varg1
))) != ERROR_SUCCESS
)
1438 VariantClear(&varg0
);
1439 ERR("MsiSetFeatureState returned %d\n", ret
);
1440 return DISP_E_EXCEPTION
;
1443 else return DISP_E_MEMBERNOTFOUND
;
1447 return DISP_E_MEMBERNOTFOUND
;
1450 VariantClear(&varg1
);
1451 VariantClear(&varg0
);
1456 /* Fill the variant pointed to by pVarResult with the value & size returned by RegQueryValueEx as dictated by the
1457 * registry value type. Used by Installer::RegistryValue. */
1458 static void variant_from_registry_value(VARIANT
*pVarResult
, DWORD dwType
, LPBYTE lpData
, DWORD dwSize
)
1460 static const WCHAR szREG_BINARY
[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
1461 static const WCHAR szREG_
[] = { '(','R','E','G','_',']',0 };
1462 WCHAR
*szString
= (WCHAR
*)lpData
;
1463 LPWSTR szNewString
= NULL
;
1464 DWORD dwNewSize
= 0;
1469 /* Registry strings may not be null terminated so we must use SysAllocStringByteLen/Len */
1470 case REG_MULTI_SZ
: /* Multi SZ change internal null characters to newlines */
1471 idx
= (dwSize
/sizeof(WCHAR
))-1;
1472 while (idx
>= 0 && !szString
[idx
]) idx
--;
1473 for (; idx
>= 0; idx
--)
1474 if (!szString
[idx
]) szString
[idx
] = '\n';
1476 V_VT(pVarResult
) = VT_BSTR
;
1477 V_BSTR(pVarResult
) = SysAllocStringByteLen((LPCSTR
)szString
, dwSize
);
1481 if (!(dwNewSize
= ExpandEnvironmentStringsW(szString
, szNewString
, dwNewSize
)))
1482 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1483 else if (!(szNewString
= msi_alloc(dwNewSize
)))
1484 ERR("Out of memory\n");
1485 else if (!(dwNewSize
= ExpandEnvironmentStringsW(szString
, szNewString
, dwNewSize
)))
1486 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1489 V_VT(pVarResult
) = VT_BSTR
;
1490 V_BSTR(pVarResult
) = SysAllocStringLen(szNewString
, dwNewSize
);
1492 msi_free(szNewString
);
1496 V_VT(pVarResult
) = VT_I4
;
1497 V_I4(pVarResult
) = *((DWORD
*)lpData
);
1501 V_VT(pVarResult
) = VT_BSTR
;
1502 V_BSTR(pVarResult
) = SysAllocString(szREG_
); /* Weird string, don't know why native returns it */
1506 V_VT(pVarResult
) = VT_BSTR
;
1507 V_BSTR(pVarResult
) = SysAllocString(szREG_BINARY
);
1511 V_VT(pVarResult
) = VT_EMPTY
;
1515 FIXME("Unhandled registry value type %d\n", dwType
);
1519 static HRESULT WINAPI
InstallerImpl_Invoke(
1520 AutomationObject
* This
,
1521 DISPID dispIdMember
,
1525 DISPPARAMS
* pDispParams
,
1526 VARIANT
* pVarResult
,
1527 EXCEPINFO
* pExcepInfo
,
1530 MSIHANDLE msiHandle
;
1531 IDispatch
*pDispatch
= NULL
;
1533 VARIANTARG varg0
, varg1
, varg2
;
1535 LPWSTR szString
= NULL
;
1538 VariantInit(&varg0
);
1539 VariantInit(&varg1
);
1540 VariantInit(&varg2
);
1542 switch (dispIdMember
)
1544 case DISPID_INSTALLER_CREATERECORD
:
1545 if (wFlags
& DISPATCH_METHOD
)
1547 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
1548 if (FAILED(hr
)) return hr
;
1549 V_VT(pVarResult
) = VT_DISPATCH
;
1550 if ((msiHandle
= MsiCreateRecord(V_I4(&varg0
))))
1552 if (SUCCEEDED(hr
= create_automation_object(msiHandle
, NULL
, (LPVOID
*)&pDispatch
, &DIID_Record
, RecordImpl_Invoke
, NULL
, 0)))
1553 V_DISPATCH(pVarResult
) = pDispatch
;
1555 ERR("Failed to create Record object, hresult 0x%08x\n", hr
);
1559 ERR("MsiCreateRecord failed\n");
1560 return DISP_E_EXCEPTION
;
1563 else return DISP_E_MEMBERNOTFOUND
;
1566 case DISPID_INSTALLER_OPENPACKAGE
:
1567 if (wFlags
& DISPATCH_METHOD
)
1569 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1570 if (FAILED(hr
)) return hr
;
1571 hr
= DispGetParam(pDispParams
, 1, VT_I4
, &varg1
, puArgErr
);
1574 VariantClear(&varg0
);
1577 V_VT(pVarResult
) = VT_DISPATCH
;
1578 if ((ret
= MsiOpenPackageExW(V_BSTR(&varg0
), V_I4(&varg1
), &msiHandle
)) == ERROR_SUCCESS
)
1580 if (SUCCEEDED(hr
= create_session(msiHandle
, (IDispatch
*)This
, &pDispatch
)))
1581 V_DISPATCH(pVarResult
) = pDispatch
;
1583 ERR("Failed to create Session object, hresult 0x%08x\n", hr
);
1587 VariantClear(&varg0
);
1588 ERR("MsiOpenPackageEx returned %d\n", ret
);
1589 return DISP_E_EXCEPTION
;
1592 else return DISP_E_MEMBERNOTFOUND
;
1595 case DISPID_INSTALLER_OPENDATABASE
:
1596 if (wFlags
& DISPATCH_METHOD
)
1598 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1599 if (FAILED(hr
)) return hr
;
1601 hr
= DispGetParam(pDispParams
, 1, VT_BSTR
, &varg1
, puArgErr
);
1604 VariantClear(&varg0
);
1608 V_VT(pVarResult
) = VT_DISPATCH
;
1609 if ((ret
= MsiOpenDatabaseW(V_BSTR(&varg0
), V_BSTR(&varg1
), &msiHandle
)) == ERROR_SUCCESS
)
1611 hr
= create_automation_object(msiHandle
, NULL
, (LPVOID
*)&pDispatch
,
1612 &DIID_Database
, DatabaseImpl_Invoke
, NULL
, 0);
1614 V_DISPATCH(pVarResult
) = pDispatch
;
1616 ERR("Failed to create Database object: 0x%08x\n", hr
);
1620 VariantClear(&varg0
);
1621 VariantClear(&varg1
);
1622 ERR("MsiOpenDatabase returned %d\n", ret
);
1623 return DISP_E_EXCEPTION
;
1626 else return DISP_E_MEMBERNOTFOUND
;
1629 case DISPID_INSTALLER_INSTALLPRODUCT
:
1630 if (wFlags
& DISPATCH_METHOD
)
1632 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1633 if (FAILED(hr
)) return hr
;
1634 hr
= DispGetParam(pDispParams
, 1, VT_BSTR
, &varg1
, puArgErr
);
1637 VariantClear(&varg0
);
1640 if ((ret
= MsiInstallProductW(V_BSTR(&varg0
), V_BSTR(&varg1
))) != ERROR_SUCCESS
)
1642 VariantClear(&varg1
);
1643 VariantClear(&varg0
);
1644 ERR("MsiInstallProduct returned %d\n", ret
);
1645 return DISP_E_EXCEPTION
;
1648 else return DISP_E_MEMBERNOTFOUND
;
1651 case DISPID_INSTALLER_REGISTRYVALUE
:
1652 if (wFlags
& DISPATCH_METHOD
) {
1655 UINT posValue
= 2; /* Save valuePos so we can save puArgErr if we are unable to do our type conversions */
1657 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
1658 if (FAILED(hr
)) return hr
;
1659 hr
= DispGetParam(pDispParams
, 1, VT_BSTR
, &varg1
, puArgErr
);
1660 if (FAILED(hr
)) return hr
;
1661 hr
= DispGetParam_CopyOnly(pDispParams
, &posValue
, &varg2
);
1664 VariantClear(&varg1
);
1667 ret
= RegOpenKeyW((HKEY
)V_I4(&varg0
), V_BSTR(&varg1
), &hkey
);
1669 /* Third parameter can be VT_EMPTY, VT_I4, or VT_BSTR */
1670 switch (V_VT(&varg2
))
1672 case VT_EMPTY
: /* Return VT_BOOL as to whether or not registry key exists */
1673 V_VT(pVarResult
) = VT_BOOL
;
1674 V_BOOL(pVarResult
) = (ret
== ERROR_SUCCESS
);
1677 case VT_BSTR
: /* Return value of specified key if it exists */
1678 if (ret
== ERROR_SUCCESS
&&
1679 (ret
= RegQueryValueExW(hkey
, V_BSTR(&varg2
), NULL
, NULL
, NULL
, &dwSize
)) == ERROR_SUCCESS
)
1681 if (!(szString
= msi_alloc(dwSize
)))
1682 ERR("Out of memory\n");
1683 else if ((ret
= RegQueryValueExW(hkey
, V_BSTR(&varg2
), NULL
, &dwType
, (LPBYTE
)szString
, &dwSize
)) == ERROR_SUCCESS
)
1684 variant_from_registry_value(pVarResult
, dwType
, (LPBYTE
)szString
, dwSize
);
1687 if (ret
!= ERROR_SUCCESS
)
1690 VariantClear(&varg2
);
1691 VariantClear(&varg1
);
1692 return DISP_E_BADINDEX
;
1696 default: /* Try to make it into VT_I4, can use VariantChangeType for this */
1697 hr
= VariantChangeType(&varg2
, &varg2
, 0, VT_I4
);
1698 if (SUCCEEDED(hr
) && ret
!= ERROR_SUCCESS
) hr
= DISP_E_BADINDEX
; /* Conversion fine, but couldn't find key */
1701 if (hr
== DISP_E_TYPEMISMATCH
) *puArgErr
= posValue
;
1702 VariantClear(&varg2
); /* Unknown type, so let's clear it */
1703 VariantClear(&varg1
);
1707 /* Retrieve class name or maximum value name or subkey name size */
1709 ret
= RegQueryInfoKeyW(hkey
, NULL
, &dwSize
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1710 else if (V_I4(&varg2
) > 0)
1711 ret
= RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &dwSize
, NULL
, NULL
, NULL
);
1712 else /* V_I4(&varg2) < 0 */
1713 ret
= RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, &dwSize
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1715 if (ret
== ERROR_SUCCESS
)
1717 if (!(szString
= msi_alloc(++dwSize
* sizeof(WCHAR
))))
1718 ERR("Out of memory\n");
1719 else if (!V_I4(&varg2
))
1720 ret
= RegQueryInfoKeyW(hkey
, szString
, &dwSize
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1721 else if (V_I4(&varg2
) > 0)
1722 ret
= RegEnumValueW(hkey
, V_I4(&varg2
)-1, szString
, &dwSize
, 0, 0, NULL
, NULL
);
1723 else /* V_I4(&varg2) < 0 */
1724 ret
= RegEnumKeyW(hkey
, -1 - V_I4(&varg2
), szString
, dwSize
);
1726 if (szString
&& ret
== ERROR_SUCCESS
)
1728 V_VT(pVarResult
) = VT_BSTR
;
1729 V_BSTR(pVarResult
) = SysAllocString(szString
);
1737 else return DISP_E_MEMBERNOTFOUND
;
1740 case DISPID_INSTALLER_PRODUCTSTATE
:
1741 if (wFlags
& DISPATCH_PROPERTYGET
) {
1742 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1743 if (FAILED(hr
)) return hr
;
1744 V_VT(pVarResult
) = VT_I4
;
1745 V_I4(pVarResult
) = MsiQueryProductStateW(V_BSTR(&varg0
));
1747 else return DISP_E_MEMBERNOTFOUND
;
1750 case DISPID_INSTALLER_PRODUCTINFO
:
1751 if (wFlags
& DISPATCH_PROPERTYGET
) {
1752 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1753 if (FAILED(hr
)) return hr
;
1754 hr
= DispGetParam(pDispParams
, 1, VT_BSTR
, &varg1
, puArgErr
);
1757 VariantClear(&varg0
);
1760 V_VT(pVarResult
) = VT_BSTR
;
1761 V_BSTR(pVarResult
) = NULL
;
1762 if ((ret
= MsiGetProductInfoW(V_BSTR(&varg0
), V_BSTR(&varg1
), NULL
, &dwSize
)) == ERROR_SUCCESS
)
1764 if (!(szString
= msi_alloc((++dwSize
)*sizeof(WCHAR
))))
1765 ERR("Out of memory\n");
1766 else if ((ret
= MsiGetProductInfoW(V_BSTR(&varg0
), V_BSTR(&varg1
), szString
, &dwSize
)) == ERROR_SUCCESS
)
1767 V_BSTR(pVarResult
) = SysAllocString(szString
);
1770 if (ret
!= ERROR_SUCCESS
)
1772 ERR("MsiGetProductInfo returned %d\n", ret
);
1773 VariantClear(&varg1
);
1774 VariantClear(&varg0
);
1775 return DISP_E_EXCEPTION
;
1778 else return DISP_E_MEMBERNOTFOUND
;
1781 case DISPID_INSTALLER_PRODUCTS
:
1782 if (wFlags
& DISPATCH_PROPERTYGET
)
1784 ListData
*ldata
= NULL
;
1786 WCHAR szProductBuf
[GUID_SIZE
];
1788 /* Find number of products */
1789 while ((ret
= MsiEnumProductsW(idx
, szProductBuf
)) == ERROR_SUCCESS
) idx
++;
1790 if (ret
!= ERROR_NO_MORE_ITEMS
)
1792 ERR("MsiEnumProducts returned %d\n", ret
);
1793 return DISP_E_EXCEPTION
;
1796 V_VT(pVarResult
) = VT_DISPATCH
;
1797 if (SUCCEEDED(hr
= create_automation_object(0, NULL
, (LPVOID
*)&pDispatch
, &DIID_StringList
, ListImpl_Invoke
, ListImpl_Free
, sizeof(ListData
))))
1799 V_DISPATCH(pVarResult
) = pDispatch
;
1801 /* Save product strings */
1802 ldata
= (ListData
*)private_data((AutomationObject
*)pDispatch
);
1803 if (!(ldata
->pVars
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(VARIANT
)*idx
)))
1804 ERR("Out of memory\n");
1807 ldata
->ulCount
= idx
;
1808 for (idx
= 0; idx
< ldata
->ulCount
; idx
++)
1810 ret
= MsiEnumProductsW(idx
, szProductBuf
);
1811 VariantInit(&ldata
->pVars
[idx
]);
1812 V_VT(&ldata
->pVars
[idx
]) = VT_BSTR
;
1813 V_BSTR(&ldata
->pVars
[idx
]) = SysAllocString(szProductBuf
);
1818 ERR("Failed to create StringList object, hresult 0x%08x\n", hr
);
1820 else return DISP_E_MEMBERNOTFOUND
;
1823 case DISPID_INSTALLER_RELATEDPRODUCTS
:
1824 if (wFlags
& DISPATCH_PROPERTYGET
)
1826 ListData
*ldata
= NULL
;
1828 WCHAR szProductBuf
[GUID_SIZE
];
1830 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1831 if (FAILED(hr
)) return hr
;
1833 /* Find number of related products */
1834 while ((ret
= MsiEnumRelatedProductsW(V_BSTR(&varg0
), 0, idx
, szProductBuf
)) == ERROR_SUCCESS
) idx
++;
1835 if (ret
!= ERROR_NO_MORE_ITEMS
)
1837 VariantClear(&varg0
);
1838 ERR("MsiEnumRelatedProducts returned %d\n", ret
);
1839 return DISP_E_EXCEPTION
;
1842 V_VT(pVarResult
) = VT_DISPATCH
;
1843 if (SUCCEEDED(hr
= create_automation_object(0, NULL
, (LPVOID
*)&pDispatch
, &DIID_StringList
, ListImpl_Invoke
, ListImpl_Free
, sizeof(ListData
))))
1845 V_DISPATCH(pVarResult
) = pDispatch
;
1847 /* Save product strings */
1848 ldata
= (ListData
*)private_data((AutomationObject
*)pDispatch
);
1849 if (!(ldata
->pVars
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(VARIANT
)*idx
)))
1850 ERR("Out of memory\n");
1853 ldata
->ulCount
= idx
;
1854 for (idx
= 0; idx
< ldata
->ulCount
; idx
++)
1856 ret
= MsiEnumRelatedProductsW(V_BSTR(&varg0
), 0, idx
, szProductBuf
);
1857 VariantInit(&ldata
->pVars
[idx
]);
1858 V_VT(&ldata
->pVars
[idx
]) = VT_BSTR
;
1859 V_BSTR(&ldata
->pVars
[idx
]) = SysAllocString(szProductBuf
);
1864 ERR("Failed to create StringList object, hresult 0x%08x\n", hr
);
1866 else return DISP_E_MEMBERNOTFOUND
;
1870 return DISP_E_MEMBERNOTFOUND
;
1873 VariantClear(&varg2
);
1874 VariantClear(&varg1
);
1875 VariantClear(&varg0
);
1880 /* Wrapper around create_automation_object to create an installer object. */
1881 HRESULT
create_msiserver(IUnknown
*pOuter
, LPVOID
*ppObj
)
1883 return create_automation_object(0, pOuter
, ppObj
, &DIID_Installer
, InstallerImpl_Invoke
, NULL
, 0);
1886 /* Wrapper around create_automation_object to create a session object. */
1887 HRESULT
create_session(MSIHANDLE msiHandle
, IDispatch
*pInstaller
, IDispatch
**pDispatch
)
1889 HRESULT hr
= create_automation_object(msiHandle
, NULL
, (LPVOID
)pDispatch
, &DIID_Session
, SessionImpl_Invoke
, NULL
, sizeof(SessionData
));
1890 if (SUCCEEDED(hr
) && pDispatch
&& *pDispatch
)
1891 ((SessionData
*)private_data((AutomationObject
*)*pDispatch
))->pInstaller
= pInstaller
;