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
);
42 #define REG_INDEX_CLASSES_ROOT 0
43 #define REG_INDEX_DYN_DATA 6
46 * AutomationObject - "base" class for all automation objects. For each interface, we implement Invoke function
47 * called from AutomationObject::Invoke, and pass this function to create_automation_object.
50 typedef interface AutomationObject AutomationObject
;
52 interface AutomationObject
{
54 * VTables - We provide IDispatch, IProvideClassInfo, IProvideClassInfo2, IProvideMultipleClassInfo
56 const IDispatchVtbl
*lpVtbl
;
57 const IProvideMultipleClassInfoVtbl
*lpvtblIProvideMultipleClassInfo
;
59 /* Object reference count */
62 /* Clsid for this class and it's appropriate ITypeInfo object */
66 /* The MSI handle of the current object */
69 /* A function that is called from AutomationObject::Invoke, specific to this type of object. */
70 HRESULT (STDMETHODCALLTYPE
*funcInvoke
)(
71 AutomationObject
* This
,
76 DISPPARAMS
* pDispParams
,
78 EXCEPINFO
* pExcepInfo
,
81 /* A function that is called from AutomationObject::Release when the object is being freed to free any private
82 * data structures (or NULL) */
83 void (STDMETHODCALLTYPE
*funcFree
)(AutomationObject
* This
);
87 * ListEnumerator - IEnumVARIANT implementation for MSI automation lists.
90 typedef interface ListEnumerator ListEnumerator
;
92 interface ListEnumerator
{
94 const IEnumVARIANTVtbl
*lpVtbl
;
96 /* Object reference count */
99 /* Current position and pointer to AutomationObject that stores actual data */
101 AutomationObject
*pObj
;
105 * Structures for additional data required by specific automation objects
114 /* The parent Installer object */
115 IDispatch
*pInstaller
;
119 static const struct IDispatchVtbl AutomationObject_Vtbl
;
120 static const struct IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl
;
121 static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl
;
123 /* Load type info so we don't have to process GetIDsOfNames */
124 HRESULT
load_type_info(IDispatch
*iface
, ITypeInfo
**pptinfo
, REFIID clsid
, LCID lcid
)
127 LPTYPELIB pLib
= NULL
;
128 LPTYPEINFO pInfo
= NULL
;
129 static const WCHAR szMsiServer
[] = {'m','s','i','s','e','r','v','e','r','.','t','l','b'};
131 TRACE("(%p)->(%s,%d)\n", iface
, debugstr_guid(clsid
), lcid
);
133 /* Load registered type library */
134 hr
= LoadRegTypeLib(&LIBID_WindowsInstaller
, 1, 0, lcid
, &pLib
);
136 hr
= LoadTypeLib(szMsiServer
, &pLib
);
138 ERR("Could not load msiserver.tlb\n");
143 /* Get type information for object */
144 hr
= ITypeLib_GetTypeInfoOfGuid(pLib
, clsid
, &pInfo
);
145 ITypeLib_Release(pLib
);
147 ERR("Could not load ITypeInfo for %s\n", debugstr_guid(clsid
));
154 /* Create the automation object, placing the result in the pointer ppObj. The automation object is created
155 * with the appropriate clsid and invocation function. */
156 static HRESULT
create_automation_object(MSIHANDLE msiHandle
, IUnknown
*pUnkOuter
, LPVOID
*ppObj
, REFIID clsid
,
157 HRESULT (STDMETHODCALLTYPE
*funcInvoke
)(AutomationObject
*,DISPID
,REFIID
,LCID
,WORD
,DISPPARAMS
*,
158 VARIANT
*,EXCEPINFO
*,UINT
*),
159 void (STDMETHODCALLTYPE
*funcFree
)(AutomationObject
*),
160 SIZE_T sizetPrivateData
)
162 AutomationObject
*object
;
165 TRACE("(%ld,%p,%p,%s,%p,%p,%ld)\n", (unsigned long)msiHandle
, pUnkOuter
, ppObj
, debugstr_guid(clsid
), funcInvoke
, funcFree
, sizetPrivateData
);
168 return CLASS_E_NOAGGREGATION
;
170 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(AutomationObject
)+sizetPrivateData
);
172 /* Set all the VTable references */
173 object
->lpVtbl
= &AutomationObject_Vtbl
;
174 object
->lpvtblIProvideMultipleClassInfo
= &AutomationObject_IProvideMultipleClassInfo_Vtbl
;
177 /* Store data that was passed */
178 object
->msiHandle
= msiHandle
;
179 object
->clsid
= (LPCLSID
)clsid
;
180 object
->funcInvoke
= funcInvoke
;
181 object
->funcFree
= funcFree
;
183 /* Load our TypeInfo so we don't have to process GetIDsOfNames */
184 object
->iTypeInfo
= NULL
;
185 hr
= load_type_info((IDispatch
*)object
, &object
->iTypeInfo
, clsid
, 0x0);
187 HeapFree(GetProcessHeap(), 0, object
);
196 /* Create a list enumerator, placing the result in the pointer ppObj. */
197 static HRESULT
create_list_enumerator(IUnknown
*pUnkOuter
, LPVOID
*ppObj
, AutomationObject
*pObj
, ULONG ulPos
)
199 ListEnumerator
*object
;
201 TRACE("(%p,%p,%p,%uld)\n", pUnkOuter
, ppObj
, pObj
, ulPos
);
204 return CLASS_E_NOAGGREGATION
;
206 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(ListEnumerator
));
208 /* Set all the VTable references */
209 object
->lpVtbl
= &ListEnumerator_Vtbl
;
212 /* Store data that was passed */
213 object
->ulPos
= ulPos
;
215 if (pObj
) IDispatch_AddRef((IDispatch
*)pObj
);
221 /* Macros to get pointer to AutomationObject from the other VTables. */
222 static inline AutomationObject
*obj_from_IProvideMultipleClassInfo( IProvideMultipleClassInfo
*iface
)
224 return (AutomationObject
*)((char*)iface
- FIELD_OFFSET(AutomationObject
, lpvtblIProvideMultipleClassInfo
));
227 /* Macro to get pointer to private object data */
228 static inline void *private_data( AutomationObject
*This
)
234 * AutomationObject methods
237 /*** IUnknown methods ***/
238 static HRESULT WINAPI
AutomationObject_QueryInterface(IDispatch
* iface
, REFIID riid
, void** ppvObject
)
240 AutomationObject
*This
= (AutomationObject
*)iface
;
242 TRACE("(%p/%p)->(%s,%p)\n", iface
, This
, debugstr_guid(riid
), ppvObject
);
244 if (ppvObject
== NULL
)
249 if (IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_IDispatch
) || IsEqualGUID(riid
, This
->clsid
))
251 else if (IsEqualGUID(riid
, &IID_IProvideClassInfo
) ||
252 IsEqualGUID(riid
, &IID_IProvideClassInfo2
) ||
253 IsEqualGUID(riid
, &IID_IProvideMultipleClassInfo
))
254 *ppvObject
= &This
->lpvtblIProvideMultipleClassInfo
;
257 TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid
));
258 return E_NOINTERFACE
;
262 * Query Interface always increases the reference count by one when it is
265 IClassFactory_AddRef(iface
);
270 static ULONG WINAPI
AutomationObject_AddRef(IDispatch
* iface
)
272 AutomationObject
*This
= (AutomationObject
*)iface
;
274 TRACE("(%p/%p)\n", iface
, This
);
276 return InterlockedIncrement(&This
->ref
);
279 static ULONG WINAPI
AutomationObject_Release(IDispatch
* iface
)
281 AutomationObject
*This
= (AutomationObject
*)iface
;
282 ULONG ref
= InterlockedDecrement(&This
->ref
);
284 TRACE("(%p/%p)\n", iface
, This
);
288 if (This
->funcFree
) This
->funcFree(This
);
289 ITypeInfo_Release(This
->iTypeInfo
);
290 MsiCloseHandle(This
->msiHandle
);
291 HeapFree(GetProcessHeap(), 0, This
);
297 /*** IDispatch methods ***/
298 static HRESULT WINAPI
AutomationObject_GetTypeInfoCount(
302 AutomationObject
*This
= (AutomationObject
*)iface
;
304 TRACE("(%p/%p)->(%p)\n", iface
, This
, pctinfo
);
309 static HRESULT WINAPI
AutomationObject_GetTypeInfo(
315 AutomationObject
*This
= (AutomationObject
*)iface
;
316 TRACE("(%p/%p)->(%d,%d,%p)\n", iface
, This
, iTInfo
, lcid
, ppTInfo
);
318 ITypeInfo_AddRef(This
->iTypeInfo
);
319 *ppTInfo
= This
->iTypeInfo
;
323 static HRESULT WINAPI
AutomationObject_GetIDsOfNames(
331 AutomationObject
*This
= (AutomationObject
*)iface
;
333 TRACE("(%p/%p)->(%p,%p,%d,%d,%p)\n", iface
, This
, riid
, rgszNames
, cNames
, lcid
, rgDispId
);
335 if (!IsEqualGUID(riid
, &IID_NULL
)) return E_INVALIDARG
;
336 hr
= ITypeInfo_GetIDsOfNames(This
->iTypeInfo
, rgszNames
, cNames
, rgDispId
);
337 if (hr
== DISP_E_UNKNOWNNAME
)
340 for (idx
=0; idx
<cNames
; idx
++)
342 if (rgDispId
[idx
] == DISPID_UNKNOWN
)
343 FIXME("Unknown member %s, clsid %s\n", debugstr_w(rgszNames
[idx
]), debugstr_guid(This
->clsid
));
349 /* Maximum number of allowed function parameters+1 */
350 #define MAX_FUNC_PARAMS 20
352 /* Some error checking is done here to simplify individual object function invocation */
353 static HRESULT WINAPI
AutomationObject_Invoke(
359 DISPPARAMS
* pDispParams
,
361 EXCEPINFO
* pExcepInfo
,
364 AutomationObject
*This
= (AutomationObject
*)iface
;
366 unsigned int uArgErr
;
367 VARIANT varResultDummy
;
368 BSTR bstrName
= NULL
;
370 TRACE("(%p/%p)->(%d,%p,%d,%d,%p,%p,%p,%p)\n", iface
, This
, dispIdMember
, riid
, lcid
, wFlags
, pDispParams
, pVarResult
, pExcepInfo
, puArgErr
);
372 if (!IsEqualIID(riid
, &IID_NULL
))
374 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid
));
375 return DISP_E_UNKNOWNNAME
;
378 if (wFlags
& DISPATCH_PROPERTYGET
&& !pVarResult
)
380 ERR("NULL pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
381 return DISP_E_PARAMNOTOPTIONAL
;
384 /* This simplifies our individual object invocation functions */
385 if (puArgErr
== NULL
) puArgErr
= &uArgErr
;
386 if (pVarResult
== NULL
) pVarResult
= &varResultDummy
;
388 /* Assume return type is void unless determined otherwise */
389 VariantInit(pVarResult
);
391 /* If we are tracing, we want to see the name of the member we are invoking */
394 ITypeInfo_GetDocumentation(This
->iTypeInfo
, dispIdMember
, &bstrName
, NULL
, NULL
, NULL
);
395 TRACE("Method %d, %s\n", dispIdMember
, debugstr_w(bstrName
));
398 hr
= This
->funcInvoke(This
,dispIdMember
,riid
,lcid
,wFlags
,pDispParams
,pVarResult
,pExcepInfo
,puArgErr
);
400 if (hr
== DISP_E_MEMBERNOTFOUND
) {
401 if (bstrName
== NULL
) ITypeInfo_GetDocumentation(This
->iTypeInfo
, dispIdMember
, &bstrName
, NULL
, NULL
, NULL
);
402 FIXME("Method %d, %s wflags %d not implemented, clsid %s\n", dispIdMember
, debugstr_w(bstrName
), wFlags
, debugstr_guid(This
->clsid
));
404 else if (pExcepInfo
&&
405 (hr
== DISP_E_PARAMNOTFOUND
||
406 hr
== DISP_E_EXCEPTION
)) {
407 static const WCHAR szComma
[] = { ',',0 };
408 static const WCHAR szExceptionSource
[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
409 WCHAR szExceptionDescription
[MAX_PATH
];
410 BSTR bstrParamNames
[MAX_FUNC_PARAMS
];
414 if (FAILED(ITypeInfo_GetNames(This
->iTypeInfo
, dispIdMember
, bstrParamNames
,
415 MAX_FUNC_PARAMS
, &namesNo
)))
417 TRACE("Failed to retrieve names for dispIdMember %d\n", dispIdMember
);
421 memset(szExceptionDescription
, 0, sizeof(szExceptionDescription
));
422 for (i
=0; i
<namesNo
; i
++)
424 if (bFirst
) bFirst
= FALSE
;
426 lstrcpyW(&szExceptionDescription
[lstrlenW(szExceptionDescription
)], szComma
);
428 lstrcpyW(&szExceptionDescription
[lstrlenW(szExceptionDescription
)], bstrParamNames
[i
]);
429 SysFreeString(bstrParamNames
[i
]);
432 memset(pExcepInfo
, 0, sizeof(EXCEPINFO
));
433 pExcepInfo
->wCode
= 1000;
434 pExcepInfo
->bstrSource
= SysAllocString(szExceptionSource
);
435 pExcepInfo
->bstrDescription
= SysAllocString(szExceptionDescription
);
436 hr
= DISP_E_EXCEPTION
;
440 /* Make sure we free the return variant if it is our dummy variant */
441 if (pVarResult
== &varResultDummy
) VariantClear(pVarResult
);
443 /* Free function name if we retrieved it */
444 SysFreeString(bstrName
);
446 TRACE("Returning 0x%08x, %s\n", hr
, SUCCEEDED(hr
) ? "ok" : "not ok");
451 static const struct IDispatchVtbl AutomationObject_Vtbl
=
453 AutomationObject_QueryInterface
,
454 AutomationObject_AddRef
,
455 AutomationObject_Release
,
456 AutomationObject_GetTypeInfoCount
,
457 AutomationObject_GetTypeInfo
,
458 AutomationObject_GetIDsOfNames
,
459 AutomationObject_Invoke
463 * IProvideMultipleClassInfo methods
466 static HRESULT WINAPI
AutomationObject_IProvideMultipleClassInfo_QueryInterface(
467 IProvideMultipleClassInfo
* iface
,
471 AutomationObject
*This
= obj_from_IProvideMultipleClassInfo(iface
);
472 return AutomationObject_QueryInterface((IDispatch
*)This
, riid
, ppvoid
);
475 static ULONG WINAPI
AutomationObject_IProvideMultipleClassInfo_AddRef(IProvideMultipleClassInfo
* iface
)
477 AutomationObject
*This
= obj_from_IProvideMultipleClassInfo(iface
);
478 return AutomationObject_AddRef((IDispatch
*)This
);
481 static ULONG WINAPI
AutomationObject_IProvideMultipleClassInfo_Release(IProvideMultipleClassInfo
* iface
)
483 AutomationObject
*This
= obj_from_IProvideMultipleClassInfo(iface
);
484 return AutomationObject_Release((IDispatch
*)This
);
487 static HRESULT WINAPI
AutomationObject_IProvideMultipleClassInfo_GetClassInfo(IProvideMultipleClassInfo
* iface
, ITypeInfo
** ppTI
)
489 AutomationObject
*This
= obj_from_IProvideMultipleClassInfo(iface
);
490 TRACE("(%p/%p)->(%p)\n", iface
, This
, ppTI
);
491 return load_type_info((IDispatch
*)This
, ppTI
, This
->clsid
, 0);
494 static HRESULT WINAPI
AutomationObject_IProvideMultipleClassInfo_GetGUID(IProvideMultipleClassInfo
* iface
, DWORD dwGuidKind
, GUID
* pGUID
)
496 AutomationObject
*This
= obj_from_IProvideMultipleClassInfo(iface
);
497 TRACE("(%p/%p)->(%d,%s)\n", iface
, This
, dwGuidKind
, debugstr_guid(pGUID
));
499 if (dwGuidKind
!= GUIDKIND_DEFAULT_SOURCE_DISP_IID
)
502 *pGUID
= *This
->clsid
;
507 static HRESULT WINAPI
AutomationObject_GetMultiTypeInfoCount(IProvideMultipleClassInfo
* iface
, ULONG
* pcti
)
509 AutomationObject
*This
= obj_from_IProvideMultipleClassInfo(iface
);
511 TRACE("(%p/%p)->(%p)\n", iface
, This
, pcti
);
516 static HRESULT WINAPI
AutomationObject_GetInfoOfIndex(IProvideMultipleClassInfo
* iface
,
519 ITypeInfo
** pptiCoClass
,
521 ULONG
* pcdispidReserved
,
525 AutomationObject
*This
= obj_from_IProvideMultipleClassInfo(iface
);
527 TRACE("(%p/%p)->(%d,%d,%p,%p,%p,%p,%p)\n", iface
, This
, iti
, dwFlags
, pptiCoClass
, pdwTIFlags
, pcdispidReserved
, piidPrimary
, piidSource
);
532 if (dwFlags
& MULTICLASSINFO_GETTYPEINFO
)
533 load_type_info((IDispatch
*)This
, pptiCoClass
, This
->clsid
, 0);
535 if (dwFlags
& MULTICLASSINFO_GETNUMRESERVEDDISPIDS
)
538 *pcdispidReserved
= 0;
541 if (dwFlags
& MULTICLASSINFO_GETIIDPRIMARY
){
542 *piidPrimary
= *This
->clsid
;
545 if (dwFlags
& MULTICLASSINFO_GETIIDSOURCE
){
546 *piidSource
= *This
->clsid
;
552 static const IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl
=
554 AutomationObject_IProvideMultipleClassInfo_QueryInterface
,
555 AutomationObject_IProvideMultipleClassInfo_AddRef
,
556 AutomationObject_IProvideMultipleClassInfo_Release
,
557 AutomationObject_IProvideMultipleClassInfo_GetClassInfo
,
558 AutomationObject_IProvideMultipleClassInfo_GetGUID
,
559 AutomationObject_GetMultiTypeInfoCount
,
560 AutomationObject_GetInfoOfIndex
564 * ListEnumerator methods
567 /*** IUnknown methods ***/
568 static HRESULT WINAPI
ListEnumerator_QueryInterface(IEnumVARIANT
* iface
, REFIID riid
, void** ppvObject
)
570 ListEnumerator
*This
= (ListEnumerator
*)iface
;
572 TRACE("(%p/%p)->(%s,%p)\n", iface
, This
, debugstr_guid(riid
), ppvObject
);
574 if (ppvObject
== NULL
)
579 if (IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_IEnumVARIANT
))
583 TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid
));
584 return E_NOINTERFACE
;
587 IClassFactory_AddRef(iface
);
591 static ULONG WINAPI
ListEnumerator_AddRef(IEnumVARIANT
* iface
)
593 ListEnumerator
*This
= (ListEnumerator
*)iface
;
595 TRACE("(%p/%p)\n", iface
, This
);
597 return InterlockedIncrement(&This
->ref
);
600 static ULONG WINAPI
ListEnumerator_Release(IEnumVARIANT
* iface
)
602 ListEnumerator
*This
= (ListEnumerator
*)iface
;
603 ULONG ref
= InterlockedDecrement(&This
->ref
);
605 TRACE("(%p/%p)\n", iface
, This
);
609 if (This
->pObj
) IDispatch_Release((IDispatch
*)This
->pObj
);
610 HeapFree(GetProcessHeap(), 0, This
);
616 /* IEnumVARIANT methods */
618 static HRESULT WINAPI
ListEnumerator_Next(IEnumVARIANT
* iface
, ULONG celt
, VARIANT
*rgVar
, ULONG
*pCeltFetched
)
620 ListEnumerator
*This
= (ListEnumerator
*)iface
;
621 ListData
*data
= (ListData
*)private_data(This
->pObj
);
624 TRACE("(%p,%uld,%p,%p)\n", iface
, celt
, rgVar
, pCeltFetched
);
626 if (pCeltFetched
!= NULL
)
632 for (local
= 0; local
< celt
; local
++)
633 VariantInit(&rgVar
[local
]);
635 for (idx
= This
->ulPos
, local
= 0; idx
< data
->ulCount
&& local
< celt
; idx
++, local
++)
636 VariantCopy(&rgVar
[local
], &data
->pVars
[idx
]);
638 if (pCeltFetched
!= NULL
)
639 *pCeltFetched
= local
;
642 return (local
< celt
) ? S_FALSE
: S_OK
;
645 static HRESULT WINAPI
ListEnumerator_Skip(IEnumVARIANT
* iface
, ULONG celt
)
647 ListEnumerator
*This
= (ListEnumerator
*)iface
;
648 ListData
*data
= (ListData
*)private_data(This
->pObj
);
650 TRACE("(%p,%uld)\n", iface
, celt
);
653 if (This
->ulPos
>= data
->ulCount
)
655 This
->ulPos
= data
->ulCount
;
661 static HRESULT WINAPI
ListEnumerator_Reset(IEnumVARIANT
* iface
)
663 ListEnumerator
*This
= (ListEnumerator
*)iface
;
665 TRACE("(%p)\n", iface
);
671 static HRESULT WINAPI
ListEnumerator_Clone(IEnumVARIANT
* iface
, IEnumVARIANT
**ppEnum
)
673 ListEnumerator
*This
= (ListEnumerator
*)iface
;
676 TRACE("(%p,%p)\n", iface
, ppEnum
);
682 hr
= create_list_enumerator(NULL
, (LPVOID
*)ppEnum
, This
->pObj
, 0);
686 IUnknown_Release(*ppEnum
);
693 static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl
=
695 ListEnumerator_QueryInterface
,
696 ListEnumerator_AddRef
,
697 ListEnumerator_Release
,
700 ListEnumerator_Reset
,
705 * Individual Object Invocation Functions
708 /* Helper function that copies a passed parameter instead of using VariantChangeType like the actual DispGetParam.
709 This function is only for VARIANT type parameters that have several types that cannot be properly discriminated
710 using DispGetParam/VariantChangeType. */
711 static HRESULT WINAPI
DispGetParam_CopyOnly(
712 DISPPARAMS
*pdispparams
, /* [in] Parameter list */
713 UINT
*position
, /* [in] Position of parameter to copy in pdispparams; on return will contain calculated position */
714 VARIANT
*pvarResult
) /* [out] Destination for resulting variant */
716 /* position is counted backwards */
719 TRACE("position=%d, cArgs=%d, cNamedArgs=%d\n",
720 *position
, pdispparams
->cArgs
, pdispparams
->cNamedArgs
);
721 if (*position
< pdispparams
->cArgs
) {
722 /* positional arg? */
723 pos
= pdispparams
->cArgs
- *position
- 1;
725 /* FIXME: is this how to handle named args? */
726 for (pos
=0; pos
<pdispparams
->cNamedArgs
; pos
++)
727 if (pdispparams
->rgdispidNamedArgs
[pos
] == *position
) break;
729 if (pos
==pdispparams
->cNamedArgs
)
730 return DISP_E_PARAMNOTFOUND
;
733 return VariantCopyInd(pvarResult
,
734 &pdispparams
->rgvarg
[pos
]);
737 static HRESULT WINAPI
SummaryInfoImpl_Invoke(
738 AutomationObject
* This
,
743 DISPPARAMS
* pDispParams
,
745 EXCEPINFO
* pExcepInfo
,
749 VARIANTARG varg0
, varg1
;
750 FILETIME ft
, ftlocal
;
757 switch (dispIdMember
)
759 case DISPID_SUMMARYINFO_PROPERTY
:
760 if (wFlags
& DISPATCH_PROPERTYGET
)
768 static WCHAR szEmpty
[] = {0};
770 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
771 if (FAILED(hr
)) return hr
;
772 ret
= MsiSummaryInfoGetPropertyW(This
->msiHandle
, V_I4(&varg0
), &type
, &value
,
773 &ft
, szEmpty
, &size
);
774 if (ret
!= ERROR_SUCCESS
&&
775 ret
!= ERROR_MORE_DATA
)
777 ERR("MsiSummaryInfoGetProperty returned %d\n", ret
);
778 return DISP_E_EXCEPTION
;
788 V_VT(pVarResult
) = VT_I4
;
789 V_I4(pVarResult
) = value
;
793 if (!(str
= msi_alloc(++size
* sizeof(WCHAR
))))
794 ERR("Out of memory\n");
795 else if ((ret
= MsiSummaryInfoGetPropertyW(This
->msiHandle
, V_I4(&varg0
), &type
, NULL
,
796 NULL
, str
, &size
)) != ERROR_SUCCESS
)
797 ERR("MsiSummaryInfoGetProperty returned %d\n", ret
);
800 V_VT(pVarResult
) = VT_BSTR
;
801 V_BSTR(pVarResult
) = SysAllocString(str
);
807 FileTimeToLocalFileTime(&ft
, &ftlocal
);
808 FileTimeToSystemTime(&ftlocal
, &st
);
809 SystemTimeToVariantTime(&st
, &date
);
811 V_VT(pVarResult
) = VT_DATE
;
812 V_DATE(pVarResult
) = date
;
816 ERR("Unhandled variant type %d\n", type
);
819 else if (wFlags
& DISPATCH_PROPERTYPUT
)
821 UINT posValue
= DISPID_PROPERTYPUT
;
823 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
824 if (FAILED(hr
)) return hr
;
825 hr
= DispGetParam_CopyOnly(pDispParams
, &posValue
, &varg1
);
828 *puArgErr
= posValue
;
832 switch (V_VT(&varg1
))
836 ret
= MsiSummaryInfoSetPropertyW(This
->msiHandle
, V_I4(&varg0
), V_VT(&varg1
), V_I4(&varg1
), NULL
, NULL
);
840 VariantTimeToSystemTime(V_DATE(&varg1
), &st
);
841 SystemTimeToFileTime(&st
, &ftlocal
);
842 LocalFileTimeToFileTime(&ftlocal
, &ft
);
843 ret
= MsiSummaryInfoSetPropertyW(This
->msiHandle
, V_I4(&varg0
), VT_FILETIME
, 0, &ft
, NULL
);
847 ret
= MsiSummaryInfoSetPropertyW(This
->msiHandle
, V_I4(&varg0
), VT_LPSTR
, 0, NULL
, V_BSTR(&varg1
));
851 FIXME("Unhandled variant type %d\n", V_VT(&varg1
));
852 VariantClear(&varg1
);
853 return DISP_E_EXCEPTION
;
856 if (ret
!= ERROR_SUCCESS
)
858 ERR("MsiSummaryInfoSetPropertyW returned %d\n", ret
);
859 return DISP_E_EXCEPTION
;
862 else return DISP_E_MEMBERNOTFOUND
;
865 case DISPID_SUMMARYINFO_PROPERTYCOUNT
:
866 if (wFlags
& DISPATCH_PROPERTYGET
) {
868 if ((ret
= MsiSummaryInfoGetPropertyCount(This
->msiHandle
, &count
)) != ERROR_SUCCESS
)
869 ERR("MsiSummaryInfoGetPropertyCount returned %d\n", ret
);
872 V_VT(pVarResult
) = VT_I4
;
873 V_I4(pVarResult
) = count
;
876 else return DISP_E_MEMBERNOTFOUND
;
880 return DISP_E_MEMBERNOTFOUND
;
883 VariantClear(&varg1
);
884 VariantClear(&varg0
);
889 static HRESULT WINAPI
RecordImpl_Invoke(
890 AutomationObject
* This
,
895 DISPPARAMS
* pDispParams
,
897 EXCEPINFO
* pExcepInfo
,
903 VARIANTARG varg0
, varg1
;
909 switch (dispIdMember
)
911 case DISPID_RECORD_FIELDCOUNT
:
912 if (wFlags
& DISPATCH_PROPERTYGET
) {
913 V_VT(pVarResult
) = VT_I4
;
914 V_I4(pVarResult
) = MsiRecordGetFieldCount(This
->msiHandle
);
916 else return DISP_E_MEMBERNOTFOUND
;
919 case DISPID_RECORD_STRINGDATA
:
920 if (wFlags
& DISPATCH_PROPERTYGET
) {
921 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
922 if (FAILED(hr
)) return hr
;
923 V_VT(pVarResult
) = VT_BSTR
;
924 V_BSTR(pVarResult
) = NULL
;
925 if ((ret
= MsiRecordGetStringW(This
->msiHandle
, V_I4(&varg0
), NULL
, &dwLen
)) == ERROR_SUCCESS
)
927 if (!(szString
= msi_alloc((++dwLen
)*sizeof(WCHAR
))))
928 ERR("Out of memory\n");
929 else if ((ret
= MsiRecordGetStringW(This
->msiHandle
, V_I4(&varg0
), szString
, &dwLen
)) == ERROR_SUCCESS
)
930 V_BSTR(pVarResult
) = SysAllocString(szString
);
933 if (ret
!= ERROR_SUCCESS
)
934 ERR("MsiRecordGetString returned %d\n", ret
);
935 } else if (wFlags
& DISPATCH_PROPERTYPUT
) {
936 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
937 if (FAILED(hr
)) return hr
;
938 hr
= DispGetParam(pDispParams
, DISPID_PROPERTYPUT
, VT_BSTR
, &varg1
, puArgErr
);
939 if (FAILED(hr
)) return hr
;
940 if ((ret
= MsiRecordSetStringW(This
->msiHandle
, V_I4(&varg0
), V_BSTR(&varg1
))) != ERROR_SUCCESS
)
942 VariantClear(&varg1
);
943 ERR("MsiRecordSetString returned %d\n", ret
);
944 return DISP_E_EXCEPTION
;
947 else return DISP_E_MEMBERNOTFOUND
;
950 case DISPID_RECORD_INTEGERDATA
:
951 if (wFlags
& DISPATCH_PROPERTYGET
) {
952 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
953 if (FAILED(hr
)) return hr
;
954 V_VT(pVarResult
) = VT_I4
;
955 V_I4(pVarResult
) = MsiRecordGetInteger(This
->msiHandle
, V_I4(&varg0
));
956 } else if (wFlags
& DISPATCH_PROPERTYPUT
) {
957 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
958 if (FAILED(hr
)) return hr
;
959 hr
= DispGetParam(pDispParams
, DISPID_PROPERTYPUT
, VT_I4
, &varg1
, puArgErr
);
960 if (FAILED(hr
)) return hr
;
961 if ((ret
= MsiRecordSetInteger(This
->msiHandle
, V_I4(&varg0
), V_I4(&varg1
))) != ERROR_SUCCESS
)
963 ERR("MsiRecordSetInteger returned %d\n", ret
);
964 return DISP_E_EXCEPTION
;
967 else return DISP_E_MEMBERNOTFOUND
;
971 return DISP_E_MEMBERNOTFOUND
;
974 VariantClear(&varg1
);
975 VariantClear(&varg0
);
980 static HRESULT WINAPI
ListImpl_Invoke(
981 AutomationObject
* This
,
986 DISPPARAMS
* pDispParams
,
988 EXCEPINFO
* pExcepInfo
,
991 ListData
*data
= (ListData
*)private_data(This
);
994 IUnknown
*pUnk
= NULL
;
998 switch (dispIdMember
)
1000 case DISPID_LIST__NEWENUM
:
1001 if (wFlags
& DISPATCH_METHOD
) {
1002 V_VT(pVarResult
) = VT_UNKNOWN
;
1003 if (SUCCEEDED(hr
= create_list_enumerator(NULL
, (LPVOID
*)&pUnk
, This
, 0)))
1004 V_UNKNOWN(pVarResult
) = pUnk
;
1006 ERR("Failed to create IEnumVARIANT object, hresult 0x%08x\n", hr
);
1008 else return DISP_E_MEMBERNOTFOUND
;
1011 case DISPID_LIST_ITEM
:
1012 if (wFlags
& DISPATCH_PROPERTYGET
) {
1013 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
1014 if (FAILED(hr
)) return hr
;
1015 if (V_I4(&varg0
) < 0 || V_I4(&varg0
) >= data
->ulCount
)
1016 return DISP_E_BADINDEX
;
1017 VariantCopy(pVarResult
, &data
->pVars
[V_I4(&varg0
)]);
1019 else return DISP_E_MEMBERNOTFOUND
;
1022 case DISPID_LIST_COUNT
:
1023 if (wFlags
& DISPATCH_PROPERTYGET
) {
1024 V_VT(pVarResult
) = VT_I4
;
1025 V_I4(pVarResult
) = data
->ulCount
;
1027 else return DISP_E_MEMBERNOTFOUND
;
1031 return DISP_E_MEMBERNOTFOUND
;
1034 VariantClear(&varg0
);
1039 static void WINAPI
ListImpl_Free(AutomationObject
*This
)
1041 ListData
*data
= private_data(This
);
1044 for (idx
=0; idx
<data
->ulCount
; idx
++)
1045 VariantClear(&data
->pVars
[idx
]);
1046 HeapFree(GetProcessHeap(), 0, data
->pVars
);
1049 static HRESULT WINAPI
ViewImpl_Invoke(
1050 AutomationObject
* This
,
1051 DISPID dispIdMember
,
1055 DISPPARAMS
* pDispParams
,
1056 VARIANT
* pVarResult
,
1057 EXCEPINFO
* pExcepInfo
,
1060 MSIHANDLE msiHandle
;
1061 IDispatch
*pDispatch
= NULL
;
1063 VARIANTARG varg0
, varg1
;
1066 VariantInit(&varg0
);
1067 VariantInit(&varg1
);
1069 switch (dispIdMember
)
1071 case DISPID_VIEW_EXECUTE
:
1072 if (wFlags
& DISPATCH_METHOD
)
1074 hr
= DispGetParam(pDispParams
, 0, VT_DISPATCH
, &varg0
, puArgErr
);
1075 if (SUCCEEDED(hr
) && V_DISPATCH(&varg0
) != NULL
)
1076 MsiViewExecute(This
->msiHandle
, ((AutomationObject
*)V_DISPATCH(&varg0
))->msiHandle
);
1078 MsiViewExecute(This
->msiHandle
, 0);
1080 else return DISP_E_MEMBERNOTFOUND
;
1083 case DISPID_VIEW_FETCH
:
1084 if (wFlags
& DISPATCH_METHOD
)
1086 V_VT(pVarResult
) = VT_DISPATCH
;
1087 if ((ret
= MsiViewFetch(This
->msiHandle
, &msiHandle
)) == ERROR_SUCCESS
)
1089 if (SUCCEEDED(hr
= create_automation_object(msiHandle
, NULL
, (LPVOID
*)&pDispatch
, &DIID_Record
, RecordImpl_Invoke
, NULL
, 0)))
1090 V_DISPATCH(pVarResult
) = pDispatch
;
1092 ERR("Failed to create Record object, hresult 0x%08x\n", hr
);
1094 else if (ret
== ERROR_NO_MORE_ITEMS
)
1095 V_DISPATCH(pVarResult
) = NULL
;
1098 ERR("MsiViewFetch returned %d\n", ret
);
1099 return DISP_E_EXCEPTION
;
1102 else return DISP_E_MEMBERNOTFOUND
;
1105 case DISPID_VIEW_MODIFY
:
1106 if (wFlags
& DISPATCH_METHOD
)
1108 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
1109 if (FAILED(hr
)) return hr
;
1110 hr
= DispGetParam(pDispParams
, 1, VT_DISPATCH
, &varg1
, puArgErr
);
1111 if (FAILED(hr
)) return hr
;
1112 if (!V_DISPATCH(&varg1
)) return DISP_E_EXCEPTION
;
1113 if ((ret
= MsiViewModify(This
->msiHandle
, V_I4(&varg0
), ((AutomationObject
*)V_DISPATCH(&varg1
))->msiHandle
)) != ERROR_SUCCESS
)
1115 VariantClear(&varg1
);
1116 ERR("MsiViewModify returned %d\n", ret
);
1117 return DISP_E_EXCEPTION
;
1120 else return DISP_E_MEMBERNOTFOUND
;
1123 case DISPID_VIEW_CLOSE
:
1124 if (wFlags
& DISPATCH_METHOD
)
1126 MsiViewClose(This
->msiHandle
);
1128 else return DISP_E_MEMBERNOTFOUND
;
1132 return DISP_E_MEMBERNOTFOUND
;
1135 VariantClear(&varg1
);
1136 VariantClear(&varg0
);
1141 static HRESULT WINAPI
DatabaseImpl_Invoke(
1142 AutomationObject
* This
,
1143 DISPID dispIdMember
,
1147 DISPPARAMS
* pDispParams
,
1148 VARIANT
* pVarResult
,
1149 EXCEPINFO
* pExcepInfo
,
1152 MSIHANDLE msiHandle
;
1153 IDispatch
*pDispatch
= NULL
;
1155 VARIANTARG varg0
, varg1
;
1158 VariantInit(&varg0
);
1159 VariantInit(&varg1
);
1161 switch (dispIdMember
)
1163 case DISPID_DATABASE_SUMMARYINFORMATION
:
1164 if (wFlags
& DISPATCH_PROPERTYGET
)
1166 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
1170 V_VT(pVarResult
) = VT_DISPATCH
;
1171 if ((ret
= MsiGetSummaryInformationW(This
->msiHandle
, NULL
, V_I4(&varg0
), &msiHandle
)) == ERROR_SUCCESS
)
1173 hr
= create_automation_object(msiHandle
, NULL
, (LPVOID
*)&pDispatch
, &DIID_SummaryInfo
, SummaryInfoImpl_Invoke
, NULL
, 0);
1175 V_DISPATCH(pVarResult
) = pDispatch
;
1177 ERR("Failed to create SummaryInfo object: 0x%08x\n", hr
);
1181 ERR("MsiGetSummaryInformation returned %d\n", ret
);
1182 return DISP_E_EXCEPTION
;
1185 else return DISP_E_MEMBERNOTFOUND
;
1188 case DISPID_DATABASE_OPENVIEW
:
1189 if (wFlags
& DISPATCH_METHOD
)
1191 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1192 if (FAILED(hr
)) return hr
;
1193 V_VT(pVarResult
) = VT_DISPATCH
;
1194 if ((ret
= MsiDatabaseOpenViewW(This
->msiHandle
, V_BSTR(&varg0
), &msiHandle
)) == ERROR_SUCCESS
)
1196 if (SUCCEEDED(hr
= create_automation_object(msiHandle
, NULL
, (LPVOID
*)&pDispatch
, &DIID_View
, ViewImpl_Invoke
, NULL
, 0)))
1197 V_DISPATCH(pVarResult
) = pDispatch
;
1199 ERR("Failed to create View object, hresult 0x%08x\n", hr
);
1203 VariantClear(&varg0
);
1204 ERR("MsiDatabaseOpenView returned %d\n", ret
);
1205 return DISP_E_EXCEPTION
;
1208 else return DISP_E_MEMBERNOTFOUND
;
1212 return DISP_E_MEMBERNOTFOUND
;
1215 VariantClear(&varg1
);
1216 VariantClear(&varg0
);
1221 static HRESULT WINAPI
SessionImpl_Invoke(
1222 AutomationObject
* This
,
1223 DISPID dispIdMember
,
1227 DISPPARAMS
* pDispParams
,
1228 VARIANT
* pVarResult
,
1229 EXCEPINFO
* pExcepInfo
,
1232 SessionData
*data
= private_data(This
);
1235 IDispatch
*pDispatch
= NULL
;
1236 MSIHANDLE msiHandle
;
1239 INSTALLSTATE iInstalled
, iAction
;
1240 VARIANTARG varg0
, varg1
;
1243 VariantInit(&varg0
);
1244 VariantInit(&varg1
);
1246 switch (dispIdMember
)
1248 case DISPID_SESSION_INSTALLER
:
1249 if (wFlags
& DISPATCH_PROPERTYGET
) {
1250 V_VT(pVarResult
) = VT_DISPATCH
;
1251 IDispatch_AddRef(data
->pInstaller
);
1252 V_DISPATCH(pVarResult
) = data
->pInstaller
;
1254 else return DISP_E_MEMBERNOTFOUND
;
1257 case DISPID_SESSION_PROPERTY
:
1258 if (wFlags
& DISPATCH_PROPERTYGET
) {
1259 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1260 if (FAILED(hr
)) return hr
;
1261 V_VT(pVarResult
) = VT_BSTR
;
1262 V_BSTR(pVarResult
) = NULL
;
1263 if ((ret
= MsiGetPropertyW(This
->msiHandle
, V_BSTR(&varg0
), NULL
, &dwLen
)) == ERROR_SUCCESS
)
1265 if (!(szString
= msi_alloc((++dwLen
)*sizeof(WCHAR
))))
1266 ERR("Out of memory\n");
1267 else if ((ret
= MsiGetPropertyW(This
->msiHandle
, V_BSTR(&varg0
), szString
, &dwLen
)) == ERROR_SUCCESS
)
1268 V_BSTR(pVarResult
) = SysAllocString(szString
);
1271 if (ret
!= ERROR_SUCCESS
)
1272 ERR("MsiGetProperty returned %d\n", ret
);
1273 } else if (wFlags
& DISPATCH_PROPERTYPUT
) {
1274 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1275 if (FAILED(hr
)) return hr
;
1276 hr
= DispGetParam(pDispParams
, DISPID_PROPERTYPUT
, VT_BSTR
, &varg1
, puArgErr
);
1278 VariantClear(&varg0
);
1281 if ((ret
= MsiSetPropertyW(This
->msiHandle
, V_BSTR(&varg0
), V_BSTR(&varg1
))) != ERROR_SUCCESS
)
1283 VariantClear(&varg0
);
1284 VariantClear(&varg1
);
1285 ERR("MsiSetProperty returned %d\n", ret
);
1286 return DISP_E_EXCEPTION
;
1289 else return DISP_E_MEMBERNOTFOUND
;
1292 case DISPID_SESSION_LANGUAGE
:
1293 if (wFlags
& DISPATCH_PROPERTYGET
) {
1294 langId
= MsiGetLanguage(This
->msiHandle
);
1295 V_VT(pVarResult
) = VT_I4
;
1296 V_I4(pVarResult
) = langId
;
1298 else return DISP_E_MEMBERNOTFOUND
;
1301 case DISPID_SESSION_MODE
:
1302 if (wFlags
& DISPATCH_PROPERTYGET
) {
1303 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
1304 if (FAILED(hr
)) return hr
;
1305 V_VT(pVarResult
) = VT_BOOL
;
1306 V_BOOL(pVarResult
) = MsiGetMode(This
->msiHandle
, V_I4(&varg0
));
1307 } else if (wFlags
& DISPATCH_PROPERTYPUT
) {
1308 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
1309 if (FAILED(hr
)) return hr
;
1310 hr
= DispGetParam(pDispParams
, DISPID_PROPERTYPUT
, VT_BOOL
, &varg1
, puArgErr
);
1311 if (FAILED(hr
)) return hr
;
1312 if ((ret
= MsiSetMode(This
->msiHandle
, V_I4(&varg0
), V_BOOL(&varg1
))) != ERROR_SUCCESS
)
1314 ERR("MsiSetMode returned %d\n", ret
);
1315 return DISP_E_EXCEPTION
;
1318 else return DISP_E_MEMBERNOTFOUND
;
1321 case DISPID_SESSION_DATABASE
:
1322 if (wFlags
& DISPATCH_PROPERTYGET
) {
1323 V_VT(pVarResult
) = VT_DISPATCH
;
1324 if ((msiHandle
= MsiGetActiveDatabase(This
->msiHandle
)))
1326 if (SUCCEEDED(hr
= create_automation_object(msiHandle
, NULL
, (LPVOID
*)&pDispatch
, &DIID_Database
, DatabaseImpl_Invoke
, NULL
, 0)))
1327 V_DISPATCH(pVarResult
) = pDispatch
;
1329 ERR("Failed to create Database object, hresult 0x%08x\n", hr
);
1333 ERR("MsiGetActiveDatabase failed\n");
1334 return DISP_E_EXCEPTION
;
1337 else return DISP_E_MEMBERNOTFOUND
;
1340 case DISPID_SESSION_DOACTION
:
1341 if (wFlags
& DISPATCH_METHOD
) {
1342 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1343 if (FAILED(hr
)) return hr
;
1344 ret
= MsiDoActionW(This
->msiHandle
, V_BSTR(&varg0
));
1345 V_VT(pVarResult
) = VT_I4
;
1348 case ERROR_FUNCTION_NOT_CALLED
:
1349 V_I4(pVarResult
) = msiDoActionStatusNoAction
;
1352 V_I4(pVarResult
) = msiDoActionStatusSuccess
;
1354 case ERROR_INSTALL_USEREXIT
:
1355 V_I4(pVarResult
) = msiDoActionStatusUserExit
;
1357 case ERROR_INSTALL_FAILURE
:
1358 V_I4(pVarResult
) = msiDoActionStatusFailure
;
1360 case ERROR_INSTALL_SUSPEND
:
1361 V_I4(pVarResult
) = msiDoActionStatusSuspend
;
1363 case ERROR_MORE_DATA
:
1364 V_I4(pVarResult
) = msiDoActionStatusFinished
;
1366 case ERROR_INVALID_HANDLE_STATE
:
1367 V_I4(pVarResult
) = msiDoActionStatusWrongState
;
1369 case ERROR_INVALID_DATA
:
1370 V_I4(pVarResult
) = msiDoActionStatusBadActionData
;
1373 VariantClear(&varg0
);
1374 FIXME("MsiDoAction returned unhandled value %d\n", ret
);
1375 return DISP_E_EXCEPTION
;
1378 else return DISP_E_MEMBERNOTFOUND
;
1381 case DISPID_SESSION_EVALUATECONDITION
:
1382 if (wFlags
& DISPATCH_METHOD
) {
1383 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1384 if (FAILED(hr
)) return hr
;
1385 V_VT(pVarResult
) = VT_I4
;
1386 V_I4(pVarResult
) = MsiEvaluateConditionW(This
->msiHandle
, V_BSTR(&varg0
));
1388 else return DISP_E_MEMBERNOTFOUND
;
1391 case DISPID_SESSION_MESSAGE
:
1392 if(!(wFlags
& DISPATCH_METHOD
))
1393 return DISP_E_MEMBERNOTFOUND
;
1395 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
1396 if (FAILED(hr
)) return hr
;
1397 hr
= DispGetParam(pDispParams
, 1, VT_DISPATCH
, &varg1
, puArgErr
);
1398 if (FAILED(hr
)) return hr
;
1400 V_VT(pVarResult
) = VT_I4
;
1402 MsiProcessMessage(This
->msiHandle
, V_I4(&varg0
), ((AutomationObject
*)V_DISPATCH(&varg1
))->msiHandle
);
1405 case DISPID_SESSION_SETINSTALLLEVEL
:
1406 if (wFlags
& DISPATCH_METHOD
) {
1407 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
1408 if (FAILED(hr
)) return hr
;
1409 if ((ret
= MsiSetInstallLevel(This
->msiHandle
, V_I4(&varg0
))) != ERROR_SUCCESS
)
1411 ERR("MsiSetInstallLevel returned %d\n", ret
);
1412 return DISP_E_EXCEPTION
;
1415 else return DISP_E_MEMBERNOTFOUND
;
1418 case DISPID_SESSION_FEATURECURRENTSTATE
:
1419 if (wFlags
& DISPATCH_PROPERTYGET
) {
1420 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1421 if (FAILED(hr
)) return hr
;
1422 V_VT(pVarResult
) = VT_I4
;
1423 if ((ret
= MsiGetFeatureStateW(This
->msiHandle
, V_BSTR(&varg0
), &iInstalled
, &iAction
)) == ERROR_SUCCESS
)
1424 V_I4(pVarResult
) = iInstalled
;
1427 ERR("MsiGetFeatureState returned %d\n", ret
);
1428 V_I4(pVarResult
) = msiInstallStateUnknown
;
1431 else return DISP_E_MEMBERNOTFOUND
;
1434 case DISPID_SESSION_FEATUREREQUESTSTATE
:
1435 if (wFlags
& DISPATCH_PROPERTYGET
) {
1436 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1437 if (FAILED(hr
)) return hr
;
1438 V_VT(pVarResult
) = VT_I4
;
1439 if ((ret
= MsiGetFeatureStateW(This
->msiHandle
, V_BSTR(&varg0
), &iInstalled
, &iAction
)) == ERROR_SUCCESS
)
1440 V_I4(pVarResult
) = iAction
;
1443 ERR("MsiGetFeatureState returned %d\n", ret
);
1444 V_I4(pVarResult
) = msiInstallStateUnknown
;
1446 } else if (wFlags
& DISPATCH_PROPERTYPUT
) {
1447 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1448 if (FAILED(hr
)) return hr
;
1449 hr
= DispGetParam(pDispParams
, DISPID_PROPERTYPUT
, VT_I4
, &varg1
, puArgErr
);
1451 VariantClear(&varg0
);
1454 if ((ret
= MsiSetFeatureStateW(This
->msiHandle
, V_BSTR(&varg0
), V_I4(&varg1
))) != ERROR_SUCCESS
)
1456 VariantClear(&varg0
);
1457 ERR("MsiSetFeatureState returned %d\n", ret
);
1458 return DISP_E_EXCEPTION
;
1461 else return DISP_E_MEMBERNOTFOUND
;
1465 return DISP_E_MEMBERNOTFOUND
;
1468 VariantClear(&varg1
);
1469 VariantClear(&varg0
);
1474 /* Fill the variant pointed to by pVarResult with the value & size returned by RegQueryValueEx as dictated by the
1475 * registry value type. Used by Installer::RegistryValue. */
1476 static void variant_from_registry_value(VARIANT
*pVarResult
, DWORD dwType
, LPBYTE lpData
, DWORD dwSize
)
1478 static const WCHAR szREG_BINARY
[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
1479 static const WCHAR szREG_
[] = { '(','R','E','G','_',']',0 };
1480 WCHAR
*szString
= (WCHAR
*)lpData
;
1481 LPWSTR szNewString
= NULL
;
1482 DWORD dwNewSize
= 0;
1487 /* Registry strings may not be null terminated so we must use SysAllocStringByteLen/Len */
1488 case REG_MULTI_SZ
: /* Multi SZ change internal null characters to newlines */
1489 idx
= (dwSize
/sizeof(WCHAR
))-1;
1490 while (idx
>= 0 && !szString
[idx
]) idx
--;
1491 for (; idx
>= 0; idx
--)
1492 if (!szString
[idx
]) szString
[idx
] = '\n';
1494 V_VT(pVarResult
) = VT_BSTR
;
1495 V_BSTR(pVarResult
) = SysAllocStringByteLen((LPCSTR
)szString
, dwSize
);
1499 if (!(dwNewSize
= ExpandEnvironmentStringsW(szString
, szNewString
, dwNewSize
)))
1500 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1501 else if (!(szNewString
= msi_alloc(dwNewSize
)))
1502 ERR("Out of memory\n");
1503 else if (!(dwNewSize
= ExpandEnvironmentStringsW(szString
, szNewString
, dwNewSize
)))
1504 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1507 V_VT(pVarResult
) = VT_BSTR
;
1508 V_BSTR(pVarResult
) = SysAllocStringLen(szNewString
, dwNewSize
);
1510 msi_free(szNewString
);
1514 V_VT(pVarResult
) = VT_I4
;
1515 V_I4(pVarResult
) = *((DWORD
*)lpData
);
1519 V_VT(pVarResult
) = VT_BSTR
;
1520 V_BSTR(pVarResult
) = SysAllocString(szREG_
); /* Weird string, don't know why native returns it */
1524 V_VT(pVarResult
) = VT_BSTR
;
1525 V_BSTR(pVarResult
) = SysAllocString(szREG_BINARY
);
1529 V_VT(pVarResult
) = VT_EMPTY
;
1533 FIXME("Unhandled registry value type %d\n", dwType
);
1537 static HRESULT WINAPI
InstallerImpl_Invoke(
1538 AutomationObject
* This
,
1539 DISPID dispIdMember
,
1543 DISPPARAMS
* pDispParams
,
1544 VARIANT
* pVarResult
,
1545 EXCEPINFO
* pExcepInfo
,
1548 MSIHANDLE msiHandle
;
1549 IDispatch
*pDispatch
= NULL
;
1551 VARIANTARG varg0
, varg1
, varg2
;
1553 LPWSTR szString
= NULL
;
1557 VariantInit(&varg0
);
1558 VariantInit(&varg1
);
1559 VariantInit(&varg2
);
1561 switch (dispIdMember
)
1563 case DISPID_INSTALLER_CREATERECORD
:
1564 if (wFlags
& DISPATCH_METHOD
)
1566 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
1567 if (FAILED(hr
)) return hr
;
1568 V_VT(pVarResult
) = VT_DISPATCH
;
1569 if ((msiHandle
= MsiCreateRecord(V_I4(&varg0
))))
1571 if (SUCCEEDED(hr
= create_automation_object(msiHandle
, NULL
, (LPVOID
*)&pDispatch
, &DIID_Record
, RecordImpl_Invoke
, NULL
, 0)))
1572 V_DISPATCH(pVarResult
) = pDispatch
;
1574 ERR("Failed to create Record object, hresult 0x%08x\n", hr
);
1578 ERR("MsiCreateRecord failed\n");
1579 return DISP_E_EXCEPTION
;
1582 else return DISP_E_MEMBERNOTFOUND
;
1585 case DISPID_INSTALLER_OPENPACKAGE
:
1586 if (wFlags
& DISPATCH_METHOD
)
1588 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1589 if (FAILED(hr
)) return hr
;
1590 hr
= DispGetParam(pDispParams
, 1, VT_I4
, &varg1
, puArgErr
);
1593 VariantClear(&varg0
);
1596 V_VT(pVarResult
) = VT_DISPATCH
;
1597 if ((ret
= MsiOpenPackageExW(V_BSTR(&varg0
), V_I4(&varg1
), &msiHandle
)) == ERROR_SUCCESS
)
1599 if (SUCCEEDED(hr
= create_session(msiHandle
, (IDispatch
*)This
, &pDispatch
)))
1600 V_DISPATCH(pVarResult
) = pDispatch
;
1602 ERR("Failed to create Session object, hresult 0x%08x\n", hr
);
1606 VariantClear(&varg0
);
1607 ERR("MsiOpenPackageEx returned %d\n", ret
);
1608 return DISP_E_EXCEPTION
;
1611 else return DISP_E_MEMBERNOTFOUND
;
1614 case DISPID_INSTALLER_OPENDATABASE
:
1615 if (wFlags
& DISPATCH_METHOD
)
1617 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1618 if (FAILED(hr
)) return hr
;
1620 hr
= DispGetParam(pDispParams
, 1, VT_BSTR
, &varg1
, puArgErr
);
1623 VariantClear(&varg0
);
1627 V_VT(pVarResult
) = VT_DISPATCH
;
1628 if ((ret
= MsiOpenDatabaseW(V_BSTR(&varg0
), V_BSTR(&varg1
), &msiHandle
)) == ERROR_SUCCESS
)
1630 hr
= create_automation_object(msiHandle
, NULL
, (LPVOID
*)&pDispatch
,
1631 &DIID_Database
, DatabaseImpl_Invoke
, NULL
, 0);
1633 V_DISPATCH(pVarResult
) = pDispatch
;
1635 ERR("Failed to create Database object: 0x%08x\n", hr
);
1639 VariantClear(&varg0
);
1640 VariantClear(&varg1
);
1641 ERR("MsiOpenDatabase returned %d\n", ret
);
1642 return DISP_E_EXCEPTION
;
1645 else return DISP_E_MEMBERNOTFOUND
;
1648 case DISPID_INSTALLER_UILEVEL
:
1649 if (wFlags
& DISPATCH_PROPERTYPUT
)
1651 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
1652 if (FAILED(hr
)) return hr
;
1653 if ((ui
= MsiSetInternalUI(V_I4(&varg0
), NULL
) == INSTALLUILEVEL_NOCHANGE
))
1655 ERR("MsiSetInternalUI failed\n");
1656 return DISP_E_EXCEPTION
;
1659 else if (wFlags
& DISPATCH_PROPERTYGET
)
1661 if ((ui
= MsiSetInternalUI(INSTALLUILEVEL_NOCHANGE
, NULL
) == INSTALLUILEVEL_NOCHANGE
))
1663 ERR("MsiSetInternalUI failed\n");
1664 return DISP_E_EXCEPTION
;
1667 V_VT(pVarResult
) = VT_I4
;
1668 V_I4(pVarResult
) = ui
;
1670 else return DISP_E_MEMBERNOTFOUND
;
1673 case DISPID_INSTALLER_INSTALLPRODUCT
:
1674 if (wFlags
& DISPATCH_METHOD
)
1676 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1677 if (FAILED(hr
)) return hr
;
1678 hr
= DispGetParam(pDispParams
, 1, VT_BSTR
, &varg1
, puArgErr
);
1681 VariantClear(&varg0
);
1684 if ((ret
= MsiInstallProductW(V_BSTR(&varg0
), V_BSTR(&varg1
))) != ERROR_SUCCESS
)
1686 VariantClear(&varg1
);
1687 VariantClear(&varg0
);
1688 ERR("MsiInstallProduct returned %d\n", ret
);
1689 return DISP_E_EXCEPTION
;
1692 else return DISP_E_MEMBERNOTFOUND
;
1695 case DISPID_INSTALLER_VERSION
:
1696 if (wFlags
& DISPATCH_PROPERTYGET
) {
1697 DLLVERSIONINFO verinfo
;
1698 WCHAR version
[MAX_PATH
];
1700 static const WCHAR format
[] = {'%','d','.','%','d','.','%','d','.','%','d',0};
1702 verinfo
.cbSize
= sizeof(DLLVERSIONINFO
);
1703 hr
= DllGetVersion(&verinfo
);
1704 if (FAILED(hr
)) return hr
;
1706 sprintfW(version
, format
, verinfo
.dwMajorVersion
, verinfo
.dwMinorVersion
,
1707 verinfo
.dwBuildNumber
, verinfo
.dwPlatformID
);
1709 V_VT(pVarResult
) = VT_BSTR
;
1710 V_BSTR(pVarResult
) = SysAllocString(version
);
1712 else return DISP_E_MEMBERNOTFOUND
;
1715 case DISPID_INSTALLER_REGISTRYVALUE
:
1716 if (wFlags
& DISPATCH_METHOD
) {
1719 UINT posValue
= 2; /* Save valuePos so we can save puArgErr if we are unable to do our type conversions */
1721 hr
= DispGetParam(pDispParams
, 0, VT_I4
, &varg0
, puArgErr
);
1722 if (FAILED(hr
)) return hr
;
1723 hr
= DispGetParam(pDispParams
, 1, VT_BSTR
, &varg1
, puArgErr
);
1724 if (FAILED(hr
)) return hr
;
1725 hr
= DispGetParam_CopyOnly(pDispParams
, &posValue
, &varg2
);
1728 VariantClear(&varg1
);
1732 if (V_I4(&varg0
) >= REG_INDEX_CLASSES_ROOT
&&
1733 V_I4(&varg0
) <= REG_INDEX_DYN_DATA
)
1734 V_I4(&varg0
) |= (UINT
)HKEY_CLASSES_ROOT
;
1736 ret
= RegOpenKeyW((HKEY
)V_I4(&varg0
), V_BSTR(&varg1
), &hkey
);
1738 /* Third parameter can be VT_EMPTY, VT_I4, or VT_BSTR */
1739 switch (V_VT(&varg2
))
1741 case VT_EMPTY
: /* Return VT_BOOL as to whether or not registry key exists */
1742 V_VT(pVarResult
) = VT_BOOL
;
1743 V_BOOL(pVarResult
) = (ret
== ERROR_SUCCESS
);
1746 case VT_BSTR
: /* Return value of specified key if it exists */
1747 if (ret
== ERROR_SUCCESS
&&
1748 (ret
= RegQueryValueExW(hkey
, V_BSTR(&varg2
), NULL
, NULL
, NULL
, &dwSize
)) == ERROR_SUCCESS
)
1750 if (!(szString
= msi_alloc(dwSize
)))
1751 ERR("Out of memory\n");
1752 else if ((ret
= RegQueryValueExW(hkey
, V_BSTR(&varg2
), NULL
, &dwType
, (LPBYTE
)szString
, &dwSize
)) == ERROR_SUCCESS
)
1753 variant_from_registry_value(pVarResult
, dwType
, (LPBYTE
)szString
, dwSize
);
1756 if (ret
!= ERROR_SUCCESS
)
1759 VariantClear(&varg2
);
1760 VariantClear(&varg1
);
1761 return DISP_E_BADINDEX
;
1765 default: /* Try to make it into VT_I4, can use VariantChangeType for this */
1766 hr
= VariantChangeType(&varg2
, &varg2
, 0, VT_I4
);
1767 if (SUCCEEDED(hr
) && ret
!= ERROR_SUCCESS
) hr
= DISP_E_BADINDEX
; /* Conversion fine, but couldn't find key */
1770 if (hr
== DISP_E_TYPEMISMATCH
) *puArgErr
= posValue
;
1771 VariantClear(&varg2
); /* Unknown type, so let's clear it */
1772 VariantClear(&varg1
);
1776 /* Retrieve class name or maximum value name or subkey name size */
1778 ret
= RegQueryInfoKeyW(hkey
, NULL
, &dwSize
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1779 else if (V_I4(&varg2
) > 0)
1780 ret
= RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &dwSize
, NULL
, NULL
, NULL
);
1781 else /* V_I4(&varg2) < 0 */
1782 ret
= RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, &dwSize
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1784 if (ret
== ERROR_SUCCESS
)
1786 if (!(szString
= msi_alloc(++dwSize
* sizeof(WCHAR
))))
1787 ERR("Out of memory\n");
1788 else if (!V_I4(&varg2
))
1789 ret
= RegQueryInfoKeyW(hkey
, szString
, &dwSize
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
1790 else if (V_I4(&varg2
) > 0)
1791 ret
= RegEnumValueW(hkey
, V_I4(&varg2
)-1, szString
, &dwSize
, 0, 0, NULL
, NULL
);
1792 else /* V_I4(&varg2) < 0 */
1793 ret
= RegEnumKeyW(hkey
, -1 - V_I4(&varg2
), szString
, dwSize
);
1795 if (szString
&& ret
== ERROR_SUCCESS
)
1797 V_VT(pVarResult
) = VT_BSTR
;
1798 V_BSTR(pVarResult
) = SysAllocString(szString
);
1806 else return DISP_E_MEMBERNOTFOUND
;
1809 case DISPID_INSTALLER_PRODUCTSTATE
:
1810 if (wFlags
& DISPATCH_PROPERTYGET
) {
1811 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1812 if (FAILED(hr
)) return hr
;
1813 V_VT(pVarResult
) = VT_I4
;
1814 V_I4(pVarResult
) = MsiQueryProductStateW(V_BSTR(&varg0
));
1816 else return DISP_E_MEMBERNOTFOUND
;
1819 case DISPID_INSTALLER_PRODUCTINFO
:
1820 if (wFlags
& DISPATCH_PROPERTYGET
) {
1821 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1822 if (FAILED(hr
)) return hr
;
1823 hr
= DispGetParam(pDispParams
, 1, VT_BSTR
, &varg1
, puArgErr
);
1826 VariantClear(&varg0
);
1829 V_VT(pVarResult
) = VT_BSTR
;
1830 V_BSTR(pVarResult
) = NULL
;
1831 if ((ret
= MsiGetProductInfoW(V_BSTR(&varg0
), V_BSTR(&varg1
), NULL
, &dwSize
)) == ERROR_SUCCESS
)
1833 if (!(szString
= msi_alloc((++dwSize
)*sizeof(WCHAR
))))
1834 ERR("Out of memory\n");
1835 else if ((ret
= MsiGetProductInfoW(V_BSTR(&varg0
), V_BSTR(&varg1
), szString
, &dwSize
)) == ERROR_SUCCESS
)
1836 V_BSTR(pVarResult
) = SysAllocString(szString
);
1839 if (ret
!= ERROR_SUCCESS
)
1841 ERR("MsiGetProductInfo returned %d\n", ret
);
1842 VariantClear(&varg1
);
1843 VariantClear(&varg0
);
1844 return DISP_E_EXCEPTION
;
1847 else return DISP_E_MEMBERNOTFOUND
;
1850 case DISPID_INSTALLER_PRODUCTS
:
1851 if (wFlags
& DISPATCH_PROPERTYGET
)
1853 ListData
*ldata
= NULL
;
1855 WCHAR szProductBuf
[GUID_SIZE
];
1857 /* Find number of products */
1858 while ((ret
= MsiEnumProductsW(idx
, szProductBuf
)) == ERROR_SUCCESS
) idx
++;
1859 if (ret
!= ERROR_NO_MORE_ITEMS
)
1861 ERR("MsiEnumProducts returned %d\n", ret
);
1862 return DISP_E_EXCEPTION
;
1865 V_VT(pVarResult
) = VT_DISPATCH
;
1866 if (SUCCEEDED(hr
= create_automation_object(0, NULL
, (LPVOID
*)&pDispatch
, &DIID_StringList
, ListImpl_Invoke
, ListImpl_Free
, sizeof(ListData
))))
1868 V_DISPATCH(pVarResult
) = pDispatch
;
1870 /* Save product strings */
1871 ldata
= (ListData
*)private_data((AutomationObject
*)pDispatch
);
1872 if (!(ldata
->pVars
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(VARIANT
)*idx
)))
1873 ERR("Out of memory\n");
1876 ldata
->ulCount
= idx
;
1877 for (idx
= 0; idx
< ldata
->ulCount
; idx
++)
1879 ret
= MsiEnumProductsW(idx
, szProductBuf
);
1880 VariantInit(&ldata
->pVars
[idx
]);
1881 V_VT(&ldata
->pVars
[idx
]) = VT_BSTR
;
1882 V_BSTR(&ldata
->pVars
[idx
]) = SysAllocString(szProductBuf
);
1887 ERR("Failed to create StringList object, hresult 0x%08x\n", hr
);
1889 else return DISP_E_MEMBERNOTFOUND
;
1892 case DISPID_INSTALLER_RELATEDPRODUCTS
:
1893 if (wFlags
& DISPATCH_PROPERTYGET
)
1895 ListData
*ldata
= NULL
;
1897 WCHAR szProductBuf
[GUID_SIZE
];
1899 hr
= DispGetParam(pDispParams
, 0, VT_BSTR
, &varg0
, puArgErr
);
1900 if (FAILED(hr
)) return hr
;
1902 /* Find number of related products */
1903 while ((ret
= MsiEnumRelatedProductsW(V_BSTR(&varg0
), 0, idx
, szProductBuf
)) == ERROR_SUCCESS
) idx
++;
1904 if (ret
!= ERROR_NO_MORE_ITEMS
)
1906 VariantClear(&varg0
);
1907 ERR("MsiEnumRelatedProducts returned %d\n", ret
);
1908 return DISP_E_EXCEPTION
;
1911 V_VT(pVarResult
) = VT_DISPATCH
;
1912 if (SUCCEEDED(hr
= create_automation_object(0, NULL
, (LPVOID
*)&pDispatch
, &DIID_StringList
, ListImpl_Invoke
, ListImpl_Free
, sizeof(ListData
))))
1914 V_DISPATCH(pVarResult
) = pDispatch
;
1916 /* Save product strings */
1917 ldata
= (ListData
*)private_data((AutomationObject
*)pDispatch
);
1918 if (!(ldata
->pVars
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(VARIANT
)*idx
)))
1919 ERR("Out of memory\n");
1922 ldata
->ulCount
= idx
;
1923 for (idx
= 0; idx
< ldata
->ulCount
; idx
++)
1925 ret
= MsiEnumRelatedProductsW(V_BSTR(&varg0
), 0, idx
, szProductBuf
);
1926 VariantInit(&ldata
->pVars
[idx
]);
1927 V_VT(&ldata
->pVars
[idx
]) = VT_BSTR
;
1928 V_BSTR(&ldata
->pVars
[idx
]) = SysAllocString(szProductBuf
);
1933 ERR("Failed to create StringList object, hresult 0x%08x\n", hr
);
1935 else return DISP_E_MEMBERNOTFOUND
;
1939 return DISP_E_MEMBERNOTFOUND
;
1942 VariantClear(&varg2
);
1943 VariantClear(&varg1
);
1944 VariantClear(&varg0
);
1949 /* Wrapper around create_automation_object to create an installer object. */
1950 HRESULT
create_msiserver(IUnknown
*pOuter
, LPVOID
*ppObj
)
1952 return create_automation_object(0, pOuter
, ppObj
, &DIID_Installer
, InstallerImpl_Invoke
, NULL
, 0);
1955 /* Wrapper around create_automation_object to create a session object. */
1956 HRESULT
create_session(MSIHANDLE msiHandle
, IDispatch
*pInstaller
, IDispatch
**pDispatch
)
1958 HRESULT hr
= create_automation_object(msiHandle
, NULL
, (LPVOID
)pDispatch
, &DIID_Session
, SessionImpl_Invoke
, NULL
, sizeof(SessionData
));
1959 if (SUCCEEDED(hr
) && pDispatch
&& *pDispatch
)
1960 ((SessionData
*)private_data((AutomationObject
*)*pDispatch
))->pInstaller
= pInstaller
;