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 MsiCloseHandle(This
->msiHandle
);
286 HeapFree(GetProcessHeap(), 0, This
);
292 /*** IDispatch methods ***/
293 static HRESULT WINAPI
AutomationObject_GetTypeInfoCount(
297 AutomationObject
*This
= (AutomationObject
*)iface
;
299 TRACE("(%p/%p)->(%p)\n", iface
, This
, pctinfo
);
304 static HRESULT WINAPI
AutomationObject_GetTypeInfo(
310 AutomationObject
*This
= (AutomationObject
*)iface
;
311 TRACE("(%p/%p)->(%d,%d,%p)\n", iface
, This
, iTInfo
, lcid
, ppTInfo
);
313 ITypeInfo_AddRef(This
->iTypeInfo
);
314 *ppTInfo
= This
->iTypeInfo
;
318 static HRESULT WINAPI
AutomationObject_GetIDsOfNames(
326 AutomationObject
*This
= (AutomationObject
*)iface
;
328 TRACE("(%p/%p)->(%p,%p,%d,%d,%p)\n", iface
, This
, riid
, rgszNames
, cNames
, lcid
, rgDispId
);
330 if (!IsEqualGUID(riid
, &IID_NULL
)) return E_INVALIDARG
;
331 hr
= ITypeInfo_GetIDsOfNames(This
->iTypeInfo
, rgszNames
, cNames
, rgDispId
);
332 if (hr
== DISP_E_UNKNOWNNAME
)
335 for (idx
=0; idx
<cNames
; idx
++)
337 if (rgDispId
[idx
] == DISPID_UNKNOWN
)
338 FIXME("Unknown member %s, clsid %s\n", debugstr_w(rgszNames
[idx
]), debugstr_guid(This
->clsid
));
344 /* Maximum number of allowed function parameters+1 */
345 #define MAX_FUNC_PARAMS 20
347 /* Some error checking is done here to simplify individual object function invocation */
348 static HRESULT WINAPI
AutomationObject_Invoke(
354 DISPPARAMS
* pDispParams
,
356 EXCEPINFO
* pExcepInfo
,
359 AutomationObject
*This
= (AutomationObject
*)iface
;
361 unsigned int uArgErr
;
362 VARIANT varResultDummy
;
363 BSTR bstrName
= NULL
;
365 TRACE("(%p/%p)->(%d,%p,%d,%d,%p,%p,%p,%p)\n", iface
, This
, dispIdMember
, riid
, lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
367 if (!IsEqualIID(riid
, &IID_NULL
))
369 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid
));
370 return DISP_E_UNKNOWNNAME
;
373 if (wFlags
& DISPATCH_PROPERTYGET
&& !pVarResult
)
375 ERR("NULL pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
376 return DISP_E_PARAMNOTOPTIONAL
;
379 /* This simplifies our individual object invocation functions */
380 if (puArgErr
== NULL
) puArgErr
= &uArgErr
;
381 if (pVarResult
== NULL
) pVarResult
= &varResultDummy
;
383 /* Assume return type is void unless determined otherwise */
384 VariantInit(pVarResult
);
386 /* If we are tracing, we want to see the name of the member we are invoking */
389 ITypeInfo_GetDocumentation(This
->iTypeInfo
, dispIdMember
, &bstrName
, NULL
, NULL
, NULL
);
390 TRACE("Method %d, %s\n", dispIdMember
, debugstr_w(bstrName
));
393 hr
= This
->funcInvoke(This
,dispIdMember
,riid
,lcid
,wFlags
,pDispParams
,pVarResult
,pExcepInfo
,puArgErr
);
395 if (hr
== DISP_E_MEMBERNOTFOUND
) {
396 if (bstrName
== NULL
) ITypeInfo_GetDocumentation(This
->iTypeInfo
, dispIdMember
, &bstrName
, NULL
, NULL
, NULL
);
397 FIXME("Method %d, %s wflags %d not implemented, clsid %s\n", dispIdMember
, debugstr_w(bstrName
), wFlags
, debugstr_guid(This
->clsid
));
399 else if (pExcepInfo
&&
400 (hr
== DISP_E_PARAMNOTFOUND
||
401 hr
== DISP_E_EXCEPTION
)) {
402 static const WCHAR szComma
[] = { ',',0 };
403 static WCHAR szExceptionSource
[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
404 WCHAR szExceptionDescription
[MAX_PATH
];
405 BSTR bstrParamNames
[MAX_FUNC_PARAMS
];
409 if (FAILED(ITypeInfo_GetNames(This
->iTypeInfo
, dispIdMember
, bstrParamNames
,
410 MAX_FUNC_PARAMS
, &namesNo
)))
412 TRACE("Failed to retrieve names for dispIdMember %d\n", dispIdMember
);
416 memset(szExceptionDescription
, 0, sizeof(szExceptionDescription
));
417 for (i
=0; i
<namesNo
; i
++)
419 if (bFirst
) bFirst
= FALSE
;
421 lstrcpyW(&szExceptionDescription
[lstrlenW(szExceptionDescription
)], szComma
);
423 lstrcpyW(&szExceptionDescription
[lstrlenW(szExceptionDescription
)], bstrParamNames
[i
]);
424 SysFreeString(bstrParamNames
[i
]);
427 memset(pExcepInfo
, 0, sizeof(EXCEPINFO
));
428 pExcepInfo
->wCode
= 1000;
429 pExcepInfo
->bstrSource
= szExceptionSource
;
430 pExcepInfo
->bstrDescription
= szExceptionDescription
;
431 hr
= DISP_E_EXCEPTION
;
435 /* Make sure we free the return variant if it is our dummy variant */
436 if (pVarResult
== &varResultDummy
) VariantClear(pVarResult
);
438 /* Free function name if we retrieved it */
439 if (bstrName
) SysFreeString(bstrName
);
441 TRACE("Returning 0x%08x, %s\n", hr
, SUCCEEDED(hr
) ? "ok" : "not ok");
446 static const struct IDispatchVtbl AutomationObject_Vtbl
=
448 AutomationObject_QueryInterface
,
449 AutomationObject_AddRef
,
450 AutomationObject_Release
,
451 AutomationObject_GetTypeInfoCount
,
452 AutomationObject_GetTypeInfo
,
453 AutomationObject_GetIDsOfNames
,
454 AutomationObject_Invoke
458 * IProvideMultipleClassInfo methods
461 static HRESULT WINAPI
AutomationObject_IProvideMultipleClassInfo_QueryInterface(
462 IProvideMultipleClassInfo
* iface
,
466 AutomationObject
*This
= obj_from_IProvideMultipleClassInfo(iface
);
467 return AutomationObject_QueryInterface((IDispatch
*)This
, riid
, ppvoid
);
470 static ULONG WINAPI
AutomationObject_IProvideMultipleClassInfo_AddRef(IProvideMultipleClassInfo
* iface
)
472 AutomationObject
*This
= obj_from_IProvideMultipleClassInfo(iface
);
473 return AutomationObject_AddRef((IDispatch
*)This
);
476 static ULONG WINAPI
AutomationObject_IProvideMultipleClassInfo_Release(IProvideMultipleClassInfo
* iface
)
478 AutomationObject
*This
= obj_from_IProvideMultipleClassInfo(iface
);
479 return AutomationObject_Release((IDispatch
*)This
);
482 static HRESULT WINAPI
AutomationObject_IProvideMultipleClassInfo_GetClassInfo(IProvideMultipleClassInfo
* iface
, ITypeInfo
** ppTI
)
484 AutomationObject
*This
= obj_from_IProvideMultipleClassInfo(iface
);
485 TRACE("(%p/%p)->(%p)\n", iface
, This
, ppTI
);
486 return load_type_info((IDispatch
*)This
, ppTI
, This
->clsid
, 0);
489 static HRESULT WINAPI
AutomationObject_IProvideMultipleClassInfo_GetGUID(IProvideMultipleClassInfo
* iface
, DWORD dwGuidKind
, GUID
* pGUID
)
491 AutomationObject
*This
= obj_from_IProvideMultipleClassInfo(iface
);
492 TRACE("(%p/%p)->(%d,%s)\n", iface
, This
, dwGuidKind
, debugstr_guid(pGUID
));
494 if (dwGuidKind
!= GUIDKIND_DEFAULT_SOURCE_DISP_IID
)
497 *pGUID
= *This
->clsid
;
502 static HRESULT WINAPI
AutomationObject_GetMultiTypeInfoCount(IProvideMultipleClassInfo
* iface
, ULONG
* pcti
)
504 AutomationObject
*This
= obj_from_IProvideMultipleClassInfo(iface
);
506 TRACE("(%p/%p)->(%p)\n", iface
, This
, pcti
);
511 static HRESULT WINAPI
AutomationObject_GetInfoOfIndex(IProvideMultipleClassInfo
* iface
,
514 ITypeInfo
** pptiCoClass
,
516 ULONG
* pcdispidReserved
,
520 AutomationObject
*This
= obj_from_IProvideMultipleClassInfo(iface
);
522 TRACE("(%p/%p)->(%d,%d,%p,%p,%p,%p,%p)\n", iface
, This
, iti
, dwFlags
, pptiCoClass
, pdwTIFlags
, pcdispidReserved
, piidPrimary
, piidSource
);
527 if (dwFlags
& MULTICLASSINFO_GETTYPEINFO
)
528 load_type_info((IDispatch
*)This
, pptiCoClass
, This
->clsid
, 0);
530 if (dwFlags
& MULTICLASSINFO_GETNUMRESERVEDDISPIDS
)
533 *pcdispidReserved
= 0;
536 if (dwFlags
& MULTICLASSINFO_GETIIDPRIMARY
){
537 *piidPrimary
= *This
->clsid
;
540 if (dwFlags
& MULTICLASSINFO_GETIIDSOURCE
){
541 *piidSource
= *This
->clsid
;
547 static const IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl
=
549 AutomationObject_IProvideMultipleClassInfo_QueryInterface
,
550 AutomationObject_IProvideMultipleClassInfo_AddRef
,
551 AutomationObject_IProvideMultipleClassInfo_Release
,
552 AutomationObject_IProvideMultipleClassInfo_GetClassInfo
,
553 AutomationObject_IProvideMultipleClassInfo_GetGUID
,
554 AutomationObject_GetMultiTypeInfoCount
,
555 AutomationObject_GetInfoOfIndex
559 * ListEnumerator methods
562 /*** IUnknown methods ***/
563 static HRESULT WINAPI
ListEnumerator_QueryInterface(IEnumVARIANT
* iface
, REFIID riid
, void** ppvObject
)
565 ListEnumerator
*This
= (ListEnumerator
*)iface
;
567 TRACE("(%p/%p)->(%s,%p)\n", iface
, This
, debugstr_guid(riid
), ppvObject
);
569 if (ppvObject
== NULL
)
574 if (IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_IEnumVARIANT
))
578 TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid
));
579 return E_NOINTERFACE
;
582 IClassFactory_AddRef(iface
);
586 static ULONG WINAPI
ListEnumerator_AddRef(IEnumVARIANT
* iface
)
588 ListEnumerator
*This
= (ListEnumerator
*)iface
;
590 TRACE("(%p/%p)\n", iface
, This
);
592 return InterlockedIncrement(&This
->ref
);
595 static ULONG WINAPI
ListEnumerator_Release(IEnumVARIANT
* iface
)
597 ListEnumerator
*This
= (ListEnumerator
*)iface
;
598 ULONG ref
= InterlockedDecrement(&This
->ref
);
600 TRACE("(%p/%p)\n", iface
, This
);
604 if (This
->pObj
) IDispatch_Release((IDispatch
*)This
->pObj
);
605 HeapFree(GetProcessHeap(), 0, This
);
611 /* IEnumVARIANT methods */
613 static HRESULT WINAPI
ListEnumerator_Next(IEnumVARIANT
* iface
, ULONG celt
, VARIANT
*rgVar
, ULONG
*pCeltFetched
)
615 ListEnumerator
*This
= (ListEnumerator
*)iface
;
616 ListData
*data
= (ListData
*)private_data(This
->pObj
);
619 TRACE("(%p,%uld,%p,%p)\n", iface
, celt
, rgVar
, pCeltFetched
);
621 if (pCeltFetched
!= NULL
)
627 for (local
= 0; local
< celt
; local
++)
628 VariantInit(&rgVar
[local
]);
630 for (idx
= This
->ulPos
, local
= 0; idx
< data
->ulCount
&& local
< celt
; idx
++, local
++)
631 VariantCopy(&rgVar
[local
], &data
->pVars
[idx
]);
633 if (pCeltFetched
!= NULL
)
634 *pCeltFetched
= local
;
637 return (local
< celt
) ? S_FALSE
: S_OK
;
640 static HRESULT WINAPI
ListEnumerator_Skip(IEnumVARIANT
* iface
, ULONG celt
)
642 ListEnumerator
*This
= (ListEnumerator
*)iface
;
643 ListData
*data
= (ListData
*)private_data(This
->pObj
);
645 TRACE("(%p,%uld)\n", iface
, celt
);
648 if (This
->ulPos
>= data
->ulCount
)
650 This
->ulPos
= data
->ulCount
;
656 static HRESULT WINAPI
ListEnumerator_Reset(IEnumVARIANT
* iface
)
658 ListEnumerator
*This
= (ListEnumerator
*)iface
;
660 TRACE("(%p)\n", iface
);
666 static HRESULT WINAPI
ListEnumerator_Clone(IEnumVARIANT
* iface
, IEnumVARIANT
**ppEnum
)
668 ListEnumerator
*This
= (ListEnumerator
*)iface
;
671 TRACE("(%p,%p)\n", iface
, ppEnum
);
677 hr
= create_list_enumerator(NULL
, (LPVOID
*)ppEnum
, This
->pObj
, 0);
681 IUnknown_Release(*ppEnum
);
685 IUnknown_AddRef(*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
,
750 switch (dispIdMember
)
752 case DISPID_SUMMARYINFO_PROPERTY
:
753 if (wFlags
& DISPATCH_PROPERTYGET
)
759 static WCHAR szEmpty
[] = {0};
761 VariantClear(pVarResult
);
763 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
764 if (FAILED(hr
)) return hr
;
767 if (pid
== PID_CODEPAGE
|| (pid
>= PID_PAGECOUNT
&& pid
<= PID_CHARCOUNT
) || PID_SECURITY
)
769 ret
= MsiSummaryInfoGetPropertyW(This
->msiHandle
, pid
, &type
, &value
,
771 if (ret
!= ERROR_SUCCESS
)
772 return DISP_E_EXCEPTION
;
774 if (pid
== PID_CODEPAGE
)
776 V_VT(pVarResult
) = VT_I2
;
777 V_I2(pVarResult
) = value
;
781 V_VT(pVarResult
) = VT_I4
;
782 V_I4(pVarResult
) = value
;
785 else if ((pid
>= PID_TITLE
&& pid
<= PID_REVNUMBER
) || pid
== PID_APPNAME
)
790 ret
= MsiSummaryInfoGetPropertyW(This
->msiHandle
, pid
, &type
, NULL
,
791 NULL
, szEmpty
, &size
);
792 if (ret
!= ERROR_MORE_DATA
)
793 return DISP_E_EXCEPTION
;
795 str
= msi_alloc(++size
* sizeof(WCHAR
));
797 return DISP_E_EXCEPTION
;
799 ret
= MsiSummaryInfoGetPropertyW(This
->msiHandle
, pid
, &type
, NULL
,
801 if (ret
!= ERROR_SUCCESS
)
804 return DISP_E_EXCEPTION
;
807 V_VT(pVarResult
) = VT_BSTR
;
808 V_BSTR(pVarResult
) = SysAllocString(str
);
811 else if (pid
>= PID_EDITTIME
&& pid
<= PID_LASTSAVE_DTM
)
817 ret
= MsiSummaryInfoGetPropertyW(This
->msiHandle
, pid
, &type
, &value
,
819 if (ret
!= ERROR_SUCCESS
)
820 return DISP_E_EXCEPTION
;
822 FileTimeToSystemTime(&ft
, &st
);
823 SystemTimeToVariantTime(&st
, &date
);
825 V_VT(pVarResult
) = VT_DATE
;
826 V_DATE(pVarResult
) = date
;
829 else return DISP_E_MEMBERNOTFOUND
;
833 ERR("Member not found: %d\n", dispIdMember
);
834 return DISP_E_MEMBERNOTFOUND
;
837 VariantClear(&varg0
);
841 static HRESULT WINAPI
RecordImpl_Invoke(
842 AutomationObject
* This
,
847 DISPPARAMS
* pDispParams
,
849 EXCEPINFO
* pExcepInfo
,
855 VARIANTARG varg0
, varg1
;
861 switch (dispIdMember
)
863 case DISPID_RECORD_FIELDCOUNT
:
864 if (wFlags
& DISPATCH_PROPERTYGET
) {
865 V_VT(pVarResult
) = VT_I4
;
866 V_I4(pVarResult
) = MsiRecordGetFieldCount(This
->msiHandle
);
868 else return DISP_E_MEMBERNOTFOUND
;
871 case DISPID_RECORD_STRINGDATA
:
872 if (wFlags
& DISPATCH_PROPERTYGET
) {
873 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
874 if (FAILED(hr
)) return hr
;
875 V_VT(pVarResult
) = VT_BSTR
;
876 V_BSTR(pVarResult
) = NULL
;
877 if ((ret
= MsiRecordGetStringW(This
->msiHandle
, V_I4(&varg0
), NULL
, &dwLen
)) == ERROR_SUCCESS
)
879 if (!(szString
= msi_alloc((++dwLen
)*sizeof(WCHAR
))))
880 ERR("Out of memory\n");
881 else if ((ret
= MsiRecordGetStringW(This
->msiHandle
, V_I4(&varg0
), szString
, &dwLen
)) == ERROR_SUCCESS
)
882 V_BSTR(pVarResult
) = SysAllocString(szString
);
885 if (ret
!= ERROR_SUCCESS
)
886 ERR("MsiRecordGetString returned %d\n", ret
);
887 } else if (wFlags
& DISPATCH_PROPERTYPUT
) {
888 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
889 if (FAILED(hr
)) return hr
;
890 hr
= DispGetParam(pDispParams
, DISPID_PROPERTYPUT
, VT_BSTR
, &varg1
, puArgErr
);
891 if (FAILED(hr
)) return hr
;
892 if ((ret
= MsiRecordSetStringW(This
->msiHandle
, V_I4(&varg0
), V_BSTR(&varg1
))) != ERROR_SUCCESS
)
894 VariantClear(&varg1
);
895 ERR("MsiRecordSetString returned %d\n", ret
);
896 return DISP_E_EXCEPTION
;
899 else return DISP_E_MEMBERNOTFOUND
;
902 case DISPID_RECORD_INTEGERDATA
:
903 if (wFlags
& DISPATCH_PROPERTYGET
) {
904 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
905 if (FAILED(hr
)) return hr
;
906 V_VT(pVarResult
) = VT_I4
;
907 V_I4(pVarResult
) = MsiRecordGetInteger(This
->msiHandle
, V_I4(&varg0
));
908 } else if (wFlags
& DISPATCH_PROPERTYPUT
) {
909 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
910 if (FAILED(hr
)) return hr
;
911 hr
= DispGetParam(pDispParams
, DISPID_PROPERTYPUT
, VT_I4
, &varg1
, puArgErr
);
912 if (FAILED(hr
)) return hr
;
913 if ((ret
= MsiRecordSetInteger(This
->msiHandle
, V_I4(&varg0
), V_I4(&varg1
))) != ERROR_SUCCESS
)
915 ERR("MsiRecordSetInteger returned %d\n", ret
);
916 return DISP_E_EXCEPTION
;
919 else return DISP_E_MEMBERNOTFOUND
;
923 return DISP_E_MEMBERNOTFOUND
;
926 VariantClear(&varg1
);
927 VariantClear(&varg0
);
932 static HRESULT WINAPI
ListImpl_Invoke(
933 AutomationObject
* This
,
938 DISPPARAMS
* pDispParams
,
940 EXCEPINFO
* pExcepInfo
,
943 ListData
*data
= (ListData
*)private_data(This
);
946 IUnknown
*pUnk
= NULL
;
950 switch (dispIdMember
)
952 case DISPID_LIST__NEWENUM
:
953 if (wFlags
& DISPATCH_METHOD
) {
954 V_VT(pVarResult
) = VT_UNKNOWN
;
955 if (SUCCEEDED(hr
= create_list_enumerator(NULL
, (LPVOID
*)&pUnk
, This
, 0)))
957 IUnknown_AddRef(pUnk
);
958 V_UNKNOWN(pVarResult
) = pUnk
;
961 ERR("Failed to create IEnumVARIANT object, hresult 0x%08x\n", hr
);
963 else return DISP_E_MEMBERNOTFOUND
;
966 case DISPID_LIST_ITEM
:
967 if (wFlags
& DISPATCH_PROPERTYGET
) {
968 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
969 if (FAILED(hr
)) return hr
;
970 if (V_I4(&varg0
) < 0 || V_I4(&varg0
) >= data
->ulCount
)
971 return DISP_E_BADINDEX
;
972 VariantCopy(pVarResult
, &data
->pVars
[V_I4(&varg0
)]);
974 else return DISP_E_MEMBERNOTFOUND
;
977 case DISPID_LIST_COUNT
:
978 if (wFlags
& DISPATCH_PROPERTYGET
) {
979 V_VT(pVarResult
) = VT_I4
;
980 V_I4(pVarResult
) = data
->ulCount
;
982 else return DISP_E_MEMBERNOTFOUND
;
986 return DISP_E_MEMBERNOTFOUND
;
989 VariantClear(&varg0
);
994 static void WINAPI
ListImpl_Free(AutomationObject
*This
)
996 ListData
*data
= private_data(This
);
999 for (idx
=0; idx
<data
->ulCount
; idx
++)
1000 VariantClear(&data
->pVars
[idx
]);
1001 HeapFree(GetProcessHeap(), 0, data
->pVars
);
1004 static HRESULT WINAPI
ViewImpl_Invoke(
1005 AutomationObject
* This
,
1006 DISPID dispIdMember
,
1010 DISPPARAMS
* pDispParams
,
1011 VARIANT
* pVarResult
,
1012 EXCEPINFO
* pExcepInfo
,
1015 MSIHANDLE msiHandle
;
1016 IDispatch
*pDispatch
= NULL
;
1018 VARIANTARG varg0
, varg1
;
1021 VariantInit(&varg0
);
1022 VariantInit(&varg1
);
1024 switch (dispIdMember
)
1026 case DISPID_VIEW_EXECUTE
:
1027 if (wFlags
& DISPATCH_METHOD
)
1029 hr
= DispGetParam(pDispParams
, 0, VT_DISPATCH
, &varg0
, puArgErr
);
1030 if (SUCCEEDED(hr
) && V_DISPATCH(&varg0
) != NULL
)
1031 MsiViewExecute(This
->msiHandle
, ((AutomationObject
*)V_DISPATCH(&varg0
))->msiHandle
);
1033 MsiViewExecute(This
->msiHandle
, 0);
1035 else return DISP_E_MEMBERNOTFOUND
;
1038 case DISPID_VIEW_FETCH
:
1039 if (wFlags
& DISPATCH_METHOD
)
1041 V_VT(pVarResult
) = VT_DISPATCH
;
1042 if ((ret
= MsiViewFetch(This
->msiHandle
, &msiHandle
)) == ERROR_SUCCESS
)
1044 if (SUCCEEDED(hr
= create_automation_object(msiHandle
, NULL
, (LPVOID
*)&pDispatch
, &DIID_Record
, RecordImpl_Invoke
, NULL
, 0)))
1046 IDispatch_AddRef(pDispatch
);
1047 V_DISPATCH(pVarResult
) = pDispatch
;
1050 ERR("Failed to create Record object, hresult 0x%08x\n", hr
);
1052 else if (ret
== ERROR_NO_MORE_ITEMS
)
1053 V_DISPATCH(pVarResult
) = NULL
;
1056 ERR("MsiViewFetch returned %d\n", ret
);
1057 return DISP_E_EXCEPTION
;
1060 else return DISP_E_MEMBERNOTFOUND
;
1063 case DISPID_VIEW_MODIFY
:
1064 if (wFlags
& DISPATCH_METHOD
)
1066 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
1067 if (FAILED(hr
)) return hr
;
1068 hr
= DispGetParam(pDispParams
, 1, VT_DISPATCH
, &varg1
, puArgErr
);
1069 if (FAILED(hr
)) return hr
;
1070 if (!V_DISPATCH(&varg1
)) return DISP_E_EXCEPTION
;
1071 if ((ret
= MsiViewModify(This
->msiHandle
, V_I4(&varg0
), ((AutomationObject
*)V_DISPATCH(&varg1
))->msiHandle
)) != ERROR_SUCCESS
)
1073 VariantClear(&varg1
);
1074 ERR("MsiViewModify returned %d\n", ret
);
1075 return DISP_E_EXCEPTION
;
1078 else return DISP_E_MEMBERNOTFOUND
;
1081 case DISPID_VIEW_CLOSE
:
1082 if (wFlags
& DISPATCH_METHOD
)
1084 MsiViewClose(This
->msiHandle
);
1086 else return DISP_E_MEMBERNOTFOUND
;
1090 return DISP_E_MEMBERNOTFOUND
;
1093 VariantClear(&varg1
);
1094 VariantClear(&varg0
);
1099 static HRESULT WINAPI
DatabaseImpl_Invoke(
1100 AutomationObject
* This
,
1101 DISPID dispIdMember
,
1105 DISPPARAMS
* pDispParams
,
1106 VARIANT
* pVarResult
,
1107 EXCEPINFO
* pExcepInfo
,
1110 MSIHANDLE msiHandle
;
1111 IDispatch
*pDispatch
= NULL
;
1113 VARIANTARG varg0
, varg1
;
1116 VariantInit(&varg0
);
1117 VariantInit(&varg1
);
1119 switch (dispIdMember
)
1121 case DISPID_DATABASE_SUMMARYINFORMATION
:
1122 if (wFlags
& DISPATCH_METHOD
)
1124 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
1128 V_VT(pVarResult
) = VT_DISPATCH
;
1129 if ((ret
= MsiGetSummaryInformationW(This
->msiHandle
, NULL
, V_I4(&varg0
), &msiHandle
)) == ERROR_SUCCESS
)
1131 hr
= create_automation_object(msiHandle
, NULL
, (LPVOID
*)&pDispatch
, &DIID_SummaryInfo
, SummaryInfoImpl_Invoke
, NULL
, 0);
1134 IDispatch_AddRef(pDispatch
);
1135 V_DISPATCH(pVarResult
) = pDispatch
;
1138 ERR("Failed to create SummaryInfo object: 0x%08x\n", hr
);
1142 ERR("MsiGetSummaryInformation returned %d\n", ret
);
1143 return DISP_E_EXCEPTION
;
1146 else return DISP_E_MEMBERNOTFOUND
;
1149 case DISPID_DATABASE_OPENVIEW
:
1150 if (wFlags
& DISPATCH_METHOD
)
1152 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1153 if (FAILED(hr
)) return hr
;
1154 V_VT(pVarResult
) = VT_DISPATCH
;
1155 if ((ret
= MsiDatabaseOpenViewW(This
->msiHandle
, V_BSTR(&varg0
), &msiHandle
)) == ERROR_SUCCESS
)
1157 if (SUCCEEDED(hr
= create_automation_object(msiHandle
, NULL
, (LPVOID
*)&pDispatch
, &DIID_View
, ViewImpl_Invoke
, NULL
, 0)))
1159 IDispatch_AddRef(pDispatch
);
1160 V_DISPATCH(pVarResult
) = pDispatch
;
1163 ERR("Failed to create View object, hresult 0x%08x\n", hr
);
1167 VariantClear(&varg0
);
1168 ERR("MsiDatabaseOpenView returned %d\n", ret
);
1169 return DISP_E_EXCEPTION
;
1172 else return DISP_E_MEMBERNOTFOUND
;
1176 return DISP_E_MEMBERNOTFOUND
;
1179 VariantClear(&varg1
);
1180 VariantClear(&varg0
);
1185 static HRESULT WINAPI
SessionImpl_Invoke(
1186 AutomationObject
* This
,
1187 DISPID dispIdMember
,
1191 DISPPARAMS
* pDispParams
,
1192 VARIANT
* pVarResult
,
1193 EXCEPINFO
* pExcepInfo
,
1196 SessionData
*data
= private_data(This
);
1199 IDispatch
*pDispatch
= NULL
;
1200 MSIHANDLE msiHandle
;
1203 INSTALLSTATE iInstalled
, iAction
;
1204 VARIANTARG varg0
, varg1
;
1207 VariantInit(&varg0
);
1208 VariantInit(&varg1
);
1210 switch (dispIdMember
)
1212 case DISPID_SESSION_INSTALLER
:
1213 if (wFlags
& DISPATCH_PROPERTYGET
) {
1214 V_VT(pVarResult
) = VT_DISPATCH
;
1215 IDispatch_AddRef(data
->pInstaller
);
1216 V_DISPATCH(pVarResult
) = data
->pInstaller
;
1218 else return DISP_E_MEMBERNOTFOUND
;
1221 case DISPID_SESSION_PROPERTY
:
1222 if (wFlags
& DISPATCH_PROPERTYGET
) {
1223 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1224 if (FAILED(hr
)) return hr
;
1225 V_VT(pVarResult
) = VT_BSTR
;
1226 V_BSTR(pVarResult
) = NULL
;
1227 if ((ret
= MsiGetPropertyW(This
->msiHandle
, V_BSTR(&varg0
), NULL
, &dwLen
)) == ERROR_SUCCESS
)
1229 if (!(szString
= msi_alloc((++dwLen
)*sizeof(WCHAR
))))
1230 ERR("Out of memory\n");
1231 else if ((ret
= MsiGetPropertyW(This
->msiHandle
, V_BSTR(&varg0
), szString
, &dwLen
)) == ERROR_SUCCESS
)
1232 V_BSTR(pVarResult
) = SysAllocString(szString
);
1235 if (ret
!= ERROR_SUCCESS
)
1236 ERR("MsiGetProperty returned %d\n", ret
);
1237 } else if (wFlags
& DISPATCH_PROPERTYPUT
) {
1238 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1239 if (FAILED(hr
)) return hr
;
1240 hr
= DispGetParam(pDispParams
, DISPID_PROPERTYPUT
, VT_BSTR
, &varg1
, puArgErr
);
1242 VariantClear(&varg0
);
1245 if ((ret
= MsiSetPropertyW(This
->msiHandle
, V_BSTR(&varg0
), V_BSTR(&varg1
))) != ERROR_SUCCESS
)
1247 VariantClear(&varg0
);
1248 VariantClear(&varg1
);
1249 ERR("MsiSetProperty returned %d\n", ret
);
1250 return DISP_E_EXCEPTION
;
1253 else return DISP_E_MEMBERNOTFOUND
;
1256 case DISPID_SESSION_LANGUAGE
:
1257 if (wFlags
& DISPATCH_PROPERTYGET
) {
1258 langId
= MsiGetLanguage(This
->msiHandle
);
1259 V_VT(pVarResult
) = VT_I4
;
1260 V_I4(pVarResult
) = langId
;
1262 else return DISP_E_MEMBERNOTFOUND
;
1265 case DISPID_SESSION_MODE
:
1266 if (wFlags
& DISPATCH_PROPERTYGET
) {
1267 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
1268 if (FAILED(hr
)) return hr
;
1269 V_VT(pVarResult
) = VT_BOOL
;
1270 V_BOOL(pVarResult
) = MsiGetMode(This
->msiHandle
, V_I4(&varg0
));
1271 } else if (wFlags
& DISPATCH_PROPERTYPUT
) {
1272 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
1273 if (FAILED(hr
)) return hr
;
1274 hr
= DispGetParam(pDispParams
, DISPID_PROPERTYPUT
, VT_BOOL
, &varg1
, puArgErr
);
1275 if (FAILED(hr
)) return hr
;
1276 if ((ret
= MsiSetMode(This
->msiHandle
, V_I4(&varg0
), V_BOOL(&varg1
))) != ERROR_SUCCESS
)
1278 ERR("MsiSetMode returned %d\n", ret
);
1279 return DISP_E_EXCEPTION
;
1282 else return DISP_E_MEMBERNOTFOUND
;
1285 case DISPID_SESSION_DATABASE
:
1286 if (wFlags
& DISPATCH_PROPERTYGET
) {
1287 V_VT(pVarResult
) = VT_DISPATCH
;
1288 if ((msiHandle
= MsiGetActiveDatabase(This
->msiHandle
)))
1290 if (SUCCEEDED(hr
= create_automation_object(msiHandle
, NULL
, (LPVOID
*)&pDispatch
, &DIID_Database
, DatabaseImpl_Invoke
, NULL
, 0)))
1292 IDispatch_AddRef(pDispatch
);
1293 V_DISPATCH(pVarResult
) = pDispatch
;
1296 ERR("Failed to create Database object, hresult 0x%08x\n", hr
);
1300 ERR("MsiGetActiveDatabase failed\n");
1301 return DISP_E_EXCEPTION
;
1304 else return DISP_E_MEMBERNOTFOUND
;
1307 case DISPID_SESSION_DOACTION
:
1308 if (wFlags
& DISPATCH_METHOD
) {
1309 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1310 if (FAILED(hr
)) return hr
;
1311 ret
= MsiDoActionW(This
->msiHandle
, V_BSTR(&varg0
));
1312 V_VT(pVarResult
) = VT_I4
;
1315 case ERROR_FUNCTION_NOT_CALLED
:
1316 V_I4(pVarResult
) = msiDoActionStatusNoAction
;
1319 V_I4(pVarResult
) = msiDoActionStatusSuccess
;
1321 case ERROR_INSTALL_USEREXIT
:
1322 V_I4(pVarResult
) = msiDoActionStatusUserExit
;
1324 case ERROR_INSTALL_FAILURE
:
1325 V_I4(pVarResult
) = msiDoActionStatusFailure
;
1327 case ERROR_INSTALL_SUSPEND
:
1328 V_I4(pVarResult
) = msiDoActionStatusSuspend
;
1330 case ERROR_MORE_DATA
:
1331 V_I4(pVarResult
) = msiDoActionStatusFinished
;
1333 case ERROR_INVALID_HANDLE_STATE
:
1334 V_I4(pVarResult
) = msiDoActionStatusWrongState
;
1336 case ERROR_INVALID_DATA
:
1337 V_I4(pVarResult
) = msiDoActionStatusBadActionData
;
1340 VariantClear(&varg0
);
1341 FIXME("MsiDoAction returned unhandled value %d\n", ret
);
1342 return DISP_E_EXCEPTION
;
1345 else return DISP_E_MEMBERNOTFOUND
;
1348 case DISPID_SESSION_EVALUATECONDITION
:
1349 if (wFlags
& DISPATCH_METHOD
) {
1350 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1351 if (FAILED(hr
)) return hr
;
1352 V_VT(pVarResult
) = VT_I4
;
1353 V_I4(pVarResult
) = MsiEvaluateConditionW(This
->msiHandle
, V_BSTR(&varg0
));
1355 else return DISP_E_MEMBERNOTFOUND
;
1358 case DISPID_SESSION_SETINSTALLLEVEL
:
1359 if (wFlags
& DISPATCH_METHOD
) {
1360 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
1361 if (FAILED(hr
)) return hr
;
1362 if ((ret
= MsiSetInstallLevel(This
->msiHandle
, V_I4(&varg0
))) != ERROR_SUCCESS
)
1364 ERR("MsiSetInstallLevel returned %d\n", ret
);
1365 return DISP_E_EXCEPTION
;
1368 else return DISP_E_MEMBERNOTFOUND
;
1371 case DISPID_SESSION_FEATURECURRENTSTATE
:
1372 if (wFlags
& DISPATCH_PROPERTYGET
) {
1373 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1374 if (FAILED(hr
)) return hr
;
1375 V_VT(pVarResult
) = VT_I4
;
1376 if ((ret
= MsiGetFeatureStateW(This
->msiHandle
, V_BSTR(&varg0
), &iInstalled
, &iAction
)) == ERROR_SUCCESS
)
1377 V_I4(pVarResult
) = iInstalled
;
1380 ERR("MsiGetFeatureState returned %d\n", ret
);
1381 V_I4(pVarResult
) = msiInstallStateUnknown
;
1384 else return DISP_E_MEMBERNOTFOUND
;
1387 case DISPID_SESSION_FEATUREREQUESTSTATE
:
1388 if (wFlags
& DISPATCH_PROPERTYGET
) {
1389 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1390 if (FAILED(hr
)) return hr
;
1391 V_VT(pVarResult
) = VT_I4
;
1392 if ((ret
= MsiGetFeatureStateW(This
->msiHandle
, V_BSTR(&varg0
), &iInstalled
, &iAction
)) == ERROR_SUCCESS
)
1393 V_I4(pVarResult
) = iAction
;
1396 ERR("MsiGetFeatureState returned %d\n", ret
);
1397 V_I4(pVarResult
) = msiInstallStateUnknown
;
1399 } else if (wFlags
& DISPATCH_PROPERTYPUT
) {
1400 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1401 if (FAILED(hr
)) return hr
;
1402 hr
= DispGetParam(pDispParams
, DISPID_PROPERTYPUT
, VT_I4
, &varg1
, puArgErr
);
1404 VariantClear(&varg0
);
1407 if ((ret
= MsiSetFeatureStateW(This
->msiHandle
, V_BSTR(&varg0
), V_I4(&varg1
))) != ERROR_SUCCESS
)
1409 VariantClear(&varg0
);
1410 ERR("MsiSetFeatureState returned %d\n", ret
);
1411 return DISP_E_EXCEPTION
;
1414 else return DISP_E_MEMBERNOTFOUND
;
1418 return DISP_E_MEMBERNOTFOUND
;
1421 VariantClear(&varg1
);
1422 VariantClear(&varg0
);
1427 /* Fill the variant pointed to by pVarResult with the value & size returned by RegQueryValueEx as dictated by the
1428 * registry value type. Used by Installer::RegistryValue. */
1429 static void variant_from_registry_value(VARIANT
*pVarResult
, DWORD dwType
, LPBYTE lpData
, DWORD dwSize
)
1431 static const WCHAR szREG_BINARY
[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
1432 static const WCHAR szREG_
[] = { '(','R','E','G','_',']',0 };
1433 WCHAR
*szString
= (WCHAR
*)lpData
;
1434 LPWSTR szNewString
= NULL
;
1435 DWORD dwNewSize
= 0;
1440 /* Registry strings may not be null terminated so we must use SysAllocStringByteLen/Len */
1441 case REG_MULTI_SZ
: /* Multi SZ change internal null characters to newlines */
1442 idx
= (dwSize
/sizeof(WCHAR
))-1;
1443 while (idx
>= 0 && !szString
[idx
]) idx
--;
1444 for (; idx
>= 0; idx
--)
1445 if (!szString
[idx
]) szString
[idx
] = '\n';
1447 V_VT(pVarResult
) = VT_BSTR
;
1448 V_BSTR(pVarResult
) = SysAllocStringByteLen((LPCSTR
)szString
, dwSize
);
1452 if (!(dwNewSize
= ExpandEnvironmentStringsW(szString
, szNewString
, dwNewSize
)))
1453 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1454 else if (!(szNewString
= msi_alloc(dwNewSize
)))
1455 ERR("Out of memory\n");
1456 else if (!(dwNewSize
= ExpandEnvironmentStringsW(szString
, szNewString
, dwNewSize
)))
1457 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1460 V_VT(pVarResult
) = VT_BSTR
;
1461 V_BSTR(pVarResult
) = SysAllocStringLen(szNewString
, dwNewSize
);
1463 msi_free(szNewString
);
1467 V_VT(pVarResult
) = VT_I4
;
1468 V_I4(pVarResult
) = *((DWORD
*)lpData
);
1472 V_VT(pVarResult
) = VT_BSTR
;
1473 V_BSTR(pVarResult
) = SysAllocString(szREG_
); /* Weird string, don't know why native returns it */
1477 V_VT(pVarResult
) = VT_BSTR
;
1478 V_BSTR(pVarResult
) = SysAllocString(szREG_BINARY
);
1482 V_VT(pVarResult
) = VT_EMPTY
;
1486 FIXME("Unhandled registry value type %d\n", dwType
);
1490 static HRESULT WINAPI
InstallerImpl_Invoke(
1491 AutomationObject
* This
,
1492 DISPID dispIdMember
,
1496 DISPPARAMS
* pDispParams
,
1497 VARIANT
* pVarResult
,
1498 EXCEPINFO
* pExcepInfo
,
1501 MSIHANDLE msiHandle
;
1502 IDispatch
*pDispatch
= NULL
;
1504 VARIANTARG varg0
, varg1
, varg2
;
1506 LPWSTR szString
= NULL
;
1509 VariantInit(&varg0
);
1510 VariantInit(&varg1
);
1511 VariantInit(&varg2
);
1513 switch (dispIdMember
)
1515 case DISPID_INSTALLER_CREATERECORD
:
1516 if (wFlags
& DISPATCH_METHOD
)
1518 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
1519 if (FAILED(hr
)) return hr
;
1520 V_VT(pVarResult
) = VT_DISPATCH
;
1521 if ((msiHandle
= MsiCreateRecord(V_I4(&varg0
))))
1523 if (SUCCEEDED(hr
= create_automation_object(msiHandle
, NULL
, (LPVOID
*)&pDispatch
, &DIID_Record
, RecordImpl_Invoke
, NULL
, 0)))
1525 IDispatch_AddRef(pDispatch
);
1526 V_DISPATCH(pVarResult
) = pDispatch
;
1529 ERR("Failed to create Record object, hresult 0x%08x\n", hr
);
1533 ERR("MsiCreateRecord failed\n");
1534 return DISP_E_EXCEPTION
;
1537 else return DISP_E_MEMBERNOTFOUND
;
1540 case DISPID_INSTALLER_OPENPACKAGE
:
1541 if (wFlags
& DISPATCH_METHOD
)
1543 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1544 if (FAILED(hr
)) return hr
;
1545 hr
= DispGetParam(pDispParams
, 1, VT_I4
, &varg1
, puArgErr
);
1548 VariantClear(&varg0
);
1551 V_VT(pVarResult
) = VT_DISPATCH
;
1552 if ((ret
= MsiOpenPackageExW(V_BSTR(&varg0
), V_I4(&varg1
), &msiHandle
)) == ERROR_SUCCESS
)
1554 if (SUCCEEDED(hr
= create_session(msiHandle
, (IDispatch
*)This
, &pDispatch
)))
1556 IDispatch_AddRef(pDispatch
);
1557 V_DISPATCH(pVarResult
) = pDispatch
;
1560 ERR("Failed to create Session object, hresult 0x%08x\n", hr
);
1564 VariantClear(&varg0
);
1565 ERR("MsiOpenPackageEx returned %d\n", ret
);
1566 return DISP_E_EXCEPTION
;
1569 else return DISP_E_MEMBERNOTFOUND
;
1572 case DISPID_INSTALLER_OPENDATABASE
:
1573 if (wFlags
& DISPATCH_METHOD
)
1575 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1576 if (FAILED(hr
)) return hr
;
1578 hr
= DispGetParam(pDispParams
, 1, VT_BSTR
, &varg1
, puArgErr
);
1581 VariantClear(&varg0
);
1585 V_VT(pVarResult
) = VT_DISPATCH
;
1586 if ((ret
= MsiOpenDatabaseW(V_BSTR(&varg0
), V_BSTR(&varg1
), &msiHandle
)) == ERROR_SUCCESS
)
1588 hr
= create_automation_object(msiHandle
, NULL
, (LPVOID
*)&pDispatch
,
1589 &DIID_Database
, DatabaseImpl_Invoke
, NULL
, 0);
1592 IDispatch_AddRef(pDispatch
);
1593 V_DISPATCH(pVarResult
) = pDispatch
;
1596 ERR("Failed to create Database object: 0x%08x\n", hr
);
1600 VariantClear(&varg0
);
1601 VariantClear(&varg1
);
1602 ERR("MsiOpenDatabase returned %d\n", ret
);
1603 return DISP_E_EXCEPTION
;
1606 else return DISP_E_MEMBERNOTFOUND
;
1609 case DISPID_INSTALLER_INSTALLPRODUCT
:
1610 if (wFlags
& DISPATCH_METHOD
)
1612 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1613 if (FAILED(hr
)) return hr
;
1614 hr
= DispGetParam(pDispParams
, 1, VT_BSTR
, &varg1
, puArgErr
);
1617 VariantClear(&varg0
);
1620 if ((ret
= MsiInstallProductW(V_BSTR(&varg0
), V_BSTR(&varg1
))) != ERROR_SUCCESS
)
1622 VariantClear(&varg1
);
1623 VariantClear(&varg0
);
1624 ERR("MsiInstallProduct returned %d\n", ret
);
1625 return DISP_E_EXCEPTION
;
1628 else return DISP_E_MEMBERNOTFOUND
;
1631 case DISPID_INSTALLER_REGISTRYVALUE
:
1632 if (wFlags
& DISPATCH_METHOD
) {
1635 UINT posValue
= 2; /* Save valuePos so we can save puArgErr if we are unable to do our type conversions */
1637 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
1638 if (FAILED(hr
)) return hr
;
1639 hr
= DispGetParam(pDispParams
, 1, VT_BSTR
, &varg1
, puArgErr
);
1640 if (FAILED(hr
)) return hr
;
1641 hr
= DispGetParam_CopyOnly(pDispParams
, &posValue
, &varg2
);
1644 VariantClear(&varg1
);
1647 ret
= RegOpenKeyW((HKEY
)V_I4(&varg0
), V_BSTR(&varg1
), &hkey
);
1649 /* Third parameter can be VT_EMPTY, VT_I4, or VT_BSTR */
1650 switch (V_VT(&varg2
))
1652 case VT_EMPTY
: /* Return VT_BOOL as to whether or not registry key exists */
1653 V_VT(pVarResult
) = VT_BOOL
;
1654 V_BOOL(pVarResult
) = (ret
== ERROR_SUCCESS
);
1657 case VT_BSTR
: /* Return value of specified key if it exists */
1658 if (ret
== ERROR_SUCCESS
&&
1659 (ret
= RegQueryValueExW(hkey
, V_BSTR(&varg2
), NULL
, NULL
, NULL
, &dwSize
)) == ERROR_SUCCESS
)
1661 if (!(szString
= msi_alloc(dwSize
)))
1662 ERR("Out of memory\n");
1663 else if ((ret
= RegQueryValueExW(hkey
, V_BSTR(&varg2
), NULL
, &dwType
, (LPBYTE
)szString
, &dwSize
)) == ERROR_SUCCESS
)
1664 variant_from_registry_value(pVarResult
, dwType
, (LPBYTE
)szString
, dwSize
);
1667 if (ret
!= ERROR_SUCCESS
)
1670 VariantClear(&varg2
);
1671 VariantClear(&varg1
);
1672 return DISP_E_BADINDEX
;
1676 default: /* Try to make it into VT_I4, can use VariantChangeType for this */
1677 hr
= VariantChangeType(&varg2
, &varg2
, 0, VT_I4
);
1678 if (SUCCEEDED(hr
) && ret
!= ERROR_SUCCESS
) hr
= DISP_E_BADINDEX
; /* Conversion fine, but couldn't find key */
1681 if (hr
== DISP_E_TYPEMISMATCH
) *puArgErr
= posValue
;
1682 VariantClear(&varg2
); /* Unknown type, so let's clear it */
1683 VariantClear(&varg1
);
1687 /* Retrieve class name or maximum value name or subkey name size */
1689 ret
= RegQueryInfoKeyW(hkey
, NULL
, &dwSize
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1690 else if (V_I4(&varg2
) > 0)
1691 ret
= RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &dwSize
, NULL
, NULL
, NULL
);
1692 else /* V_I4(&varg2) < 0 */
1693 ret
= RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, &dwSize
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1695 if (ret
== ERROR_SUCCESS
)
1697 if (!(szString
= msi_alloc(++dwSize
* sizeof(WCHAR
))))
1698 ERR("Out of memory\n");
1699 else if (!V_I4(&varg2
))
1700 ret
= RegQueryInfoKeyW(hkey
, szString
, &dwSize
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1701 else if (V_I4(&varg2
) > 0)
1702 ret
= RegEnumValueW(hkey
, V_I4(&varg2
)-1, szString
, &dwSize
, 0, 0, NULL
, NULL
);
1703 else /* V_I4(&varg2) < 0 */
1704 ret
= RegEnumKeyW(hkey
, -1 - V_I4(&varg2
), szString
, dwSize
);
1706 if (szString
&& ret
== ERROR_SUCCESS
)
1708 V_VT(pVarResult
) = VT_BSTR
;
1709 V_BSTR(pVarResult
) = SysAllocString(szString
);
1717 else return DISP_E_MEMBERNOTFOUND
;
1720 case DISPID_INSTALLER_PRODUCTSTATE
:
1721 if (wFlags
& DISPATCH_PROPERTYGET
) {
1722 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1723 if (FAILED(hr
)) return hr
;
1724 V_VT(pVarResult
) = VT_I4
;
1725 V_I4(pVarResult
) = MsiQueryProductStateW(V_BSTR(&varg0
));
1727 else return DISP_E_MEMBERNOTFOUND
;
1730 case DISPID_INSTALLER_PRODUCTINFO
:
1731 if (wFlags
& DISPATCH_PROPERTYGET
) {
1732 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1733 if (FAILED(hr
)) return hr
;
1734 hr
= DispGetParam(pDispParams
, 1, VT_BSTR
, &varg1
, puArgErr
);
1737 VariantClear(&varg0
);
1740 V_VT(pVarResult
) = VT_BSTR
;
1741 V_BSTR(pVarResult
) = NULL
;
1742 if ((ret
= MsiGetProductInfoW(V_BSTR(&varg0
), V_BSTR(&varg1
), NULL
, &dwSize
)) == ERROR_SUCCESS
)
1744 if (!(szString
= msi_alloc((++dwSize
)*sizeof(WCHAR
))))
1745 ERR("Out of memory\n");
1746 else if ((ret
= MsiGetProductInfoW(V_BSTR(&varg0
), V_BSTR(&varg1
), szString
, &dwSize
)) == ERROR_SUCCESS
)
1747 V_BSTR(pVarResult
) = SysAllocString(szString
);
1750 if (ret
!= ERROR_SUCCESS
)
1752 ERR("MsiGetProductInfo returned %d\n", ret
);
1753 VariantClear(&varg1
);
1754 VariantClear(&varg0
);
1755 return DISP_E_EXCEPTION
;
1758 else return DISP_E_MEMBERNOTFOUND
;
1761 case DISPID_INSTALLER_PRODUCTS
:
1762 if (wFlags
& DISPATCH_PROPERTYGET
)
1764 ListData
*ldata
= NULL
;
1766 WCHAR szProductBuf
[GUID_SIZE
];
1768 /* Find number of products */
1769 while ((ret
= MsiEnumProductsW(idx
, szProductBuf
)) == ERROR_SUCCESS
) idx
++;
1770 if (ret
!= ERROR_NO_MORE_ITEMS
)
1772 ERR("MsiEnumProducts returned %d\n", ret
);
1773 return DISP_E_EXCEPTION
;
1776 V_VT(pVarResult
) = VT_DISPATCH
;
1777 if (SUCCEEDED(hr
= create_automation_object(0, NULL
, (LPVOID
*)&pDispatch
, &DIID_StringList
, ListImpl_Invoke
, ListImpl_Free
, sizeof(ListData
))))
1779 IDispatch_AddRef(pDispatch
);
1780 V_DISPATCH(pVarResult
) = pDispatch
;
1782 /* Save product strings */
1783 ldata
= (ListData
*)private_data((AutomationObject
*)pDispatch
);
1784 if (!(ldata
->pVars
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(VARIANT
)*idx
)))
1785 ERR("Out of memory\n");
1788 ldata
->ulCount
= idx
;
1789 for (idx
= 0; idx
< ldata
->ulCount
; idx
++)
1791 ret
= MsiEnumProductsW(idx
, szProductBuf
);
1792 VariantInit(&ldata
->pVars
[idx
]);
1793 V_VT(&ldata
->pVars
[idx
]) = VT_BSTR
;
1794 V_BSTR(&ldata
->pVars
[idx
]) = SysAllocString(szProductBuf
);
1799 ERR("Failed to create StringList object, hresult 0x%08x\n", hr
);
1801 else return DISP_E_MEMBERNOTFOUND
;
1804 case DISPID_INSTALLER_RELATEDPRODUCTS
:
1805 if (wFlags
& DISPATCH_PROPERTYGET
)
1807 ListData
*ldata
= NULL
;
1809 WCHAR szProductBuf
[GUID_SIZE
];
1811 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1812 if (FAILED(hr
)) return hr
;
1814 /* Find number of related products */
1815 while ((ret
= MsiEnumRelatedProductsW(V_BSTR(&varg0
), 0, idx
, szProductBuf
)) == ERROR_SUCCESS
) idx
++;
1816 if (ret
!= ERROR_NO_MORE_ITEMS
)
1818 VariantClear(&varg0
);
1819 ERR("MsiEnumRelatedProducts returned %d\n", ret
);
1820 return DISP_E_EXCEPTION
;
1823 V_VT(pVarResult
) = VT_DISPATCH
;
1824 if (SUCCEEDED(hr
= create_automation_object(0, NULL
, (LPVOID
*)&pDispatch
, &DIID_StringList
, ListImpl_Invoke
, ListImpl_Free
, sizeof(ListData
))))
1826 IDispatch_AddRef(pDispatch
);
1827 V_DISPATCH(pVarResult
) = pDispatch
;
1829 /* Save product strings */
1830 ldata
= (ListData
*)private_data((AutomationObject
*)pDispatch
);
1831 if (!(ldata
->pVars
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(VARIANT
)*idx
)))
1832 ERR("Out of memory\n");
1835 ldata
->ulCount
= idx
;
1836 for (idx
= 0; idx
< ldata
->ulCount
; idx
++)
1838 ret
= MsiEnumRelatedProductsW(V_BSTR(&varg0
), 0, idx
, szProductBuf
);
1839 VariantInit(&ldata
->pVars
[idx
]);
1840 V_VT(&ldata
->pVars
[idx
]) = VT_BSTR
;
1841 V_BSTR(&ldata
->pVars
[idx
]) = SysAllocString(szProductBuf
);
1846 ERR("Failed to create StringList object, hresult 0x%08x\n", hr
);
1848 else return DISP_E_MEMBERNOTFOUND
;
1852 ERR("Member not found: %d\n", dispIdMember
);
1853 return DISP_E_MEMBERNOTFOUND
;
1856 VariantClear(&varg2
);
1857 VariantClear(&varg1
);
1858 VariantClear(&varg0
);
1863 /* Wrapper around create_automation_object to create an installer object. */
1864 HRESULT
create_msiserver(IUnknown
*pOuter
, LPVOID
*ppObj
)
1866 return create_automation_object(0, pOuter
, ppObj
, &DIID_Installer
, InstallerImpl_Invoke
, NULL
, 0);
1869 /* Wrapper around create_automation_object to create a session object. */
1870 HRESULT
create_session(MSIHANDLE msiHandle
, IDispatch
*pInstaller
, IDispatch
**pDispatch
)
1872 HRESULT hr
= create_automation_object(msiHandle
, NULL
, (LPVOID
)pDispatch
, &DIID_Session
, SessionImpl_Invoke
, NULL
, sizeof(SessionData
));
1873 if (SUCCEEDED(hr
) && pDispatch
&& *pDispatch
)
1874 ((SessionData
*)private_data((AutomationObject
*)*pDispatch
))->pInstaller
= pInstaller
;