2 * Implementation of OLE Automation for Microsoft Installer (msi.dll)
4 * Copyright 2007 Misha Koshelev
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
34 #include "wine/debug.h"
35 #include "wine/unicode.h"
37 #include "msiserver.h"
38 #include "msiserver_dispids.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(msi);
42 #define REG_INDEX_CLASSES_ROOT 0
43 #define REG_INDEX_DYN_DATA 6
46 * AutomationObject - "base" class for all automation objects. For each interface, we implement Invoke function
47 * called from AutomationObject::Invoke.
50 typedef struct AutomationObject AutomationObject;
52 typedef HRESULT (*autoInvokeFunc)(AutomationObject* This,
53 DISPID dispIdMember, REFIID riid, LCID lcid, WORD flags, DISPPARAMS* pDispParams,
54 VARIANT* result, EXCEPINFO* ei, UINT* arg_err);
56 typedef void (*autoFreeFunc)(AutomationObject* This);
58 struct AutomationObject {
59 IDispatch IDispatch_iface;
60 IProvideMultipleClassInfo IProvideMultipleClassInfo_iface;
63 /* Clsid for this class and it's appropriate ITypeInfo object */
67 /* The MSI handle of the current object */
70 /* A function that is called from AutomationObject::Invoke, specific to this type of object. */
71 autoInvokeFunc funcInvoke;
72 /* A function that is called from AutomationObject::Release when the object is being freed to free any private
73 * data structures (or NULL) */
74 autoFreeFunc funcFree;
78 AutomationObject autoobj;
83 static HRESULT create_database(MSIHANDLE, IDispatch**);
84 static HRESULT create_list_enumerator(ListObject*, void**);
85 static HRESULT create_summaryinfo(MSIHANDLE, IDispatch**);
86 static HRESULT create_view(MSIHANDLE, IDispatch**);
88 /* ListEnumerator - IEnumVARIANT implementation for MSI automation lists */
90 IEnumVARIANT IEnumVARIANT_iface;
93 /* Current position and pointer to AutomationObject that stores actual data */
99 AutomationObject autoobj;
100 IDispatch *installer;
103 static inline AutomationObject *impl_from_IProvideMultipleClassInfo( IProvideMultipleClassInfo *iface )
105 return CONTAINING_RECORD(iface, AutomationObject, IProvideMultipleClassInfo_iface);
108 static inline AutomationObject *impl_from_IDispatch( IDispatch *iface )
110 return CONTAINING_RECORD(iface, AutomationObject, IDispatch_iface);
113 /* Load type info so we don't have to process GetIDsOfNames */
114 HRESULT load_type_info(IDispatch *iface, ITypeInfo **pptinfo, REFIID clsid, LCID lcid)
116 static const WCHAR msiserverW[] = {'m','s','i','s','e','r','v','e','r','.','t','l','b',0};
117 ITypeInfo *ti = NULL;
118 ITypeLib *lib = NULL;
121 TRACE("(%p)->(%s, %d)\n", iface, debugstr_guid(clsid), lcid);
123 /* Load registered type library */
124 hr = LoadRegTypeLib(&LIBID_WindowsInstaller, 1, 0, lcid, &lib);
126 hr = LoadTypeLib(msiserverW, &lib);
128 ERR("Could not load msiserver.tlb\n");
133 /* Get type information for object */
134 hr = ITypeLib_GetTypeInfoOfGuid(lib, clsid, &ti);
135 ITypeLib_Release(lib);
137 ERR("Could not load ITypeInfo for %s\n", debugstr_guid(clsid));
144 /* AutomationObject methods */
145 static HRESULT WINAPI AutomationObject_QueryInterface(IDispatch* iface, REFIID riid, void** ppvObject)
147 AutomationObject *This = impl_from_IDispatch(iface);
149 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
151 if (ppvObject == NULL)
156 if (IsEqualGUID(riid, &IID_IUnknown) ||
157 IsEqualGUID(riid, &IID_IDispatch) ||
158 IsEqualGUID(riid, This->clsid))
159 *ppvObject = &This->IDispatch_iface;
160 else if (IsEqualGUID(riid, &IID_IProvideClassInfo) ||
161 IsEqualGUID(riid, &IID_IProvideClassInfo2) ||
162 IsEqualGUID(riid, &IID_IProvideMultipleClassInfo))
163 *ppvObject = &This->IProvideMultipleClassInfo_iface;
166 TRACE("() : asking for unsupported interface %s\n", debugstr_guid(riid));
167 return E_NOINTERFACE;
170 IDispatch_AddRef(iface);
175 static ULONG WINAPI AutomationObject_AddRef(IDispatch* iface)
177 AutomationObject *This = impl_from_IDispatch(iface);
179 TRACE("(%p/%p)\n", iface, This);
181 return InterlockedIncrement(&This->ref);
184 static ULONG WINAPI AutomationObject_Release(IDispatch* iface)
186 AutomationObject *This = impl_from_IDispatch(iface);
187 ULONG ref = InterlockedDecrement(&This->ref);
189 TRACE("(%p/%p)\n", iface, This);
193 if (This->funcFree) This->funcFree(This);
194 ITypeInfo_Release(This->iTypeInfo);
195 MsiCloseHandle(This->msiHandle);
202 static HRESULT WINAPI AutomationObject_GetTypeInfoCount(
206 AutomationObject *This = impl_from_IDispatch(iface);
208 TRACE("(%p/%p)->(%p)\n", iface, This, pctinfo);
213 static HRESULT WINAPI AutomationObject_GetTypeInfo(
219 AutomationObject *This = impl_from_IDispatch(iface);
220 TRACE("(%p/%p)->(%d,%d,%p)\n", iface, This, iTInfo, lcid, ppTInfo);
222 ITypeInfo_AddRef(This->iTypeInfo);
223 *ppTInfo = This->iTypeInfo;
227 static HRESULT WINAPI AutomationObject_GetIDsOfNames(
235 AutomationObject *This = impl_from_IDispatch(iface);
237 TRACE("(%p/%p)->(%p,%p,%d,%d,%p)\n", iface, This, riid, rgszNames, cNames, lcid, rgDispId);
239 if (!IsEqualGUID(riid, &IID_NULL)) return E_INVALIDARG;
240 hr = ITypeInfo_GetIDsOfNames(This->iTypeInfo, rgszNames, cNames, rgDispId);
241 if (hr == DISP_E_UNKNOWNNAME)
244 for (idx=0; idx<cNames; idx++)
246 if (rgDispId[idx] == DISPID_UNKNOWN)
247 FIXME("Unknown member %s, clsid %s\n", debugstr_w(rgszNames[idx]), debugstr_guid(This->clsid));
253 /* Maximum number of allowed function parameters+1 */
254 #define MAX_FUNC_PARAMS 20
256 /* Some error checking is done here to simplify individual object function invocation */
257 static HRESULT WINAPI AutomationObject_Invoke(
263 DISPPARAMS* pDispParams,
265 EXCEPINFO* pExcepInfo,
268 AutomationObject *This = impl_from_IDispatch(iface);
270 unsigned int uArgErr;
271 VARIANT varResultDummy;
272 BSTR bstrName = NULL;
274 TRACE("(%p/%p)->(%d,%p,%d,%d,%p,%p,%p,%p)\n", iface, This, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
276 if (!IsEqualIID(riid, &IID_NULL))
278 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
279 return DISP_E_UNKNOWNNAME;
282 if (wFlags & DISPATCH_PROPERTYGET && !pVarResult)
284 ERR("NULL pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
285 return DISP_E_PARAMNOTOPTIONAL;
288 /* This simplifies our individual object invocation functions */
289 if (puArgErr == NULL) puArgErr = &uArgErr;
290 if (pVarResult == NULL) pVarResult = &varResultDummy;
292 /* Assume return type is void unless determined otherwise */
293 VariantInit(pVarResult);
295 /* If we are tracing, we want to see the name of the member we are invoking */
298 ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL);
299 TRACE("Method %d, %s\n", dispIdMember, debugstr_w(bstrName));
302 hr = This->funcInvoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
304 if (hr == DISP_E_MEMBERNOTFOUND) {
305 if (bstrName == NULL) ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL);
306 FIXME("Method %d, %s wflags %d not implemented, clsid %s\n", dispIdMember, debugstr_w(bstrName), wFlags, debugstr_guid(This->clsid));
308 else if (pExcepInfo &&
309 (hr == DISP_E_PARAMNOTFOUND ||
310 hr == DISP_E_EXCEPTION)) {
311 static const WCHAR szComma[] = { ',',0 };
312 static const WCHAR szExceptionSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
313 WCHAR szExceptionDescription[MAX_PATH];
314 BSTR bstrParamNames[MAX_FUNC_PARAMS];
318 if (FAILED(ITypeInfo_GetNames(This->iTypeInfo, dispIdMember, bstrParamNames,
319 MAX_FUNC_PARAMS, &namesNo)))
321 TRACE("Failed to retrieve names for dispIdMember %d\n", dispIdMember);
325 memset(szExceptionDescription, 0, sizeof(szExceptionDescription));
326 for (i=0; i<namesNo; i++)
328 if (bFirst) bFirst = FALSE;
330 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], szComma);
332 lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], bstrParamNames[i]);
333 SysFreeString(bstrParamNames[i]);
336 memset(pExcepInfo, 0, sizeof(EXCEPINFO));
337 pExcepInfo->wCode = 1000;
338 pExcepInfo->bstrSource = SysAllocString(szExceptionSource);
339 pExcepInfo->bstrDescription = SysAllocString(szExceptionDescription);
340 hr = DISP_E_EXCEPTION;
344 /* Make sure we free the return variant if it is our dummy variant */
345 if (pVarResult == &varResultDummy) VariantClear(pVarResult);
347 /* Free function name if we retrieved it */
348 SysFreeString(bstrName);
350 TRACE("Returning 0x%08x, %s\n", hr, SUCCEEDED(hr) ? "ok" : "not ok");
355 static const struct IDispatchVtbl AutomationObjectVtbl =
357 AutomationObject_QueryInterface,
358 AutomationObject_AddRef,
359 AutomationObject_Release,
360 AutomationObject_GetTypeInfoCount,
361 AutomationObject_GetTypeInfo,
362 AutomationObject_GetIDsOfNames,
363 AutomationObject_Invoke
367 * IProvideMultipleClassInfo methods
370 static HRESULT WINAPI ProvideMultipleClassInfo_QueryInterface(
371 IProvideMultipleClassInfo* iface,
375 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
376 return IDispatch_QueryInterface(&This->IDispatch_iface, riid, ppvoid);
379 static ULONG WINAPI ProvideMultipleClassInfo_AddRef(IProvideMultipleClassInfo* iface)
381 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
382 return IDispatch_AddRef(&This->IDispatch_iface);
385 static ULONG WINAPI ProvideMultipleClassInfo_Release(IProvideMultipleClassInfo* iface)
387 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
388 return IDispatch_Release(&This->IDispatch_iface);
391 static HRESULT WINAPI ProvideMultipleClassInfo_GetClassInfo(IProvideMultipleClassInfo* iface, ITypeInfo** ppTI)
393 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
394 TRACE("(%p/%p)->(%p)\n", iface, This, ppTI);
395 return load_type_info(&This->IDispatch_iface, ppTI, This->clsid, 0);
398 static HRESULT WINAPI ProvideMultipleClassInfo_GetGUID(IProvideMultipleClassInfo* iface, DWORD dwGuidKind, GUID* pGUID)
400 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
401 TRACE("(%p/%p)->(%d,%s)\n", iface, This, dwGuidKind, debugstr_guid(pGUID));
403 if (dwGuidKind != GUIDKIND_DEFAULT_SOURCE_DISP_IID)
406 *pGUID = *This->clsid;
411 static HRESULT WINAPI ProvideMultipleClassInfo_GetMultiTypeInfoCount(IProvideMultipleClassInfo* iface, ULONG* pcti)
413 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
415 TRACE("(%p/%p)->(%p)\n", iface, This, pcti);
420 static HRESULT WINAPI ProvideMultipleClassInfo_GetInfoOfIndex(IProvideMultipleClassInfo* iface,
423 ITypeInfo** pptiCoClass,
425 ULONG* pcdispidReserved,
429 AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
431 TRACE("(%p/%p)->(%d,%d,%p,%p,%p,%p,%p)\n", iface, This, iti, dwFlags, pptiCoClass, pdwTIFlags, pcdispidReserved, piidPrimary, piidSource);
436 if (dwFlags & MULTICLASSINFO_GETTYPEINFO)
437 load_type_info(&This->IDispatch_iface, pptiCoClass, This->clsid, 0);
439 if (dwFlags & MULTICLASSINFO_GETNUMRESERVEDDISPIDS)
442 *pcdispidReserved = 0;
445 if (dwFlags & MULTICLASSINFO_GETIIDPRIMARY){
446 *piidPrimary = *This->clsid;
449 if (dwFlags & MULTICLASSINFO_GETIIDSOURCE){
450 *piidSource = *This->clsid;
456 static const IProvideMultipleClassInfoVtbl ProvideMultipleClassInfoVtbl =
458 ProvideMultipleClassInfo_QueryInterface,
459 ProvideMultipleClassInfo_AddRef,
460 ProvideMultipleClassInfo_Release,
461 ProvideMultipleClassInfo_GetClassInfo,
462 ProvideMultipleClassInfo_GetGUID,
463 ProvideMultipleClassInfo_GetMultiTypeInfoCount,
464 ProvideMultipleClassInfo_GetInfoOfIndex
467 static HRESULT init_automation_object(AutomationObject *This, MSIHANDLE msiHandle, REFIID clsid,
468 autoInvokeFunc invokeFunc, autoFreeFunc freeFunc)
470 TRACE("(%p, %d, %s, %p, %p)\n", This, msiHandle, debugstr_guid(clsid), invokeFunc, freeFunc);
472 This->IDispatch_iface.lpVtbl = &AutomationObjectVtbl;
473 This->IProvideMultipleClassInfo_iface.lpVtbl = &ProvideMultipleClassInfoVtbl;
476 This->msiHandle = msiHandle;
477 This->clsid = (LPCLSID)clsid;
478 This->funcInvoke = invokeFunc;
479 This->funcFree = freeFunc;
481 /* Load our TypeInfo so we don't have to process GetIDsOfNames */
482 This->iTypeInfo = NULL;
483 return load_type_info(&This->IDispatch_iface, &This->iTypeInfo, clsid, 0);
487 * ListEnumerator methods
490 static inline ListEnumerator *impl_from_IEnumVARIANT(IEnumVARIANT* iface)
492 return CONTAINING_RECORD(iface, ListEnumerator, IEnumVARIANT_iface);
495 static HRESULT WINAPI ListEnumerator_QueryInterface(IEnumVARIANT* iface, REFIID riid,
498 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
500 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
502 if (ppvObject == NULL)
507 if (IsEqualGUID(riid, &IID_IUnknown) ||
508 IsEqualGUID(riid, &IID_IEnumVARIANT))
510 *ppvObject = &This->IEnumVARIANT_iface;
514 TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid));
515 return E_NOINTERFACE;
518 IEnumVARIANT_AddRef(iface);
522 static ULONG WINAPI ListEnumerator_AddRef(IEnumVARIANT* iface)
524 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
526 TRACE("(%p/%p)\n", iface, This);
528 return InterlockedIncrement(&This->ref);
531 static ULONG WINAPI ListEnumerator_Release(IEnumVARIANT* iface)
533 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
534 ULONG ref = InterlockedDecrement(&This->ref);
536 TRACE("(%p/%p)\n", iface, This);
540 if (This->list) IDispatch_Release(&This->list->autoobj.IDispatch_iface);
547 static HRESULT WINAPI ListEnumerator_Next(IEnumVARIANT* iface, ULONG celt, VARIANT* rgVar,
550 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
553 TRACE("(%p, %uld, %p, %p)\n", iface, celt, rgVar, fetched);
555 if (fetched) *fetched = 0;
560 for (local = 0; local < celt; local++)
561 VariantInit(&rgVar[local]);
563 for (i = This->pos, local = 0; i < This->list->count && local < celt; i++, local++)
564 VariantCopy(&rgVar[local], &This->list->data[i]);
566 if (fetched) *fetched = local;
569 return (local < celt) ? S_FALSE : S_OK;
572 static HRESULT WINAPI ListEnumerator_Skip(IEnumVARIANT* iface, ULONG celt)
574 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
576 TRACE("(%p,%uld)\n", iface, celt);
579 if (This->pos >= This->list->count)
581 This->pos = This->list->count;
588 static HRESULT WINAPI ListEnumerator_Reset(IEnumVARIANT* iface)
590 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
592 TRACE("(%p)\n", iface);
598 static HRESULT WINAPI ListEnumerator_Clone(IEnumVARIANT* iface, IEnumVARIANT **ppEnum)
600 ListEnumerator *This = impl_from_IEnumVARIANT(iface);
603 TRACE("(%p,%p)\n", iface, ppEnum);
609 hr = create_list_enumerator(This->list, (LPVOID *)ppEnum);
612 if (*ppEnum) IEnumVARIANT_Release(*ppEnum);
619 static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl =
621 ListEnumerator_QueryInterface,
622 ListEnumerator_AddRef,
623 ListEnumerator_Release,
626 ListEnumerator_Reset,
630 /* Create a list enumerator, placing the result in the pointer ppObj. */
631 static HRESULT create_list_enumerator(ListObject *list, void **ppObj)
633 ListEnumerator *object;
635 TRACE("(%p, %p)\n", list, ppObj);
637 object = msi_alloc(sizeof(ListEnumerator));
639 /* Set all the VTable references */
640 object->IEnumVARIANT_iface.lpVtbl = &ListEnumerator_Vtbl;
643 /* Store data that was passed */
646 if (list) IDispatch_AddRef(&list->autoobj.IDispatch_iface);
653 * Individual Object Invocation Functions
656 /* Helper function that copies a passed parameter instead of using VariantChangeType like the actual DispGetParam.
657 This function is only for VARIANT type parameters that have several types that cannot be properly discriminated
658 using DispGetParam/VariantChangeType. */
659 static HRESULT DispGetParam_CopyOnly(
660 DISPPARAMS *pdispparams, /* [in] Parameter list */
661 UINT *position, /* [in] Position of parameter to copy in pdispparams; on return will contain calculated position */
662 VARIANT *pvarResult) /* [out] Destination for resulting variant */
664 /* position is counted backwards */
667 TRACE("position=%d, cArgs=%d, cNamedArgs=%d\n",
668 *position, pdispparams->cArgs, pdispparams->cNamedArgs);
669 if (*position < pdispparams->cArgs) {
670 /* positional arg? */
671 pos = pdispparams->cArgs - *position - 1;
673 /* FIXME: is this how to handle named args? */
674 for (pos=0; pos<pdispparams->cNamedArgs; pos++)
675 if (pdispparams->rgdispidNamedArgs[pos] == *position) break;
677 if (pos==pdispparams->cNamedArgs)
678 return DISP_E_PARAMNOTFOUND;
681 return VariantCopyInd(pvarResult,
682 &pdispparams->rgvarg[pos]);
685 static HRESULT SummaryInfoImpl_Invoke(
686 AutomationObject* This,
691 DISPPARAMS* pDispParams,
693 EXCEPINFO* pExcepInfo,
697 VARIANTARG varg0, varg1;
698 FILETIME ft, ftlocal;
705 switch (dispIdMember)
707 case DISPID_SUMMARYINFO_PROPERTY:
708 if (wFlags & DISPATCH_PROPERTYGET)
716 static WCHAR szEmpty[] = {0};
718 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
719 if (FAILED(hr)) return hr;
720 ret = MsiSummaryInfoGetPropertyW(This->msiHandle, V_I4(&varg0), &type, &value,
721 &ft, szEmpty, &size);
722 if (ret != ERROR_SUCCESS &&
723 ret != ERROR_MORE_DATA)
725 ERR("MsiSummaryInfoGetProperty returned %d\n", ret);
726 return DISP_E_EXCEPTION;
736 V_VT(pVarResult) = VT_I4;
737 V_I4(pVarResult) = value;
741 if (!(str = msi_alloc(++size * sizeof(WCHAR))))
742 ERR("Out of memory\n");
743 else if ((ret = MsiSummaryInfoGetPropertyW(This->msiHandle, V_I4(&varg0), &type, NULL,
744 NULL, str, &size)) != ERROR_SUCCESS)
745 ERR("MsiSummaryInfoGetProperty returned %d\n", ret);
748 V_VT(pVarResult) = VT_BSTR;
749 V_BSTR(pVarResult) = SysAllocString(str);
755 FileTimeToLocalFileTime(&ft, &ftlocal);
756 FileTimeToSystemTime(&ftlocal, &st);
757 SystemTimeToVariantTime(&st, &date);
759 V_VT(pVarResult) = VT_DATE;
760 V_DATE(pVarResult) = date;
764 ERR("Unhandled variant type %d\n", type);
767 else if (wFlags & DISPATCH_PROPERTYPUT)
769 UINT posValue = DISPID_PROPERTYPUT;
771 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
772 if (FAILED(hr)) return hr;
773 hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg1);
776 *puArgErr = posValue;
780 switch (V_VT(&varg1))
784 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), V_VT(&varg1), V_I4(&varg1), NULL, NULL);
788 VariantTimeToSystemTime(V_DATE(&varg1), &st);
789 SystemTimeToFileTime(&st, &ftlocal);
790 LocalFileTimeToFileTime(&ftlocal, &ft);
791 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), VT_FILETIME, 0, &ft, NULL);
795 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), VT_LPSTR, 0, NULL, V_BSTR(&varg1));
799 FIXME("Unhandled variant type %d\n", V_VT(&varg1));
800 VariantClear(&varg1);
801 return DISP_E_EXCEPTION;
804 if (ret != ERROR_SUCCESS)
806 ERR("MsiSummaryInfoSetPropertyW returned %d\n", ret);
807 return DISP_E_EXCEPTION;
810 else return DISP_E_MEMBERNOTFOUND;
813 case DISPID_SUMMARYINFO_PROPERTYCOUNT:
814 if (wFlags & DISPATCH_PROPERTYGET) {
816 if ((ret = MsiSummaryInfoGetPropertyCount(This->msiHandle, &count)) != ERROR_SUCCESS)
817 ERR("MsiSummaryInfoGetPropertyCount returned %d\n", ret);
820 V_VT(pVarResult) = VT_I4;
821 V_I4(pVarResult) = count;
824 else return DISP_E_MEMBERNOTFOUND;
828 return DISP_E_MEMBERNOTFOUND;
831 VariantClear(&varg1);
832 VariantClear(&varg0);
837 static HRESULT RecordImpl_Invoke(
838 AutomationObject* This,
843 DISPPARAMS* pDispParams,
845 EXCEPINFO* pExcepInfo,
851 VARIANTARG varg0, varg1;
857 switch (dispIdMember)
859 case DISPID_RECORD_FIELDCOUNT:
860 if (wFlags & DISPATCH_PROPERTYGET) {
861 V_VT(pVarResult) = VT_I4;
862 V_I4(pVarResult) = MsiRecordGetFieldCount(This->msiHandle);
864 else return DISP_E_MEMBERNOTFOUND;
867 case DISPID_RECORD_STRINGDATA:
868 if (wFlags & DISPATCH_PROPERTYGET) {
869 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
870 if (FAILED(hr)) return hr;
871 V_VT(pVarResult) = VT_BSTR;
872 V_BSTR(pVarResult) = NULL;
873 if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
875 if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
876 ERR("Out of memory\n");
877 else if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
878 V_BSTR(pVarResult) = SysAllocString(szString);
881 if (ret != ERROR_SUCCESS)
882 ERR("MsiRecordGetString returned %d\n", ret);
883 } else if (wFlags & DISPATCH_PROPERTYPUT) {
884 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
885 if (FAILED(hr)) return hr;
886 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
887 if (FAILED(hr)) return hr;
888 if ((ret = MsiRecordSetStringW(This->msiHandle, V_I4(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
890 VariantClear(&varg1);
891 ERR("MsiRecordSetString returned %d\n", ret);
892 return DISP_E_EXCEPTION;
895 else return DISP_E_MEMBERNOTFOUND;
898 case DISPID_RECORD_INTEGERDATA:
899 if (wFlags & DISPATCH_PROPERTYGET) {
900 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
901 if (FAILED(hr)) return hr;
902 V_VT(pVarResult) = VT_I4;
903 V_I4(pVarResult) = MsiRecordGetInteger(This->msiHandle, V_I4(&varg0));
904 } else if (wFlags & DISPATCH_PROPERTYPUT) {
905 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
906 if (FAILED(hr)) return hr;
907 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
908 if (FAILED(hr)) return hr;
909 if ((ret = MsiRecordSetInteger(This->msiHandle, V_I4(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
911 ERR("MsiRecordSetInteger returned %d\n", ret);
912 return DISP_E_EXCEPTION;
915 else return DISP_E_MEMBERNOTFOUND;
919 return DISP_E_MEMBERNOTFOUND;
922 VariantClear(&varg1);
923 VariantClear(&varg0);
928 static HRESULT create_record(MSIHANDLE msiHandle, IDispatch **disp)
930 AutomationObject *record;
933 record = msi_alloc(sizeof(*record));
934 if (!record) return E_OUTOFMEMORY;
936 hr = init_automation_object(record, msiHandle, &DIID_Record, RecordImpl_Invoke, NULL);
943 *disp = &record->IDispatch_iface;
948 static HRESULT ListImpl_Invoke(
949 AutomationObject* This,
954 DISPPARAMS* pDispParams,
956 EXCEPINFO* pExcepInfo,
959 ListObject *list = (ListObject*)This;
960 IUnknown *pUnk = NULL;
963 switch (dispIdMember)
965 case DISPID_LIST__NEWENUM:
966 if (wFlags & DISPATCH_METHOD) {
967 V_VT(pVarResult) = VT_UNKNOWN;
968 if (SUCCEEDED(hr = create_list_enumerator(list, (LPVOID *)&pUnk)))
969 V_UNKNOWN(pVarResult) = pUnk;
971 ERR("Failed to create IEnumVARIANT object, hresult 0x%08x\n", hr);
973 else return DISP_E_MEMBERNOTFOUND;
976 case DISPID_LIST_ITEM:
977 if (wFlags & DISPATCH_PROPERTYGET) {
981 hr = DispGetParam(pDispParams, 0, VT_I4, &index, puArgErr);
982 if (FAILED(hr)) return hr;
983 if (V_I4(&index) < 0 || V_I4(&index) >= list->count)
984 return DISP_E_BADINDEX;
985 VariantCopy(pVarResult, &list->data[V_I4(&index)]);
987 else return DISP_E_MEMBERNOTFOUND;
990 case DISPID_LIST_COUNT:
991 if (wFlags & DISPATCH_PROPERTYGET) {
992 V_VT(pVarResult) = VT_I4;
993 V_I4(pVarResult) = list->count;
995 else return DISP_E_MEMBERNOTFOUND;
999 return DISP_E_MEMBERNOTFOUND;
1005 static void ListImpl_Free(AutomationObject *This)
1007 ListObject *list = (ListObject*)This;
1010 for (i = 0; i < list->count; i++)
1011 VariantClear(&list->data[i]);
1012 msi_free(list->data);
1015 static HRESULT get_products_count(const WCHAR *product, int *len)
1021 WCHAR dataW[GUID_SIZE];
1024 /* all or related only */
1026 ret = MsiEnumRelatedProductsW(product, 0, i, dataW);
1028 ret = MsiEnumProductsW(i, dataW);
1030 if (ret == ERROR_NO_MORE_ITEMS) break;
1032 if (ret != ERROR_SUCCESS)
1033 return DISP_E_EXCEPTION;
1043 static HRESULT create_list(const WCHAR *product, IDispatch **dispatch)
1049 list = msi_alloc_zero(sizeof(ListObject));
1050 if (!list) return E_OUTOFMEMORY;
1052 hr = init_automation_object(&list->autoobj, 0, &DIID_StringList, ListImpl_Invoke, ListImpl_Free);
1059 *dispatch = &list->autoobj.IDispatch_iface;
1061 hr = get_products_count(product, &list->count);
1064 IDispatch_Release(*dispatch);
1068 list->data = msi_alloc(list->count*sizeof(VARIANT));
1071 IDispatch_Release(*dispatch);
1072 return E_OUTOFMEMORY;
1075 for (i = 0; i < list->count; i++)
1077 WCHAR dataW[GUID_SIZE];
1080 /* all or related only */
1082 ret = MsiEnumRelatedProductsW(product, 0, i, dataW);
1084 ret = MsiEnumProductsW(i, dataW);
1086 if (ret == ERROR_NO_MORE_ITEMS) break;
1088 V_VT(&list->data[i]) = VT_BSTR;
1089 V_BSTR(&list->data[i]) = SysAllocString(dataW);
1095 static HRESULT ViewImpl_Invoke(
1096 AutomationObject* This,
1097 DISPID dispIdMember,
1101 DISPPARAMS* pDispParams,
1102 VARIANT* pVarResult,
1103 EXCEPINFO* pExcepInfo,
1106 MSIHANDLE msiHandle;
1108 VARIANTARG varg0, varg1;
1111 VariantInit(&varg0);
1112 VariantInit(&varg1);
1114 switch (dispIdMember)
1116 case DISPID_VIEW_EXECUTE:
1117 if (wFlags & DISPATCH_METHOD)
1119 hr = DispGetParam(pDispParams, 0, VT_DISPATCH, &varg0, puArgErr);
1120 if (SUCCEEDED(hr) && V_DISPATCH(&varg0) != NULL)
1121 MsiViewExecute(This->msiHandle, ((AutomationObject *)V_DISPATCH(&varg0))->msiHandle);
1123 MsiViewExecute(This->msiHandle, 0);
1125 else return DISP_E_MEMBERNOTFOUND;
1128 case DISPID_VIEW_FETCH:
1129 if (wFlags & DISPATCH_METHOD)
1131 V_VT(pVarResult) = VT_DISPATCH;
1132 if ((ret = MsiViewFetch(This->msiHandle, &msiHandle)) == ERROR_SUCCESS)
1134 IDispatch *dispatch = NULL;
1136 if (SUCCEEDED(hr = create_record(msiHandle, &dispatch)))
1137 V_DISPATCH(pVarResult) = dispatch;
1139 ERR("Failed to create Record object, hresult 0x%08x\n", hr);
1141 else if (ret == ERROR_NO_MORE_ITEMS)
1142 V_DISPATCH(pVarResult) = NULL;
1145 ERR("MsiViewFetch returned %d\n", ret);
1146 return DISP_E_EXCEPTION;
1149 else return DISP_E_MEMBERNOTFOUND;
1152 case DISPID_VIEW_MODIFY:
1153 if (wFlags & DISPATCH_METHOD)
1155 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1156 if (FAILED(hr)) return hr;
1157 hr = DispGetParam(pDispParams, 1, VT_DISPATCH, &varg1, puArgErr);
1158 if (FAILED(hr)) return hr;
1159 if (!V_DISPATCH(&varg1)) return DISP_E_EXCEPTION;
1160 if ((ret = MsiViewModify(This->msiHandle, V_I4(&varg0), ((AutomationObject *)V_DISPATCH(&varg1))->msiHandle)) != ERROR_SUCCESS)
1162 VariantClear(&varg1);
1163 ERR("MsiViewModify returned %d\n", ret);
1164 return DISP_E_EXCEPTION;
1167 else return DISP_E_MEMBERNOTFOUND;
1170 case DISPID_VIEW_CLOSE:
1171 if (wFlags & DISPATCH_METHOD)
1173 MsiViewClose(This->msiHandle);
1175 else return DISP_E_MEMBERNOTFOUND;
1179 return DISP_E_MEMBERNOTFOUND;
1182 VariantClear(&varg1);
1183 VariantClear(&varg0);
1188 static HRESULT DatabaseImpl_LastErrorRecord(WORD wFlags,
1189 DISPPARAMS* pDispParams,
1190 VARIANT* pVarResult,
1191 EXCEPINFO* pExcepInfo,
1194 if (!(wFlags & DISPATCH_METHOD))
1195 return DISP_E_MEMBERNOTFOUND;
1199 VariantInit(pVarResult);
1203 static HRESULT DatabaseImpl_Invoke(
1204 AutomationObject* This,
1205 DISPID dispIdMember,
1209 DISPPARAMS* pDispParams,
1210 VARIANT* pVarResult,
1211 EXCEPINFO* pExcepInfo,
1214 IDispatch *dispatch = NULL;
1215 MSIHANDLE msiHandle;
1217 VARIANTARG varg0, varg1;
1220 VariantInit(&varg0);
1221 VariantInit(&varg1);
1223 switch (dispIdMember)
1225 case DISPID_DATABASE_SUMMARYINFORMATION:
1226 if (wFlags & DISPATCH_PROPERTYGET)
1228 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1232 V_VT(pVarResult) = VT_DISPATCH;
1233 if ((ret = MsiGetSummaryInformationW(This->msiHandle, NULL, V_I4(&varg0), &msiHandle)) == ERROR_SUCCESS)
1235 hr = create_summaryinfo(msiHandle, &dispatch);
1237 V_DISPATCH(pVarResult) = dispatch;
1239 ERR("Failed to create SummaryInfo object: 0x%08x\n", hr);
1243 ERR("MsiGetSummaryInformation returned %d\n", ret);
1244 return DISP_E_EXCEPTION;
1247 else return DISP_E_MEMBERNOTFOUND;
1250 case DISPID_DATABASE_OPENVIEW:
1251 if (wFlags & DISPATCH_METHOD)
1253 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1254 if (FAILED(hr)) return hr;
1255 V_VT(pVarResult) = VT_DISPATCH;
1256 if ((ret = MsiDatabaseOpenViewW(This->msiHandle, V_BSTR(&varg0), &msiHandle)) == ERROR_SUCCESS)
1258 if (SUCCEEDED(hr = create_view(msiHandle, &dispatch)))
1259 V_DISPATCH(pVarResult) = dispatch;
1261 ERR("Failed to create View object, hresult 0x%08x\n", hr);
1265 VariantClear(&varg0);
1266 ERR("MsiDatabaseOpenView returned %d\n", ret);
1267 return DISP_E_EXCEPTION;
1270 else return DISP_E_MEMBERNOTFOUND;
1273 case DISPID_INSTALLER_LASTERRORRECORD:
1274 return DatabaseImpl_LastErrorRecord(wFlags, pDispParams,
1275 pVarResult, pExcepInfo,
1279 return DISP_E_MEMBERNOTFOUND;
1282 VariantClear(&varg1);
1283 VariantClear(&varg0);
1288 static HRESULT SessionImpl_Invoke(
1289 AutomationObject* This,
1290 DISPID dispIdMember,
1294 DISPPARAMS* pDispParams,
1295 VARIANT* pVarResult,
1296 EXCEPINFO* pExcepInfo,
1299 SessionObject *session = (SessionObject*)This;
1302 MSIHANDLE msiHandle;
1305 INSTALLSTATE iInstalled, iAction;
1306 VARIANTARG varg0, varg1;
1309 VariantInit(&varg0);
1310 VariantInit(&varg1);
1312 switch (dispIdMember)
1314 case DISPID_SESSION_INSTALLER:
1315 if (wFlags & DISPATCH_PROPERTYGET) {
1316 V_VT(pVarResult) = VT_DISPATCH;
1317 IDispatch_AddRef(session->installer);
1318 V_DISPATCH(pVarResult) = session->installer;
1320 else return DISP_E_MEMBERNOTFOUND;
1323 case DISPID_SESSION_PROPERTY:
1324 if (wFlags & DISPATCH_PROPERTYGET) {
1325 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1326 if (FAILED(hr)) return hr;
1327 V_VT(pVarResult) = VT_BSTR;
1328 V_BSTR(pVarResult) = NULL;
1329 if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
1331 if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
1332 ERR("Out of memory\n");
1333 else if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
1334 V_BSTR(pVarResult) = SysAllocString(szString);
1337 if (ret != ERROR_SUCCESS)
1338 ERR("MsiGetProperty returned %d\n", ret);
1339 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1340 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1341 if (FAILED(hr)) return hr;
1342 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1344 VariantClear(&varg0);
1347 if ((ret = MsiSetPropertyW(This->msiHandle, V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
1349 VariantClear(&varg0);
1350 VariantClear(&varg1);
1351 ERR("MsiSetProperty returned %d\n", ret);
1352 return DISP_E_EXCEPTION;
1355 else return DISP_E_MEMBERNOTFOUND;
1358 case DISPID_SESSION_LANGUAGE:
1359 if (wFlags & DISPATCH_PROPERTYGET) {
1360 langId = MsiGetLanguage(This->msiHandle);
1361 V_VT(pVarResult) = VT_I4;
1362 V_I4(pVarResult) = langId;
1364 else return DISP_E_MEMBERNOTFOUND;
1367 case DISPID_SESSION_MODE:
1368 if (wFlags & DISPATCH_PROPERTYGET) {
1369 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1370 if (FAILED(hr)) return hr;
1371 V_VT(pVarResult) = VT_BOOL;
1372 V_BOOL(pVarResult) = MsiGetMode(This->msiHandle, V_I4(&varg0));
1373 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1374 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1375 if (FAILED(hr)) return hr;
1376 hr = DispGetParam(pDispParams, 1, VT_BOOL, &varg1, puArgErr);
1377 if (FAILED(hr)) return hr;
1378 if ((ret = MsiSetMode(This->msiHandle, V_I4(&varg0), V_BOOL(&varg1))) != ERROR_SUCCESS)
1380 ERR("MsiSetMode returned %d\n", ret);
1381 return DISP_E_EXCEPTION;
1384 else return DISP_E_MEMBERNOTFOUND;
1387 case DISPID_SESSION_DATABASE:
1388 if (wFlags & DISPATCH_PROPERTYGET) {
1389 V_VT(pVarResult) = VT_DISPATCH;
1390 if ((msiHandle = MsiGetActiveDatabase(This->msiHandle)))
1392 IDispatch *dispatch;
1394 if (SUCCEEDED(hr = create_database(msiHandle, &dispatch)))
1395 V_DISPATCH(pVarResult) = dispatch;
1397 ERR("Failed to create Database object, hresult 0x%08x\n", hr);
1401 ERR("MsiGetActiveDatabase failed\n");
1402 return DISP_E_EXCEPTION;
1405 else return DISP_E_MEMBERNOTFOUND;
1408 case DISPID_SESSION_DOACTION:
1409 if (wFlags & DISPATCH_METHOD) {
1410 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1411 if (FAILED(hr)) return hr;
1412 ret = MsiDoActionW(This->msiHandle, V_BSTR(&varg0));
1413 V_VT(pVarResult) = VT_I4;
1416 case ERROR_FUNCTION_NOT_CALLED:
1417 V_I4(pVarResult) = msiDoActionStatusNoAction;
1420 V_I4(pVarResult) = msiDoActionStatusSuccess;
1422 case ERROR_INSTALL_USEREXIT:
1423 V_I4(pVarResult) = msiDoActionStatusUserExit;
1425 case ERROR_INSTALL_FAILURE:
1426 V_I4(pVarResult) = msiDoActionStatusFailure;
1428 case ERROR_INSTALL_SUSPEND:
1429 V_I4(pVarResult) = msiDoActionStatusSuspend;
1431 case ERROR_MORE_DATA:
1432 V_I4(pVarResult) = msiDoActionStatusFinished;
1434 case ERROR_INVALID_HANDLE_STATE:
1435 V_I4(pVarResult) = msiDoActionStatusWrongState;
1437 case ERROR_INVALID_DATA:
1438 V_I4(pVarResult) = msiDoActionStatusBadActionData;
1441 VariantClear(&varg0);
1442 FIXME("MsiDoAction returned unhandled value %d\n", ret);
1443 return DISP_E_EXCEPTION;
1446 else return DISP_E_MEMBERNOTFOUND;
1449 case DISPID_SESSION_EVALUATECONDITION:
1450 if (wFlags & DISPATCH_METHOD) {
1451 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1452 if (FAILED(hr)) return hr;
1453 V_VT(pVarResult) = VT_I4;
1454 V_I4(pVarResult) = MsiEvaluateConditionW(This->msiHandle, V_BSTR(&varg0));
1456 else return DISP_E_MEMBERNOTFOUND;
1459 case DISPID_SESSION_MESSAGE:
1460 if(!(wFlags & DISPATCH_METHOD))
1461 return DISP_E_MEMBERNOTFOUND;
1463 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1464 if (FAILED(hr)) return hr;
1465 hr = DispGetParam(pDispParams, 1, VT_DISPATCH, &varg1, puArgErr);
1466 if (FAILED(hr)) return hr;
1468 V_VT(pVarResult) = VT_I4;
1470 MsiProcessMessage(This->msiHandle, V_I4(&varg0), ((AutomationObject *)V_DISPATCH(&varg1))->msiHandle);
1473 case DISPID_SESSION_SETINSTALLLEVEL:
1474 if (wFlags & DISPATCH_METHOD) {
1475 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1476 if (FAILED(hr)) return hr;
1477 if ((ret = MsiSetInstallLevel(This->msiHandle, V_I4(&varg0))) != ERROR_SUCCESS)
1479 ERR("MsiSetInstallLevel returned %d\n", ret);
1480 return DISP_E_EXCEPTION;
1483 else return DISP_E_MEMBERNOTFOUND;
1486 case DISPID_SESSION_FEATURECURRENTSTATE:
1487 if (wFlags & DISPATCH_PROPERTYGET) {
1488 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1489 if (FAILED(hr)) return hr;
1490 V_VT(pVarResult) = VT_I4;
1491 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1492 V_I4(pVarResult) = iInstalled;
1495 ERR("MsiGetFeatureState returned %d\n", ret);
1496 V_I4(pVarResult) = msiInstallStateUnknown;
1499 else return DISP_E_MEMBERNOTFOUND;
1502 case DISPID_SESSION_FEATUREREQUESTSTATE:
1503 if (wFlags & DISPATCH_PROPERTYGET) {
1504 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1505 if (FAILED(hr)) return hr;
1506 V_VT(pVarResult) = VT_I4;
1507 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1508 V_I4(pVarResult) = iAction;
1511 ERR("MsiGetFeatureState returned %d\n", ret);
1512 V_I4(pVarResult) = msiInstallStateUnknown;
1514 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1515 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1516 if (FAILED(hr)) return hr;
1517 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1519 VariantClear(&varg0);
1522 if ((ret = MsiSetFeatureStateW(This->msiHandle, V_BSTR(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
1524 VariantClear(&varg0);
1525 ERR("MsiSetFeatureState returned %d\n", ret);
1526 return DISP_E_EXCEPTION;
1529 else return DISP_E_MEMBERNOTFOUND;
1533 return DISP_E_MEMBERNOTFOUND;
1536 VariantClear(&varg1);
1537 VariantClear(&varg0);
1542 /* Fill the variant pointed to by pVarResult with the value & size returned by RegQueryValueEx as dictated by the
1543 * registry value type. Used by Installer::RegistryValue. */
1544 static void variant_from_registry_value(VARIANT *pVarResult, DWORD dwType, LPBYTE lpData, DWORD dwSize)
1546 static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
1547 static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
1548 WCHAR *szString = (WCHAR *)lpData;
1549 LPWSTR szNewString = NULL;
1550 DWORD dwNewSize = 0;
1555 /* Registry strings may not be null terminated so we must use SysAllocStringByteLen/Len */
1556 case REG_MULTI_SZ: /* Multi SZ change internal null characters to newlines */
1557 idx = (dwSize/sizeof(WCHAR))-1;
1558 while (idx >= 0 && !szString[idx]) idx--;
1559 for (; idx >= 0; idx--)
1560 if (!szString[idx]) szString[idx] = '\n';
1563 V_VT(pVarResult) = VT_BSTR;
1564 V_BSTR(pVarResult) = SysAllocStringByteLen((LPCSTR)szString, dwSize);
1568 if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1569 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1570 else if (!(szNewString = msi_alloc(dwNewSize * sizeof(WCHAR))))
1571 ERR("Out of memory\n");
1572 else if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1573 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1576 V_VT(pVarResult) = VT_BSTR;
1577 V_BSTR(pVarResult) = SysAllocStringLen(szNewString, dwNewSize);
1579 msi_free(szNewString);
1583 V_VT(pVarResult) = VT_I4;
1584 V_I4(pVarResult) = *((DWORD *)lpData);
1588 V_VT(pVarResult) = VT_BSTR;
1589 V_BSTR(pVarResult) = SysAllocString(szREG_); /* Weird string, don't know why native returns it */
1593 V_VT(pVarResult) = VT_BSTR;
1594 V_BSTR(pVarResult) = SysAllocString(szREG_BINARY);
1598 V_VT(pVarResult) = VT_EMPTY;
1602 FIXME("Unhandled registry value type %d\n", dwType);
1606 static HRESULT InstallerImpl_CreateRecord(WORD wFlags,
1607 DISPPARAMS* pDispParams,
1608 VARIANT* pVarResult,
1609 EXCEPINFO* pExcepInfo,
1615 IDispatch* dispatch;
1617 if (!(wFlags & DISPATCH_METHOD))
1618 return DISP_E_MEMBERNOTFOUND;
1620 VariantInit(&varg0);
1621 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1625 V_VT(pVarResult) = VT_DISPATCH;
1627 hrec = MsiCreateRecord(V_I4(&varg0));
1629 return DISP_E_EXCEPTION;
1631 hr = create_record(hrec, &dispatch);
1633 V_DISPATCH(pVarResult) = dispatch;
1638 static HRESULT InstallerImpl_OpenPackage(AutomationObject* This,
1640 DISPPARAMS* pDispParams,
1641 VARIANT* pVarResult,
1642 EXCEPINFO* pExcepInfo,
1648 IDispatch* dispatch;
1649 VARIANTARG varg0, varg1;
1651 if (!(wFlags & DISPATCH_METHOD))
1652 return DISP_E_MEMBERNOTFOUND;
1654 if (pDispParams->cArgs == 0)
1655 return DISP_E_TYPEMISMATCH;
1657 if (V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1]) != VT_BSTR)
1658 return DISP_E_TYPEMISMATCH;
1660 VariantInit(&varg0);
1661 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1665 VariantInit(&varg1);
1666 if (pDispParams->cArgs == 2)
1668 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1674 V_VT(&varg1) = VT_I4;
1678 V_VT(pVarResult) = VT_DISPATCH;
1680 ret = MsiOpenPackageExW(V_BSTR(&varg0), V_I4(&varg1), &hpkg);
1681 if (ret != ERROR_SUCCESS)
1683 hr = DISP_E_EXCEPTION;
1687 hr = create_session(hpkg, &This->IDispatch_iface, &dispatch);
1689 V_DISPATCH(pVarResult) = dispatch;
1692 VariantClear(&varg0);
1693 VariantClear(&varg1);
1697 static HRESULT InstallerImpl_OpenProduct(WORD wFlags,
1698 DISPPARAMS* pDispParams,
1699 VARIANT* pVarResult,
1700 EXCEPINFO* pExcepInfo,
1706 if (!(wFlags & DISPATCH_METHOD))
1707 return DISP_E_MEMBERNOTFOUND;
1709 VariantInit(&varg0);
1710 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1714 FIXME("%s\n", debugstr_w(V_BSTR(&varg0)));
1716 VariantInit(pVarResult);
1718 VariantClear(&varg0);
1722 static HRESULT InstallerImpl_OpenDatabase(WORD wFlags,
1723 DISPPARAMS* pDispParams,
1724 VARIANT* pVarResult,
1725 EXCEPINFO* pExcepInfo,
1731 IDispatch* dispatch;
1732 VARIANTARG varg0, varg1;
1734 if (!(wFlags & DISPATCH_METHOD))
1735 return DISP_E_MEMBERNOTFOUND;
1737 VariantInit(&varg0);
1738 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1742 VariantInit(&varg1);
1743 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1747 V_VT(pVarResult) = VT_DISPATCH;
1749 ret = MsiOpenDatabaseW(V_BSTR(&varg0), V_BSTR(&varg1), &hdb);
1750 if (ret != ERROR_SUCCESS)
1752 hr = DISP_E_EXCEPTION;
1756 hr = create_database(hdb, &dispatch);
1758 V_DISPATCH(pVarResult) = dispatch;
1761 VariantClear(&varg0);
1762 VariantClear(&varg1);
1766 static HRESULT InstallerImpl_SummaryInformation(WORD wFlags,
1767 DISPPARAMS* pDispParams,
1768 VARIANT* pVarResult,
1769 EXCEPINFO* pExcepInfo,
1772 if (!(wFlags & DISPATCH_METHOD))
1773 return DISP_E_MEMBERNOTFOUND;
1777 VariantInit(pVarResult);
1781 static HRESULT InstallerImpl_UILevel(WORD wFlags,
1782 DISPPARAMS* pDispParams,
1783 VARIANT* pVarResult,
1784 EXCEPINFO* pExcepInfo,
1791 if (!(wFlags & DISPATCH_PROPERTYPUT) && !(wFlags & DISPATCH_PROPERTYGET))
1792 return DISP_E_MEMBERNOTFOUND;
1794 if (wFlags & DISPATCH_PROPERTYPUT)
1796 VariantInit(&varg0);
1797 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1801 ui = MsiSetInternalUI(V_I4(&varg0), NULL);
1802 if (ui == INSTALLUILEVEL_NOCHANGE)
1803 return DISP_E_EXCEPTION;
1805 else if (wFlags & DISPATCH_PROPERTYGET)
1807 ui = MsiSetInternalUI(INSTALLUILEVEL_NOCHANGE, NULL);
1808 if (ui == INSTALLUILEVEL_NOCHANGE)
1809 return DISP_E_EXCEPTION;
1811 V_VT(pVarResult) = VT_I4;
1812 V_I4(pVarResult) = ui;
1818 static HRESULT InstallerImpl_EnableLog(WORD wFlags,
1819 DISPPARAMS* pDispParams,
1820 VARIANT* pVarResult,
1821 EXCEPINFO* pExcepInfo,
1824 if (!(wFlags & DISPATCH_METHOD))
1825 return DISP_E_MEMBERNOTFOUND;
1829 VariantInit(pVarResult);
1833 static HRESULT InstallerImpl_InstallProduct(WORD wFlags,
1834 DISPPARAMS* pDispParams,
1835 VARIANT* pVarResult,
1836 EXCEPINFO* pExcepInfo,
1841 VARIANTARG varg0, varg1;
1843 if (!(wFlags & DISPATCH_METHOD))
1844 return DISP_E_MEMBERNOTFOUND;
1846 VariantInit(&varg0);
1847 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1851 VariantInit(&varg1);
1852 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1856 ret = MsiInstallProductW(V_BSTR(&varg0), V_BSTR(&varg1));
1857 if (ret != ERROR_SUCCESS)
1859 hr = DISP_E_EXCEPTION;
1864 VariantClear(&varg0);
1865 VariantClear(&varg1);
1869 static HRESULT InstallerImpl_Version(WORD wFlags,
1870 VARIANT* pVarResult,
1871 EXCEPINFO* pExcepInfo,
1875 DLLVERSIONINFO verinfo;
1876 WCHAR version[MAX_PATH];
1878 static const WCHAR format[] = {
1879 '%','d','.','%','d','.','%','d','.','%','d',0};
1881 if (!(wFlags & DISPATCH_PROPERTYGET))
1882 return DISP_E_MEMBERNOTFOUND;
1884 verinfo.cbSize = sizeof(DLLVERSIONINFO);
1885 hr = DllGetVersion(&verinfo);
1889 sprintfW(version, format, verinfo.dwMajorVersion, verinfo.dwMinorVersion,
1890 verinfo.dwBuildNumber, verinfo.dwPlatformID);
1892 V_VT(pVarResult) = VT_BSTR;
1893 V_BSTR(pVarResult) = SysAllocString(version);
1897 static HRESULT InstallerImpl_LastErrorRecord(WORD wFlags,
1898 DISPPARAMS* pDispParams,
1899 VARIANT* pVarResult,
1900 EXCEPINFO* pExcepInfo,
1903 if (!(wFlags & DISPATCH_METHOD))
1904 return DISP_E_MEMBERNOTFOUND;
1908 VariantInit(pVarResult);
1912 static HRESULT InstallerImpl_RegistryValue(WORD wFlags,
1913 DISPPARAMS* pDispParams,
1914 VARIANT* pVarResult,
1915 EXCEPINFO* pExcepInfo,
1923 LPWSTR szString = NULL;
1924 VARIANTARG varg0, varg1, varg2;
1926 if (!(wFlags & DISPATCH_METHOD))
1927 return DISP_E_MEMBERNOTFOUND;
1929 VariantInit(&varg0);
1930 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1934 VariantInit(&varg1);
1935 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1939 /* Save valuePos so we can save puArgErr if we are unable to do our type
1943 VariantInit(&varg2);
1944 hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg2);
1948 if (V_I4(&varg0) >= REG_INDEX_CLASSES_ROOT &&
1949 V_I4(&varg0) <= REG_INDEX_DYN_DATA)
1951 V_I4(&varg0) |= (UINT_PTR)HKEY_CLASSES_ROOT;
1954 ret = RegOpenKeyW((HKEY)(UINT_PTR)V_I4(&varg0), V_BSTR(&varg1), &hkey);
1956 /* Only VT_EMPTY case can do anything if the key doesn't exist. */
1957 if (ret != ERROR_SUCCESS && V_VT(&varg2) != VT_EMPTY)
1959 hr = DISP_E_BADINDEX;
1963 /* Third parameter can be VT_EMPTY, VT_I4, or VT_BSTR */
1964 switch (V_VT(&varg2))
1966 /* Return VT_BOOL clarifying whether registry key exists or not. */
1968 V_VT(pVarResult) = VT_BOOL;
1969 V_BOOL(pVarResult) = (ret == ERROR_SUCCESS);
1972 /* Return the value of specified key if it exists. */
1974 ret = RegQueryValueExW(hkey, V_BSTR(&varg2),
1975 NULL, NULL, NULL, &size);
1976 if (ret != ERROR_SUCCESS)
1978 hr = DISP_E_BADINDEX;
1982 szString = msi_alloc(size);
1989 ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL,
1990 &type, (LPBYTE)szString, &size);
1991 if (ret != ERROR_SUCCESS)
1994 hr = DISP_E_BADINDEX;
1998 variant_from_registry_value(pVarResult, type,
1999 (LPBYTE)szString, size);
2003 /* Try to make it into VT_I4, can use VariantChangeType for this. */
2005 hr = VariantChangeType(&varg2, &varg2, 0, VT_I4);
2008 if (hr == DISP_E_TYPEMISMATCH)
2009 *puArgErr = posValue;
2014 /* Retrieve class name or maximum value name or subkey name size. */
2016 ret = RegQueryInfoKeyW(hkey, NULL, &size, NULL, NULL, NULL,
2017 NULL, NULL, NULL, NULL, NULL, NULL);
2018 else if (V_I4(&varg2) > 0)
2019 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL,
2020 NULL, NULL, &size, NULL, NULL, NULL);
2021 else /* V_I4(&varg2) < 0 */
2022 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, &size,
2023 NULL, NULL, NULL, NULL, NULL, NULL);
2025 if (ret != ERROR_SUCCESS)
2028 szString = msi_alloc(++size * sizeof(WCHAR));
2036 ret = RegQueryInfoKeyW(hkey, szString, &size,NULL, NULL, NULL,
2037 NULL, NULL, NULL, NULL, NULL, NULL);
2038 else if (V_I4(&varg2) > 0)
2039 ret = RegEnumValueW(hkey, V_I4(&varg2)-1, szString,
2040 &size, 0, 0, NULL, NULL);
2041 else /* V_I4(&varg2) < 0 */
2042 ret = RegEnumKeyW(hkey, -1 - V_I4(&varg2), szString, size);
2044 if (ret == ERROR_SUCCESS)
2046 V_VT(pVarResult) = VT_BSTR;
2047 V_BSTR(pVarResult) = SysAllocString(szString);
2054 VariantClear(&varg0);
2055 VariantClear(&varg1);
2056 VariantClear(&varg2);
2061 static HRESULT InstallerImpl_Environment(WORD wFlags,
2062 DISPPARAMS* pDispParams,
2063 VARIANT* pVarResult,
2064 EXCEPINFO* pExcepInfo,
2067 if (!(wFlags & DISPATCH_METHOD))
2068 return DISP_E_MEMBERNOTFOUND;
2072 VariantInit(pVarResult);
2076 static HRESULT InstallerImpl_FileAttributes(WORD wFlags,
2077 DISPPARAMS* pDispParams,
2078 VARIANT* pVarResult,
2079 EXCEPINFO* pExcepInfo,
2082 if (!(wFlags & DISPATCH_METHOD))
2083 return DISP_E_MEMBERNOTFOUND;
2087 VariantInit(pVarResult);
2091 static HRESULT InstallerImpl_FileSize(WORD wFlags,
2092 DISPPARAMS* pDispParams,
2093 VARIANT* pVarResult,
2094 EXCEPINFO* pExcepInfo,
2097 if (!(wFlags & DISPATCH_METHOD))
2098 return DISP_E_MEMBERNOTFOUND;
2102 VariantInit(pVarResult);
2106 static HRESULT InstallerImpl_FileVersion(WORD wFlags,
2107 DISPPARAMS* pDispParams,
2108 VARIANT* pVarResult,
2109 EXCEPINFO* pExcepInfo,
2112 if (!(wFlags & DISPATCH_METHOD))
2113 return DISP_E_MEMBERNOTFOUND;
2117 VariantInit(pVarResult);
2121 static HRESULT InstallerImpl_ProductState(WORD wFlags,
2122 DISPPARAMS* pDispParams,
2123 VARIANT* pVarResult,
2124 EXCEPINFO* pExcepInfo,
2130 if (!(wFlags & DISPATCH_PROPERTYGET))
2131 return DISP_E_MEMBERNOTFOUND;
2133 VariantInit(&varg0);
2134 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
2138 V_VT(pVarResult) = VT_I4;
2139 V_I4(pVarResult) = MsiQueryProductStateW(V_BSTR(&varg0));
2141 VariantClear(&varg0);
2145 static HRESULT InstallerImpl_ProductInfo(WORD wFlags,
2146 DISPPARAMS* pDispParams,
2147 VARIANT* pVarResult,
2148 EXCEPINFO* pExcepInfo,
2155 VARIANTARG varg0, varg1;
2157 if (!(wFlags & DISPATCH_PROPERTYGET))
2158 return DISP_E_MEMBERNOTFOUND;
2160 VariantInit(&varg0);
2161 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
2165 VariantInit(&varg1);
2166 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
2170 V_VT(pVarResult) = VT_BSTR;
2171 V_BSTR(pVarResult) = NULL;
2173 ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), NULL, &size);
2174 if (ret != ERROR_SUCCESS)
2176 hr = DISP_E_EXCEPTION;
2180 str = msi_alloc(++size * sizeof(WCHAR));
2187 ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), str, &size);
2188 if (ret != ERROR_SUCCESS)
2190 hr = DISP_E_EXCEPTION;
2194 V_BSTR(pVarResult) = SysAllocString(str);
2199 VariantClear(&varg0);
2200 VariantClear(&varg1);
2204 static HRESULT InstallerImpl_Products(WORD flags,
2205 DISPPARAMS* pDispParams,
2207 EXCEPINFO* pExcepInfo,
2210 IDispatch *dispatch;
2213 if (!(flags & DISPATCH_PROPERTYGET))
2214 return DISP_E_MEMBERNOTFOUND;
2216 hr = create_list(NULL, &dispatch);
2220 V_VT(result) = VT_DISPATCH;
2221 V_DISPATCH(result) = dispatch;
2226 static HRESULT InstallerImpl_RelatedProducts(WORD flags,
2227 DISPPARAMS* pDispParams,
2229 EXCEPINFO* pExcepInfo,
2232 IDispatch* dispatch;
2236 if (!(flags & DISPATCH_PROPERTYGET))
2237 return DISP_E_MEMBERNOTFOUND;
2239 VariantInit(&related);
2240 hr = DispGetParam(pDispParams, 0, VT_BSTR, &related, puArgErr);
2244 hr = create_list(V_BSTR(&related), &dispatch);
2245 VariantClear(&related);
2247 V_VT(result) = VT_DISPATCH;
2248 V_DISPATCH(result) = dispatch;
2253 static HRESULT InstallerImpl_Invoke(
2254 AutomationObject* This,
2255 DISPID dispIdMember,
2259 DISPPARAMS* pDispParams,
2260 VARIANT* pVarResult,
2261 EXCEPINFO* pExcepInfo,
2264 switch (dispIdMember)
2266 case DISPID_INSTALLER_CREATERECORD:
2267 return InstallerImpl_CreateRecord(wFlags, pDispParams,
2268 pVarResult, pExcepInfo, puArgErr);
2270 case DISPID_INSTALLER_OPENPACKAGE:
2271 return InstallerImpl_OpenPackage(This, wFlags, pDispParams,
2272 pVarResult, pExcepInfo, puArgErr);
2274 case DISPID_INSTALLER_OPENPRODUCT:
2275 return InstallerImpl_OpenProduct(wFlags, pDispParams,
2276 pVarResult, pExcepInfo, puArgErr);
2278 case DISPID_INSTALLER_OPENDATABASE:
2279 return InstallerImpl_OpenDatabase(wFlags, pDispParams,
2280 pVarResult, pExcepInfo, puArgErr);
2282 case DISPID_INSTALLER_SUMMARYINFORMATION:
2283 return InstallerImpl_SummaryInformation(wFlags, pDispParams,
2284 pVarResult, pExcepInfo,
2287 case DISPID_INSTALLER_UILEVEL:
2288 return InstallerImpl_UILevel(wFlags, pDispParams,
2289 pVarResult, pExcepInfo, puArgErr);
2291 case DISPID_INSTALLER_ENABLELOG:
2292 return InstallerImpl_EnableLog(wFlags, pDispParams,
2293 pVarResult, pExcepInfo, puArgErr);
2295 case DISPID_INSTALLER_INSTALLPRODUCT:
2296 return InstallerImpl_InstallProduct(wFlags, pDispParams,
2297 pVarResult, pExcepInfo,
2300 case DISPID_INSTALLER_VERSION:
2301 return InstallerImpl_Version(wFlags, pVarResult,
2302 pExcepInfo, puArgErr);
2304 case DISPID_INSTALLER_LASTERRORRECORD:
2305 return InstallerImpl_LastErrorRecord(wFlags, pDispParams,
2306 pVarResult, pExcepInfo,
2309 case DISPID_INSTALLER_REGISTRYVALUE:
2310 return InstallerImpl_RegistryValue(wFlags, pDispParams,
2311 pVarResult, pExcepInfo,
2314 case DISPID_INSTALLER_ENVIRONMENT:
2315 return InstallerImpl_Environment(wFlags, pDispParams,
2316 pVarResult, pExcepInfo, puArgErr);
2318 case DISPID_INSTALLER_FILEATTRIBUTES:
2319 return InstallerImpl_FileAttributes(wFlags, pDispParams,
2320 pVarResult, pExcepInfo,
2323 case DISPID_INSTALLER_FILESIZE:
2324 return InstallerImpl_FileSize(wFlags, pDispParams,
2325 pVarResult, pExcepInfo, puArgErr);
2327 case DISPID_INSTALLER_FILEVERSION:
2328 return InstallerImpl_FileVersion(wFlags, pDispParams,
2329 pVarResult, pExcepInfo, puArgErr);
2331 case DISPID_INSTALLER_PRODUCTSTATE:
2332 return InstallerImpl_ProductState(wFlags, pDispParams,
2333 pVarResult, pExcepInfo, puArgErr);
2335 case DISPID_INSTALLER_PRODUCTINFO:
2336 return InstallerImpl_ProductInfo(wFlags, pDispParams,
2337 pVarResult, pExcepInfo, puArgErr);
2339 case DISPID_INSTALLER_PRODUCTS:
2340 return InstallerImpl_Products(wFlags, pDispParams,
2341 pVarResult, pExcepInfo, puArgErr);
2343 case DISPID_INSTALLER_RELATEDPRODUCTS:
2344 return InstallerImpl_RelatedProducts(wFlags, pDispParams,
2345 pVarResult, pExcepInfo,
2349 return DISP_E_MEMBERNOTFOUND;
2353 HRESULT create_msiserver(IUnknown *outer, void **ppObj)
2355 AutomationObject *installer;
2358 TRACE("(%p %p)\n", outer, ppObj);
2361 return CLASS_E_NOAGGREGATION;
2363 installer = msi_alloc(sizeof(AutomationObject));
2364 if (!installer) return E_OUTOFMEMORY;
2366 hr = init_automation_object(installer, 0, &DIID_Installer, InstallerImpl_Invoke, NULL);
2369 msi_free(installer);
2373 *ppObj = &installer->IDispatch_iface;
2378 HRESULT create_session(MSIHANDLE msiHandle, IDispatch *installer, IDispatch **disp)
2380 SessionObject *session;
2383 session = msi_alloc(sizeof(SessionObject));
2384 if (!session) return E_OUTOFMEMORY;
2386 hr = init_automation_object(&session->autoobj, msiHandle, &DIID_Session, SessionImpl_Invoke, NULL);
2393 session->installer = installer;
2394 *disp = &session->autoobj.IDispatch_iface;
2399 static HRESULT create_database(MSIHANDLE msiHandle, IDispatch **dispatch)
2401 AutomationObject *database;
2404 TRACE("(%d %p)\n", msiHandle, dispatch);
2406 database = msi_alloc(sizeof(AutomationObject));
2407 if (!database) return E_OUTOFMEMORY;
2409 hr = init_automation_object(database, msiHandle, &DIID_Database, DatabaseImpl_Invoke, NULL);
2416 *dispatch = &database->IDispatch_iface;
2421 static HRESULT create_view(MSIHANDLE msiHandle, IDispatch **dispatch)
2423 AutomationObject *view;
2426 TRACE("(%d %p)\n", msiHandle, dispatch);
2428 view = msi_alloc(sizeof(AutomationObject));
2429 if (!view) return E_OUTOFMEMORY;
2431 hr = init_automation_object(view, msiHandle, &DIID_View, ViewImpl_Invoke, NULL);
2438 *dispatch = &view->IDispatch_iface;
2443 static HRESULT create_summaryinfo(MSIHANDLE msiHandle, IDispatch **disp)
2445 AutomationObject *info;
2448 info = msi_alloc(sizeof(*info));
2449 if (!info) return E_OUTOFMEMORY;
2451 hr = init_automation_object(info, msiHandle, &DIID_SummaryInfo, SummaryInfoImpl_Invoke, NULL);
2458 *disp = &info->IDispatch_iface;