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
34 #include "wine/debug.h"
35 #include "wine/unicode.h"
37 #include "msiserver.h"
38 #include "msiserver_dispids.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(msi
);
43 * AutomationObject - "base" class for all automation objects. For each interface, we implement Invoke function
44 * called from AutomationObject::Invoke, and pass this function to create_automation_object.
47 typedef interface AutomationObject AutomationObject
;
49 interface AutomationObject
{
51 * VTables - We provide IDispatch, IProvideClassInfo, IProvideClassInfo2, IProvideMultipleClassInfo
53 const IDispatchVtbl
*lpVtbl
;
54 const IProvideMultipleClassInfoVtbl
*lpvtblIProvideMultipleClassInfo
;
56 /* Object reference count */
59 /* Clsid for this class and it's appropriate ITypeInfo object */
63 /* The MSI handle of the current object */
66 /* A function that is called from AutomationObject::Invoke, specific to this type of object. */
67 HRESULT (STDMETHODCALLTYPE
*funcInvoke
)(
68 AutomationObject
* This
,
73 DISPPARAMS
* pDispParams
,
75 EXCEPINFO
* pExcepInfo
,
78 /* A function that is called from AutomationObject::Release when the object is being freed to free any private
79 * data structures (or NULL) */
80 void (STDMETHODCALLTYPE
*funcFree
)(AutomationObject
* This
);
84 * ListEnumerator - IEnumVARIANT implementation for MSI automation lists.
87 typedef interface ListEnumerator ListEnumerator
;
89 interface ListEnumerator
{
91 const IEnumVARIANTVtbl
*lpVtbl
;
93 /* Object reference count */
96 /* Current position and pointer to AutomationObject that stores actual data */
98 AutomationObject
*pObj
;
102 * Structures for additional data required by specific automation objects
111 /* The parent Installer object */
112 IDispatch
*pInstaller
;
116 static const struct IDispatchVtbl AutomationObject_Vtbl
;
117 static const struct IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl
;
118 static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl
;
120 /* Load type info so we don't have to process GetIDsOfNames */
121 HRESULT
load_type_info(IDispatch
*iface
, ITypeInfo
**pptinfo
, REFIID clsid
, LCID lcid
)
124 LPTYPELIB pLib
= NULL
;
125 LPTYPEINFO pInfo
= NULL
;
126 static const WCHAR szMsiServer
[] = {'m','s','i','s','e','r','v','e','r','.','t','l','b'};
128 TRACE("(%p)->(%s,%d)\n", iface
, debugstr_guid(clsid
), lcid
);
130 /* Load registered type library */
131 hr
= LoadRegTypeLib(&LIBID_WindowsInstaller
, 1, 0, lcid
, &pLib
);
133 hr
= LoadTypeLib(szMsiServer
, &pLib
);
135 ERR("Could not load msiserver.tlb\n");
140 /* Get type information for object */
141 hr
= ITypeLib_GetTypeInfoOfGuid(pLib
, clsid
, &pInfo
);
142 ITypeLib_Release(pLib
);
144 ERR("Could not load ITypeInfo for %s\n", debugstr_guid(clsid
));
151 /* Create the automation object, placing the result in the pointer ppObj. The automation object is created
152 * with the appropriate clsid and invocation function. */
153 static HRESULT
create_automation_object(MSIHANDLE msiHandle
, IUnknown
*pUnkOuter
, LPVOID
*ppObj
, REFIID clsid
,
154 HRESULT (STDMETHODCALLTYPE
*funcInvoke
)(AutomationObject
*,DISPID
,REFIID
,LCID
,WORD
,DISPPARAMS
*,
155 VARIANT
*,EXCEPINFO
*,UINT
*),
156 void (STDMETHODCALLTYPE
*funcFree
)(AutomationObject
*),
157 SIZE_T sizetPrivateData
)
159 AutomationObject
*object
;
162 TRACE("(%ld,%p,%p,%s,%p,%p,%ld)\n", (unsigned long)msiHandle
, pUnkOuter
, ppObj
, debugstr_guid(clsid
), funcInvoke
, funcFree
, sizetPrivateData
);
165 return CLASS_E_NOAGGREGATION
;
167 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(AutomationObject
)+sizetPrivateData
);
169 /* Set all the VTable references */
170 object
->lpVtbl
= &AutomationObject_Vtbl
;
171 object
->lpvtblIProvideMultipleClassInfo
= &AutomationObject_IProvideMultipleClassInfo_Vtbl
;
174 /* Store data that was passed */
175 object
->msiHandle
= msiHandle
;
176 object
->clsid
= (LPCLSID
)clsid
;
177 object
->funcInvoke
= funcInvoke
;
178 object
->funcFree
= funcFree
;
180 /* Load our TypeInfo so we don't have to process GetIDsOfNames */
181 object
->iTypeInfo
= NULL
;
182 hr
= load_type_info((IDispatch
*)object
, &object
->iTypeInfo
, clsid
, 0x0);
184 HeapFree(GetProcessHeap(), 0, object
);
193 /* Create a list enumerator, placing the result in the pointer ppObj. */
194 static HRESULT
create_list_enumerator(IUnknown
*pUnkOuter
, LPVOID
*ppObj
, AutomationObject
*pObj
, ULONG ulPos
)
196 ListEnumerator
*object
;
198 TRACE("(%p,%p,%p,%uld)\n", pUnkOuter
, ppObj
, pObj
, ulPos
);
201 return CLASS_E_NOAGGREGATION
;
203 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(ListEnumerator
));
205 /* Set all the VTable references */
206 object
->lpVtbl
= &ListEnumerator_Vtbl
;
209 /* Store data that was passed */
210 object
->ulPos
= ulPos
;
212 if (pObj
) IDispatch_AddRef((IDispatch
*)pObj
);
218 /* Macros to get pointer to AutomationObject from the other VTables. */
219 static inline AutomationObject
*obj_from_IProvideMultipleClassInfo( IProvideMultipleClassInfo
*iface
)
221 return (AutomationObject
*)((char*)iface
- FIELD_OFFSET(AutomationObject
, lpvtblIProvideMultipleClassInfo
));
224 /* Macro to get pointer to private object data */
225 static inline void *private_data( AutomationObject
*This
)
231 * AutomationObject methods
234 /*** IUnknown methods ***/
235 static HRESULT WINAPI
AutomationObject_QueryInterface(IDispatch
* iface
, REFIID riid
, void** ppvObject
)
237 AutomationObject
*This
= (AutomationObject
*)iface
;
239 TRACE("(%p/%p)->(%s,%p)\n", iface
, This
, debugstr_guid(riid
), ppvObject
);
241 if (ppvObject
== NULL
)
246 if (IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_IDispatch
) || IsEqualGUID(riid
, This
->clsid
))
248 else if (IsEqualGUID(riid
, &IID_IProvideClassInfo
) ||
249 IsEqualGUID(riid
, &IID_IProvideClassInfo2
) ||
250 IsEqualGUID(riid
, &IID_IProvideMultipleClassInfo
))
251 *ppvObject
= &This
->lpvtblIProvideMultipleClassInfo
;
254 TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid
));
255 return E_NOINTERFACE
;
259 * Query Interface always increases the reference count by one when it is
262 IClassFactory_AddRef(iface
);
267 static ULONG WINAPI
AutomationObject_AddRef(IDispatch
* iface
)
269 AutomationObject
*This
= (AutomationObject
*)iface
;
271 TRACE("(%p/%p)\n", iface
, This
);
273 return InterlockedIncrement(&This
->ref
);
276 static ULONG WINAPI
AutomationObject_Release(IDispatch
* iface
)
278 AutomationObject
*This
= (AutomationObject
*)iface
;
279 ULONG ref
= InterlockedDecrement(&This
->ref
);
281 TRACE("(%p/%p)\n", iface
, This
);
285 if (This
->funcFree
) This
->funcFree(This
);
286 ITypeInfo_Release(This
->iTypeInfo
);
287 MsiCloseHandle(This
->msiHandle
);
288 HeapFree(GetProcessHeap(), 0, This
);
294 /*** IDispatch methods ***/
295 static HRESULT WINAPI
AutomationObject_GetTypeInfoCount(
299 AutomationObject
*This
= (AutomationObject
*)iface
;
301 TRACE("(%p/%p)->(%p)\n", iface
, This
, pctinfo
);
306 static HRESULT WINAPI
AutomationObject_GetTypeInfo(
312 AutomationObject
*This
= (AutomationObject
*)iface
;
313 TRACE("(%p/%p)->(%d,%d,%p)\n", iface
, This
, iTInfo
, lcid
, ppTInfo
);
315 ITypeInfo_AddRef(This
->iTypeInfo
);
316 *ppTInfo
= This
->iTypeInfo
;
320 static HRESULT WINAPI
AutomationObject_GetIDsOfNames(
328 AutomationObject
*This
= (AutomationObject
*)iface
;
330 TRACE("(%p/%p)->(%p,%p,%d,%d,%p)\n", iface
, This
, riid
, rgszNames
, cNames
, lcid
, rgDispId
);
332 if (!IsEqualGUID(riid
, &IID_NULL
)) return E_INVALIDARG
;
333 hr
= ITypeInfo_GetIDsOfNames(This
->iTypeInfo
, rgszNames
, cNames
, rgDispId
);
334 if (hr
== DISP_E_UNKNOWNNAME
)
337 for (idx
=0; idx
<cNames
; idx
++)
339 if (rgDispId
[idx
] == DISPID_UNKNOWN
)
340 FIXME("Unknown member %s, clsid %s\n", debugstr_w(rgszNames
[idx
]), debugstr_guid(This
->clsid
));
346 /* Maximum number of allowed function parameters+1 */
347 #define MAX_FUNC_PARAMS 20
349 /* Some error checking is done here to simplify individual object function invocation */
350 static HRESULT WINAPI
AutomationObject_Invoke(
356 DISPPARAMS
* pDispParams
,
358 EXCEPINFO
* pExcepInfo
,
361 AutomationObject
*This
= (AutomationObject
*)iface
;
363 unsigned int uArgErr
;
364 VARIANT varResultDummy
;
365 BSTR bstrName
= NULL
;
367 TRACE("(%p/%p)->(%d,%p,%d,%d,%p,%p,%p,%p)\n", iface
, This
, dispIdMember
, riid
, lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
369 if (!IsEqualIID(riid
, &IID_NULL
))
371 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid
));
372 return DISP_E_UNKNOWNNAME
;
375 if (wFlags
& DISPATCH_PROPERTYGET
&& !pVarResult
)
377 ERR("NULL pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
378 return DISP_E_PARAMNOTOPTIONAL
;
381 /* This simplifies our individual object invocation functions */
382 if (puArgErr
== NULL
) puArgErr
= &uArgErr
;
383 if (pVarResult
== NULL
) pVarResult
= &varResultDummy
;
385 /* Assume return type is void unless determined otherwise */
386 VariantInit(pVarResult
);
388 /* If we are tracing, we want to see the name of the member we are invoking */
391 ITypeInfo_GetDocumentation(This
->iTypeInfo
, dispIdMember
, &bstrName
, NULL
, NULL
, NULL
);
392 TRACE("Method %d, %s\n", dispIdMember
, debugstr_w(bstrName
));
395 hr
= This
->funcInvoke(This
,dispIdMember
,riid
,lcid
,wFlags
,pDispParams
,pVarResult
,pExcepInfo
,puArgErr
);
397 if (hr
== DISP_E_MEMBERNOTFOUND
) {
398 if (bstrName
== NULL
) ITypeInfo_GetDocumentation(This
->iTypeInfo
, dispIdMember
, &bstrName
, NULL
, NULL
, NULL
);
399 FIXME("Method %d, %s wflags %d not implemented, clsid %s\n", dispIdMember
, debugstr_w(bstrName
), wFlags
, debugstr_guid(This
->clsid
));
401 else if (pExcepInfo
&&
402 (hr
== DISP_E_PARAMNOTFOUND
||
403 hr
== DISP_E_EXCEPTION
)) {
404 static const WCHAR szComma
[] = { ',',0 };
405 static WCHAR szExceptionSource
[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
406 WCHAR szExceptionDescription
[MAX_PATH
];
407 BSTR bstrParamNames
[MAX_FUNC_PARAMS
];
411 if (FAILED(ITypeInfo_GetNames(This
->iTypeInfo
, dispIdMember
, bstrParamNames
,
412 MAX_FUNC_PARAMS
, &namesNo
)))
414 TRACE("Failed to retrieve names for dispIdMember %d\n", dispIdMember
);
418 memset(szExceptionDescription
, 0, sizeof(szExceptionDescription
));
419 for (i
=0; i
<namesNo
; i
++)
421 if (bFirst
) bFirst
= FALSE
;
423 lstrcpyW(&szExceptionDescription
[lstrlenW(szExceptionDescription
)], szComma
);
425 lstrcpyW(&szExceptionDescription
[lstrlenW(szExceptionDescription
)], bstrParamNames
[i
]);
426 SysFreeString(bstrParamNames
[i
]);
429 memset(pExcepInfo
, 0, sizeof(EXCEPINFO
));
430 pExcepInfo
->wCode
= 1000;
431 pExcepInfo
->bstrSource
= SysAllocString(szExceptionSource
);
432 pExcepInfo
->bstrDescription
= SysAllocString(szExceptionDescription
);
433 hr
= DISP_E_EXCEPTION
;
437 /* Make sure we free the return variant if it is our dummy variant */
438 if (pVarResult
== &varResultDummy
) VariantClear(pVarResult
);
440 /* Free function name if we retrieved it */
441 if (bstrName
) SysFreeString(bstrName
);
443 TRACE("Returning 0x%08x, %s\n", hr
, SUCCEEDED(hr
) ? "ok" : "not ok");
448 static const struct IDispatchVtbl AutomationObject_Vtbl
=
450 AutomationObject_QueryInterface
,
451 AutomationObject_AddRef
,
452 AutomationObject_Release
,
453 AutomationObject_GetTypeInfoCount
,
454 AutomationObject_GetTypeInfo
,
455 AutomationObject_GetIDsOfNames
,
456 AutomationObject_Invoke
460 * IProvideMultipleClassInfo methods
463 static HRESULT WINAPI
AutomationObject_IProvideMultipleClassInfo_QueryInterface(
464 IProvideMultipleClassInfo
* iface
,
468 AutomationObject
*This
= obj_from_IProvideMultipleClassInfo(iface
);
469 return AutomationObject_QueryInterface((IDispatch
*)This
, riid
, ppvoid
);
472 static ULONG WINAPI
AutomationObject_IProvideMultipleClassInfo_AddRef(IProvideMultipleClassInfo
* iface
)
474 AutomationObject
*This
= obj_from_IProvideMultipleClassInfo(iface
);
475 return AutomationObject_AddRef((IDispatch
*)This
);
478 static ULONG WINAPI
AutomationObject_IProvideMultipleClassInfo_Release(IProvideMultipleClassInfo
* iface
)
480 AutomationObject
*This
= obj_from_IProvideMultipleClassInfo(iface
);
481 return AutomationObject_Release((IDispatch
*)This
);
484 static HRESULT WINAPI
AutomationObject_IProvideMultipleClassInfo_GetClassInfo(IProvideMultipleClassInfo
* iface
, ITypeInfo
** ppTI
)
486 AutomationObject
*This
= obj_from_IProvideMultipleClassInfo(iface
);
487 TRACE("(%p/%p)->(%p)\n", iface
, This
, ppTI
);
488 return load_type_info((IDispatch
*)This
, ppTI
, This
->clsid
, 0);
491 static HRESULT WINAPI
AutomationObject_IProvideMultipleClassInfo_GetGUID(IProvideMultipleClassInfo
* iface
, DWORD dwGuidKind
, GUID
* pGUID
)
493 AutomationObject
*This
= obj_from_IProvideMultipleClassInfo(iface
);
494 TRACE("(%p/%p)->(%d,%s)\n", iface
, This
, dwGuidKind
, debugstr_guid(pGUID
));
496 if (dwGuidKind
!= GUIDKIND_DEFAULT_SOURCE_DISP_IID
)
499 *pGUID
= *This
->clsid
;
504 static HRESULT WINAPI
AutomationObject_GetMultiTypeInfoCount(IProvideMultipleClassInfo
* iface
, ULONG
* pcti
)
506 AutomationObject
*This
= obj_from_IProvideMultipleClassInfo(iface
);
508 TRACE("(%p/%p)->(%p)\n", iface
, This
, pcti
);
513 static HRESULT WINAPI
AutomationObject_GetInfoOfIndex(IProvideMultipleClassInfo
* iface
,
516 ITypeInfo
** pptiCoClass
,
518 ULONG
* pcdispidReserved
,
522 AutomationObject
*This
= obj_from_IProvideMultipleClassInfo(iface
);
524 TRACE("(%p/%p)->(%d,%d,%p,%p,%p,%p,%p)\n", iface
, This
, iti
, dwFlags
, pptiCoClass
, pdwTIFlags
, pcdispidReserved
, piidPrimary
, piidSource
);
529 if (dwFlags
& MULTICLASSINFO_GETTYPEINFO
)
530 load_type_info((IDispatch
*)This
, pptiCoClass
, This
->clsid
, 0);
532 if (dwFlags
& MULTICLASSINFO_GETNUMRESERVEDDISPIDS
)
535 *pcdispidReserved
= 0;
538 if (dwFlags
& MULTICLASSINFO_GETIIDPRIMARY
){
539 *piidPrimary
= *This
->clsid
;
542 if (dwFlags
& MULTICLASSINFO_GETIIDSOURCE
){
543 *piidSource
= *This
->clsid
;
549 static const IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl
=
551 AutomationObject_IProvideMultipleClassInfo_QueryInterface
,
552 AutomationObject_IProvideMultipleClassInfo_AddRef
,
553 AutomationObject_IProvideMultipleClassInfo_Release
,
554 AutomationObject_IProvideMultipleClassInfo_GetClassInfo
,
555 AutomationObject_IProvideMultipleClassInfo_GetGUID
,
556 AutomationObject_GetMultiTypeInfoCount
,
557 AutomationObject_GetInfoOfIndex
561 * ListEnumerator methods
564 /*** IUnknown methods ***/
565 static HRESULT WINAPI
ListEnumerator_QueryInterface(IEnumVARIANT
* iface
, REFIID riid
, void** ppvObject
)
567 ListEnumerator
*This
= (ListEnumerator
*)iface
;
569 TRACE("(%p/%p)->(%s,%p)\n", iface
, This
, debugstr_guid(riid
), ppvObject
);
571 if (ppvObject
== NULL
)
576 if (IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_IEnumVARIANT
))
580 TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid
));
581 return E_NOINTERFACE
;
584 IClassFactory_AddRef(iface
);
588 static ULONG WINAPI
ListEnumerator_AddRef(IEnumVARIANT
* iface
)
590 ListEnumerator
*This
= (ListEnumerator
*)iface
;
592 TRACE("(%p/%p)\n", iface
, This
);
594 return InterlockedIncrement(&This
->ref
);
597 static ULONG WINAPI
ListEnumerator_Release(IEnumVARIANT
* iface
)
599 ListEnumerator
*This
= (ListEnumerator
*)iface
;
600 ULONG ref
= InterlockedDecrement(&This
->ref
);
602 TRACE("(%p/%p)\n", iface
, This
);
606 if (This
->pObj
) IDispatch_Release((IDispatch
*)This
->pObj
);
607 HeapFree(GetProcessHeap(), 0, This
);
613 /* IEnumVARIANT methods */
615 static HRESULT WINAPI
ListEnumerator_Next(IEnumVARIANT
* iface
, ULONG celt
, VARIANT
*rgVar
, ULONG
*pCeltFetched
)
617 ListEnumerator
*This
= (ListEnumerator
*)iface
;
618 ListData
*data
= (ListData
*)private_data(This
->pObj
);
621 TRACE("(%p,%uld,%p,%p)\n", iface
, celt
, rgVar
, pCeltFetched
);
623 if (pCeltFetched
!= NULL
)
629 for (local
= 0; local
< celt
; local
++)
630 VariantInit(&rgVar
[local
]);
632 for (idx
= This
->ulPos
, local
= 0; idx
< data
->ulCount
&& local
< celt
; idx
++, local
++)
633 VariantCopy(&rgVar
[local
], &data
->pVars
[idx
]);
635 if (pCeltFetched
!= NULL
)
636 *pCeltFetched
= local
;
639 return (local
< celt
) ? S_FALSE
: S_OK
;
642 static HRESULT WINAPI
ListEnumerator_Skip(IEnumVARIANT
* iface
, ULONG celt
)
644 ListEnumerator
*This
= (ListEnumerator
*)iface
;
645 ListData
*data
= (ListData
*)private_data(This
->pObj
);
647 TRACE("(%p,%uld)\n", iface
, celt
);
650 if (This
->ulPos
>= data
->ulCount
)
652 This
->ulPos
= data
->ulCount
;
658 static HRESULT WINAPI
ListEnumerator_Reset(IEnumVARIANT
* iface
)
660 ListEnumerator
*This
= (ListEnumerator
*)iface
;
662 TRACE("(%p)\n", iface
);
668 static HRESULT WINAPI
ListEnumerator_Clone(IEnumVARIANT
* iface
, IEnumVARIANT
**ppEnum
)
670 ListEnumerator
*This
= (ListEnumerator
*)iface
;
673 TRACE("(%p,%p)\n", iface
, ppEnum
);
679 hr
= create_list_enumerator(NULL
, (LPVOID
*)ppEnum
, This
->pObj
, 0);
683 IUnknown_Release(*ppEnum
);
690 static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl
=
692 ListEnumerator_QueryInterface
,
693 ListEnumerator_AddRef
,
694 ListEnumerator_Release
,
697 ListEnumerator_Reset
,
702 * Individual Object Invocation Functions
705 /* Helper function that copies a passed parameter instead of using VariantChangeType like the actual DispGetParam.
706 This function is only for VARIANT type parameters that have several types that cannot be properly discriminated
707 using DispGetParam/VariantChangeType. */
708 static HRESULT WINAPI
DispGetParam_CopyOnly(
709 DISPPARAMS
*pdispparams
, /* [in] Parameter list */
710 UINT
*position
, /* [in] Position of parameter to copy in pdispparams; on return will contain calculated position */
711 VARIANT
*pvarResult
) /* [out] Destination for resulting variant */
713 /* position is counted backwards */
716 TRACE("position=%d, cArgs=%d, cNamedArgs=%d\n",
717 *position
, pdispparams
->cArgs
, pdispparams
->cNamedArgs
);
718 if (*position
< pdispparams
->cArgs
) {
719 /* positional arg? */
720 pos
= pdispparams
->cArgs
- *position
- 1;
722 /* FIXME: is this how to handle named args? */
723 for (pos
=0; pos
<pdispparams
->cNamedArgs
; pos
++)
724 if (pdispparams
->rgdispidNamedArgs
[pos
] == *position
) break;
726 if (pos
==pdispparams
->cNamedArgs
)
727 return DISP_E_PARAMNOTFOUND
;
730 return VariantCopyInd(pvarResult
,
731 &pdispparams
->rgvarg
[pos
]);
734 static HRESULT WINAPI
SummaryInfoImpl_Invoke(
735 AutomationObject
* This
,
740 DISPPARAMS
* pDispParams
,
742 EXCEPINFO
* pExcepInfo
,
746 VARIANTARG varg0
, varg1
;
747 FILETIME ft
, ftlocal
;
754 switch (dispIdMember
)
756 case DISPID_SUMMARYINFO_PROPERTY
:
757 if (wFlags
& DISPATCH_PROPERTYGET
)
765 static WCHAR szEmpty
[] = {0};
767 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
768 if (FAILED(hr
)) return hr
;
769 ret
= MsiSummaryInfoGetPropertyW(This
->msiHandle
, V_I4(&varg0
), &type
, &value
,
770 &ft
, szEmpty
, &size
);
771 if (ret
!= ERROR_SUCCESS
&&
772 ret
!= ERROR_MORE_DATA
)
774 ERR("MsiSummaryInfoGetProperty returned %d\n", ret
);
775 return DISP_E_EXCEPTION
;
785 V_VT(pVarResult
) = VT_I4
;
786 V_I4(pVarResult
) = value
;
790 if (!(str
= msi_alloc(++size
* sizeof(WCHAR
))))
791 ERR("Out of memory\n");
792 else if ((ret
= MsiSummaryInfoGetPropertyW(This
->msiHandle
, V_I4(&varg0
), &type
, NULL
,
793 NULL
, str
, &size
)) != ERROR_SUCCESS
)
794 ERR("MsiSummaryInfoGetProperty returned %d\n", ret
);
797 V_VT(pVarResult
) = VT_BSTR
;
798 V_BSTR(pVarResult
) = SysAllocString(str
);
804 FileTimeToLocalFileTime(&ft
, &ftlocal
);
805 FileTimeToSystemTime(&ftlocal
, &st
);
806 SystemTimeToVariantTime(&st
, &date
);
808 V_VT(pVarResult
) = VT_DATE
;
809 V_DATE(pVarResult
) = date
;
813 ERR("Unhandled variant type %d\n", type
);
816 else if (wFlags
& DISPATCH_PROPERTYPUT
)
818 UINT posValue
= DISPID_PROPERTYPUT
;
820 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
821 if (FAILED(hr
)) return hr
;
822 hr
= DispGetParam_CopyOnly(pDispParams
, &posValue
, &varg1
);
825 *puArgErr
= posValue
;
829 switch (V_VT(&varg1
))
833 ret
= MsiSummaryInfoSetPropertyW(This
->msiHandle
, V_I4(&varg0
), V_VT(&varg1
), V_I4(&varg1
), NULL
, NULL
);
837 VariantTimeToSystemTime(V_DATE(&varg1
), &st
);
838 SystemTimeToFileTime(&st
, &ftlocal
);
839 LocalFileTimeToFileTime(&ftlocal
, &ft
);
840 ret
= MsiSummaryInfoSetPropertyW(This
->msiHandle
, V_I4(&varg0
), VT_FILETIME
, 0, &ft
, NULL
);
844 ret
= MsiSummaryInfoSetPropertyW(This
->msiHandle
, V_I4(&varg0
), VT_LPSTR
, 0, NULL
, V_BSTR(&varg1
));
848 FIXME("Unhandled variant type %d\n", V_VT(&varg1
));
849 VariantClear(&varg1
);
850 return DISP_E_EXCEPTION
;
853 if (ret
!= ERROR_SUCCESS
)
855 ERR("MsiSummaryInfoSetPropertyW returned %d\n", ret
);
856 return DISP_E_EXCEPTION
;
859 else return DISP_E_MEMBERNOTFOUND
;
862 case DISPID_SUMMARYINFO_PROPERTYCOUNT
:
863 if (wFlags
& DISPATCH_PROPERTYGET
) {
865 if ((ret
= MsiSummaryInfoGetPropertyCount(This
->msiHandle
, &count
)) != ERROR_SUCCESS
)
866 ERR("MsiSummaryInfoGetPropertyCount returned %d\n", ret
);
869 V_VT(pVarResult
) = VT_I4
;
870 V_I4(pVarResult
) = count
;
873 else return DISP_E_MEMBERNOTFOUND
;
877 return DISP_E_MEMBERNOTFOUND
;
880 VariantClear(&varg1
);
881 VariantClear(&varg0
);
886 static HRESULT WINAPI
RecordImpl_Invoke(
887 AutomationObject
* This
,
892 DISPPARAMS
* pDispParams
,
894 EXCEPINFO
* pExcepInfo
,
900 VARIANTARG varg0
, varg1
;
906 switch (dispIdMember
)
908 case DISPID_RECORD_FIELDCOUNT
:
909 if (wFlags
& DISPATCH_PROPERTYGET
) {
910 V_VT(pVarResult
) = VT_I4
;
911 V_I4(pVarResult
) = MsiRecordGetFieldCount(This
->msiHandle
);
913 else return DISP_E_MEMBERNOTFOUND
;
916 case DISPID_RECORD_STRINGDATA
:
917 if (wFlags
& DISPATCH_PROPERTYGET
) {
918 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
919 if (FAILED(hr
)) return hr
;
920 V_VT(pVarResult
) = VT_BSTR
;
921 V_BSTR(pVarResult
) = NULL
;
922 if ((ret
= MsiRecordGetStringW(This
->msiHandle
, V_I4(&varg0
), NULL
, &dwLen
)) == ERROR_SUCCESS
)
924 if (!(szString
= msi_alloc((++dwLen
)*sizeof(WCHAR
))))
925 ERR("Out of memory\n");
926 else if ((ret
= MsiRecordGetStringW(This
->msiHandle
, V_I4(&varg0
), szString
, &dwLen
)) == ERROR_SUCCESS
)
927 V_BSTR(pVarResult
) = SysAllocString(szString
);
930 if (ret
!= ERROR_SUCCESS
)
931 ERR("MsiRecordGetString returned %d\n", ret
);
932 } else if (wFlags
& DISPATCH_PROPERTYPUT
) {
933 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
934 if (FAILED(hr
)) return hr
;
935 hr
= DispGetParam(pDispParams
, DISPID_PROPERTYPUT
, VT_BSTR
, &varg1
, puArgErr
);
936 if (FAILED(hr
)) return hr
;
937 if ((ret
= MsiRecordSetStringW(This
->msiHandle
, V_I4(&varg0
), V_BSTR(&varg1
))) != ERROR_SUCCESS
)
939 VariantClear(&varg1
);
940 ERR("MsiRecordSetString returned %d\n", ret
);
941 return DISP_E_EXCEPTION
;
944 else return DISP_E_MEMBERNOTFOUND
;
947 case DISPID_RECORD_INTEGERDATA
:
948 if (wFlags
& DISPATCH_PROPERTYGET
) {
949 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
950 if (FAILED(hr
)) return hr
;
951 V_VT(pVarResult
) = VT_I4
;
952 V_I4(pVarResult
) = MsiRecordGetInteger(This
->msiHandle
, V_I4(&varg0
));
953 } else if (wFlags
& DISPATCH_PROPERTYPUT
) {
954 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
955 if (FAILED(hr
)) return hr
;
956 hr
= DispGetParam(pDispParams
, DISPID_PROPERTYPUT
, VT_I4
, &varg1
, puArgErr
);
957 if (FAILED(hr
)) return hr
;
958 if ((ret
= MsiRecordSetInteger(This
->msiHandle
, V_I4(&varg0
), V_I4(&varg1
))) != ERROR_SUCCESS
)
960 ERR("MsiRecordSetInteger returned %d\n", ret
);
961 return DISP_E_EXCEPTION
;
964 else return DISP_E_MEMBERNOTFOUND
;
968 return DISP_E_MEMBERNOTFOUND
;
971 VariantClear(&varg1
);
972 VariantClear(&varg0
);
977 static HRESULT WINAPI
ListImpl_Invoke(
978 AutomationObject
* This
,
983 DISPPARAMS
* pDispParams
,
985 EXCEPINFO
* pExcepInfo
,
988 ListData
*data
= (ListData
*)private_data(This
);
991 IUnknown
*pUnk
= NULL
;
995 switch (dispIdMember
)
997 case DISPID_LIST__NEWENUM
:
998 if (wFlags
& DISPATCH_METHOD
) {
999 V_VT(pVarResult
) = VT_UNKNOWN
;
1000 if (SUCCEEDED(hr
= create_list_enumerator(NULL
, (LPVOID
*)&pUnk
, This
, 0)))
1001 V_UNKNOWN(pVarResult
) = pUnk
;
1003 ERR("Failed to create IEnumVARIANT object, hresult 0x%08x\n", hr
);
1005 else return DISP_E_MEMBERNOTFOUND
;
1008 case DISPID_LIST_ITEM
:
1009 if (wFlags
& DISPATCH_PROPERTYGET
) {
1010 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
1011 if (FAILED(hr
)) return hr
;
1012 if (V_I4(&varg0
) < 0 || V_I4(&varg0
) >= data
->ulCount
)
1013 return DISP_E_BADINDEX
;
1014 VariantCopy(pVarResult
, &data
->pVars
[V_I4(&varg0
)]);
1016 else return DISP_E_MEMBERNOTFOUND
;
1019 case DISPID_LIST_COUNT
:
1020 if (wFlags
& DISPATCH_PROPERTYGET
) {
1021 V_VT(pVarResult
) = VT_I4
;
1022 V_I4(pVarResult
) = data
->ulCount
;
1024 else return DISP_E_MEMBERNOTFOUND
;
1028 return DISP_E_MEMBERNOTFOUND
;
1031 VariantClear(&varg0
);
1036 static void WINAPI
ListImpl_Free(AutomationObject
*This
)
1038 ListData
*data
= private_data(This
);
1041 for (idx
=0; idx
<data
->ulCount
; idx
++)
1042 VariantClear(&data
->pVars
[idx
]);
1043 HeapFree(GetProcessHeap(), 0, data
->pVars
);
1046 static HRESULT WINAPI
ViewImpl_Invoke(
1047 AutomationObject
* This
,
1048 DISPID dispIdMember
,
1052 DISPPARAMS
* pDispParams
,
1053 VARIANT
* pVarResult
,
1054 EXCEPINFO
* pExcepInfo
,
1057 MSIHANDLE msiHandle
;
1058 IDispatch
*pDispatch
= NULL
;
1060 VARIANTARG varg0
, varg1
;
1063 VariantInit(&varg0
);
1064 VariantInit(&varg1
);
1066 switch (dispIdMember
)
1068 case DISPID_VIEW_EXECUTE
:
1069 if (wFlags
& DISPATCH_METHOD
)
1071 hr
= DispGetParam(pDispParams
, 0, VT_DISPATCH
, &varg0
, puArgErr
);
1072 if (SUCCEEDED(hr
) && V_DISPATCH(&varg0
) != NULL
)
1073 MsiViewExecute(This
->msiHandle
, ((AutomationObject
*)V_DISPATCH(&varg0
))->msiHandle
);
1075 MsiViewExecute(This
->msiHandle
, 0);
1077 else return DISP_E_MEMBERNOTFOUND
;
1080 case DISPID_VIEW_FETCH
:
1081 if (wFlags
& DISPATCH_METHOD
)
1083 V_VT(pVarResult
) = VT_DISPATCH
;
1084 if ((ret
= MsiViewFetch(This
->msiHandle
, &msiHandle
)) == ERROR_SUCCESS
)
1086 if (SUCCEEDED(hr
= create_automation_object(msiHandle
, NULL
, (LPVOID
*)&pDispatch
, &DIID_Record
, RecordImpl_Invoke
, NULL
, 0)))
1087 V_DISPATCH(pVarResult
) = pDispatch
;
1089 ERR("Failed to create Record object, hresult 0x%08x\n", hr
);
1091 else if (ret
== ERROR_NO_MORE_ITEMS
)
1092 V_DISPATCH(pVarResult
) = NULL
;
1095 ERR("MsiViewFetch returned %d\n", ret
);
1096 return DISP_E_EXCEPTION
;
1099 else return DISP_E_MEMBERNOTFOUND
;
1102 case DISPID_VIEW_MODIFY
:
1103 if (wFlags
& DISPATCH_METHOD
)
1105 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
1106 if (FAILED(hr
)) return hr
;
1107 hr
= DispGetParam(pDispParams
, 1, VT_DISPATCH
, &varg1
, puArgErr
);
1108 if (FAILED(hr
)) return hr
;
1109 if (!V_DISPATCH(&varg1
)) return DISP_E_EXCEPTION
;
1110 if ((ret
= MsiViewModify(This
->msiHandle
, V_I4(&varg0
), ((AutomationObject
*)V_DISPATCH(&varg1
))->msiHandle
)) != ERROR_SUCCESS
)
1112 VariantClear(&varg1
);
1113 ERR("MsiViewModify returned %d\n", ret
);
1114 return DISP_E_EXCEPTION
;
1117 else return DISP_E_MEMBERNOTFOUND
;
1120 case DISPID_VIEW_CLOSE
:
1121 if (wFlags
& DISPATCH_METHOD
)
1123 MsiViewClose(This
->msiHandle
);
1125 else return DISP_E_MEMBERNOTFOUND
;
1129 return DISP_E_MEMBERNOTFOUND
;
1132 VariantClear(&varg1
);
1133 VariantClear(&varg0
);
1138 static HRESULT WINAPI
DatabaseImpl_Invoke(
1139 AutomationObject
* This
,
1140 DISPID dispIdMember
,
1144 DISPPARAMS
* pDispParams
,
1145 VARIANT
* pVarResult
,
1146 EXCEPINFO
* pExcepInfo
,
1149 MSIHANDLE msiHandle
;
1150 IDispatch
*pDispatch
= NULL
;
1152 VARIANTARG varg0
, varg1
;
1155 VariantInit(&varg0
);
1156 VariantInit(&varg1
);
1158 switch (dispIdMember
)
1160 case DISPID_DATABASE_SUMMARYINFORMATION
:
1161 if (wFlags
& DISPATCH_PROPERTYGET
)
1163 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
1167 V_VT(pVarResult
) = VT_DISPATCH
;
1168 if ((ret
= MsiGetSummaryInformationW(This
->msiHandle
, NULL
, V_I4(&varg0
), &msiHandle
)) == ERROR_SUCCESS
)
1170 hr
= create_automation_object(msiHandle
, NULL
, (LPVOID
*)&pDispatch
, &DIID_SummaryInfo
, SummaryInfoImpl_Invoke
, NULL
, 0);
1172 V_DISPATCH(pVarResult
) = pDispatch
;
1174 ERR("Failed to create SummaryInfo object: 0x%08x\n", hr
);
1178 ERR("MsiGetSummaryInformation returned %d\n", ret
);
1179 return DISP_E_EXCEPTION
;
1182 else return DISP_E_MEMBERNOTFOUND
;
1185 case DISPID_DATABASE_OPENVIEW
:
1186 if (wFlags
& DISPATCH_METHOD
)
1188 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1189 if (FAILED(hr
)) return hr
;
1190 V_VT(pVarResult
) = VT_DISPATCH
;
1191 if ((ret
= MsiDatabaseOpenViewW(This
->msiHandle
, V_BSTR(&varg0
), &msiHandle
)) == ERROR_SUCCESS
)
1193 if (SUCCEEDED(hr
= create_automation_object(msiHandle
, NULL
, (LPVOID
*)&pDispatch
, &DIID_View
, ViewImpl_Invoke
, NULL
, 0)))
1194 V_DISPATCH(pVarResult
) = pDispatch
;
1196 ERR("Failed to create View object, hresult 0x%08x\n", hr
);
1200 VariantClear(&varg0
);
1201 ERR("MsiDatabaseOpenView returned %d\n", ret
);
1202 return DISP_E_EXCEPTION
;
1205 else return DISP_E_MEMBERNOTFOUND
;
1209 return DISP_E_MEMBERNOTFOUND
;
1212 VariantClear(&varg1
);
1213 VariantClear(&varg0
);
1218 static HRESULT WINAPI
SessionImpl_Invoke(
1219 AutomationObject
* This
,
1220 DISPID dispIdMember
,
1224 DISPPARAMS
* pDispParams
,
1225 VARIANT
* pVarResult
,
1226 EXCEPINFO
* pExcepInfo
,
1229 SessionData
*data
= private_data(This
);
1232 IDispatch
*pDispatch
= NULL
;
1233 MSIHANDLE msiHandle
;
1236 INSTALLSTATE iInstalled
, iAction
;
1237 VARIANTARG varg0
, varg1
;
1240 VariantInit(&varg0
);
1241 VariantInit(&varg1
);
1243 switch (dispIdMember
)
1245 case DISPID_SESSION_INSTALLER
:
1246 if (wFlags
& DISPATCH_PROPERTYGET
) {
1247 V_VT(pVarResult
) = VT_DISPATCH
;
1248 IDispatch_AddRef(data
->pInstaller
);
1249 V_DISPATCH(pVarResult
) = data
->pInstaller
;
1251 else return DISP_E_MEMBERNOTFOUND
;
1254 case DISPID_SESSION_PROPERTY
:
1255 if (wFlags
& DISPATCH_PROPERTYGET
) {
1256 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1257 if (FAILED(hr
)) return hr
;
1258 V_VT(pVarResult
) = VT_BSTR
;
1259 V_BSTR(pVarResult
) = NULL
;
1260 if ((ret
= MsiGetPropertyW(This
->msiHandle
, V_BSTR(&varg0
), NULL
, &dwLen
)) == ERROR_SUCCESS
)
1262 if (!(szString
= msi_alloc((++dwLen
)*sizeof(WCHAR
))))
1263 ERR("Out of memory\n");
1264 else if ((ret
= MsiGetPropertyW(This
->msiHandle
, V_BSTR(&varg0
), szString
, &dwLen
)) == ERROR_SUCCESS
)
1265 V_BSTR(pVarResult
) = SysAllocString(szString
);
1268 if (ret
!= ERROR_SUCCESS
)
1269 ERR("MsiGetProperty returned %d\n", ret
);
1270 } else if (wFlags
& DISPATCH_PROPERTYPUT
) {
1271 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1272 if (FAILED(hr
)) return hr
;
1273 hr
= DispGetParam(pDispParams
, DISPID_PROPERTYPUT
, VT_BSTR
, &varg1
, puArgErr
);
1275 VariantClear(&varg0
);
1278 if ((ret
= MsiSetPropertyW(This
->msiHandle
, V_BSTR(&varg0
), V_BSTR(&varg1
))) != ERROR_SUCCESS
)
1280 VariantClear(&varg0
);
1281 VariantClear(&varg1
);
1282 ERR("MsiSetProperty returned %d\n", ret
);
1283 return DISP_E_EXCEPTION
;
1286 else return DISP_E_MEMBERNOTFOUND
;
1289 case DISPID_SESSION_LANGUAGE
:
1290 if (wFlags
& DISPATCH_PROPERTYGET
) {
1291 langId
= MsiGetLanguage(This
->msiHandle
);
1292 V_VT(pVarResult
) = VT_I4
;
1293 V_I4(pVarResult
) = langId
;
1295 else return DISP_E_MEMBERNOTFOUND
;
1298 case DISPID_SESSION_MODE
:
1299 if (wFlags
& DISPATCH_PROPERTYGET
) {
1300 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
1301 if (FAILED(hr
)) return hr
;
1302 V_VT(pVarResult
) = VT_BOOL
;
1303 V_BOOL(pVarResult
) = MsiGetMode(This
->msiHandle
, V_I4(&varg0
));
1304 } else if (wFlags
& DISPATCH_PROPERTYPUT
) {
1305 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
1306 if (FAILED(hr
)) return hr
;
1307 hr
= DispGetParam(pDispParams
, DISPID_PROPERTYPUT
, VT_BOOL
, &varg1
, puArgErr
);
1308 if (FAILED(hr
)) return hr
;
1309 if ((ret
= MsiSetMode(This
->msiHandle
, V_I4(&varg0
), V_BOOL(&varg1
))) != ERROR_SUCCESS
)
1311 ERR("MsiSetMode returned %d\n", ret
);
1312 return DISP_E_EXCEPTION
;
1315 else return DISP_E_MEMBERNOTFOUND
;
1318 case DISPID_SESSION_DATABASE
:
1319 if (wFlags
& DISPATCH_PROPERTYGET
) {
1320 V_VT(pVarResult
) = VT_DISPATCH
;
1321 if ((msiHandle
= MsiGetActiveDatabase(This
->msiHandle
)))
1323 if (SUCCEEDED(hr
= create_automation_object(msiHandle
, NULL
, (LPVOID
*)&pDispatch
, &DIID_Database
, DatabaseImpl_Invoke
, NULL
, 0)))
1324 V_DISPATCH(pVarResult
) = pDispatch
;
1326 ERR("Failed to create Database object, hresult 0x%08x\n", hr
);
1330 ERR("MsiGetActiveDatabase failed\n");
1331 return DISP_E_EXCEPTION
;
1334 else return DISP_E_MEMBERNOTFOUND
;
1337 case DISPID_SESSION_DOACTION
:
1338 if (wFlags
& DISPATCH_METHOD
) {
1339 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1340 if (FAILED(hr
)) return hr
;
1341 ret
= MsiDoActionW(This
->msiHandle
, V_BSTR(&varg0
));
1342 V_VT(pVarResult
) = VT_I4
;
1345 case ERROR_FUNCTION_NOT_CALLED
:
1346 V_I4(pVarResult
) = msiDoActionStatusNoAction
;
1349 V_I4(pVarResult
) = msiDoActionStatusSuccess
;
1351 case ERROR_INSTALL_USEREXIT
:
1352 V_I4(pVarResult
) = msiDoActionStatusUserExit
;
1354 case ERROR_INSTALL_FAILURE
:
1355 V_I4(pVarResult
) = msiDoActionStatusFailure
;
1357 case ERROR_INSTALL_SUSPEND
:
1358 V_I4(pVarResult
) = msiDoActionStatusSuspend
;
1360 case ERROR_MORE_DATA
:
1361 V_I4(pVarResult
) = msiDoActionStatusFinished
;
1363 case ERROR_INVALID_HANDLE_STATE
:
1364 V_I4(pVarResult
) = msiDoActionStatusWrongState
;
1366 case ERROR_INVALID_DATA
:
1367 V_I4(pVarResult
) = msiDoActionStatusBadActionData
;
1370 VariantClear(&varg0
);
1371 FIXME("MsiDoAction returned unhandled value %d\n", ret
);
1372 return DISP_E_EXCEPTION
;
1375 else return DISP_E_MEMBERNOTFOUND
;
1378 case DISPID_SESSION_EVALUATECONDITION
:
1379 if (wFlags
& DISPATCH_METHOD
) {
1380 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1381 if (FAILED(hr
)) return hr
;
1382 V_VT(pVarResult
) = VT_I4
;
1383 V_I4(pVarResult
) = MsiEvaluateConditionW(This
->msiHandle
, V_BSTR(&varg0
));
1385 else return DISP_E_MEMBERNOTFOUND
;
1388 case DISPID_SESSION_SETINSTALLLEVEL
:
1389 if (wFlags
& DISPATCH_METHOD
) {
1390 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
1391 if (FAILED(hr
)) return hr
;
1392 if ((ret
= MsiSetInstallLevel(This
->msiHandle
, V_I4(&varg0
))) != ERROR_SUCCESS
)
1394 ERR("MsiSetInstallLevel returned %d\n", ret
);
1395 return DISP_E_EXCEPTION
;
1398 else return DISP_E_MEMBERNOTFOUND
;
1401 case DISPID_SESSION_FEATURECURRENTSTATE
:
1402 if (wFlags
& DISPATCH_PROPERTYGET
) {
1403 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1404 if (FAILED(hr
)) return hr
;
1405 V_VT(pVarResult
) = VT_I4
;
1406 if ((ret
= MsiGetFeatureStateW(This
->msiHandle
, V_BSTR(&varg0
), &iInstalled
, &iAction
)) == ERROR_SUCCESS
)
1407 V_I4(pVarResult
) = iInstalled
;
1410 ERR("MsiGetFeatureState returned %d\n", ret
);
1411 V_I4(pVarResult
) = msiInstallStateUnknown
;
1414 else return DISP_E_MEMBERNOTFOUND
;
1417 case DISPID_SESSION_FEATUREREQUESTSTATE
:
1418 if (wFlags
& DISPATCH_PROPERTYGET
) {
1419 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1420 if (FAILED(hr
)) return hr
;
1421 V_VT(pVarResult
) = VT_I4
;
1422 if ((ret
= MsiGetFeatureStateW(This
->msiHandle
, V_BSTR(&varg0
), &iInstalled
, &iAction
)) == ERROR_SUCCESS
)
1423 V_I4(pVarResult
) = iAction
;
1426 ERR("MsiGetFeatureState returned %d\n", ret
);
1427 V_I4(pVarResult
) = msiInstallStateUnknown
;
1429 } else if (wFlags
& DISPATCH_PROPERTYPUT
) {
1430 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1431 if (FAILED(hr
)) return hr
;
1432 hr
= DispGetParam(pDispParams
, DISPID_PROPERTYPUT
, VT_I4
, &varg1
, puArgErr
);
1434 VariantClear(&varg0
);
1437 if ((ret
= MsiSetFeatureStateW(This
->msiHandle
, V_BSTR(&varg0
), V_I4(&varg1
))) != ERROR_SUCCESS
)
1439 VariantClear(&varg0
);
1440 ERR("MsiSetFeatureState returned %d\n", ret
);
1441 return DISP_E_EXCEPTION
;
1444 else return DISP_E_MEMBERNOTFOUND
;
1448 return DISP_E_MEMBERNOTFOUND
;
1451 VariantClear(&varg1
);
1452 VariantClear(&varg0
);
1457 /* Fill the variant pointed to by pVarResult with the value & size returned by RegQueryValueEx as dictated by the
1458 * registry value type. Used by Installer::RegistryValue. */
1459 static void variant_from_registry_value(VARIANT
*pVarResult
, DWORD dwType
, LPBYTE lpData
, DWORD dwSize
)
1461 static const WCHAR szREG_BINARY
[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
1462 static const WCHAR szREG_
[] = { '(','R','E','G','_',']',0 };
1463 WCHAR
*szString
= (WCHAR
*)lpData
;
1464 LPWSTR szNewString
= NULL
;
1465 DWORD dwNewSize
= 0;
1470 /* Registry strings may not be null terminated so we must use SysAllocStringByteLen/Len */
1471 case REG_MULTI_SZ
: /* Multi SZ change internal null characters to newlines */
1472 idx
= (dwSize
/sizeof(WCHAR
))-1;
1473 while (idx
>= 0 && !szString
[idx
]) idx
--;
1474 for (; idx
>= 0; idx
--)
1475 if (!szString
[idx
]) szString
[idx
] = '\n';
1477 V_VT(pVarResult
) = VT_BSTR
;
1478 V_BSTR(pVarResult
) = SysAllocStringByteLen((LPCSTR
)szString
, dwSize
);
1482 if (!(dwNewSize
= ExpandEnvironmentStringsW(szString
, szNewString
, dwNewSize
)))
1483 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1484 else if (!(szNewString
= msi_alloc(dwNewSize
)))
1485 ERR("Out of memory\n");
1486 else if (!(dwNewSize
= ExpandEnvironmentStringsW(szString
, szNewString
, dwNewSize
)))
1487 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1490 V_VT(pVarResult
) = VT_BSTR
;
1491 V_BSTR(pVarResult
) = SysAllocStringLen(szNewString
, dwNewSize
);
1493 msi_free(szNewString
);
1497 V_VT(pVarResult
) = VT_I4
;
1498 V_I4(pVarResult
) = *((DWORD
*)lpData
);
1502 V_VT(pVarResult
) = VT_BSTR
;
1503 V_BSTR(pVarResult
) = SysAllocString(szREG_
); /* Weird string, don't know why native returns it */
1507 V_VT(pVarResult
) = VT_BSTR
;
1508 V_BSTR(pVarResult
) = SysAllocString(szREG_BINARY
);
1512 V_VT(pVarResult
) = VT_EMPTY
;
1516 FIXME("Unhandled registry value type %d\n", dwType
);
1520 static HRESULT WINAPI
InstallerImpl_Invoke(
1521 AutomationObject
* This
,
1522 DISPID dispIdMember
,
1526 DISPPARAMS
* pDispParams
,
1527 VARIANT
* pVarResult
,
1528 EXCEPINFO
* pExcepInfo
,
1531 MSIHANDLE msiHandle
;
1532 IDispatch
*pDispatch
= NULL
;
1534 VARIANTARG varg0
, varg1
, varg2
;
1536 LPWSTR szString
= NULL
;
1540 VariantInit(&varg0
);
1541 VariantInit(&varg1
);
1542 VariantInit(&varg2
);
1544 switch (dispIdMember
)
1546 case DISPID_INSTALLER_CREATERECORD
:
1547 if (wFlags
& DISPATCH_METHOD
)
1549 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
1550 if (FAILED(hr
)) return hr
;
1551 V_VT(pVarResult
) = VT_DISPATCH
;
1552 if ((msiHandle
= MsiCreateRecord(V_I4(&varg0
))))
1554 if (SUCCEEDED(hr
= create_automation_object(msiHandle
, NULL
, (LPVOID
*)&pDispatch
, &DIID_Record
, RecordImpl_Invoke
, NULL
, 0)))
1555 V_DISPATCH(pVarResult
) = pDispatch
;
1557 ERR("Failed to create Record object, hresult 0x%08x\n", hr
);
1561 ERR("MsiCreateRecord failed\n");
1562 return DISP_E_EXCEPTION
;
1565 else return DISP_E_MEMBERNOTFOUND
;
1568 case DISPID_INSTALLER_OPENPACKAGE
:
1569 if (wFlags
& DISPATCH_METHOD
)
1571 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1572 if (FAILED(hr
)) return hr
;
1573 hr
= DispGetParam(pDispParams
, 1, VT_I4
, &varg1
, puArgErr
);
1576 VariantClear(&varg0
);
1579 V_VT(pVarResult
) = VT_DISPATCH
;
1580 if ((ret
= MsiOpenPackageExW(V_BSTR(&varg0
), V_I4(&varg1
), &msiHandle
)) == ERROR_SUCCESS
)
1582 if (SUCCEEDED(hr
= create_session(msiHandle
, (IDispatch
*)This
, &pDispatch
)))
1583 V_DISPATCH(pVarResult
) = pDispatch
;
1585 ERR("Failed to create Session object, hresult 0x%08x\n", hr
);
1589 VariantClear(&varg0
);
1590 ERR("MsiOpenPackageEx returned %d\n", ret
);
1591 return DISP_E_EXCEPTION
;
1594 else return DISP_E_MEMBERNOTFOUND
;
1597 case DISPID_INSTALLER_OPENDATABASE
:
1598 if (wFlags
& DISPATCH_METHOD
)
1600 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1601 if (FAILED(hr
)) return hr
;
1603 hr
= DispGetParam(pDispParams
, 1, VT_BSTR
, &varg1
, puArgErr
);
1606 VariantClear(&varg0
);
1610 V_VT(pVarResult
) = VT_DISPATCH
;
1611 if ((ret
= MsiOpenDatabaseW(V_BSTR(&varg0
), V_BSTR(&varg1
), &msiHandle
)) == ERROR_SUCCESS
)
1613 hr
= create_automation_object(msiHandle
, NULL
, (LPVOID
*)&pDispatch
,
1614 &DIID_Database
, DatabaseImpl_Invoke
, NULL
, 0);
1616 V_DISPATCH(pVarResult
) = pDispatch
;
1618 ERR("Failed to create Database object: 0x%08x\n", hr
);
1622 VariantClear(&varg0
);
1623 VariantClear(&varg1
);
1624 ERR("MsiOpenDatabase returned %d\n", ret
);
1625 return DISP_E_EXCEPTION
;
1628 else return DISP_E_MEMBERNOTFOUND
;
1631 case DISPID_INSTALLER_UILEVEL
:
1632 if (wFlags
& DISPATCH_PROPERTYPUT
)
1634 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
1635 if (FAILED(hr
)) return hr
;
1636 if ((ui
= MsiSetInternalUI(V_I4(&varg0
), NULL
) == INSTALLUILEVEL_NOCHANGE
))
1638 ERR("MsiSetInternalUI failed\n");
1639 return DISP_E_EXCEPTION
;
1642 else if (wFlags
& DISPATCH_PROPERTYGET
)
1644 if ((ui
= MsiSetInternalUI(INSTALLUILEVEL_NOCHANGE
, NULL
) == INSTALLUILEVEL_NOCHANGE
))
1646 ERR("MsiSetInternalUI failed\n");
1647 return DISP_E_EXCEPTION
;
1650 V_VT(pVarResult
) = VT_I4
;
1651 V_I4(pVarResult
) = ui
;
1653 else return DISP_E_MEMBERNOTFOUND
;
1656 case DISPID_INSTALLER_INSTALLPRODUCT
:
1657 if (wFlags
& DISPATCH_METHOD
)
1659 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1660 if (FAILED(hr
)) return hr
;
1661 hr
= DispGetParam(pDispParams
, 1, VT_BSTR
, &varg1
, puArgErr
);
1664 VariantClear(&varg0
);
1667 if ((ret
= MsiInstallProductW(V_BSTR(&varg0
), V_BSTR(&varg1
))) != ERROR_SUCCESS
)
1669 VariantClear(&varg1
);
1670 VariantClear(&varg0
);
1671 ERR("MsiInstallProduct returned %d\n", ret
);
1672 return DISP_E_EXCEPTION
;
1675 else return DISP_E_MEMBERNOTFOUND
;
1678 case DISPID_INSTALLER_VERSION
:
1679 if (wFlags
& DISPATCH_PROPERTYGET
) {
1680 DLLVERSIONINFO verinfo
;
1681 WCHAR version
[MAX_PATH
];
1683 static const WCHAR format
[] = {'%','d','.','%','d','.','%','d','.','%','d',0};
1685 verinfo
.cbSize
= sizeof(DLLVERSIONINFO
);
1686 hr
= DllGetVersion(&verinfo
);
1687 if (FAILED(hr
)) return hr
;
1689 sprintfW(version
, format
, verinfo
.dwMajorVersion
, verinfo
.dwMinorVersion
,
1690 verinfo
.dwBuildNumber
, verinfo
.dwPlatformID
);
1692 V_VT(pVarResult
) = VT_BSTR
;
1693 V_BSTR(pVarResult
) = SysAllocString(version
);
1695 else return DISP_E_MEMBERNOTFOUND
;
1698 case DISPID_INSTALLER_REGISTRYVALUE
:
1699 if (wFlags
& DISPATCH_METHOD
) {
1702 UINT posValue
= 2; /* Save valuePos so we can save puArgErr if we are unable to do our type conversions */
1704 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
1705 if (FAILED(hr
)) return hr
;
1706 hr
= DispGetParam(pDispParams
, 1, VT_BSTR
, &varg1
, puArgErr
);
1707 if (FAILED(hr
)) return hr
;
1708 hr
= DispGetParam_CopyOnly(pDispParams
, &posValue
, &varg2
);
1711 VariantClear(&varg1
);
1714 ret
= RegOpenKeyW((HKEY
)V_I4(&varg0
), V_BSTR(&varg1
), &hkey
);
1716 /* Third parameter can be VT_EMPTY, VT_I4, or VT_BSTR */
1717 switch (V_VT(&varg2
))
1719 case VT_EMPTY
: /* Return VT_BOOL as to whether or not registry key exists */
1720 V_VT(pVarResult
) = VT_BOOL
;
1721 V_BOOL(pVarResult
) = (ret
== ERROR_SUCCESS
);
1724 case VT_BSTR
: /* Return value of specified key if it exists */
1725 if (ret
== ERROR_SUCCESS
&&
1726 (ret
= RegQueryValueExW(hkey
, V_BSTR(&varg2
), NULL
, NULL
, NULL
, &dwSize
)) == ERROR_SUCCESS
)
1728 if (!(szString
= msi_alloc(dwSize
)))
1729 ERR("Out of memory\n");
1730 else if ((ret
= RegQueryValueExW(hkey
, V_BSTR(&varg2
), NULL
, &dwType
, (LPBYTE
)szString
, &dwSize
)) == ERROR_SUCCESS
)
1731 variant_from_registry_value(pVarResult
, dwType
, (LPBYTE
)szString
, dwSize
);
1734 if (ret
!= ERROR_SUCCESS
)
1737 VariantClear(&varg2
);
1738 VariantClear(&varg1
);
1739 return DISP_E_BADINDEX
;
1743 default: /* Try to make it into VT_I4, can use VariantChangeType for this */
1744 hr
= VariantChangeType(&varg2
, &varg2
, 0, VT_I4
);
1745 if (SUCCEEDED(hr
) && ret
!= ERROR_SUCCESS
) hr
= DISP_E_BADINDEX
; /* Conversion fine, but couldn't find key */
1748 if (hr
== DISP_E_TYPEMISMATCH
) *puArgErr
= posValue
;
1749 VariantClear(&varg2
); /* Unknown type, so let's clear it */
1750 VariantClear(&varg1
);
1754 /* Retrieve class name or maximum value name or subkey name size */
1756 ret
= RegQueryInfoKeyW(hkey
, NULL
, &dwSize
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1757 else if (V_I4(&varg2
) > 0)
1758 ret
= RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &dwSize
, NULL
, NULL
, NULL
);
1759 else /* V_I4(&varg2) < 0 */
1760 ret
= RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, &dwSize
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1762 if (ret
== ERROR_SUCCESS
)
1764 if (!(szString
= msi_alloc(++dwSize
* sizeof(WCHAR
))))
1765 ERR("Out of memory\n");
1766 else if (!V_I4(&varg2
))
1767 ret
= RegQueryInfoKeyW(hkey
, szString
, &dwSize
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1768 else if (V_I4(&varg2
) > 0)
1769 ret
= RegEnumValueW(hkey
, V_I4(&varg2
)-1, szString
, &dwSize
, 0, 0, NULL
, NULL
);
1770 else /* V_I4(&varg2) < 0 */
1771 ret
= RegEnumKeyW(hkey
, -1 - V_I4(&varg2
), szString
, dwSize
);
1773 if (szString
&& ret
== ERROR_SUCCESS
)
1775 V_VT(pVarResult
) = VT_BSTR
;
1776 V_BSTR(pVarResult
) = SysAllocString(szString
);
1784 else return DISP_E_MEMBERNOTFOUND
;
1787 case DISPID_INSTALLER_PRODUCTSTATE
:
1788 if (wFlags
& DISPATCH_PROPERTYGET
) {
1789 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1790 if (FAILED(hr
)) return hr
;
1791 V_VT(pVarResult
) = VT_I4
;
1792 V_I4(pVarResult
) = MsiQueryProductStateW(V_BSTR(&varg0
));
1794 else return DISP_E_MEMBERNOTFOUND
;
1797 case DISPID_INSTALLER_PRODUCTINFO
:
1798 if (wFlags
& DISPATCH_PROPERTYGET
) {
1799 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1800 if (FAILED(hr
)) return hr
;
1801 hr
= DispGetParam(pDispParams
, 1, VT_BSTR
, &varg1
, puArgErr
);
1804 VariantClear(&varg0
);
1807 V_VT(pVarResult
) = VT_BSTR
;
1808 V_BSTR(pVarResult
) = NULL
;
1809 if ((ret
= MsiGetProductInfoW(V_BSTR(&varg0
), V_BSTR(&varg1
), NULL
, &dwSize
)) == ERROR_SUCCESS
)
1811 if (!(szString
= msi_alloc((++dwSize
)*sizeof(WCHAR
))))
1812 ERR("Out of memory\n");
1813 else if ((ret
= MsiGetProductInfoW(V_BSTR(&varg0
), V_BSTR(&varg1
), szString
, &dwSize
)) == ERROR_SUCCESS
)
1814 V_BSTR(pVarResult
) = SysAllocString(szString
);
1817 if (ret
!= ERROR_SUCCESS
)
1819 ERR("MsiGetProductInfo returned %d\n", ret
);
1820 VariantClear(&varg1
);
1821 VariantClear(&varg0
);
1822 return DISP_E_EXCEPTION
;
1825 else return DISP_E_MEMBERNOTFOUND
;
1828 case DISPID_INSTALLER_PRODUCTS
:
1829 if (wFlags
& DISPATCH_PROPERTYGET
)
1831 ListData
*ldata
= NULL
;
1833 WCHAR szProductBuf
[GUID_SIZE
];
1835 /* Find number of products */
1836 while ((ret
= MsiEnumProductsW(idx
, szProductBuf
)) == ERROR_SUCCESS
) idx
++;
1837 if (ret
!= ERROR_NO_MORE_ITEMS
)
1839 ERR("MsiEnumProducts returned %d\n", ret
);
1840 return DISP_E_EXCEPTION
;
1843 V_VT(pVarResult
) = VT_DISPATCH
;
1844 if (SUCCEEDED(hr
= create_automation_object(0, NULL
, (LPVOID
*)&pDispatch
, &DIID_StringList
, ListImpl_Invoke
, ListImpl_Free
, sizeof(ListData
))))
1846 V_DISPATCH(pVarResult
) = pDispatch
;
1848 /* Save product strings */
1849 ldata
= (ListData
*)private_data((AutomationObject
*)pDispatch
);
1850 if (!(ldata
->pVars
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(VARIANT
)*idx
)))
1851 ERR("Out of memory\n");
1854 ldata
->ulCount
= idx
;
1855 for (idx
= 0; idx
< ldata
->ulCount
; idx
++)
1857 ret
= MsiEnumProductsW(idx
, szProductBuf
);
1858 VariantInit(&ldata
->pVars
[idx
]);
1859 V_VT(&ldata
->pVars
[idx
]) = VT_BSTR
;
1860 V_BSTR(&ldata
->pVars
[idx
]) = SysAllocString(szProductBuf
);
1865 ERR("Failed to create StringList object, hresult 0x%08x\n", hr
);
1867 else return DISP_E_MEMBERNOTFOUND
;
1870 case DISPID_INSTALLER_RELATEDPRODUCTS
:
1871 if (wFlags
& DISPATCH_PROPERTYGET
)
1873 ListData
*ldata
= NULL
;
1875 WCHAR szProductBuf
[GUID_SIZE
];
1877 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1878 if (FAILED(hr
)) return hr
;
1880 /* Find number of related products */
1881 while ((ret
= MsiEnumRelatedProductsW(V_BSTR(&varg0
), 0, idx
, szProductBuf
)) == ERROR_SUCCESS
) idx
++;
1882 if (ret
!= ERROR_NO_MORE_ITEMS
)
1884 VariantClear(&varg0
);
1885 ERR("MsiEnumRelatedProducts returned %d\n", ret
);
1886 return DISP_E_EXCEPTION
;
1889 V_VT(pVarResult
) = VT_DISPATCH
;
1890 if (SUCCEEDED(hr
= create_automation_object(0, NULL
, (LPVOID
*)&pDispatch
, &DIID_StringList
, ListImpl_Invoke
, ListImpl_Free
, sizeof(ListData
))))
1892 V_DISPATCH(pVarResult
) = pDispatch
;
1894 /* Save product strings */
1895 ldata
= (ListData
*)private_data((AutomationObject
*)pDispatch
);
1896 if (!(ldata
->pVars
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(VARIANT
)*idx
)))
1897 ERR("Out of memory\n");
1900 ldata
->ulCount
= idx
;
1901 for (idx
= 0; idx
< ldata
->ulCount
; idx
++)
1903 ret
= MsiEnumRelatedProductsW(V_BSTR(&varg0
), 0, idx
, szProductBuf
);
1904 VariantInit(&ldata
->pVars
[idx
]);
1905 V_VT(&ldata
->pVars
[idx
]) = VT_BSTR
;
1906 V_BSTR(&ldata
->pVars
[idx
]) = SysAllocString(szProductBuf
);
1911 ERR("Failed to create StringList object, hresult 0x%08x\n", hr
);
1913 else return DISP_E_MEMBERNOTFOUND
;
1917 return DISP_E_MEMBERNOTFOUND
;
1920 VariantClear(&varg2
);
1921 VariantClear(&varg1
);
1922 VariantClear(&varg0
);
1927 /* Wrapper around create_automation_object to create an installer object. */
1928 HRESULT
create_msiserver(IUnknown
*pOuter
, LPVOID
*ppObj
)
1930 return create_automation_object(0, pOuter
, ppObj
, &DIID_Installer
, InstallerImpl_Invoke
, NULL
, 0);
1933 /* Wrapper around create_automation_object to create a session object. */
1934 HRESULT
create_session(MSIHANDLE msiHandle
, IDispatch
*pInstaller
, IDispatch
**pDispatch
)
1936 HRESULT hr
= create_automation_object(msiHandle
, NULL
, (LPVOID
)pDispatch
, &DIID_Session
, SessionImpl_Invoke
, NULL
, sizeof(SessionData
));
1937 if (SUCCEEDED(hr
) && pDispatch
&& *pDispatch
)
1938 ((SessionData
*)private_data((AutomationObject
*)*pDispatch
))->pInstaller
= pInstaller
;