2 * Implementation of OLE Automation for Microsoft Installer (msi.dll)
4 * Copyright 2007 Misha Koshelev
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
33 #include "wine/debug.h"
34 #include "wine/unicode.h"
36 #include "msiserver.h"
37 #include "msiserver_dispids.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(msi);
42 * AutomationObject - "base" class for all automation objects. For each interface, we implement Invoke function
43 * called from AutomationObject::Invoke, and pass this function to create_automation_object.
46 typedef interface AutomationObject AutomationObject;
48 interface AutomationObject {
50 * VTables - We provide IDispatch, IProvideClassInfo, IProvideClassInfo2, IProvideMultipleClassInfo
52 const IDispatchVtbl *lpVtbl;
53 const IProvideMultipleClassInfoVtbl *lpvtblIProvideMultipleClassInfo;
55 /* Object reference count */
58 /* Clsid for this class and it's appropriate ITypeInfo object */
62 /* The MSI handle of the current object */
65 /* A function that is called from AutomationObject::Invoke, specific to this type of object. */
66 HRESULT (STDMETHODCALLTYPE *funcInvoke)(
67 AutomationObject* This,
72 DISPPARAMS* pDispParams,
74 EXCEPINFO* pExcepInfo,
77 /* A function that is called from AutomationObject::Release when the object is being freed to free any private
78 * data structures (or NULL) */
79 void (STDMETHODCALLTYPE *funcFree)(AutomationObject* This);
83 * ListEnumerator - IEnumVARIANT implementation for MSI automation lists.
86 typedef interface ListEnumerator ListEnumerator;
88 interface ListEnumerator {
90 const IEnumVARIANTVtbl *lpVtbl;
92 /* Object reference count */
95 /* Current position and pointer to AutomationObject that stores actual data */
97 AutomationObject *pObj;
101 * Structures for additional data required by specific automation objects
110 /* The parent Installer object */
111 IDispatch *pInstaller;
115 static const struct IDispatchVtbl AutomationObject_Vtbl;
116 static const struct IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl;
117 static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl;
119 /* Load type info so we don't have to process GetIDsOfNames */
120 HRESULT load_type_info(IDispatch *iface, ITypeInfo **pptinfo, REFIID clsid, LCID lcid)
123 LPTYPELIB pLib = NULL;
124 LPTYPEINFO pInfo = NULL;
125 static const WCHAR szMsiServer[] = {'m','s','i','s','e','r','v','e','r','.','t','l','b'};
127 TRACE("(%p)->(%s,%d)\n", iface, debugstr_guid(clsid), lcid);
129 /* Load registered type library */
130 hr = LoadRegTypeLib(&LIBID_WindowsInstaller, 1, 0, lcid, &pLib);
132 hr = LoadTypeLib(szMsiServer, &pLib);
134 ERR("Could not load msiserver.tlb\n");
139 /* Get type information for object */
140 hr = ITypeLib_GetTypeInfoOfGuid(pLib, clsid, &pInfo);
141 ITypeLib_Release(pLib);
143 ERR("Could not load ITypeInfo for %s\n", debugstr_guid(clsid));
150 /* Create the automation object, placing the result in the pointer ppObj. The automation object is created
151 * with the appropriate clsid and invocation function. */
152 HRESULT create_automation_object(MSIHANDLE msiHandle, IUnknown *pUnkOuter, LPVOID *ppObj, REFIID clsid,
153 HRESULT (STDMETHODCALLTYPE *funcInvoke)(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,
154 VARIANT*,EXCEPINFO*,UINT*),
155 void (STDMETHODCALLTYPE *funcFree)(AutomationObject*),
156 SIZE_T sizetPrivateData)
158 AutomationObject *object;
161 TRACE("(%ld,%p,%p,%s,%p,%p,%ld)\n", (unsigned long)msiHandle, pUnkOuter, ppObj, debugstr_guid(clsid), funcInvoke, funcFree, sizetPrivateData);
164 return CLASS_E_NOAGGREGATION;
166 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AutomationObject)+sizetPrivateData);
168 /* Set all the VTable references */
169 object->lpVtbl = &AutomationObject_Vtbl;
170 object->lpvtblIProvideMultipleClassInfo = &AutomationObject_IProvideMultipleClassInfo_Vtbl;
173 /* Store data that was passed */
174 object->msiHandle = msiHandle;
175 object->clsid = (LPCLSID)clsid;
176 object->funcInvoke = funcInvoke;
177 object->funcFree = funcFree;
179 /* Load our TypeInfo so we don't have to process GetIDsOfNames */
180 object->iTypeInfo = NULL;
181 hr = load_type_info((IDispatch *)object, &object->iTypeInfo, clsid, 0x0);
183 HeapFree(GetProcessHeap(), 0, object);
192 /* Create a list enumerator, placing the result in the pointer ppObj. */
193 HRESULT create_list_enumerator(IUnknown *pUnkOuter, LPVOID *ppObj, AutomationObject *pObj, ULONG ulPos)
195 ListEnumerator *object;
197 TRACE("(%p,%p,%p,%uld)\n", pUnkOuter, ppObj, pObj, ulPos);
200 return CLASS_E_NOAGGREGATION;
202 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ListEnumerator));
204 /* Set all the VTable references */
205 object->lpVtbl = &ListEnumerator_Vtbl;
208 /* Store data that was passed */
209 object->ulPos = ulPos;
211 if (pObj) IDispatch_AddRef((IDispatch *)pObj);
217 /* Macros to get pointer to AutomationObject from the other VTables. */
218 static inline AutomationObject *obj_from_IProvideMultipleClassInfo( IProvideMultipleClassInfo *iface )
220 return (AutomationObject *)((char*)iface - FIELD_OFFSET(AutomationObject, lpvtblIProvideMultipleClassInfo));
223 /* Macro to get pointer to private object data */
224 static inline void *private_data( AutomationObject *This )
230 * AutomationObject methods
233 /*** IUnknown methods ***/
234 static HRESULT WINAPI AutomationObject_QueryInterface(IDispatch* iface, REFIID riid, void** ppvObject)
236 AutomationObject *This = (AutomationObject *)iface;
238 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
240 if (ppvObject == NULL)
245 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDispatch) || IsEqualGUID(riid, This->clsid))
247 else if (IsEqualGUID(riid, &IID_IProvideClassInfo) ||
248 IsEqualGUID(riid, &IID_IProvideClassInfo2) ||
249 IsEqualGUID(riid, &IID_IProvideMultipleClassInfo))
250 *ppvObject = &This->lpvtblIProvideMultipleClassInfo;
253 TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid));
254 return E_NOINTERFACE;
258 * Query Interface always increases the reference count by one when it is
261 IClassFactory_AddRef(iface);
266 static ULONG WINAPI AutomationObject_AddRef(IDispatch* iface)
268 AutomationObject *This = (AutomationObject *)iface;
270 TRACE("(%p/%p)\n", iface, This);
272 return InterlockedIncrement(&This->ref);
275 static ULONG WINAPI AutomationObject_Release(IDispatch* iface)
277 AutomationObject *This = (AutomationObject *)iface;
278 ULONG ref = InterlockedDecrement(&This->ref);
280 TRACE("(%p/%p)\n", iface, This);
284 if (This->funcFree) This->funcFree(This);
285 MsiCloseHandle(This->msiHandle);
286 HeapFree(GetProcessHeap(), 0, This);
292 /*** IDispatch methods ***/
293 static HRESULT WINAPI AutomationObject_GetTypeInfoCount(
297 AutomationObject *This = (AutomationObject *)iface;
299 TRACE("(%p/%p)->(%p)\n", iface, This, pctinfo);
304 static HRESULT WINAPI AutomationObject_GetTypeInfo(
310 AutomationObject *This = (AutomationObject *)iface;
311 TRACE("(%p/%p)->(%d,%d,%p)\n", iface, This, iTInfo, lcid, ppTInfo);
313 ITypeInfo_AddRef(This->iTypeInfo);
314 *ppTInfo = This->iTypeInfo;
318 static HRESULT WINAPI AutomationObject_GetIDsOfNames(
326 AutomationObject *This = (AutomationObject *)iface;
328 TRACE("(%p/%p)->(%p,%p,%d,%d,%p)\n", iface, This, riid, rgszNames, cNames, lcid, rgDispId);
330 if (!IsEqualGUID(riid, &IID_NULL)) return E_INVALIDARG;
331 hr = ITypeInfo_GetIDsOfNames(This->iTypeInfo, rgszNames, cNames, rgDispId);
332 if (hr == DISP_E_UNKNOWNNAME)
335 for (idx=0; idx<cNames; idx++)
337 if (rgDispId[idx] == DISPID_UNKNOWN)
338 FIXME("Unknown member %s, clsid %s\n", debugstr_w(rgszNames[idx]), debugstr_guid(This->clsid));
344 /* Maximum number of allowed function parameters+1 */
345 #define MAX_FUNC_PARAMS 20
347 /* Some error checking is done here to simplify individual object function invocation */
348 static HRESULT WINAPI AutomationObject_Invoke(
354 DISPPARAMS* pDispParams,
356 EXCEPINFO* pExcepInfo,
359 AutomationObject *This = (AutomationObject *)iface;
361 unsigned int uArgErr;
362 VARIANT varResultDummy;
363 BSTR bstrName = NULL;
365 TRACE("(%p/%p)->(%d,%p,%d,%d,%p,%p,%p,%p)\n", iface, This, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
367 if (!IsEqualIID(riid, &IID_NULL))
369 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
370 return DISP_E_UNKNOWNNAME;
373 if (wFlags & DISPATCH_PROPERTYGET && !pVarResult)
375 ERR("NULL pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
376 return DISP_E_PARAMNOTOPTIONAL;
379 /* This simplifies our individual object invocation functions */
380 if (puArgErr == NULL) puArgErr = &uArgErr;
381 if (pVarResult == NULL) pVarResult = &varResultDummy;
383 /* Assume return type is void unless determined otherwise */
384 VariantInit(pVarResult);
386 /* If we are tracing, we want to see the name of the member we are invoking */
389 ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL);
390 TRACE("Method %d, %s\n", dispIdMember, debugstr_w(bstrName));
393 hr = This->funcInvoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
395 if (hr == DISP_E_MEMBERNOTFOUND) {
396 if (bstrName == NULL) ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL);
397 FIXME("Method %d, %s wflags %d not implemented, clsid %s\n", dispIdMember, debugstr_w(bstrName), wFlags, debugstr_guid(This->clsid));
399 else if (pExcepInfo &&
400 (hr == DISP_E_PARAMNOTFOUND ||
401 hr == DISP_E_EXCEPTION)) {
402 static const WCHAR szComma[] = { ',',0 };
403 static WCHAR szExceptionSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
404 WCHAR szExceptionDescription[MAX_PATH];
405 BSTR bstrParamNames[MAX_FUNC_PARAMS];
409 if (FAILED(ITypeInfo_GetNames(This->iTypeInfo, dispIdMember, bstrParamNames,
410 MAX_FUNC_PARAMS, &namesNo)))
412 TRACE("Failed to retrieve names for dispIdMember %d\n", dispIdMember);
416 memset(szExceptionDescription, 0, sizeof(szExceptionDescription));
417 for (i=0; i<namesNo; i++)
419 if (bFirst) bFirst = FALSE;
421 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], szComma);
423 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], bstrParamNames[i]);
424 SysFreeString(bstrParamNames[i]);
427 memset(pExcepInfo, 0, sizeof(EXCEPINFO));
428 pExcepInfo->wCode = 1000;
429 pExcepInfo->bstrSource = szExceptionSource;
430 pExcepInfo->bstrDescription = szExceptionDescription;
431 hr = DISP_E_EXCEPTION;
435 /* Make sure we free the return variant if it is our dummy variant */
436 if (pVarResult == &varResultDummy) VariantClear(pVarResult);
438 /* Free function name if we retrieved it */
439 if (bstrName) SysFreeString(bstrName);
441 TRACE("Returning 0x%08x, %s\n", hr, SUCCEEDED(hr) ? "ok" : "not ok");
446 static const struct IDispatchVtbl AutomationObject_Vtbl =
448 AutomationObject_QueryInterface,
449 AutomationObject_AddRef,
450 AutomationObject_Release,
451 AutomationObject_GetTypeInfoCount,
452 AutomationObject_GetTypeInfo,
453 AutomationObject_GetIDsOfNames,
454 AutomationObject_Invoke
458 * IProvideMultipleClassInfo methods
461 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_QueryInterface(
462 IProvideMultipleClassInfo* iface,
466 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
467 return AutomationObject_QueryInterface((IDispatch *)This, riid, ppvoid);
470 static ULONG WINAPI AutomationObject_IProvideMultipleClassInfo_AddRef(IProvideMultipleClassInfo* iface)
472 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
473 return AutomationObject_AddRef((IDispatch *)This);
476 static ULONG WINAPI AutomationObject_IProvideMultipleClassInfo_Release(IProvideMultipleClassInfo* iface)
478 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
479 return AutomationObject_Release((IDispatch *)This);
482 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_GetClassInfo(IProvideMultipleClassInfo* iface, ITypeInfo** ppTI)
484 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
485 TRACE("(%p/%p)->(%p)\n", iface, This, ppTI);
486 return load_type_info((IDispatch *)This, ppTI, This->clsid, 0);
489 static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_GetGUID(IProvideMultipleClassInfo* iface, DWORD dwGuidKind, GUID* pGUID)
491 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
492 TRACE("(%p/%p)->(%d,%s)\n", iface, This, dwGuidKind, debugstr_guid(pGUID));
494 if (dwGuidKind != GUIDKIND_DEFAULT_SOURCE_DISP_IID)
497 *pGUID = *This->clsid;
502 static HRESULT WINAPI AutomationObject_GetMultiTypeInfoCount(IProvideMultipleClassInfo* iface, ULONG* pcti)
504 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
506 TRACE("(%p/%p)->(%p)\n", iface, This, pcti);
511 static HRESULT WINAPI AutomationObject_GetInfoOfIndex(IProvideMultipleClassInfo* iface,
514 ITypeInfo** pptiCoClass,
516 ULONG* pcdispidReserved,
520 AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
522 TRACE("(%p/%p)->(%d,%d,%p,%p,%p,%p,%p)\n", iface, This, iti, dwFlags, pptiCoClass, pdwTIFlags, pcdispidReserved, piidPrimary, piidSource);
527 if (dwFlags & MULTICLASSINFO_GETTYPEINFO)
528 load_type_info((IDispatch *)This, pptiCoClass, This->clsid, 0);
530 if (dwFlags & MULTICLASSINFO_GETNUMRESERVEDDISPIDS)
533 *pcdispidReserved = 0;
536 if (dwFlags & MULTICLASSINFO_GETIIDPRIMARY){
537 *piidPrimary = *This->clsid;
540 if (dwFlags & MULTICLASSINFO_GETIIDSOURCE){
541 *piidSource = *This->clsid;
547 static const IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl =
549 AutomationObject_IProvideMultipleClassInfo_QueryInterface,
550 AutomationObject_IProvideMultipleClassInfo_AddRef,
551 AutomationObject_IProvideMultipleClassInfo_Release,
552 AutomationObject_IProvideMultipleClassInfo_GetClassInfo,
553 AutomationObject_IProvideMultipleClassInfo_GetGUID,
554 AutomationObject_GetMultiTypeInfoCount,
555 AutomationObject_GetInfoOfIndex
559 * ListEnumerator methods
562 /*** IUnknown methods ***/
563 static HRESULT WINAPI ListEnumerator_QueryInterface(IEnumVARIANT* iface, REFIID riid, void** ppvObject)
565 ListEnumerator *This = (ListEnumerator *)iface;
567 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
569 if (ppvObject == NULL)
574 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IEnumVARIANT))
578 TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid));
579 return E_NOINTERFACE;
582 IClassFactory_AddRef(iface);
586 static ULONG WINAPI ListEnumerator_AddRef(IEnumVARIANT* iface)
588 ListEnumerator *This = (ListEnumerator *)iface;
590 TRACE("(%p/%p)\n", iface, This);
592 return InterlockedIncrement(&This->ref);
595 static ULONG WINAPI ListEnumerator_Release(IEnumVARIANT* iface)
597 ListEnumerator *This = (ListEnumerator *)iface;
598 ULONG ref = InterlockedDecrement(&This->ref);
600 TRACE("(%p/%p)\n", iface, This);
604 if (This->pObj) IDispatch_Release((IDispatch *)This->pObj);
605 HeapFree(GetProcessHeap(), 0, This);
611 /* IEnumVARIANT methods */
613 static HRESULT WINAPI ListEnumerator_Next(IEnumVARIANT* iface, ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched)
615 ListEnumerator *This = (ListEnumerator *)iface;
616 ListData *data = (ListData *)private_data(This->pObj);
619 TRACE("(%p,%uld,%p,%p)\n", iface, celt, rgVar, pCeltFetched);
621 if (pCeltFetched != NULL)
627 for (local = 0; local < celt; local++)
628 VariantInit(&rgVar[local]);
630 for (idx = This->ulPos, local = 0; idx < data->ulCount && local < celt; idx++, local++)
631 VariantCopy(&rgVar[local], &data->pVars[idx]);
633 if (pCeltFetched != NULL)
634 *pCeltFetched = local;
637 return (local < celt) ? S_FALSE : S_OK;
640 static HRESULT WINAPI ListEnumerator_Skip(IEnumVARIANT* iface, ULONG celt)
642 ListEnumerator *This = (ListEnumerator *)iface;
643 ListData *data = (ListData *)private_data(This->pObj);
645 TRACE("(%p,%uld)\n", iface, celt);
648 if (This->ulPos >= data->ulCount)
650 This->ulPos = data->ulCount;
656 static HRESULT WINAPI ListEnumerator_Reset(IEnumVARIANT* iface)
658 ListEnumerator *This = (ListEnumerator *)iface;
660 TRACE("(%p)\n", iface);
666 static HRESULT WINAPI ListEnumerator_Clone(IEnumVARIANT* iface, IEnumVARIANT **ppEnum)
668 ListEnumerator *This = (ListEnumerator *)iface;
671 TRACE("(%p,%p)\n", iface, ppEnum);
677 hr = create_list_enumerator(NULL, (LPVOID *)ppEnum, This->pObj, 0);
681 IUnknown_Release(*ppEnum);
685 IUnknown_AddRef(*ppEnum);
689 static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl =
691 ListEnumerator_QueryInterface,
692 ListEnumerator_AddRef,
693 ListEnumerator_Release,
696 ListEnumerator_Reset,
701 * Individual Object Invocation Functions
704 /* Helper function that copies a passed parameter instead of using VariantChangeType like the actual DispGetParam.
705 This function is only for VARIANT type parameters that have several types that cannot be properly discriminated
706 using DispGetParam/VariantChangeType. */
707 HRESULT WINAPI DispGetParam_CopyOnly(
708 DISPPARAMS *pdispparams, /* [in] Parameter list */
709 UINT *position, /* [in] Position of parameter to copy in pdispparams; on return will contain calculated position */
710 VARIANT *pvarResult) /* [out] Destination for resulting variant */
712 /* position is counted backwards */
715 TRACE("position=%d, cArgs=%d, cNamedArgs=%d\n",
716 *position, pdispparams->cArgs, pdispparams->cNamedArgs);
717 if (*position < pdispparams->cArgs) {
718 /* positional arg? */
719 pos = pdispparams->cArgs - *position - 1;
721 /* FIXME: is this how to handle named args? */
722 for (pos=0; pos<pdispparams->cNamedArgs; pos++)
723 if (pdispparams->rgdispidNamedArgs[pos] == *position) break;
725 if (pos==pdispparams->cNamedArgs)
726 return DISP_E_PARAMNOTFOUND;
729 return VariantCopyInd(pvarResult,
730 &pdispparams->rgvarg[pos]);
733 static HRESULT WINAPI RecordImpl_Invoke(
734 AutomationObject* This,
739 DISPPARAMS* pDispParams,
741 EXCEPINFO* pExcepInfo,
747 VARIANTARG varg0, varg1;
753 switch (dispIdMember)
755 case DISPID_RECORD_FIELDCOUNT:
756 if (wFlags & DISPATCH_PROPERTYGET) {
757 V_VT(pVarResult) = VT_I4;
758 V_I4(pVarResult) = MsiRecordGetFieldCount(This->msiHandle);
760 else return DISP_E_MEMBERNOTFOUND;
763 case DISPID_RECORD_STRINGDATA:
764 if (wFlags & DISPATCH_PROPERTYGET) {
765 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
766 if (FAILED(hr)) return hr;
767 V_VT(pVarResult) = VT_BSTR;
768 V_BSTR(pVarResult) = NULL;
769 if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
771 if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
772 ERR("Out of memory\n");
773 else if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
774 V_BSTR(pVarResult) = SysAllocString(szString);
777 if (ret != ERROR_SUCCESS)
778 ERR("MsiRecordGetString returned %d\n", ret);
779 } else if (wFlags & DISPATCH_PROPERTYPUT) {
780 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
781 if (FAILED(hr)) return hr;
782 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BSTR, &varg1, puArgErr);
783 if (FAILED(hr)) return hr;
784 if ((ret = MsiRecordSetStringW(This->msiHandle, V_I4(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
786 VariantClear(&varg1);
787 ERR("MsiRecordSetString returned %d\n", ret);
788 return DISP_E_EXCEPTION;
791 else return DISP_E_MEMBERNOTFOUND;
794 case DISPID_RECORD_INTEGERDATA:
795 if (wFlags & DISPATCH_PROPERTYGET) {
796 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
797 if (FAILED(hr)) return hr;
798 V_VT(pVarResult) = VT_I4;
799 V_I4(pVarResult) = MsiRecordGetInteger(This->msiHandle, V_I4(&varg0));
800 } else if (wFlags & DISPATCH_PROPERTYPUT) {
801 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
802 if (FAILED(hr)) return hr;
803 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_I4, &varg1, puArgErr);
804 if (FAILED(hr)) return hr;
805 if ((ret = MsiRecordSetInteger(This->msiHandle, V_I4(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
807 ERR("MsiRecordSetInteger returned %d\n", ret);
808 return DISP_E_EXCEPTION;
811 else return DISP_E_MEMBERNOTFOUND;
815 return DISP_E_MEMBERNOTFOUND;
818 VariantClear(&varg1);
819 VariantClear(&varg0);
824 static HRESULT WINAPI ListImpl_Invoke(
825 AutomationObject* This,
830 DISPPARAMS* pDispParams,
832 EXCEPINFO* pExcepInfo,
835 ListData *data = (ListData *)private_data(This);
838 IUnknown *pUnk = NULL;
842 switch (dispIdMember)
844 case DISPID_LIST__NEWENUM:
845 if (wFlags & DISPATCH_METHOD) {
846 V_VT(pVarResult) = VT_UNKNOWN;
847 if (SUCCEEDED(hr = create_list_enumerator(NULL, (LPVOID *)&pUnk, This, 0)))
849 IUnknown_AddRef(pUnk);
850 V_UNKNOWN(pVarResult) = pUnk;
853 ERR("Failed to create IEnumVARIANT object, hresult 0x%08x\n", hr);
855 else return DISP_E_MEMBERNOTFOUND;
858 case DISPID_LIST_ITEM:
859 if (wFlags & DISPATCH_PROPERTYGET) {
860 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
861 if (FAILED(hr)) return hr;
862 if (V_I4(&varg0) < 0 || V_I4(&varg0) >= data->ulCount)
863 return DISP_E_BADINDEX;
864 VariantCopy(pVarResult, &data->pVars[V_I4(&varg0)]);
866 else return DISP_E_MEMBERNOTFOUND;
869 case DISPID_LIST_COUNT:
870 if (wFlags & DISPATCH_PROPERTYGET) {
871 V_VT(pVarResult) = VT_I4;
872 V_I4(pVarResult) = data->ulCount;
874 else return DISP_E_MEMBERNOTFOUND;
878 return DISP_E_MEMBERNOTFOUND;
881 VariantClear(&varg0);
886 static void WINAPI ListImpl_Free(AutomationObject *This)
888 ListData *data = private_data(This);
891 for (idx=0; idx<data->ulCount; idx++)
892 VariantClear(&data->pVars[idx]);
893 HeapFree(GetProcessHeap(), 0, data->pVars);
896 static HRESULT WINAPI ViewImpl_Invoke(
897 AutomationObject* This,
902 DISPPARAMS* pDispParams,
904 EXCEPINFO* pExcepInfo,
908 IDispatch *pDispatch = NULL;
910 VARIANTARG varg0, varg1;
916 switch (dispIdMember)
918 case DISPID_VIEW_EXECUTE:
919 if (wFlags & DISPATCH_METHOD)
921 hr = DispGetParam(pDispParams, 0, VT_DISPATCH, &varg0, puArgErr);
922 if (SUCCEEDED(hr) && V_DISPATCH(&varg0) != NULL)
923 MsiViewExecute(This->msiHandle, ((AutomationObject *)V_DISPATCH(&varg0))->msiHandle);
925 MsiViewExecute(This->msiHandle, 0);
927 else return DISP_E_MEMBERNOTFOUND;
930 case DISPID_VIEW_FETCH:
931 if (wFlags & DISPATCH_METHOD)
933 V_VT(pVarResult) = VT_DISPATCH;
934 if ((ret = MsiViewFetch(This->msiHandle, &msiHandle)) == ERROR_SUCCESS)
936 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Record, RecordImpl_Invoke, NULL, 0)))
938 IDispatch_AddRef(pDispatch);
939 V_DISPATCH(pVarResult) = pDispatch;
942 ERR("Failed to create Record object, hresult 0x%08x\n", hr);
944 else if (ret == ERROR_NO_MORE_ITEMS)
945 V_DISPATCH(pVarResult) = NULL;
948 ERR("MsiViewFetch returned %d\n", ret);
949 return DISP_E_EXCEPTION;
952 else return DISP_E_MEMBERNOTFOUND;
955 case DISPID_VIEW_MODIFY:
956 if (wFlags & DISPATCH_METHOD)
958 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
959 if (FAILED(hr)) return hr;
960 hr = DispGetParam(pDispParams, 1, VT_DISPATCH, &varg1, puArgErr);
961 if (FAILED(hr)) return hr;
962 if (!V_DISPATCH(&varg1)) return DISP_E_EXCEPTION;
963 if ((ret = MsiViewModify(This->msiHandle, V_I4(&varg0), ((AutomationObject *)V_DISPATCH(&varg1))->msiHandle)) != ERROR_SUCCESS)
965 VariantClear(&varg1);
966 ERR("MsiViewModify returned %d\n", ret);
967 return DISP_E_EXCEPTION;
970 else return DISP_E_MEMBERNOTFOUND;
973 case DISPID_VIEW_CLOSE:
974 if (wFlags & DISPATCH_METHOD)
976 MsiViewClose(This->msiHandle);
978 else return DISP_E_MEMBERNOTFOUND;
982 return DISP_E_MEMBERNOTFOUND;
985 VariantClear(&varg1);
986 VariantClear(&varg0);
991 static HRESULT WINAPI DatabaseImpl_Invoke(
992 AutomationObject* This,
997 DISPPARAMS* pDispParams,
999 EXCEPINFO* pExcepInfo,
1002 MSIHANDLE msiHandle;
1003 IDispatch *pDispatch = NULL;
1005 VARIANTARG varg0, varg1;
1008 VariantInit(&varg0);
1009 VariantInit(&varg1);
1011 switch (dispIdMember)
1013 case DISPID_DATABASE_OPENVIEW:
1014 if (wFlags & DISPATCH_METHOD)
1016 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1017 if (FAILED(hr)) return hr;
1018 V_VT(pVarResult) = VT_DISPATCH;
1019 if ((ret = MsiDatabaseOpenViewW(This->msiHandle, V_BSTR(&varg0), &msiHandle)) == ERROR_SUCCESS)
1021 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_View, ViewImpl_Invoke, NULL, 0)))
1023 IDispatch_AddRef(pDispatch);
1024 V_DISPATCH(pVarResult) = pDispatch;
1027 ERR("Failed to create View object, hresult 0x%08x\n", hr);
1031 VariantClear(&varg0);
1032 ERR("MsiDatabaseOpenView returned %d\n", ret);
1033 return DISP_E_EXCEPTION;
1036 else return DISP_E_MEMBERNOTFOUND;
1040 return DISP_E_MEMBERNOTFOUND;
1043 VariantClear(&varg1);
1044 VariantClear(&varg0);
1049 static HRESULT WINAPI SessionImpl_Invoke(
1050 AutomationObject* This,
1051 DISPID dispIdMember,
1055 DISPPARAMS* pDispParams,
1056 VARIANT* pVarResult,
1057 EXCEPINFO* pExcepInfo,
1060 SessionData *data = private_data(This);
1063 IDispatch *pDispatch = NULL;
1064 MSIHANDLE msiHandle;
1067 INSTALLSTATE iInstalled, iAction;
1068 VARIANTARG varg0, varg1;
1071 VariantInit(&varg0);
1072 VariantInit(&varg1);
1074 switch (dispIdMember)
1076 case DISPID_SESSION_INSTALLER:
1077 if (wFlags & DISPATCH_PROPERTYGET) {
1078 V_VT(pVarResult) = VT_DISPATCH;
1079 IDispatch_AddRef(data->pInstaller);
1080 V_DISPATCH(pVarResult) = data->pInstaller;
1082 else return DISP_E_MEMBERNOTFOUND;
1085 case DISPID_SESSION_PROPERTY:
1086 if (wFlags & DISPATCH_PROPERTYGET) {
1087 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1088 if (FAILED(hr)) return hr;
1089 V_VT(pVarResult) = VT_BSTR;
1090 V_BSTR(pVarResult) = NULL;
1091 if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
1093 if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
1094 ERR("Out of memory\n");
1095 else if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
1096 V_BSTR(pVarResult) = SysAllocString(szString);
1099 if (ret != ERROR_SUCCESS)
1100 ERR("MsiGetProperty returned %d\n", ret);
1101 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1102 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1103 if (FAILED(hr)) return hr;
1104 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BSTR, &varg1, puArgErr);
1106 VariantClear(&varg0);
1109 if ((ret = MsiSetPropertyW(This->msiHandle, V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
1111 VariantClear(&varg0);
1112 VariantClear(&varg1);
1113 ERR("MsiSetProperty returned %d\n", ret);
1114 return DISP_E_EXCEPTION;
1117 else return DISP_E_MEMBERNOTFOUND;
1120 case DISPID_SESSION_LANGUAGE:
1121 if (wFlags & DISPATCH_PROPERTYGET) {
1122 langId = MsiGetLanguage(This->msiHandle);
1123 V_VT(pVarResult) = VT_I4;
1124 V_I4(pVarResult) = langId;
1126 else return DISP_E_MEMBERNOTFOUND;
1129 case DISPID_SESSION_MODE:
1130 if (wFlags & DISPATCH_PROPERTYGET) {
1131 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1132 if (FAILED(hr)) return hr;
1133 V_VT(pVarResult) = VT_BOOL;
1134 V_BOOL(pVarResult) = MsiGetMode(This->msiHandle, V_I4(&varg0));
1135 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1136 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1137 if (FAILED(hr)) return hr;
1138 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BOOL, &varg1, puArgErr);
1139 if (FAILED(hr)) return hr;
1140 if ((ret = MsiSetMode(This->msiHandle, V_I4(&varg0), V_BOOL(&varg1))) != ERROR_SUCCESS)
1142 ERR("MsiSetMode returned %d\n", ret);
1143 return DISP_E_EXCEPTION;
1146 else return DISP_E_MEMBERNOTFOUND;
1149 case DISPID_SESSION_DATABASE:
1150 if (wFlags & DISPATCH_PROPERTYGET) {
1151 V_VT(pVarResult) = VT_DISPATCH;
1152 if ((msiHandle = MsiGetActiveDatabase(This->msiHandle)))
1154 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Database, DatabaseImpl_Invoke, NULL, 0)))
1156 IDispatch_AddRef(pDispatch);
1157 V_DISPATCH(pVarResult) = pDispatch;
1160 ERR("Failed to create Database object, hresult 0x%08x\n", hr);
1164 ERR("MsiGetActiveDatabase failed\n");
1165 return DISP_E_EXCEPTION;
1168 else return DISP_E_MEMBERNOTFOUND;
1171 case DISPID_SESSION_DOACTION:
1172 if (wFlags & DISPATCH_METHOD) {
1173 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1174 if (FAILED(hr)) return hr;
1175 ret = MsiDoActionW(This->msiHandle, V_BSTR(&varg0));
1176 V_VT(pVarResult) = VT_I4;
1179 case ERROR_FUNCTION_NOT_CALLED:
1180 V_I4(pVarResult) = msiDoActionStatusNoAction;
1183 V_I4(pVarResult) = msiDoActionStatusSuccess;
1185 case ERROR_INSTALL_USEREXIT:
1186 V_I4(pVarResult) = msiDoActionStatusUserExit;
1188 case ERROR_INSTALL_FAILURE:
1189 V_I4(pVarResult) = msiDoActionStatusFailure;
1191 case ERROR_INSTALL_SUSPEND:
1192 V_I4(pVarResult) = msiDoActionStatusSuspend;
1194 case ERROR_MORE_DATA:
1195 V_I4(pVarResult) = msiDoActionStatusFinished;
1197 case ERROR_INVALID_HANDLE_STATE:
1198 V_I4(pVarResult) = msiDoActionStatusWrongState;
1200 case ERROR_INVALID_DATA:
1201 V_I4(pVarResult) = msiDoActionStatusBadActionData;
1204 VariantClear(&varg0);
1205 FIXME("MsiDoAction returned unhandled value %d\n", ret);
1206 return DISP_E_EXCEPTION;
1209 else return DISP_E_MEMBERNOTFOUND;
1212 case DISPID_SESSION_EVALUATECONDITION:
1213 if (wFlags & DISPATCH_METHOD) {
1214 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1215 if (FAILED(hr)) return hr;
1216 V_VT(pVarResult) = VT_I4;
1217 V_I4(pVarResult) = MsiEvaluateConditionW(This->msiHandle, V_BSTR(&varg0));
1219 else return DISP_E_MEMBERNOTFOUND;
1222 case DISPID_SESSION_SETINSTALLLEVEL:
1223 if (wFlags & DISPATCH_METHOD) {
1224 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1225 if (FAILED(hr)) return hr;
1226 if ((ret = MsiSetInstallLevel(This->msiHandle, V_I4(&varg0))) != ERROR_SUCCESS)
1228 ERR("MsiSetInstallLevel returned %d\n", ret);
1229 return DISP_E_EXCEPTION;
1232 else return DISP_E_MEMBERNOTFOUND;
1235 case DISPID_SESSION_FEATURECURRENTSTATE:
1236 if (wFlags & DISPATCH_PROPERTYGET) {
1237 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1238 if (FAILED(hr)) return hr;
1239 V_VT(pVarResult) = VT_I4;
1240 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1241 V_I4(pVarResult) = iInstalled;
1244 ERR("MsiGetFeatureState returned %d\n", ret);
1245 V_I4(pVarResult) = msiInstallStateUnknown;
1248 else return DISP_E_MEMBERNOTFOUND;
1251 case DISPID_SESSION_FEATUREREQUESTSTATE:
1252 if (wFlags & DISPATCH_PROPERTYGET) {
1253 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1254 if (FAILED(hr)) return hr;
1255 V_VT(pVarResult) = VT_I4;
1256 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1257 V_I4(pVarResult) = iAction;
1260 ERR("MsiGetFeatureState returned %d\n", ret);
1261 V_I4(pVarResult) = msiInstallStateUnknown;
1263 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1264 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1265 if (FAILED(hr)) return hr;
1266 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_I4, &varg1, puArgErr);
1268 VariantClear(&varg0);
1271 if ((ret = MsiSetFeatureStateW(This->msiHandle, V_BSTR(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
1273 VariantClear(&varg0);
1274 ERR("MsiSetFeatureState returned %d\n", ret);
1275 return DISP_E_EXCEPTION;
1278 else return DISP_E_MEMBERNOTFOUND;
1282 return DISP_E_MEMBERNOTFOUND;
1285 VariantClear(&varg1);
1286 VariantClear(&varg0);
1291 /* Fill the variant pointed to by pVarResult with the value & size returned by RegQueryValueEx as dictated by the
1292 * registry value type. Used by Installer::RegistryValue. */
1293 static void variant_from_registry_value(VARIANT *pVarResult, DWORD dwType, LPBYTE lpData, DWORD dwSize)
1295 static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
1296 static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
1297 WCHAR *szString = (WCHAR *)lpData;
1298 LPWSTR szNewString = NULL;
1299 DWORD dwNewSize = 0;
1304 /* Registry strings may not be null terminated so we must use SysAllocStringByteLen/Len */
1305 case REG_MULTI_SZ: /* Multi SZ change internal null characters to newlines */
1306 idx = (dwSize/sizeof(WCHAR))-1;
1307 while (idx >= 0 && !szString[idx]) idx--;
1308 for (; idx >= 0; idx--)
1309 if (!szString[idx]) szString[idx] = '\n';
1311 V_VT(pVarResult) = VT_BSTR;
1312 V_BSTR(pVarResult) = SysAllocStringByteLen((LPCSTR)szString, dwSize);
1316 if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1317 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1318 else if (!(szNewString = msi_alloc(dwNewSize)))
1319 ERR("Out of memory\n");
1320 else if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1321 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1324 V_VT(pVarResult) = VT_BSTR;
1325 V_BSTR(pVarResult) = SysAllocStringLen(szNewString, dwNewSize);
1327 msi_free(szNewString);
1331 V_VT(pVarResult) = VT_I4;
1332 V_I4(pVarResult) = *((DWORD *)lpData);
1336 V_VT(pVarResult) = VT_BSTR;
1337 V_BSTR(pVarResult) = SysAllocString(szREG_); /* Weird string, don't know why native returns it */
1341 V_VT(pVarResult) = VT_BSTR;
1342 V_BSTR(pVarResult) = SysAllocString(szREG_BINARY);
1346 V_VT(pVarResult) = VT_EMPTY;
1350 FIXME("Unhandled registry value type %d\n", dwType);
1354 static HRESULT WINAPI InstallerImpl_Invoke(
1355 AutomationObject* This,
1356 DISPID dispIdMember,
1360 DISPPARAMS* pDispParams,
1361 VARIANT* pVarResult,
1362 EXCEPINFO* pExcepInfo,
1365 MSIHANDLE msiHandle;
1366 IDispatch *pDispatch = NULL;
1368 VARIANTARG varg0, varg1, varg2;
1370 LPWSTR szString = NULL;
1373 VariantInit(&varg0);
1374 VariantInit(&varg1);
1375 VariantInit(&varg2);
1377 switch (dispIdMember)
1379 case DISPID_INSTALLER_CREATERECORD:
1380 if (wFlags & DISPATCH_METHOD)
1382 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1383 if (FAILED(hr)) return hr;
1384 V_VT(pVarResult) = VT_DISPATCH;
1385 if ((msiHandle = MsiCreateRecord(V_I4(&varg0))))
1387 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Record, RecordImpl_Invoke, NULL, 0)))
1389 IDispatch_AddRef(pDispatch);
1390 V_DISPATCH(pVarResult) = pDispatch;
1393 ERR("Failed to create Record object, hresult 0x%08x\n", hr);
1397 ERR("MsiCreateRecord failed\n");
1398 return DISP_E_EXCEPTION;
1401 else return DISP_E_MEMBERNOTFOUND;
1404 case DISPID_INSTALLER_OPENPACKAGE:
1405 if (wFlags & DISPATCH_METHOD)
1407 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1408 if (FAILED(hr)) return hr;
1409 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1412 VariantClear(&varg0);
1415 V_VT(pVarResult) = VT_DISPATCH;
1416 if ((ret = MsiOpenPackageExW(V_BSTR(&varg0), V_I4(&varg1), &msiHandle)) == ERROR_SUCCESS)
1418 if (SUCCEEDED(hr = create_session(msiHandle, (IDispatch *)This, &pDispatch)))
1420 IDispatch_AddRef(pDispatch);
1421 V_DISPATCH(pVarResult) = pDispatch;
1424 ERR("Failed to create Session object, hresult 0x%08x\n", hr);
1428 VariantClear(&varg0);
1429 ERR("MsiOpenPackageEx returned %d\n", ret);
1430 return DISP_E_EXCEPTION;
1433 else return DISP_E_MEMBERNOTFOUND;
1436 case DISPID_INSTALLER_INSTALLPRODUCT:
1437 if (wFlags & DISPATCH_METHOD)
1439 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1440 if (FAILED(hr)) return hr;
1441 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1444 VariantClear(&varg0);
1447 if ((ret = MsiInstallProductW(V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
1449 VariantClear(&varg1);
1450 VariantClear(&varg0);
1451 ERR("MsiInstallProduct returned %d\n", ret);
1452 return DISP_E_EXCEPTION;
1455 else return DISP_E_MEMBERNOTFOUND;
1458 case DISPID_INSTALLER_REGISTRYVALUE:
1459 if (wFlags & DISPATCH_METHOD) {
1462 UINT posValue = 2; /* Save valuePos so we can save puArgErr if we are unable to do our type conversions */
1464 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1465 if (FAILED(hr)) return hr;
1466 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1467 if (FAILED(hr)) return hr;
1468 hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg2);
1471 VariantClear(&varg1);
1474 ret = RegOpenKeyW((HKEY)V_I4(&varg0), V_BSTR(&varg1), &hkey);
1476 /* Third parameter can be VT_EMPTY, VT_I4, or VT_BSTR */
1477 switch (V_VT(&varg2))
1479 case VT_EMPTY: /* Return VT_BOOL as to whether or not registry key exists */
1480 V_VT(pVarResult) = VT_BOOL;
1481 V_BOOL(pVarResult) = (ret == ERROR_SUCCESS);
1484 case VT_BSTR: /* Return value of specified key if it exists */
1485 if (ret == ERROR_SUCCESS &&
1486 (ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL, NULL, NULL, &dwSize)) == ERROR_SUCCESS)
1488 if (!(szString = msi_alloc(dwSize)))
1489 ERR("Out of memory\n");
1490 else if ((ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL, &dwType, (LPBYTE)szString, &dwSize)) == ERROR_SUCCESS)
1491 variant_from_registry_value(pVarResult, dwType, (LPBYTE)szString, dwSize);
1494 if (ret != ERROR_SUCCESS)
1497 VariantClear(&varg2);
1498 VariantClear(&varg1);
1499 return DISP_E_BADINDEX;
1503 default: /* Try to make it into VT_I4, can use VariantChangeType for this */
1504 hr = VariantChangeType(&varg2, &varg2, 0, VT_I4);
1505 if (SUCCEEDED(hr) && ret != ERROR_SUCCESS) hr = DISP_E_BADINDEX; /* Conversion fine, but couldn't find key */
1508 if (hr == DISP_E_TYPEMISMATCH) *puArgErr = posValue;
1509 VariantClear(&varg2); /* Unknown type, so let's clear it */
1510 VariantClear(&varg1);
1514 /* Retrieve class name or maximum value name or subkey name size */
1516 ret = RegQueryInfoKeyW(hkey, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1517 else if (V_I4(&varg2) > 0)
1518 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL);
1519 else /* V_I4(&varg2) < 0 */
1520 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
1522 if (ret == ERROR_SUCCESS)
1524 if (!(szString = msi_alloc(++dwSize * sizeof(WCHAR))))
1525 ERR("Out of memory\n");
1526 else if (!V_I4(&varg2))
1527 ret = RegQueryInfoKeyW(hkey, szString, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1528 else if (V_I4(&varg2) > 0)
1529 ret = RegEnumValueW(hkey, V_I4(&varg2)-1, szString, &dwSize, 0, 0, NULL, NULL);
1530 else /* V_I4(&varg2) < 0 */
1531 ret = RegEnumKeyW(hkey, -1 - V_I4(&varg2), szString, dwSize);
1533 if (szString && ret == ERROR_SUCCESS)
1535 V_VT(pVarResult) = VT_BSTR;
1536 V_BSTR(pVarResult) = SysAllocString(szString);
1544 else return DISP_E_MEMBERNOTFOUND;
1547 case DISPID_INSTALLER_PRODUCTSTATE:
1548 if (wFlags & DISPATCH_PROPERTYGET) {
1549 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1550 if (FAILED(hr)) return hr;
1551 V_VT(pVarResult) = VT_I4;
1552 V_I4(pVarResult) = MsiQueryProductStateW(V_BSTR(&varg0));
1554 else return DISP_E_MEMBERNOTFOUND;
1557 case DISPID_INSTALLER_PRODUCTINFO:
1558 if (wFlags & DISPATCH_PROPERTYGET) {
1559 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1560 if (FAILED(hr)) return hr;
1561 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1564 VariantClear(&varg0);
1567 V_VT(pVarResult) = VT_BSTR;
1568 V_BSTR(pVarResult) = NULL;
1569 if ((ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), NULL, &dwSize)) == ERROR_SUCCESS)
1571 if (!(szString = msi_alloc((++dwSize)*sizeof(WCHAR))))
1572 ERR("Out of memory\n");
1573 else if ((ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), szString, &dwSize)) == ERROR_SUCCESS)
1574 V_BSTR(pVarResult) = SysAllocString(szString);
1577 if (ret != ERROR_SUCCESS)
1579 ERR("MsiGetProductInfo returned %d\n", ret);
1580 VariantClear(&varg1);
1581 VariantClear(&varg0);
1582 return DISP_E_EXCEPTION;
1585 else return DISP_E_MEMBERNOTFOUND;
1588 case DISPID_INSTALLER_PRODUCTS:
1589 if (wFlags & DISPATCH_PROPERTYGET)
1591 ListData *ldata = NULL;
1593 WCHAR szProductBuf[GUID_SIZE];
1595 /* Find number of products */
1596 while ((ret = MsiEnumProductsW(idx, szProductBuf)) == ERROR_SUCCESS) idx++;
1597 if (ret != ERROR_NO_MORE_ITEMS)
1599 ERR("MsiEnumProducts returned %d\n", ret);
1600 return DISP_E_EXCEPTION;
1603 V_VT(pVarResult) = VT_DISPATCH;
1604 if (SUCCEEDED(hr = create_automation_object(0, NULL, (LPVOID*)&pDispatch, &DIID_StringList, ListImpl_Invoke, ListImpl_Free, sizeof(ListData))))
1606 IDispatch_AddRef(pDispatch);
1607 V_DISPATCH(pVarResult) = pDispatch;
1609 /* Save product strings */
1610 ldata = (ListData *)private_data((AutomationObject *)pDispatch);
1611 if (!(ldata->pVars = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(VARIANT)*idx)))
1612 ERR("Out of memory\n");
1615 ldata->ulCount = idx;
1616 for (idx = 0; idx < ldata->ulCount; idx++)
1618 ret = MsiEnumProductsW(idx, szProductBuf);
1619 VariantInit(&ldata->pVars[idx]);
1620 V_VT(&ldata->pVars[idx]) = VT_BSTR;
1621 V_BSTR(&ldata->pVars[idx]) = SysAllocString(szProductBuf);
1626 ERR("Failed to create StringList object, hresult 0x%08x\n", hr);
1628 else return DISP_E_MEMBERNOTFOUND;
1631 case DISPID_INSTALLER_RELATEDPRODUCTS:
1632 if (wFlags & DISPATCH_PROPERTYGET)
1634 ListData *ldata = NULL;
1636 WCHAR szProductBuf[GUID_SIZE];
1638 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1639 if (FAILED(hr)) return hr;
1641 /* Find number of related products */
1642 while ((ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, szProductBuf)) == ERROR_SUCCESS) idx++;
1643 if (ret != ERROR_NO_MORE_ITEMS)
1645 VariantClear(&varg0);
1646 ERR("MsiEnumRelatedProducts returned %d\n", ret);
1647 return DISP_E_EXCEPTION;
1650 V_VT(pVarResult) = VT_DISPATCH;
1651 if (SUCCEEDED(hr = create_automation_object(0, NULL, (LPVOID*)&pDispatch, &DIID_StringList, ListImpl_Invoke, ListImpl_Free, sizeof(ListData))))
1653 IDispatch_AddRef(pDispatch);
1654 V_DISPATCH(pVarResult) = pDispatch;
1656 /* Save product strings */
1657 ldata = (ListData *)private_data((AutomationObject *)pDispatch);
1658 if (!(ldata->pVars = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(VARIANT)*idx)))
1659 ERR("Out of memory\n");
1662 ldata->ulCount = idx;
1663 for (idx = 0; idx < ldata->ulCount; idx++)
1665 ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, szProductBuf);
1666 VariantInit(&ldata->pVars[idx]);
1667 V_VT(&ldata->pVars[idx]) = VT_BSTR;
1668 V_BSTR(&ldata->pVars[idx]) = SysAllocString(szProductBuf);
1673 ERR("Failed to create StringList object, hresult 0x%08x\n", hr);
1675 else return DISP_E_MEMBERNOTFOUND;
1679 return DISP_E_MEMBERNOTFOUND;
1682 VariantClear(&varg2);
1683 VariantClear(&varg1);
1684 VariantClear(&varg0);
1689 /* Wrapper around create_automation_object to create an installer object. */
1690 HRESULT create_msiserver(IUnknown *pOuter, LPVOID *ppObj)
1692 return create_automation_object(0, pOuter, ppObj, &DIID_Installer, InstallerImpl_Invoke, NULL, 0);
1695 /* Wrapper around create_automation_object to create a session object. */
1696 HRESULT create_session(MSIHANDLE msiHandle, IDispatch *pInstaller, IDispatch **pDispatch)
1698 HRESULT hr = create_automation_object(msiHandle, NULL, (LPVOID)pDispatch, &DIID_Session, SessionImpl_Invoke, NULL, sizeof(SessionData));
1699 if (SUCCEEDED(hr) && pDispatch && *pDispatch)
1700 ((SessionData *)private_data((AutomationObject *)*pDispatch))->pInstaller = pInstaller;