push c718ce09c2ff12a5f254019f4a72fa896c170c07
[wine/hacks.git] / dlls / msi / automation.c
blob0b631acad6b9ee73b966a484628d6391438eb951
1 /*
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
21 #define COBJMACROS
23 #include <stdarg.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winerror.h"
27 #include "winuser.h"
28 #include "winreg.h"
29 #include "msidefs.h"
30 #include "msipriv.h"
31 #include "activscp.h"
32 #include "oleauto.h"
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 */
56 LONG ref;
58 /* Clsid for this class and it's appropriate ITypeInfo object */
59 LPCLSID clsid;
60 ITypeInfo *iTypeInfo;
62 /* The MSI handle of the current object */
63 MSIHANDLE msiHandle;
65 /* A function that is called from AutomationObject::Invoke, specific to this type of object. */
66 HRESULT (STDMETHODCALLTYPE *funcInvoke)(
67 AutomationObject* This,
68 DISPID dispIdMember,
69 REFIID riid,
70 LCID lcid,
71 WORD wFlags,
72 DISPPARAMS* pDispParams,
73 VARIANT* pVarResult,
74 EXCEPINFO* pExcepInfo,
75 UINT* puArgErr);
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 {
89 /* VTables */
90 const IEnumVARIANTVtbl *lpVtbl;
92 /* Object reference count */
93 LONG ref;
95 /* Current position and pointer to AutomationObject that stores actual data */
96 ULONG ulPos;
97 AutomationObject *pObj;
101 * Structures for additional data required by specific automation objects
104 typedef struct {
105 ULONG ulCount;
106 VARIANT *pVars;
107 } ListData;
109 typedef struct {
110 /* The parent Installer object */
111 IDispatch *pInstaller;
112 } SessionData;
114 /* VTables */
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)
122 HRESULT hr;
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);
131 if (FAILED(hr)) {
132 hr = LoadTypeLib(szMsiServer, &pLib);
133 if (FAILED(hr)) {
134 ERR("Could not load msiserver.tlb\n");
135 return hr;
139 /* Get type information for object */
140 hr = ITypeLib_GetTypeInfoOfGuid(pLib, clsid, &pInfo);
141 ITypeLib_Release(pLib);
142 if (FAILED(hr)) {
143 ERR("Could not load ITypeInfo for %s\n", debugstr_guid(clsid));
144 return hr;
146 *pptinfo = pInfo;
147 return S_OK;
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;
159 HRESULT hr;
161 TRACE("(%ld,%p,%p,%s,%p,%p,%ld)\n", (unsigned long)msiHandle, pUnkOuter, ppObj, debugstr_guid(clsid), funcInvoke, funcFree, sizetPrivateData);
163 if( pUnkOuter )
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;
171 object->ref = 1;
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);
182 if (FAILED(hr)) {
183 HeapFree(GetProcessHeap(), 0, object);
184 return hr;
187 *ppObj = object;
189 return S_OK;
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);
199 if( pUnkOuter )
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;
206 object->ref = 1;
208 /* Store data that was passed */
209 object->ulPos = ulPos;
210 object->pObj = pObj;
211 if (pObj) IDispatch_AddRef((IDispatch *)pObj);
213 *ppObj = object;
214 return S_OK;
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 )
226 return This + 1;
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)
241 return E_INVALIDARG;
243 *ppvObject = 0;
245 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDispatch) || IsEqualGUID(riid, This->clsid))
246 *ppvObject = This;
247 else if (IsEqualGUID(riid, &IID_IProvideClassInfo) ||
248 IsEqualGUID(riid, &IID_IProvideClassInfo2) ||
249 IsEqualGUID(riid, &IID_IProvideMultipleClassInfo))
250 *ppvObject = &This->lpvtblIProvideMultipleClassInfo;
251 else
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
259 * successful
261 IClassFactory_AddRef(iface);
263 return S_OK;
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);
282 if (!ref)
284 if (This->funcFree) This->funcFree(This);
285 ITypeInfo_Release(This->iTypeInfo);
286 MsiCloseHandle(This->msiHandle);
287 HeapFree(GetProcessHeap(), 0, This);
290 return ref;
293 /*** IDispatch methods ***/
294 static HRESULT WINAPI AutomationObject_GetTypeInfoCount(
295 IDispatch* iface,
296 UINT* pctinfo)
298 AutomationObject *This = (AutomationObject *)iface;
300 TRACE("(%p/%p)->(%p)\n", iface, This, pctinfo);
301 *pctinfo = 1;
302 return S_OK;
305 static HRESULT WINAPI AutomationObject_GetTypeInfo(
306 IDispatch* iface,
307 UINT iTInfo,
308 LCID lcid,
309 ITypeInfo** ppTInfo)
311 AutomationObject *This = (AutomationObject *)iface;
312 TRACE("(%p/%p)->(%d,%d,%p)\n", iface, This, iTInfo, lcid, ppTInfo);
314 ITypeInfo_AddRef(This->iTypeInfo);
315 *ppTInfo = This->iTypeInfo;
316 return S_OK;
319 static HRESULT WINAPI AutomationObject_GetIDsOfNames(
320 IDispatch* iface,
321 REFIID riid,
322 LPOLESTR* rgszNames,
323 UINT cNames,
324 LCID lcid,
325 DISPID* rgDispId)
327 AutomationObject *This = (AutomationObject *)iface;
328 HRESULT hr;
329 TRACE("(%p/%p)->(%p,%p,%d,%d,%p)\n", iface, This, riid, rgszNames, cNames, lcid, rgDispId);
331 if (!IsEqualGUID(riid, &IID_NULL)) return E_INVALIDARG;
332 hr = ITypeInfo_GetIDsOfNames(This->iTypeInfo, rgszNames, cNames, rgDispId);
333 if (hr == DISP_E_UNKNOWNNAME)
335 int idx;
336 for (idx=0; idx<cNames; idx++)
338 if (rgDispId[idx] == DISPID_UNKNOWN)
339 FIXME("Unknown member %s, clsid %s\n", debugstr_w(rgszNames[idx]), debugstr_guid(This->clsid));
342 return hr;
345 /* Maximum number of allowed function parameters+1 */
346 #define MAX_FUNC_PARAMS 20
348 /* Some error checking is done here to simplify individual object function invocation */
349 static HRESULT WINAPI AutomationObject_Invoke(
350 IDispatch* iface,
351 DISPID dispIdMember,
352 REFIID riid,
353 LCID lcid,
354 WORD wFlags,
355 DISPPARAMS* pDispParams,
356 VARIANT* pVarResult,
357 EXCEPINFO* pExcepInfo,
358 UINT* puArgErr)
360 AutomationObject *This = (AutomationObject *)iface;
361 HRESULT hr;
362 unsigned int uArgErr;
363 VARIANT varResultDummy;
364 BSTR bstrName = NULL;
366 TRACE("(%p/%p)->(%d,%p,%d,%d,%p,%p,%p,%p)\n", iface, This, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
368 if (!IsEqualIID(riid, &IID_NULL))
370 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
371 return DISP_E_UNKNOWNNAME;
374 if (wFlags & DISPATCH_PROPERTYGET && !pVarResult)
376 ERR("NULL pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
377 return DISP_E_PARAMNOTOPTIONAL;
380 /* This simplifies our individual object invocation functions */
381 if (puArgErr == NULL) puArgErr = &uArgErr;
382 if (pVarResult == NULL) pVarResult = &varResultDummy;
384 /* Assume return type is void unless determined otherwise */
385 VariantInit(pVarResult);
387 /* If we are tracing, we want to see the name of the member we are invoking */
388 if (TRACE_ON(msi))
390 ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL);
391 TRACE("Method %d, %s\n", dispIdMember, debugstr_w(bstrName));
394 hr = This->funcInvoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
396 if (hr == DISP_E_MEMBERNOTFOUND) {
397 if (bstrName == NULL) ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL);
398 FIXME("Method %d, %s wflags %d not implemented, clsid %s\n", dispIdMember, debugstr_w(bstrName), wFlags, debugstr_guid(This->clsid));
400 else if (pExcepInfo &&
401 (hr == DISP_E_PARAMNOTFOUND ||
402 hr == DISP_E_EXCEPTION)) {
403 static const WCHAR szComma[] = { ',',0 };
404 static WCHAR szExceptionSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
405 WCHAR szExceptionDescription[MAX_PATH];
406 BSTR bstrParamNames[MAX_FUNC_PARAMS];
407 unsigned namesNo, i;
408 BOOL bFirst = TRUE;
410 if (FAILED(ITypeInfo_GetNames(This->iTypeInfo, dispIdMember, bstrParamNames,
411 MAX_FUNC_PARAMS, &namesNo)))
413 TRACE("Failed to retrieve names for dispIdMember %d\n", dispIdMember);
415 else
417 memset(szExceptionDescription, 0, sizeof(szExceptionDescription));
418 for (i=0; i<namesNo; i++)
420 if (bFirst) bFirst = FALSE;
421 else {
422 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], szComma);
424 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], bstrParamNames[i]);
425 SysFreeString(bstrParamNames[i]);
428 memset(pExcepInfo, 0, sizeof(EXCEPINFO));
429 pExcepInfo->wCode = 1000;
430 pExcepInfo->bstrSource = SysAllocString(szExceptionSource);
431 pExcepInfo->bstrDescription = SysAllocString(szExceptionDescription);
432 hr = DISP_E_EXCEPTION;
436 /* Make sure we free the return variant if it is our dummy variant */
437 if (pVarResult == &varResultDummy) VariantClear(pVarResult);
439 /* Free function name if we retrieved it */
440 if (bstrName) SysFreeString(bstrName);
442 TRACE("Returning 0x%08x, %s\n", hr, SUCCEEDED(hr) ? "ok" : "not ok");
444 return hr;
447 static const struct IDispatchVtbl AutomationObject_Vtbl =
449 AutomationObject_QueryInterface,
450 AutomationObject_AddRef,
451 AutomationObject_Release,
452 AutomationObject_GetTypeInfoCount,
453 AutomationObject_GetTypeInfo,
454 AutomationObject_GetIDsOfNames,
455 AutomationObject_Invoke
459 * IProvideMultipleClassInfo methods
462 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_QueryInterface(
463 IProvideMultipleClassInfo* iface,
464 REFIID riid,
465 VOID** ppvoid)
467 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
468 return AutomationObject_QueryInterface((IDispatch *)This, riid, ppvoid);
471 static ULONG WINAPI AutomationObject_IProvideMultipleClassInfo_AddRef(IProvideMultipleClassInfo* iface)
473 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
474 return AutomationObject_AddRef((IDispatch *)This);
477 static ULONG WINAPI AutomationObject_IProvideMultipleClassInfo_Release(IProvideMultipleClassInfo* iface)
479 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
480 return AutomationObject_Release((IDispatch *)This);
483 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_GetClassInfo(IProvideMultipleClassInfo* iface, ITypeInfo** ppTI)
485 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
486 TRACE("(%p/%p)->(%p)\n", iface, This, ppTI);
487 return load_type_info((IDispatch *)This, ppTI, This->clsid, 0);
490 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_GetGUID(IProvideMultipleClassInfo* iface, DWORD dwGuidKind, GUID* pGUID)
492 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
493 TRACE("(%p/%p)->(%d,%s)\n", iface, This, dwGuidKind, debugstr_guid(pGUID));
495 if (dwGuidKind != GUIDKIND_DEFAULT_SOURCE_DISP_IID)
496 return E_INVALIDARG;
497 else {
498 *pGUID = *This->clsid;
499 return S_OK;
503 static HRESULT WINAPI AutomationObject_GetMultiTypeInfoCount(IProvideMultipleClassInfo* iface, ULONG* pcti)
505 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
507 TRACE("(%p/%p)->(%p)\n", iface, This, pcti);
508 *pcti = 1;
509 return S_OK;
512 static HRESULT WINAPI AutomationObject_GetInfoOfIndex(IProvideMultipleClassInfo* iface,
513 ULONG iti,
514 DWORD dwFlags,
515 ITypeInfo** pptiCoClass,
516 DWORD* pdwTIFlags,
517 ULONG* pcdispidReserved,
518 IID* piidPrimary,
519 IID* piidSource)
521 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
523 TRACE("(%p/%p)->(%d,%d,%p,%p,%p,%p,%p)\n", iface, This, iti, dwFlags, pptiCoClass, pdwTIFlags, pcdispidReserved, piidPrimary, piidSource);
525 if (iti != 0)
526 return E_INVALIDARG;
528 if (dwFlags & MULTICLASSINFO_GETTYPEINFO)
529 load_type_info((IDispatch *)This, pptiCoClass, This->clsid, 0);
531 if (dwFlags & MULTICLASSINFO_GETNUMRESERVEDDISPIDS)
533 *pdwTIFlags = 0;
534 *pcdispidReserved = 0;
537 if (dwFlags & MULTICLASSINFO_GETIIDPRIMARY){
538 *piidPrimary = *This->clsid;
541 if (dwFlags & MULTICLASSINFO_GETIIDSOURCE){
542 *piidSource = *This->clsid;
545 return S_OK;
548 static const IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl =
550 AutomationObject_IProvideMultipleClassInfo_QueryInterface,
551 AutomationObject_IProvideMultipleClassInfo_AddRef,
552 AutomationObject_IProvideMultipleClassInfo_Release,
553 AutomationObject_IProvideMultipleClassInfo_GetClassInfo,
554 AutomationObject_IProvideMultipleClassInfo_GetGUID,
555 AutomationObject_GetMultiTypeInfoCount,
556 AutomationObject_GetInfoOfIndex
560 * ListEnumerator methods
563 /*** IUnknown methods ***/
564 static HRESULT WINAPI ListEnumerator_QueryInterface(IEnumVARIANT* iface, REFIID riid, void** ppvObject)
566 ListEnumerator *This = (ListEnumerator *)iface;
568 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
570 if (ppvObject == NULL)
571 return E_INVALIDARG;
573 *ppvObject = 0;
575 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IEnumVARIANT))
576 *ppvObject = This;
577 else
579 TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid));
580 return E_NOINTERFACE;
583 IClassFactory_AddRef(iface);
584 return S_OK;
587 static ULONG WINAPI ListEnumerator_AddRef(IEnumVARIANT* iface)
589 ListEnumerator *This = (ListEnumerator *)iface;
591 TRACE("(%p/%p)\n", iface, This);
593 return InterlockedIncrement(&This->ref);
596 static ULONG WINAPI ListEnumerator_Release(IEnumVARIANT* iface)
598 ListEnumerator *This = (ListEnumerator *)iface;
599 ULONG ref = InterlockedDecrement(&This->ref);
601 TRACE("(%p/%p)\n", iface, This);
603 if (!ref)
605 if (This->pObj) IDispatch_Release((IDispatch *)This->pObj);
606 HeapFree(GetProcessHeap(), 0, This);
609 return ref;
612 /* IEnumVARIANT methods */
614 static HRESULT WINAPI ListEnumerator_Next(IEnumVARIANT* iface, ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched)
616 ListEnumerator *This = (ListEnumerator *)iface;
617 ListData *data = (ListData *)private_data(This->pObj);
618 ULONG idx, local;
620 TRACE("(%p,%uld,%p,%p)\n", iface, celt, rgVar, pCeltFetched);
622 if (pCeltFetched != NULL)
623 *pCeltFetched = 0;
625 if (rgVar == NULL)
626 return S_FALSE;
628 for (local = 0; local < celt; local++)
629 VariantInit(&rgVar[local]);
631 for (idx = This->ulPos, local = 0; idx < data->ulCount && local < celt; idx++, local++)
632 VariantCopy(&rgVar[local], &data->pVars[idx]);
634 if (pCeltFetched != NULL)
635 *pCeltFetched = local;
636 This->ulPos = idx;
638 return (local < celt) ? S_FALSE : S_OK;
641 static HRESULT WINAPI ListEnumerator_Skip(IEnumVARIANT* iface, ULONG celt)
643 ListEnumerator *This = (ListEnumerator *)iface;
644 ListData *data = (ListData *)private_data(This->pObj);
646 TRACE("(%p,%uld)\n", iface, celt);
648 This->ulPos += celt;
649 if (This->ulPos >= data->ulCount)
651 This->ulPos = data->ulCount;
652 return S_FALSE;
654 return S_OK;
657 static HRESULT WINAPI ListEnumerator_Reset(IEnumVARIANT* iface)
659 ListEnumerator *This = (ListEnumerator *)iface;
661 TRACE("(%p)\n", iface);
663 This->ulPos = 0;
664 return S_OK;
667 static HRESULT WINAPI ListEnumerator_Clone(IEnumVARIANT* iface, IEnumVARIANT **ppEnum)
669 ListEnumerator *This = (ListEnumerator *)iface;
670 HRESULT hr;
672 TRACE("(%p,%p)\n", iface, ppEnum);
674 if (ppEnum == NULL)
675 return S_FALSE;
677 *ppEnum = NULL;
678 hr = create_list_enumerator(NULL, (LPVOID *)ppEnum, This->pObj, 0);
679 if (FAILED(hr))
681 if (*ppEnum)
682 IUnknown_Release(*ppEnum);
683 return hr;
686 return S_OK;
689 static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl =
691 ListEnumerator_QueryInterface,
692 ListEnumerator_AddRef,
693 ListEnumerator_Release,
694 ListEnumerator_Next,
695 ListEnumerator_Skip,
696 ListEnumerator_Reset,
697 ListEnumerator_Clone
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 */
713 UINT pos;
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;
720 } else {
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;
728 *position = pos;
729 return VariantCopyInd(pvarResult,
730 &pdispparams->rgvarg[pos]);
733 static HRESULT WINAPI SummaryInfoImpl_Invoke(
734 AutomationObject* This,
735 DISPID dispIdMember,
736 REFIID riid,
737 LCID lcid,
738 WORD wFlags,
739 DISPPARAMS* pDispParams,
740 VARIANT* pVarResult,
741 EXCEPINFO* pExcepInfo,
742 UINT* puArgErr)
744 UINT ret;
745 VARIANTARG varg0, varg1;
746 FILETIME ft, ftlocal;
747 SYSTEMTIME st;
748 HRESULT hr;
750 VariantInit(&varg0);
751 VariantInit(&varg1);
753 switch (dispIdMember)
755 case DISPID_SUMMARYINFO_PROPERTY:
756 if (wFlags & DISPATCH_PROPERTYGET)
758 UINT type;
759 INT value;
760 DWORD size = 0;
761 DATE date;
762 LPWSTR str;
764 static WCHAR szEmpty[] = {0};
766 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
767 if (FAILED(hr)) return hr;
768 ret = MsiSummaryInfoGetPropertyW(This->msiHandle, V_I4(&varg0), &type, &value,
769 &ft, szEmpty, &size);
770 if (ret != ERROR_SUCCESS &&
771 ret != ERROR_MORE_DATA)
773 ERR("MsiSummaryInfoGetProperty returned %d\n", ret);
774 return DISP_E_EXCEPTION;
777 switch (type)
779 case VT_EMPTY:
780 break;
782 case VT_I2:
783 case VT_I4:
784 V_VT(pVarResult) = VT_I4;
785 V_I4(pVarResult) = value;
786 break;
788 case VT_LPSTR:
789 if (!(str = msi_alloc(++size * sizeof(WCHAR))))
790 ERR("Out of memory\n");
791 else if ((ret = MsiSummaryInfoGetPropertyW(This->msiHandle, V_I4(&varg0), &type, NULL,
792 NULL, str, &size)) != ERROR_SUCCESS)
793 ERR("MsiSummaryInfoGetProperty returned %d\n", ret);
794 else
796 V_VT(pVarResult) = VT_BSTR;
797 V_BSTR(pVarResult) = SysAllocString(str);
799 msi_free(str);
800 break;
802 case VT_FILETIME:
803 FileTimeToLocalFileTime(&ft, &ftlocal);
804 FileTimeToSystemTime(&ftlocal, &st);
805 SystemTimeToVariantTime(&st, &date);
807 V_VT(pVarResult) = VT_DATE;
808 V_DATE(pVarResult) = date;
809 break;
811 default:
812 ERR("Unhandled variant type %d\n", type);
815 else if (wFlags & DISPATCH_PROPERTYPUT)
817 UINT posValue = DISPID_PROPERTYPUT;
819 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
820 if (FAILED(hr)) return hr;
821 hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg1);
822 if (FAILED(hr))
824 *puArgErr = posValue;
825 return hr;
828 switch (V_VT(&varg1))
830 case VT_I2:
831 case VT_I4:
832 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), V_VT(&varg1), V_I4(&varg1), NULL, NULL);
833 break;
835 case VT_DATE:
836 VariantTimeToSystemTime(V_DATE(&varg1), &st);
837 SystemTimeToFileTime(&st, &ftlocal);
838 LocalFileTimeToFileTime(&ftlocal, &ft);
839 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), VT_FILETIME, 0, &ft, NULL);
840 break;
842 case VT_BSTR:
843 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), VT_LPSTR, 0, NULL, V_BSTR(&varg1));
844 break;
846 default:
847 FIXME("Unhandled variant type %d\n", V_VT(&varg1));
848 VariantClear(&varg1);
849 return DISP_E_EXCEPTION;
852 if (ret != ERROR_SUCCESS)
854 ERR("MsiSummaryInfoSetPropertyW returned %d\n", ret);
855 return DISP_E_EXCEPTION;
858 else return DISP_E_MEMBERNOTFOUND;
859 break;
861 case DISPID_SUMMARYINFO_PROPERTYCOUNT:
862 if (wFlags & DISPATCH_PROPERTYGET) {
863 UINT count;
864 if ((ret = MsiSummaryInfoGetPropertyCount(This->msiHandle, &count)) != ERROR_SUCCESS)
865 ERR("MsiSummaryInfoGetPropertyCount returned %d\n", ret);
866 else
868 V_VT(pVarResult) = VT_I4;
869 V_I4(pVarResult) = count;
872 else return DISP_E_MEMBERNOTFOUND;
873 break;
875 default:
876 return DISP_E_MEMBERNOTFOUND;
879 VariantClear(&varg1);
880 VariantClear(&varg0);
882 return S_OK;
885 static HRESULT WINAPI RecordImpl_Invoke(
886 AutomationObject* This,
887 DISPID dispIdMember,
888 REFIID riid,
889 LCID lcid,
890 WORD wFlags,
891 DISPPARAMS* pDispParams,
892 VARIANT* pVarResult,
893 EXCEPINFO* pExcepInfo,
894 UINT* puArgErr)
896 WCHAR *szString;
897 DWORD dwLen;
898 UINT ret;
899 VARIANTARG varg0, varg1;
900 HRESULT hr;
902 VariantInit(&varg0);
903 VariantInit(&varg1);
905 switch (dispIdMember)
907 case DISPID_RECORD_FIELDCOUNT:
908 if (wFlags & DISPATCH_PROPERTYGET) {
909 V_VT(pVarResult) = VT_I4;
910 V_I4(pVarResult) = MsiRecordGetFieldCount(This->msiHandle);
912 else return DISP_E_MEMBERNOTFOUND;
913 break;
915 case DISPID_RECORD_STRINGDATA:
916 if (wFlags & DISPATCH_PROPERTYGET) {
917 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
918 if (FAILED(hr)) return hr;
919 V_VT(pVarResult) = VT_BSTR;
920 V_BSTR(pVarResult) = NULL;
921 if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
923 if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
924 ERR("Out of memory\n");
925 else if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
926 V_BSTR(pVarResult) = SysAllocString(szString);
927 msi_free(szString);
929 if (ret != ERROR_SUCCESS)
930 ERR("MsiRecordGetString returned %d\n", ret);
931 } else if (wFlags & DISPATCH_PROPERTYPUT) {
932 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
933 if (FAILED(hr)) return hr;
934 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BSTR, &varg1, puArgErr);
935 if (FAILED(hr)) return hr;
936 if ((ret = MsiRecordSetStringW(This->msiHandle, V_I4(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
938 VariantClear(&varg1);
939 ERR("MsiRecordSetString returned %d\n", ret);
940 return DISP_E_EXCEPTION;
943 else return DISP_E_MEMBERNOTFOUND;
944 break;
946 case DISPID_RECORD_INTEGERDATA:
947 if (wFlags & DISPATCH_PROPERTYGET) {
948 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
949 if (FAILED(hr)) return hr;
950 V_VT(pVarResult) = VT_I4;
951 V_I4(pVarResult) = MsiRecordGetInteger(This->msiHandle, V_I4(&varg0));
952 } else if (wFlags & DISPATCH_PROPERTYPUT) {
953 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
954 if (FAILED(hr)) return hr;
955 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_I4, &varg1, puArgErr);
956 if (FAILED(hr)) return hr;
957 if ((ret = MsiRecordSetInteger(This->msiHandle, V_I4(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
959 ERR("MsiRecordSetInteger returned %d\n", ret);
960 return DISP_E_EXCEPTION;
963 else return DISP_E_MEMBERNOTFOUND;
964 break;
966 default:
967 return DISP_E_MEMBERNOTFOUND;
970 VariantClear(&varg1);
971 VariantClear(&varg0);
973 return S_OK;
976 static HRESULT WINAPI ListImpl_Invoke(
977 AutomationObject* This,
978 DISPID dispIdMember,
979 REFIID riid,
980 LCID lcid,
981 WORD wFlags,
982 DISPPARAMS* pDispParams,
983 VARIANT* pVarResult,
984 EXCEPINFO* pExcepInfo,
985 UINT* puArgErr)
987 ListData *data = (ListData *)private_data(This);
988 HRESULT hr;
989 VARIANTARG varg0;
990 IUnknown *pUnk = NULL;
992 VariantInit(&varg0);
994 switch (dispIdMember)
996 case DISPID_LIST__NEWENUM:
997 if (wFlags & DISPATCH_METHOD) {
998 V_VT(pVarResult) = VT_UNKNOWN;
999 if (SUCCEEDED(hr = create_list_enumerator(NULL, (LPVOID *)&pUnk, This, 0)))
1000 V_UNKNOWN(pVarResult) = pUnk;
1001 else
1002 ERR("Failed to create IEnumVARIANT object, hresult 0x%08x\n", hr);
1004 else return DISP_E_MEMBERNOTFOUND;
1005 break;
1007 case DISPID_LIST_ITEM:
1008 if (wFlags & DISPATCH_PROPERTYGET) {
1009 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1010 if (FAILED(hr)) return hr;
1011 if (V_I4(&varg0) < 0 || V_I4(&varg0) >= data->ulCount)
1012 return DISP_E_BADINDEX;
1013 VariantCopy(pVarResult, &data->pVars[V_I4(&varg0)]);
1015 else return DISP_E_MEMBERNOTFOUND;
1016 break;
1018 case DISPID_LIST_COUNT:
1019 if (wFlags & DISPATCH_PROPERTYGET) {
1020 V_VT(pVarResult) = VT_I4;
1021 V_I4(pVarResult) = data->ulCount;
1023 else return DISP_E_MEMBERNOTFOUND;
1024 break;
1026 default:
1027 return DISP_E_MEMBERNOTFOUND;
1030 VariantClear(&varg0);
1032 return S_OK;
1035 static void WINAPI ListImpl_Free(AutomationObject *This)
1037 ListData *data = private_data(This);
1038 ULONG idx;
1040 for (idx=0; idx<data->ulCount; idx++)
1041 VariantClear(&data->pVars[idx]);
1042 HeapFree(GetProcessHeap(), 0, data->pVars);
1045 static HRESULT WINAPI ViewImpl_Invoke(
1046 AutomationObject* This,
1047 DISPID dispIdMember,
1048 REFIID riid,
1049 LCID lcid,
1050 WORD wFlags,
1051 DISPPARAMS* pDispParams,
1052 VARIANT* pVarResult,
1053 EXCEPINFO* pExcepInfo,
1054 UINT* puArgErr)
1056 MSIHANDLE msiHandle;
1057 IDispatch *pDispatch = NULL;
1058 UINT ret;
1059 VARIANTARG varg0, varg1;
1060 HRESULT hr;
1062 VariantInit(&varg0);
1063 VariantInit(&varg1);
1065 switch (dispIdMember)
1067 case DISPID_VIEW_EXECUTE:
1068 if (wFlags & DISPATCH_METHOD)
1070 hr = DispGetParam(pDispParams, 0, VT_DISPATCH, &varg0, puArgErr);
1071 if (SUCCEEDED(hr) && V_DISPATCH(&varg0) != NULL)
1072 MsiViewExecute(This->msiHandle, ((AutomationObject *)V_DISPATCH(&varg0))->msiHandle);
1073 else
1074 MsiViewExecute(This->msiHandle, 0);
1076 else return DISP_E_MEMBERNOTFOUND;
1077 break;
1079 case DISPID_VIEW_FETCH:
1080 if (wFlags & DISPATCH_METHOD)
1082 V_VT(pVarResult) = VT_DISPATCH;
1083 if ((ret = MsiViewFetch(This->msiHandle, &msiHandle)) == ERROR_SUCCESS)
1085 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Record, RecordImpl_Invoke, NULL, 0)))
1086 V_DISPATCH(pVarResult) = pDispatch;
1087 else
1088 ERR("Failed to create Record object, hresult 0x%08x\n", hr);
1090 else if (ret == ERROR_NO_MORE_ITEMS)
1091 V_DISPATCH(pVarResult) = NULL;
1092 else
1094 ERR("MsiViewFetch returned %d\n", ret);
1095 return DISP_E_EXCEPTION;
1098 else return DISP_E_MEMBERNOTFOUND;
1099 break;
1101 case DISPID_VIEW_MODIFY:
1102 if (wFlags & DISPATCH_METHOD)
1104 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1105 if (FAILED(hr)) return hr;
1106 hr = DispGetParam(pDispParams, 1, VT_DISPATCH, &varg1, puArgErr);
1107 if (FAILED(hr)) return hr;
1108 if (!V_DISPATCH(&varg1)) return DISP_E_EXCEPTION;
1109 if ((ret = MsiViewModify(This->msiHandle, V_I4(&varg0), ((AutomationObject *)V_DISPATCH(&varg1))->msiHandle)) != ERROR_SUCCESS)
1111 VariantClear(&varg1);
1112 ERR("MsiViewModify returned %d\n", ret);
1113 return DISP_E_EXCEPTION;
1116 else return DISP_E_MEMBERNOTFOUND;
1117 break;
1119 case DISPID_VIEW_CLOSE:
1120 if (wFlags & DISPATCH_METHOD)
1122 MsiViewClose(This->msiHandle);
1124 else return DISP_E_MEMBERNOTFOUND;
1125 break;
1127 default:
1128 return DISP_E_MEMBERNOTFOUND;
1131 VariantClear(&varg1);
1132 VariantClear(&varg0);
1134 return S_OK;
1137 static HRESULT WINAPI DatabaseImpl_Invoke(
1138 AutomationObject* This,
1139 DISPID dispIdMember,
1140 REFIID riid,
1141 LCID lcid,
1142 WORD wFlags,
1143 DISPPARAMS* pDispParams,
1144 VARIANT* pVarResult,
1145 EXCEPINFO* pExcepInfo,
1146 UINT* puArgErr)
1148 MSIHANDLE msiHandle;
1149 IDispatch *pDispatch = NULL;
1150 UINT ret;
1151 VARIANTARG varg0, varg1;
1152 HRESULT hr;
1154 VariantInit(&varg0);
1155 VariantInit(&varg1);
1157 switch (dispIdMember)
1159 case DISPID_DATABASE_SUMMARYINFORMATION:
1160 if (wFlags & DISPATCH_PROPERTYGET)
1162 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1163 if (FAILED(hr))
1164 V_I4(&varg0) = 0;
1166 V_VT(pVarResult) = VT_DISPATCH;
1167 if ((ret = MsiGetSummaryInformationW(This->msiHandle, NULL, V_I4(&varg0), &msiHandle)) == ERROR_SUCCESS)
1169 hr = create_automation_object(msiHandle, NULL, (LPVOID *)&pDispatch, &DIID_SummaryInfo, SummaryInfoImpl_Invoke, NULL, 0);
1170 if (SUCCEEDED(hr))
1171 V_DISPATCH(pVarResult) = pDispatch;
1172 else
1173 ERR("Failed to create SummaryInfo object: 0x%08x\n", hr);
1175 else
1177 ERR("MsiGetSummaryInformation returned %d\n", ret);
1178 return DISP_E_EXCEPTION;
1181 else return DISP_E_MEMBERNOTFOUND;
1182 break;
1184 case DISPID_DATABASE_OPENVIEW:
1185 if (wFlags & DISPATCH_METHOD)
1187 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1188 if (FAILED(hr)) return hr;
1189 V_VT(pVarResult) = VT_DISPATCH;
1190 if ((ret = MsiDatabaseOpenViewW(This->msiHandle, V_BSTR(&varg0), &msiHandle)) == ERROR_SUCCESS)
1192 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_View, ViewImpl_Invoke, NULL, 0)))
1193 V_DISPATCH(pVarResult) = pDispatch;
1194 else
1195 ERR("Failed to create View object, hresult 0x%08x\n", hr);
1197 else
1199 VariantClear(&varg0);
1200 ERR("MsiDatabaseOpenView returned %d\n", ret);
1201 return DISP_E_EXCEPTION;
1204 else return DISP_E_MEMBERNOTFOUND;
1205 break;
1207 default:
1208 return DISP_E_MEMBERNOTFOUND;
1211 VariantClear(&varg1);
1212 VariantClear(&varg0);
1214 return S_OK;
1217 static HRESULT WINAPI SessionImpl_Invoke(
1218 AutomationObject* This,
1219 DISPID dispIdMember,
1220 REFIID riid,
1221 LCID lcid,
1222 WORD wFlags,
1223 DISPPARAMS* pDispParams,
1224 VARIANT* pVarResult,
1225 EXCEPINFO* pExcepInfo,
1226 UINT* puArgErr)
1228 SessionData *data = private_data(This);
1229 WCHAR *szString;
1230 DWORD dwLen;
1231 IDispatch *pDispatch = NULL;
1232 MSIHANDLE msiHandle;
1233 LANGID langId;
1234 UINT ret;
1235 INSTALLSTATE iInstalled, iAction;
1236 VARIANTARG varg0, varg1;
1237 HRESULT hr;
1239 VariantInit(&varg0);
1240 VariantInit(&varg1);
1242 switch (dispIdMember)
1244 case DISPID_SESSION_INSTALLER:
1245 if (wFlags & DISPATCH_PROPERTYGET) {
1246 V_VT(pVarResult) = VT_DISPATCH;
1247 IDispatch_AddRef(data->pInstaller);
1248 V_DISPATCH(pVarResult) = data->pInstaller;
1250 else return DISP_E_MEMBERNOTFOUND;
1251 break;
1253 case DISPID_SESSION_PROPERTY:
1254 if (wFlags & DISPATCH_PROPERTYGET) {
1255 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1256 if (FAILED(hr)) return hr;
1257 V_VT(pVarResult) = VT_BSTR;
1258 V_BSTR(pVarResult) = NULL;
1259 if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
1261 if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
1262 ERR("Out of memory\n");
1263 else if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
1264 V_BSTR(pVarResult) = SysAllocString(szString);
1265 msi_free(szString);
1267 if (ret != ERROR_SUCCESS)
1268 ERR("MsiGetProperty returned %d\n", ret);
1269 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1270 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1271 if (FAILED(hr)) return hr;
1272 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BSTR, &varg1, puArgErr);
1273 if (FAILED(hr)) {
1274 VariantClear(&varg0);
1275 return hr;
1277 if ((ret = MsiSetPropertyW(This->msiHandle, V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
1279 VariantClear(&varg0);
1280 VariantClear(&varg1);
1281 ERR("MsiSetProperty returned %d\n", ret);
1282 return DISP_E_EXCEPTION;
1285 else return DISP_E_MEMBERNOTFOUND;
1286 break;
1288 case DISPID_SESSION_LANGUAGE:
1289 if (wFlags & DISPATCH_PROPERTYGET) {
1290 langId = MsiGetLanguage(This->msiHandle);
1291 V_VT(pVarResult) = VT_I4;
1292 V_I4(pVarResult) = langId;
1294 else return DISP_E_MEMBERNOTFOUND;
1295 break;
1297 case DISPID_SESSION_MODE:
1298 if (wFlags & DISPATCH_PROPERTYGET) {
1299 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1300 if (FAILED(hr)) return hr;
1301 V_VT(pVarResult) = VT_BOOL;
1302 V_BOOL(pVarResult) = MsiGetMode(This->msiHandle, V_I4(&varg0));
1303 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1304 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1305 if (FAILED(hr)) return hr;
1306 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BOOL, &varg1, puArgErr);
1307 if (FAILED(hr)) return hr;
1308 if ((ret = MsiSetMode(This->msiHandle, V_I4(&varg0), V_BOOL(&varg1))) != ERROR_SUCCESS)
1310 ERR("MsiSetMode returned %d\n", ret);
1311 return DISP_E_EXCEPTION;
1314 else return DISP_E_MEMBERNOTFOUND;
1315 break;
1317 case DISPID_SESSION_DATABASE:
1318 if (wFlags & DISPATCH_PROPERTYGET) {
1319 V_VT(pVarResult) = VT_DISPATCH;
1320 if ((msiHandle = MsiGetActiveDatabase(This->msiHandle)))
1322 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Database, DatabaseImpl_Invoke, NULL, 0)))
1323 V_DISPATCH(pVarResult) = pDispatch;
1324 else
1325 ERR("Failed to create Database object, hresult 0x%08x\n", hr);
1327 else
1329 ERR("MsiGetActiveDatabase failed\n");
1330 return DISP_E_EXCEPTION;
1333 else return DISP_E_MEMBERNOTFOUND;
1334 break;
1336 case DISPID_SESSION_DOACTION:
1337 if (wFlags & DISPATCH_METHOD) {
1338 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1339 if (FAILED(hr)) return hr;
1340 ret = MsiDoActionW(This->msiHandle, V_BSTR(&varg0));
1341 V_VT(pVarResult) = VT_I4;
1342 switch (ret)
1344 case ERROR_FUNCTION_NOT_CALLED:
1345 V_I4(pVarResult) = msiDoActionStatusNoAction;
1346 break;
1347 case ERROR_SUCCESS:
1348 V_I4(pVarResult) = msiDoActionStatusSuccess;
1349 break;
1350 case ERROR_INSTALL_USEREXIT:
1351 V_I4(pVarResult) = msiDoActionStatusUserExit;
1352 break;
1353 case ERROR_INSTALL_FAILURE:
1354 V_I4(pVarResult) = msiDoActionStatusFailure;
1355 break;
1356 case ERROR_INSTALL_SUSPEND:
1357 V_I4(pVarResult) = msiDoActionStatusSuspend;
1358 break;
1359 case ERROR_MORE_DATA:
1360 V_I4(pVarResult) = msiDoActionStatusFinished;
1361 break;
1362 case ERROR_INVALID_HANDLE_STATE:
1363 V_I4(pVarResult) = msiDoActionStatusWrongState;
1364 break;
1365 case ERROR_INVALID_DATA:
1366 V_I4(pVarResult) = msiDoActionStatusBadActionData;
1367 break;
1368 default:
1369 VariantClear(&varg0);
1370 FIXME("MsiDoAction returned unhandled value %d\n", ret);
1371 return DISP_E_EXCEPTION;
1374 else return DISP_E_MEMBERNOTFOUND;
1375 break;
1377 case DISPID_SESSION_EVALUATECONDITION:
1378 if (wFlags & DISPATCH_METHOD) {
1379 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1380 if (FAILED(hr)) return hr;
1381 V_VT(pVarResult) = VT_I4;
1382 V_I4(pVarResult) = MsiEvaluateConditionW(This->msiHandle, V_BSTR(&varg0));
1384 else return DISP_E_MEMBERNOTFOUND;
1385 break;
1387 case DISPID_SESSION_SETINSTALLLEVEL:
1388 if (wFlags & DISPATCH_METHOD) {
1389 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1390 if (FAILED(hr)) return hr;
1391 if ((ret = MsiSetInstallLevel(This->msiHandle, V_I4(&varg0))) != ERROR_SUCCESS)
1393 ERR("MsiSetInstallLevel returned %d\n", ret);
1394 return DISP_E_EXCEPTION;
1397 else return DISP_E_MEMBERNOTFOUND;
1398 break;
1400 case DISPID_SESSION_FEATURECURRENTSTATE:
1401 if (wFlags & DISPATCH_PROPERTYGET) {
1402 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1403 if (FAILED(hr)) return hr;
1404 V_VT(pVarResult) = VT_I4;
1405 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1406 V_I4(pVarResult) = iInstalled;
1407 else
1409 ERR("MsiGetFeatureState returned %d\n", ret);
1410 V_I4(pVarResult) = msiInstallStateUnknown;
1413 else return DISP_E_MEMBERNOTFOUND;
1414 break;
1416 case DISPID_SESSION_FEATUREREQUESTSTATE:
1417 if (wFlags & DISPATCH_PROPERTYGET) {
1418 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1419 if (FAILED(hr)) return hr;
1420 V_VT(pVarResult) = VT_I4;
1421 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1422 V_I4(pVarResult) = iAction;
1423 else
1425 ERR("MsiGetFeatureState returned %d\n", ret);
1426 V_I4(pVarResult) = msiInstallStateUnknown;
1428 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1429 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1430 if (FAILED(hr)) return hr;
1431 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_I4, &varg1, puArgErr);
1432 if (FAILED(hr)) {
1433 VariantClear(&varg0);
1434 return hr;
1436 if ((ret = MsiSetFeatureStateW(This->msiHandle, V_BSTR(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
1438 VariantClear(&varg0);
1439 ERR("MsiSetFeatureState returned %d\n", ret);
1440 return DISP_E_EXCEPTION;
1443 else return DISP_E_MEMBERNOTFOUND;
1444 break;
1446 default:
1447 return DISP_E_MEMBERNOTFOUND;
1450 VariantClear(&varg1);
1451 VariantClear(&varg0);
1453 return S_OK;
1456 /* Fill the variant pointed to by pVarResult with the value & size returned by RegQueryValueEx as dictated by the
1457 * registry value type. Used by Installer::RegistryValue. */
1458 static void variant_from_registry_value(VARIANT *pVarResult, DWORD dwType, LPBYTE lpData, DWORD dwSize)
1460 static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
1461 static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
1462 WCHAR *szString = (WCHAR *)lpData;
1463 LPWSTR szNewString = NULL;
1464 DWORD dwNewSize = 0;
1465 int idx;
1467 switch (dwType)
1469 /* Registry strings may not be null terminated so we must use SysAllocStringByteLen/Len */
1470 case REG_MULTI_SZ: /* Multi SZ change internal null characters to newlines */
1471 idx = (dwSize/sizeof(WCHAR))-1;
1472 while (idx >= 0 && !szString[idx]) idx--;
1473 for (; idx >= 0; idx--)
1474 if (!szString[idx]) szString[idx] = '\n';
1475 case REG_SZ:
1476 V_VT(pVarResult) = VT_BSTR;
1477 V_BSTR(pVarResult) = SysAllocStringByteLen((LPCSTR)szString, dwSize);
1478 break;
1480 case REG_EXPAND_SZ:
1481 if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1482 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1483 else if (!(szNewString = msi_alloc(dwNewSize)))
1484 ERR("Out of memory\n");
1485 else if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1486 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1487 else
1489 V_VT(pVarResult) = VT_BSTR;
1490 V_BSTR(pVarResult) = SysAllocStringLen(szNewString, dwNewSize);
1492 msi_free(szNewString);
1493 break;
1495 case REG_DWORD:
1496 V_VT(pVarResult) = VT_I4;
1497 V_I4(pVarResult) = *((DWORD *)lpData);
1498 break;
1500 case REG_QWORD:
1501 V_VT(pVarResult) = VT_BSTR;
1502 V_BSTR(pVarResult) = SysAllocString(szREG_); /* Weird string, don't know why native returns it */
1503 break;
1505 case REG_BINARY:
1506 V_VT(pVarResult) = VT_BSTR;
1507 V_BSTR(pVarResult) = SysAllocString(szREG_BINARY);
1508 break;
1510 case REG_NONE:
1511 V_VT(pVarResult) = VT_EMPTY;
1512 break;
1514 default:
1515 FIXME("Unhandled registry value type %d\n", dwType);
1519 static HRESULT WINAPI InstallerImpl_Invoke(
1520 AutomationObject* This,
1521 DISPID dispIdMember,
1522 REFIID riid,
1523 LCID lcid,
1524 WORD wFlags,
1525 DISPPARAMS* pDispParams,
1526 VARIANT* pVarResult,
1527 EXCEPINFO* pExcepInfo,
1528 UINT* puArgErr)
1530 MSIHANDLE msiHandle;
1531 IDispatch *pDispatch = NULL;
1532 UINT ret;
1533 VARIANTARG varg0, varg1, varg2;
1534 HRESULT hr;
1535 LPWSTR szString = NULL;
1536 DWORD dwSize = 0;
1538 VariantInit(&varg0);
1539 VariantInit(&varg1);
1540 VariantInit(&varg2);
1542 switch (dispIdMember)
1544 case DISPID_INSTALLER_CREATERECORD:
1545 if (wFlags & DISPATCH_METHOD)
1547 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1548 if (FAILED(hr)) return hr;
1549 V_VT(pVarResult) = VT_DISPATCH;
1550 if ((msiHandle = MsiCreateRecord(V_I4(&varg0))))
1552 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Record, RecordImpl_Invoke, NULL, 0)))
1553 V_DISPATCH(pVarResult) = pDispatch;
1554 else
1555 ERR("Failed to create Record object, hresult 0x%08x\n", hr);
1557 else
1559 ERR("MsiCreateRecord failed\n");
1560 return DISP_E_EXCEPTION;
1563 else return DISP_E_MEMBERNOTFOUND;
1564 break;
1566 case DISPID_INSTALLER_OPENPACKAGE:
1567 if (wFlags & DISPATCH_METHOD)
1569 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1570 if (FAILED(hr)) return hr;
1571 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1572 if (FAILED(hr))
1574 VariantClear(&varg0);
1575 return hr;
1577 V_VT(pVarResult) = VT_DISPATCH;
1578 if ((ret = MsiOpenPackageExW(V_BSTR(&varg0), V_I4(&varg1), &msiHandle)) == ERROR_SUCCESS)
1580 if (SUCCEEDED(hr = create_session(msiHandle, (IDispatch *)This, &pDispatch)))
1581 V_DISPATCH(pVarResult) = pDispatch;
1582 else
1583 ERR("Failed to create Session object, hresult 0x%08x\n", hr);
1585 else
1587 VariantClear(&varg0);
1588 ERR("MsiOpenPackageEx returned %d\n", ret);
1589 return DISP_E_EXCEPTION;
1592 else return DISP_E_MEMBERNOTFOUND;
1593 break;
1595 case DISPID_INSTALLER_OPENDATABASE:
1596 if (wFlags & DISPATCH_METHOD)
1598 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1599 if (FAILED(hr)) return hr;
1601 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1602 if (FAILED(hr))
1604 VariantClear(&varg0);
1605 return hr;
1608 V_VT(pVarResult) = VT_DISPATCH;
1609 if ((ret = MsiOpenDatabaseW(V_BSTR(&varg0), V_BSTR(&varg1), &msiHandle)) == ERROR_SUCCESS)
1611 hr = create_automation_object(msiHandle, NULL, (LPVOID *)&pDispatch,
1612 &DIID_Database, DatabaseImpl_Invoke, NULL, 0);
1613 if (SUCCEEDED(hr))
1614 V_DISPATCH(pVarResult) = pDispatch;
1615 else
1616 ERR("Failed to create Database object: 0x%08x\n", hr);
1618 else
1620 VariantClear(&varg0);
1621 VariantClear(&varg1);
1622 ERR("MsiOpenDatabase returned %d\n", ret);
1623 return DISP_E_EXCEPTION;
1626 else return DISP_E_MEMBERNOTFOUND;
1627 break;
1629 case DISPID_INSTALLER_INSTALLPRODUCT:
1630 if (wFlags & DISPATCH_METHOD)
1632 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1633 if (FAILED(hr)) return hr;
1634 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1635 if (FAILED(hr))
1637 VariantClear(&varg0);
1638 return hr;
1640 if ((ret = MsiInstallProductW(V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
1642 VariantClear(&varg1);
1643 VariantClear(&varg0);
1644 ERR("MsiInstallProduct returned %d\n", ret);
1645 return DISP_E_EXCEPTION;
1648 else return DISP_E_MEMBERNOTFOUND;
1649 break;
1651 case DISPID_INSTALLER_REGISTRYVALUE:
1652 if (wFlags & DISPATCH_METHOD) {
1653 HKEY hkey;
1654 DWORD dwType;
1655 UINT posValue = 2; /* Save valuePos so we can save puArgErr if we are unable to do our type conversions */
1657 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1658 if (FAILED(hr)) return hr;
1659 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1660 if (FAILED(hr)) return hr;
1661 hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg2);
1662 if (FAILED(hr))
1664 VariantClear(&varg1);
1665 return hr;
1667 ret = RegOpenKeyW((HKEY)V_I4(&varg0), V_BSTR(&varg1), &hkey);
1669 /* Third parameter can be VT_EMPTY, VT_I4, or VT_BSTR */
1670 switch (V_VT(&varg2))
1672 case VT_EMPTY: /* Return VT_BOOL as to whether or not registry key exists */
1673 V_VT(pVarResult) = VT_BOOL;
1674 V_BOOL(pVarResult) = (ret == ERROR_SUCCESS);
1675 break;
1677 case VT_BSTR: /* Return value of specified key if it exists */
1678 if (ret == ERROR_SUCCESS &&
1679 (ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL, NULL, NULL, &dwSize)) == ERROR_SUCCESS)
1681 if (!(szString = msi_alloc(dwSize)))
1682 ERR("Out of memory\n");
1683 else if ((ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL, &dwType, (LPBYTE)szString, &dwSize)) == ERROR_SUCCESS)
1684 variant_from_registry_value(pVarResult, dwType, (LPBYTE)szString, dwSize);
1687 if (ret != ERROR_SUCCESS)
1689 msi_free(szString);
1690 VariantClear(&varg2);
1691 VariantClear(&varg1);
1692 return DISP_E_BADINDEX;
1694 break;
1696 default: /* Try to make it into VT_I4, can use VariantChangeType for this */
1697 hr = VariantChangeType(&varg2, &varg2, 0, VT_I4);
1698 if (SUCCEEDED(hr) && ret != ERROR_SUCCESS) hr = DISP_E_BADINDEX; /* Conversion fine, but couldn't find key */
1699 if (FAILED(hr))
1701 if (hr == DISP_E_TYPEMISMATCH) *puArgErr = posValue;
1702 VariantClear(&varg2); /* Unknown type, so let's clear it */
1703 VariantClear(&varg1);
1704 return hr;
1707 /* Retrieve class name or maximum value name or subkey name size */
1708 if (!V_I4(&varg2))
1709 ret = RegQueryInfoKeyW(hkey, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1710 else if (V_I4(&varg2) > 0)
1711 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL);
1712 else /* V_I4(&varg2) < 0 */
1713 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
1715 if (ret == ERROR_SUCCESS)
1717 if (!(szString = msi_alloc(++dwSize * sizeof(WCHAR))))
1718 ERR("Out of memory\n");
1719 else if (!V_I4(&varg2))
1720 ret = RegQueryInfoKeyW(hkey, szString, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1721 else if (V_I4(&varg2) > 0)
1722 ret = RegEnumValueW(hkey, V_I4(&varg2)-1, szString, &dwSize, 0, 0, NULL, NULL);
1723 else /* V_I4(&varg2) < 0 */
1724 ret = RegEnumKeyW(hkey, -1 - V_I4(&varg2), szString, dwSize);
1726 if (szString && ret == ERROR_SUCCESS)
1728 V_VT(pVarResult) = VT_BSTR;
1729 V_BSTR(pVarResult) = SysAllocString(szString);
1734 msi_free(szString);
1735 RegCloseKey(hkey);
1737 else return DISP_E_MEMBERNOTFOUND;
1738 break;
1740 case DISPID_INSTALLER_PRODUCTSTATE:
1741 if (wFlags & DISPATCH_PROPERTYGET) {
1742 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1743 if (FAILED(hr)) return hr;
1744 V_VT(pVarResult) = VT_I4;
1745 V_I4(pVarResult) = MsiQueryProductStateW(V_BSTR(&varg0));
1747 else return DISP_E_MEMBERNOTFOUND;
1748 break;
1750 case DISPID_INSTALLER_PRODUCTINFO:
1751 if (wFlags & DISPATCH_PROPERTYGET) {
1752 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1753 if (FAILED(hr)) return hr;
1754 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1755 if (FAILED(hr))
1757 VariantClear(&varg0);
1758 return hr;
1760 V_VT(pVarResult) = VT_BSTR;
1761 V_BSTR(pVarResult) = NULL;
1762 if ((ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), NULL, &dwSize)) == ERROR_SUCCESS)
1764 if (!(szString = msi_alloc((++dwSize)*sizeof(WCHAR))))
1765 ERR("Out of memory\n");
1766 else if ((ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), szString, &dwSize)) == ERROR_SUCCESS)
1767 V_BSTR(pVarResult) = SysAllocString(szString);
1768 msi_free(szString);
1770 if (ret != ERROR_SUCCESS)
1772 ERR("MsiGetProductInfo returned %d\n", ret);
1773 VariantClear(&varg1);
1774 VariantClear(&varg0);
1775 return DISP_E_EXCEPTION;
1778 else return DISP_E_MEMBERNOTFOUND;
1779 break;
1781 case DISPID_INSTALLER_PRODUCTS:
1782 if (wFlags & DISPATCH_PROPERTYGET)
1784 ListData *ldata = NULL;
1785 ULONG idx = 0;
1786 WCHAR szProductBuf[GUID_SIZE];
1788 /* Find number of products */
1789 while ((ret = MsiEnumProductsW(idx, szProductBuf)) == ERROR_SUCCESS) idx++;
1790 if (ret != ERROR_NO_MORE_ITEMS)
1792 ERR("MsiEnumProducts returned %d\n", ret);
1793 return DISP_E_EXCEPTION;
1796 V_VT(pVarResult) = VT_DISPATCH;
1797 if (SUCCEEDED(hr = create_automation_object(0, NULL, (LPVOID*)&pDispatch, &DIID_StringList, ListImpl_Invoke, ListImpl_Free, sizeof(ListData))))
1799 V_DISPATCH(pVarResult) = pDispatch;
1801 /* Save product strings */
1802 ldata = (ListData *)private_data((AutomationObject *)pDispatch);
1803 if (!(ldata->pVars = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(VARIANT)*idx)))
1804 ERR("Out of memory\n");
1805 else
1807 ldata->ulCount = idx;
1808 for (idx = 0; idx < ldata->ulCount; idx++)
1810 ret = MsiEnumProductsW(idx, szProductBuf);
1811 VariantInit(&ldata->pVars[idx]);
1812 V_VT(&ldata->pVars[idx]) = VT_BSTR;
1813 V_BSTR(&ldata->pVars[idx]) = SysAllocString(szProductBuf);
1817 else
1818 ERR("Failed to create StringList object, hresult 0x%08x\n", hr);
1820 else return DISP_E_MEMBERNOTFOUND;
1821 break;
1823 case DISPID_INSTALLER_RELATEDPRODUCTS:
1824 if (wFlags & DISPATCH_PROPERTYGET)
1826 ListData *ldata = NULL;
1827 ULONG idx = 0;
1828 WCHAR szProductBuf[GUID_SIZE];
1830 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1831 if (FAILED(hr)) return hr;
1833 /* Find number of related products */
1834 while ((ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, szProductBuf)) == ERROR_SUCCESS) idx++;
1835 if (ret != ERROR_NO_MORE_ITEMS)
1837 VariantClear(&varg0);
1838 ERR("MsiEnumRelatedProducts returned %d\n", ret);
1839 return DISP_E_EXCEPTION;
1842 V_VT(pVarResult) = VT_DISPATCH;
1843 if (SUCCEEDED(hr = create_automation_object(0, NULL, (LPVOID*)&pDispatch, &DIID_StringList, ListImpl_Invoke, ListImpl_Free, sizeof(ListData))))
1845 V_DISPATCH(pVarResult) = pDispatch;
1847 /* Save product strings */
1848 ldata = (ListData *)private_data((AutomationObject *)pDispatch);
1849 if (!(ldata->pVars = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(VARIANT)*idx)))
1850 ERR("Out of memory\n");
1851 else
1853 ldata->ulCount = idx;
1854 for (idx = 0; idx < ldata->ulCount; idx++)
1856 ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, szProductBuf);
1857 VariantInit(&ldata->pVars[idx]);
1858 V_VT(&ldata->pVars[idx]) = VT_BSTR;
1859 V_BSTR(&ldata->pVars[idx]) = SysAllocString(szProductBuf);
1863 else
1864 ERR("Failed to create StringList object, hresult 0x%08x\n", hr);
1866 else return DISP_E_MEMBERNOTFOUND;
1867 break;
1869 default:
1870 return DISP_E_MEMBERNOTFOUND;
1873 VariantClear(&varg2);
1874 VariantClear(&varg1);
1875 VariantClear(&varg0);
1877 return S_OK;
1880 /* Wrapper around create_automation_object to create an installer object. */
1881 HRESULT create_msiserver(IUnknown *pOuter, LPVOID *ppObj)
1883 return create_automation_object(0, pOuter, ppObj, &DIID_Installer, InstallerImpl_Invoke, NULL, 0);
1886 /* Wrapper around create_automation_object to create a session object. */
1887 HRESULT create_session(MSIHANDLE msiHandle, IDispatch *pInstaller, IDispatch **pDispatch)
1889 HRESULT hr = create_automation_object(msiHandle, NULL, (LPVOID)pDispatch, &DIID_Session, SessionImpl_Invoke, NULL, sizeof(SessionData));
1890 if (SUCCEEDED(hr) && pDispatch && *pDispatch)
1891 ((SessionData *)private_data((AutomationObject *)*pDispatch))->pInstaller = pInstaller;
1892 return hr;