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