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 = SysAllocString(szExceptionSource);
430 pExcepInfo->bstrDescription = SysAllocString(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 SummaryInfoImpl_Invoke(
734 AutomationObject* This,
739 DISPPARAMS* pDispParams,
741 EXCEPINFO* pExcepInfo,
745 VARIANTARG varg0, varg1;
746 FILETIME ft, ftlocal;
753 switch (dispIdMember)
755 case DISPID_SUMMARYINFO_PROPERTY:
756 if (wFlags & DISPATCH_PROPERTYGET)
764 static WCHAR szEmpty[] = {0};
766 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
767 if (FAILED(hr)) return hr;
768 ret = MsiSummaryInfoGetPropertyW(This->msiHandle, V_I4(&varg0), &type, &value,
769 &ft, szEmpty, &size);
770 if (ret != ERROR_SUCCESS &&
771 ret != ERROR_MORE_DATA)
773 ERR("MsiSummaryInfoGetProperty returned %d\n", ret);
774 return DISP_E_EXCEPTION;
784 V_VT(pVarResult) = VT_I4;
785 V_I4(pVarResult) = value;
789 if (!(str = msi_alloc(++size * sizeof(WCHAR))))
790 ERR("Out of memory\n");
791 else if ((ret = MsiSummaryInfoGetPropertyW(This->msiHandle, V_I4(&varg0), &type, NULL,
792 NULL, str, &size)) != ERROR_SUCCESS)
793 ERR("MsiSummaryInfoGetProperty returned %d\n", ret);
796 V_VT(pVarResult) = VT_BSTR;
797 V_BSTR(pVarResult) = SysAllocString(str);
803 FileTimeToLocalFileTime(&ft, &ftlocal);
804 FileTimeToSystemTime(&ftlocal, &st);
805 SystemTimeToVariantTime(&st, &date);
807 V_VT(pVarResult) = VT_DATE;
808 V_DATE(pVarResult) = date;
812 ERR("Unhandled variant type %d\n", type);
815 else if (wFlags & DISPATCH_PROPERTYPUT)
817 UINT posValue = DISPID_PROPERTYPUT;
819 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
820 if (FAILED(hr)) return hr;
821 hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg1);
824 *puArgErr = posValue;
828 switch (V_VT(&varg1))
832 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), V_VT(&varg1), V_I4(&varg1), NULL, NULL);
836 VariantTimeToSystemTime(V_DATE(&varg1), &st);
837 SystemTimeToFileTime(&st, &ftlocal);
838 LocalFileTimeToFileTime(&ftlocal, &ft);
839 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), VT_FILETIME, 0, &ft, NULL);
843 ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), VT_LPSTR, 0, NULL, V_BSTR(&varg1));
847 FIXME("Unhandled variant type %d\n", V_VT(&varg1));
848 VariantClear(&varg1);
849 return DISP_E_EXCEPTION;
852 if (ret != ERROR_SUCCESS)
854 ERR("MsiSummaryInfoSetPropertyW returned %d\n", ret);
855 return DISP_E_EXCEPTION;
858 else return DISP_E_MEMBERNOTFOUND;
861 case DISPID_SUMMARYINFO_PROPERTYCOUNT:
862 if (wFlags & DISPATCH_PROPERTYGET) {
864 if ((ret = MsiSummaryInfoGetPropertyCount(This->msiHandle, &count)) != ERROR_SUCCESS)
865 ERR("MsiSummaryInfoGetPropertyCount returned %d\n", ret);
868 V_VT(pVarResult) = VT_I4;
869 V_I4(pVarResult) = count;
872 else return DISP_E_MEMBERNOTFOUND;
876 return DISP_E_MEMBERNOTFOUND;
879 VariantClear(&varg1);
880 VariantClear(&varg0);
885 static HRESULT WINAPI RecordImpl_Invoke(
886 AutomationObject* This,
891 DISPPARAMS* pDispParams,
893 EXCEPINFO* pExcepInfo,
899 VARIANTARG varg0, varg1;
905 switch (dispIdMember)
907 case DISPID_RECORD_FIELDCOUNT:
908 if (wFlags & DISPATCH_PROPERTYGET) {
909 V_VT(pVarResult) = VT_I4;
910 V_I4(pVarResult) = MsiRecordGetFieldCount(This->msiHandle);
912 else return DISP_E_MEMBERNOTFOUND;
915 case DISPID_RECORD_STRINGDATA:
916 if (wFlags & DISPATCH_PROPERTYGET) {
917 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
918 if (FAILED(hr)) return hr;
919 V_VT(pVarResult) = VT_BSTR;
920 V_BSTR(pVarResult) = NULL;
921 if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
923 if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
924 ERR("Out of memory\n");
925 else if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
926 V_BSTR(pVarResult) = SysAllocString(szString);
929 if (ret != ERROR_SUCCESS)
930 ERR("MsiRecordGetString returned %d\n", ret);
931 } else if (wFlags & DISPATCH_PROPERTYPUT) {
932 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
933 if (FAILED(hr)) return hr;
934 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BSTR, &varg1, puArgErr);
935 if (FAILED(hr)) return hr;
936 if ((ret = MsiRecordSetStringW(This->msiHandle, V_I4(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
938 VariantClear(&varg1);
939 ERR("MsiRecordSetString returned %d\n", ret);
940 return DISP_E_EXCEPTION;
943 else return DISP_E_MEMBERNOTFOUND;
946 case DISPID_RECORD_INTEGERDATA:
947 if (wFlags & DISPATCH_PROPERTYGET) {
948 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
949 if (FAILED(hr)) return hr;
950 V_VT(pVarResult) = VT_I4;
951 V_I4(pVarResult) = MsiRecordGetInteger(This->msiHandle, V_I4(&varg0));
952 } else if (wFlags & DISPATCH_PROPERTYPUT) {
953 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
954 if (FAILED(hr)) return hr;
955 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_I4, &varg1, puArgErr);
956 if (FAILED(hr)) return hr;
957 if ((ret = MsiRecordSetInteger(This->msiHandle, V_I4(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
959 ERR("MsiRecordSetInteger returned %d\n", ret);
960 return DISP_E_EXCEPTION;
963 else return DISP_E_MEMBERNOTFOUND;
967 return DISP_E_MEMBERNOTFOUND;
970 VariantClear(&varg1);
971 VariantClear(&varg0);
976 static HRESULT WINAPI ListImpl_Invoke(
977 AutomationObject* This,
982 DISPPARAMS* pDispParams,
984 EXCEPINFO* pExcepInfo,
987 ListData *data = (ListData *)private_data(This);
990 IUnknown *pUnk = NULL;
994 switch (dispIdMember)
996 case DISPID_LIST__NEWENUM:
997 if (wFlags & DISPATCH_METHOD) {
998 V_VT(pVarResult) = VT_UNKNOWN;
999 if (SUCCEEDED(hr = create_list_enumerator(NULL, (LPVOID *)&pUnk, This, 0)))
1001 IUnknown_AddRef(pUnk);
1002 V_UNKNOWN(pVarResult) = pUnk;
1005 ERR("Failed to create IEnumVARIANT object, hresult 0x%08x\n", hr);
1007 else return DISP_E_MEMBERNOTFOUND;
1010 case DISPID_LIST_ITEM:
1011 if (wFlags & DISPATCH_PROPERTYGET) {
1012 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1013 if (FAILED(hr)) return hr;
1014 if (V_I4(&varg0) < 0 || V_I4(&varg0) >= data->ulCount)
1015 return DISP_E_BADINDEX;
1016 VariantCopy(pVarResult, &data->pVars[V_I4(&varg0)]);
1018 else return DISP_E_MEMBERNOTFOUND;
1021 case DISPID_LIST_COUNT:
1022 if (wFlags & DISPATCH_PROPERTYGET) {
1023 V_VT(pVarResult) = VT_I4;
1024 V_I4(pVarResult) = data->ulCount;
1026 else return DISP_E_MEMBERNOTFOUND;
1030 return DISP_E_MEMBERNOTFOUND;
1033 VariantClear(&varg0);
1038 static void WINAPI ListImpl_Free(AutomationObject *This)
1040 ListData *data = private_data(This);
1043 for (idx=0; idx<data->ulCount; idx++)
1044 VariantClear(&data->pVars[idx]);
1045 HeapFree(GetProcessHeap(), 0, data->pVars);
1048 static HRESULT WINAPI ViewImpl_Invoke(
1049 AutomationObject* This,
1050 DISPID dispIdMember,
1054 DISPPARAMS* pDispParams,
1055 VARIANT* pVarResult,
1056 EXCEPINFO* pExcepInfo,
1059 MSIHANDLE msiHandle;
1060 IDispatch *pDispatch = NULL;
1062 VARIANTARG varg0, varg1;
1065 VariantInit(&varg0);
1066 VariantInit(&varg1);
1068 switch (dispIdMember)
1070 case DISPID_VIEW_EXECUTE:
1071 if (wFlags & DISPATCH_METHOD)
1073 hr = DispGetParam(pDispParams, 0, VT_DISPATCH, &varg0, puArgErr);
1074 if (SUCCEEDED(hr) && V_DISPATCH(&varg0) != NULL)
1075 MsiViewExecute(This->msiHandle, ((AutomationObject *)V_DISPATCH(&varg0))->msiHandle);
1077 MsiViewExecute(This->msiHandle, 0);
1079 else return DISP_E_MEMBERNOTFOUND;
1082 case DISPID_VIEW_FETCH:
1083 if (wFlags & DISPATCH_METHOD)
1085 V_VT(pVarResult) = VT_DISPATCH;
1086 if ((ret = MsiViewFetch(This->msiHandle, &msiHandle)) == ERROR_SUCCESS)
1088 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Record, RecordImpl_Invoke, NULL, 0)))
1090 IDispatch_AddRef(pDispatch);
1091 V_DISPATCH(pVarResult) = pDispatch;
1094 ERR("Failed to create Record object, hresult 0x%08x\n", hr);
1096 else if (ret == ERROR_NO_MORE_ITEMS)
1097 V_DISPATCH(pVarResult) = NULL;
1100 ERR("MsiViewFetch returned %d\n", ret);
1101 return DISP_E_EXCEPTION;
1104 else return DISP_E_MEMBERNOTFOUND;
1107 case DISPID_VIEW_MODIFY:
1108 if (wFlags & DISPATCH_METHOD)
1110 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1111 if (FAILED(hr)) return hr;
1112 hr = DispGetParam(pDispParams, 1, VT_DISPATCH, &varg1, puArgErr);
1113 if (FAILED(hr)) return hr;
1114 if (!V_DISPATCH(&varg1)) return DISP_E_EXCEPTION;
1115 if ((ret = MsiViewModify(This->msiHandle, V_I4(&varg0), ((AutomationObject *)V_DISPATCH(&varg1))->msiHandle)) != ERROR_SUCCESS)
1117 VariantClear(&varg1);
1118 ERR("MsiViewModify returned %d\n", ret);
1119 return DISP_E_EXCEPTION;
1122 else return DISP_E_MEMBERNOTFOUND;
1125 case DISPID_VIEW_CLOSE:
1126 if (wFlags & DISPATCH_METHOD)
1128 MsiViewClose(This->msiHandle);
1130 else return DISP_E_MEMBERNOTFOUND;
1134 return DISP_E_MEMBERNOTFOUND;
1137 VariantClear(&varg1);
1138 VariantClear(&varg0);
1143 static HRESULT WINAPI DatabaseImpl_Invoke(
1144 AutomationObject* This,
1145 DISPID dispIdMember,
1149 DISPPARAMS* pDispParams,
1150 VARIANT* pVarResult,
1151 EXCEPINFO* pExcepInfo,
1154 MSIHANDLE msiHandle;
1155 IDispatch *pDispatch = NULL;
1157 VARIANTARG varg0, varg1;
1160 VariantInit(&varg0);
1161 VariantInit(&varg1);
1163 switch (dispIdMember)
1165 case DISPID_DATABASE_SUMMARYINFORMATION:
1166 if (wFlags & DISPATCH_PROPERTYGET)
1168 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1172 V_VT(pVarResult) = VT_DISPATCH;
1173 if ((ret = MsiGetSummaryInformationW(This->msiHandle, NULL, V_I4(&varg0), &msiHandle)) == ERROR_SUCCESS)
1175 hr = create_automation_object(msiHandle, NULL, (LPVOID *)&pDispatch, &DIID_SummaryInfo, SummaryInfoImpl_Invoke, NULL, 0);
1178 IDispatch_AddRef(pDispatch);
1179 V_DISPATCH(pVarResult) = pDispatch;
1182 ERR("Failed to create SummaryInfo object: 0x%08x\n", hr);
1186 ERR("MsiGetSummaryInformation returned %d\n", ret);
1187 return DISP_E_EXCEPTION;
1190 else return DISP_E_MEMBERNOTFOUND;
1193 case DISPID_DATABASE_OPENVIEW:
1194 if (wFlags & DISPATCH_METHOD)
1196 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1197 if (FAILED(hr)) return hr;
1198 V_VT(pVarResult) = VT_DISPATCH;
1199 if ((ret = MsiDatabaseOpenViewW(This->msiHandle, V_BSTR(&varg0), &msiHandle)) == ERROR_SUCCESS)
1201 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_View, ViewImpl_Invoke, NULL, 0)))
1203 IDispatch_AddRef(pDispatch);
1204 V_DISPATCH(pVarResult) = pDispatch;
1207 ERR("Failed to create View object, hresult 0x%08x\n", hr);
1211 VariantClear(&varg0);
1212 ERR("MsiDatabaseOpenView returned %d\n", ret);
1213 return DISP_E_EXCEPTION;
1216 else return DISP_E_MEMBERNOTFOUND;
1220 return DISP_E_MEMBERNOTFOUND;
1223 VariantClear(&varg1);
1224 VariantClear(&varg0);
1229 static HRESULT WINAPI SessionImpl_Invoke(
1230 AutomationObject* This,
1231 DISPID dispIdMember,
1235 DISPPARAMS* pDispParams,
1236 VARIANT* pVarResult,
1237 EXCEPINFO* pExcepInfo,
1240 SessionData *data = private_data(This);
1243 IDispatch *pDispatch = NULL;
1244 MSIHANDLE msiHandle;
1247 INSTALLSTATE iInstalled, iAction;
1248 VARIANTARG varg0, varg1;
1251 VariantInit(&varg0);
1252 VariantInit(&varg1);
1254 switch (dispIdMember)
1256 case DISPID_SESSION_INSTALLER:
1257 if (wFlags & DISPATCH_PROPERTYGET) {
1258 V_VT(pVarResult) = VT_DISPATCH;
1259 IDispatch_AddRef(data->pInstaller);
1260 V_DISPATCH(pVarResult) = data->pInstaller;
1262 else return DISP_E_MEMBERNOTFOUND;
1265 case DISPID_SESSION_PROPERTY:
1266 if (wFlags & DISPATCH_PROPERTYGET) {
1267 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1268 if (FAILED(hr)) return hr;
1269 V_VT(pVarResult) = VT_BSTR;
1270 V_BSTR(pVarResult) = NULL;
1271 if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
1273 if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
1274 ERR("Out of memory\n");
1275 else if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
1276 V_BSTR(pVarResult) = SysAllocString(szString);
1279 if (ret != ERROR_SUCCESS)
1280 ERR("MsiGetProperty returned %d\n", ret);
1281 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1282 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1283 if (FAILED(hr)) return hr;
1284 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BSTR, &varg1, puArgErr);
1286 VariantClear(&varg0);
1289 if ((ret = MsiSetPropertyW(This->msiHandle, V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
1291 VariantClear(&varg0);
1292 VariantClear(&varg1);
1293 ERR("MsiSetProperty returned %d\n", ret);
1294 return DISP_E_EXCEPTION;
1297 else return DISP_E_MEMBERNOTFOUND;
1300 case DISPID_SESSION_LANGUAGE:
1301 if (wFlags & DISPATCH_PROPERTYGET) {
1302 langId = MsiGetLanguage(This->msiHandle);
1303 V_VT(pVarResult) = VT_I4;
1304 V_I4(pVarResult) = langId;
1306 else return DISP_E_MEMBERNOTFOUND;
1309 case DISPID_SESSION_MODE:
1310 if (wFlags & DISPATCH_PROPERTYGET) {
1311 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1312 if (FAILED(hr)) return hr;
1313 V_VT(pVarResult) = VT_BOOL;
1314 V_BOOL(pVarResult) = MsiGetMode(This->msiHandle, V_I4(&varg0));
1315 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1316 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1317 if (FAILED(hr)) return hr;
1318 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BOOL, &varg1, puArgErr);
1319 if (FAILED(hr)) return hr;
1320 if ((ret = MsiSetMode(This->msiHandle, V_I4(&varg0), V_BOOL(&varg1))) != ERROR_SUCCESS)
1322 ERR("MsiSetMode returned %d\n", ret);
1323 return DISP_E_EXCEPTION;
1326 else return DISP_E_MEMBERNOTFOUND;
1329 case DISPID_SESSION_DATABASE:
1330 if (wFlags & DISPATCH_PROPERTYGET) {
1331 V_VT(pVarResult) = VT_DISPATCH;
1332 if ((msiHandle = MsiGetActiveDatabase(This->msiHandle)))
1334 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Database, DatabaseImpl_Invoke, NULL, 0)))
1336 IDispatch_AddRef(pDispatch);
1337 V_DISPATCH(pVarResult) = pDispatch;
1340 ERR("Failed to create Database object, hresult 0x%08x\n", hr);
1344 ERR("MsiGetActiveDatabase failed\n");
1345 return DISP_E_EXCEPTION;
1348 else return DISP_E_MEMBERNOTFOUND;
1351 case DISPID_SESSION_DOACTION:
1352 if (wFlags & DISPATCH_METHOD) {
1353 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1354 if (FAILED(hr)) return hr;
1355 ret = MsiDoActionW(This->msiHandle, V_BSTR(&varg0));
1356 V_VT(pVarResult) = VT_I4;
1359 case ERROR_FUNCTION_NOT_CALLED:
1360 V_I4(pVarResult) = msiDoActionStatusNoAction;
1363 V_I4(pVarResult) = msiDoActionStatusSuccess;
1365 case ERROR_INSTALL_USEREXIT:
1366 V_I4(pVarResult) = msiDoActionStatusUserExit;
1368 case ERROR_INSTALL_FAILURE:
1369 V_I4(pVarResult) = msiDoActionStatusFailure;
1371 case ERROR_INSTALL_SUSPEND:
1372 V_I4(pVarResult) = msiDoActionStatusSuspend;
1374 case ERROR_MORE_DATA:
1375 V_I4(pVarResult) = msiDoActionStatusFinished;
1377 case ERROR_INVALID_HANDLE_STATE:
1378 V_I4(pVarResult) = msiDoActionStatusWrongState;
1380 case ERROR_INVALID_DATA:
1381 V_I4(pVarResult) = msiDoActionStatusBadActionData;
1384 VariantClear(&varg0);
1385 FIXME("MsiDoAction returned unhandled value %d\n", ret);
1386 return DISP_E_EXCEPTION;
1389 else return DISP_E_MEMBERNOTFOUND;
1392 case DISPID_SESSION_EVALUATECONDITION:
1393 if (wFlags & DISPATCH_METHOD) {
1394 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1395 if (FAILED(hr)) return hr;
1396 V_VT(pVarResult) = VT_I4;
1397 V_I4(pVarResult) = MsiEvaluateConditionW(This->msiHandle, V_BSTR(&varg0));
1399 else return DISP_E_MEMBERNOTFOUND;
1402 case DISPID_SESSION_SETINSTALLLEVEL:
1403 if (wFlags & DISPATCH_METHOD) {
1404 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1405 if (FAILED(hr)) return hr;
1406 if ((ret = MsiSetInstallLevel(This->msiHandle, V_I4(&varg0))) != ERROR_SUCCESS)
1408 ERR("MsiSetInstallLevel returned %d\n", ret);
1409 return DISP_E_EXCEPTION;
1412 else return DISP_E_MEMBERNOTFOUND;
1415 case DISPID_SESSION_FEATURECURRENTSTATE:
1416 if (wFlags & DISPATCH_PROPERTYGET) {
1417 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1418 if (FAILED(hr)) return hr;
1419 V_VT(pVarResult) = VT_I4;
1420 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1421 V_I4(pVarResult) = iInstalled;
1424 ERR("MsiGetFeatureState returned %d\n", ret);
1425 V_I4(pVarResult) = msiInstallStateUnknown;
1428 else return DISP_E_MEMBERNOTFOUND;
1431 case DISPID_SESSION_FEATUREREQUESTSTATE:
1432 if (wFlags & DISPATCH_PROPERTYGET) {
1433 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1434 if (FAILED(hr)) return hr;
1435 V_VT(pVarResult) = VT_I4;
1436 if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
1437 V_I4(pVarResult) = iAction;
1440 ERR("MsiGetFeatureState returned %d\n", ret);
1441 V_I4(pVarResult) = msiInstallStateUnknown;
1443 } else if (wFlags & DISPATCH_PROPERTYPUT) {
1444 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1445 if (FAILED(hr)) return hr;
1446 hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_I4, &varg1, puArgErr);
1448 VariantClear(&varg0);
1451 if ((ret = MsiSetFeatureStateW(This->msiHandle, V_BSTR(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
1453 VariantClear(&varg0);
1454 ERR("MsiSetFeatureState returned %d\n", ret);
1455 return DISP_E_EXCEPTION;
1458 else return DISP_E_MEMBERNOTFOUND;
1462 return DISP_E_MEMBERNOTFOUND;
1465 VariantClear(&varg1);
1466 VariantClear(&varg0);
1471 /* Fill the variant pointed to by pVarResult with the value & size returned by RegQueryValueEx as dictated by the
1472 * registry value type. Used by Installer::RegistryValue. */
1473 static void variant_from_registry_value(VARIANT *pVarResult, DWORD dwType, LPBYTE lpData, DWORD dwSize)
1475 static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
1476 static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
1477 WCHAR *szString = (WCHAR *)lpData;
1478 LPWSTR szNewString = NULL;
1479 DWORD dwNewSize = 0;
1484 /* Registry strings may not be null terminated so we must use SysAllocStringByteLen/Len */
1485 case REG_MULTI_SZ: /* Multi SZ change internal null characters to newlines */
1486 idx = (dwSize/sizeof(WCHAR))-1;
1487 while (idx >= 0 && !szString[idx]) idx--;
1488 for (; idx >= 0; idx--)
1489 if (!szString[idx]) szString[idx] = '\n';
1491 V_VT(pVarResult) = VT_BSTR;
1492 V_BSTR(pVarResult) = SysAllocStringByteLen((LPCSTR)szString, dwSize);
1496 if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1497 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1498 else if (!(szNewString = msi_alloc(dwNewSize)))
1499 ERR("Out of memory\n");
1500 else if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
1501 ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
1504 V_VT(pVarResult) = VT_BSTR;
1505 V_BSTR(pVarResult) = SysAllocStringLen(szNewString, dwNewSize);
1507 msi_free(szNewString);
1511 V_VT(pVarResult) = VT_I4;
1512 V_I4(pVarResult) = *((DWORD *)lpData);
1516 V_VT(pVarResult) = VT_BSTR;
1517 V_BSTR(pVarResult) = SysAllocString(szREG_); /* Weird string, don't know why native returns it */
1521 V_VT(pVarResult) = VT_BSTR;
1522 V_BSTR(pVarResult) = SysAllocString(szREG_BINARY);
1526 V_VT(pVarResult) = VT_EMPTY;
1530 FIXME("Unhandled registry value type %d\n", dwType);
1534 static HRESULT WINAPI InstallerImpl_Invoke(
1535 AutomationObject* This,
1536 DISPID dispIdMember,
1540 DISPPARAMS* pDispParams,
1541 VARIANT* pVarResult,
1542 EXCEPINFO* pExcepInfo,
1545 MSIHANDLE msiHandle;
1546 IDispatch *pDispatch = NULL;
1548 VARIANTARG varg0, varg1, varg2;
1550 LPWSTR szString = NULL;
1553 VariantInit(&varg0);
1554 VariantInit(&varg1);
1555 VariantInit(&varg2);
1557 switch (dispIdMember)
1559 case DISPID_INSTALLER_CREATERECORD:
1560 if (wFlags & DISPATCH_METHOD)
1562 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1563 if (FAILED(hr)) return hr;
1564 V_VT(pVarResult) = VT_DISPATCH;
1565 if ((msiHandle = MsiCreateRecord(V_I4(&varg0))))
1567 if (SUCCEEDED(hr = create_automation_object(msiHandle, NULL, (LPVOID*)&pDispatch, &DIID_Record, RecordImpl_Invoke, NULL, 0)))
1569 IDispatch_AddRef(pDispatch);
1570 V_DISPATCH(pVarResult) = pDispatch;
1573 ERR("Failed to create Record object, hresult 0x%08x\n", hr);
1577 ERR("MsiCreateRecord failed\n");
1578 return DISP_E_EXCEPTION;
1581 else return DISP_E_MEMBERNOTFOUND;
1584 case DISPID_INSTALLER_OPENPACKAGE:
1585 if (wFlags & DISPATCH_METHOD)
1587 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1588 if (FAILED(hr)) return hr;
1589 hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
1592 VariantClear(&varg0);
1595 V_VT(pVarResult) = VT_DISPATCH;
1596 if ((ret = MsiOpenPackageExW(V_BSTR(&varg0), V_I4(&varg1), &msiHandle)) == ERROR_SUCCESS)
1598 if (SUCCEEDED(hr = create_session(msiHandle, (IDispatch *)This, &pDispatch)))
1600 IDispatch_AddRef(pDispatch);
1601 V_DISPATCH(pVarResult) = pDispatch;
1604 ERR("Failed to create Session object, hresult 0x%08x\n", hr);
1608 VariantClear(&varg0);
1609 ERR("MsiOpenPackageEx returned %d\n", ret);
1610 return DISP_E_EXCEPTION;
1613 else return DISP_E_MEMBERNOTFOUND;
1616 case DISPID_INSTALLER_OPENDATABASE:
1617 if (wFlags & DISPATCH_METHOD)
1619 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1620 if (FAILED(hr)) return hr;
1622 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1625 VariantClear(&varg0);
1629 V_VT(pVarResult) = VT_DISPATCH;
1630 if ((ret = MsiOpenDatabaseW(V_BSTR(&varg0), V_BSTR(&varg1), &msiHandle)) == ERROR_SUCCESS)
1632 hr = create_automation_object(msiHandle, NULL, (LPVOID *)&pDispatch,
1633 &DIID_Database, DatabaseImpl_Invoke, NULL, 0);
1636 IDispatch_AddRef(pDispatch);
1637 V_DISPATCH(pVarResult) = pDispatch;
1640 ERR("Failed to create Database object: 0x%08x\n", hr);
1644 VariantClear(&varg0);
1645 VariantClear(&varg1);
1646 ERR("MsiOpenDatabase returned %d\n", ret);
1647 return DISP_E_EXCEPTION;
1650 else return DISP_E_MEMBERNOTFOUND;
1653 case DISPID_INSTALLER_INSTALLPRODUCT:
1654 if (wFlags & DISPATCH_METHOD)
1656 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1657 if (FAILED(hr)) return hr;
1658 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1661 VariantClear(&varg0);
1664 if ((ret = MsiInstallProductW(V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
1666 VariantClear(&varg1);
1667 VariantClear(&varg0);
1668 ERR("MsiInstallProduct returned %d\n", ret);
1669 return DISP_E_EXCEPTION;
1672 else return DISP_E_MEMBERNOTFOUND;
1675 case DISPID_INSTALLER_REGISTRYVALUE:
1676 if (wFlags & DISPATCH_METHOD) {
1679 UINT posValue = 2; /* Save valuePos so we can save puArgErr if we are unable to do our type conversions */
1681 hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
1682 if (FAILED(hr)) return hr;
1683 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1684 if (FAILED(hr)) return hr;
1685 hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg2);
1688 VariantClear(&varg1);
1691 ret = RegOpenKeyW((HKEY)V_I4(&varg0), V_BSTR(&varg1), &hkey);
1693 /* Third parameter can be VT_EMPTY, VT_I4, or VT_BSTR */
1694 switch (V_VT(&varg2))
1696 case VT_EMPTY: /* Return VT_BOOL as to whether or not registry key exists */
1697 V_VT(pVarResult) = VT_BOOL;
1698 V_BOOL(pVarResult) = (ret == ERROR_SUCCESS);
1701 case VT_BSTR: /* Return value of specified key if it exists */
1702 if (ret == ERROR_SUCCESS &&
1703 (ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL, NULL, NULL, &dwSize)) == ERROR_SUCCESS)
1705 if (!(szString = msi_alloc(dwSize)))
1706 ERR("Out of memory\n");
1707 else if ((ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL, &dwType, (LPBYTE)szString, &dwSize)) == ERROR_SUCCESS)
1708 variant_from_registry_value(pVarResult, dwType, (LPBYTE)szString, dwSize);
1711 if (ret != ERROR_SUCCESS)
1714 VariantClear(&varg2);
1715 VariantClear(&varg1);
1716 return DISP_E_BADINDEX;
1720 default: /* Try to make it into VT_I4, can use VariantChangeType for this */
1721 hr = VariantChangeType(&varg2, &varg2, 0, VT_I4);
1722 if (SUCCEEDED(hr) && ret != ERROR_SUCCESS) hr = DISP_E_BADINDEX; /* Conversion fine, but couldn't find key */
1725 if (hr == DISP_E_TYPEMISMATCH) *puArgErr = posValue;
1726 VariantClear(&varg2); /* Unknown type, so let's clear it */
1727 VariantClear(&varg1);
1731 /* Retrieve class name or maximum value name or subkey name size */
1733 ret = RegQueryInfoKeyW(hkey, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1734 else if (V_I4(&varg2) > 0)
1735 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL);
1736 else /* V_I4(&varg2) < 0 */
1737 ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
1739 if (ret == ERROR_SUCCESS)
1741 if (!(szString = msi_alloc(++dwSize * sizeof(WCHAR))))
1742 ERR("Out of memory\n");
1743 else if (!V_I4(&varg2))
1744 ret = RegQueryInfoKeyW(hkey, szString, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1745 else if (V_I4(&varg2) > 0)
1746 ret = RegEnumValueW(hkey, V_I4(&varg2)-1, szString, &dwSize, 0, 0, NULL, NULL);
1747 else /* V_I4(&varg2) < 0 */
1748 ret = RegEnumKeyW(hkey, -1 - V_I4(&varg2), szString, dwSize);
1750 if (szString && ret == ERROR_SUCCESS)
1752 V_VT(pVarResult) = VT_BSTR;
1753 V_BSTR(pVarResult) = SysAllocString(szString);
1761 else return DISP_E_MEMBERNOTFOUND;
1764 case DISPID_INSTALLER_PRODUCTSTATE:
1765 if (wFlags & DISPATCH_PROPERTYGET) {
1766 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1767 if (FAILED(hr)) return hr;
1768 V_VT(pVarResult) = VT_I4;
1769 V_I4(pVarResult) = MsiQueryProductStateW(V_BSTR(&varg0));
1771 else return DISP_E_MEMBERNOTFOUND;
1774 case DISPID_INSTALLER_PRODUCTINFO:
1775 if (wFlags & DISPATCH_PROPERTYGET) {
1776 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1777 if (FAILED(hr)) return hr;
1778 hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
1781 VariantClear(&varg0);
1784 V_VT(pVarResult) = VT_BSTR;
1785 V_BSTR(pVarResult) = NULL;
1786 if ((ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), NULL, &dwSize)) == ERROR_SUCCESS)
1788 if (!(szString = msi_alloc((++dwSize)*sizeof(WCHAR))))
1789 ERR("Out of memory\n");
1790 else if ((ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), szString, &dwSize)) == ERROR_SUCCESS)
1791 V_BSTR(pVarResult) = SysAllocString(szString);
1794 if (ret != ERROR_SUCCESS)
1796 ERR("MsiGetProductInfo returned %d\n", ret);
1797 VariantClear(&varg1);
1798 VariantClear(&varg0);
1799 return DISP_E_EXCEPTION;
1802 else return DISP_E_MEMBERNOTFOUND;
1805 case DISPID_INSTALLER_PRODUCTS:
1806 if (wFlags & DISPATCH_PROPERTYGET)
1808 ListData *ldata = NULL;
1810 WCHAR szProductBuf[GUID_SIZE];
1812 /* Find number of products */
1813 while ((ret = MsiEnumProductsW(idx, szProductBuf)) == ERROR_SUCCESS) idx++;
1814 if (ret != ERROR_NO_MORE_ITEMS)
1816 ERR("MsiEnumProducts returned %d\n", ret);
1817 return DISP_E_EXCEPTION;
1820 V_VT(pVarResult) = VT_DISPATCH;
1821 if (SUCCEEDED(hr = create_automation_object(0, NULL, (LPVOID*)&pDispatch, &DIID_StringList, ListImpl_Invoke, ListImpl_Free, sizeof(ListData))))
1823 IDispatch_AddRef(pDispatch);
1824 V_DISPATCH(pVarResult) = pDispatch;
1826 /* Save product strings */
1827 ldata = (ListData *)private_data((AutomationObject *)pDispatch);
1828 if (!(ldata->pVars = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(VARIANT)*idx)))
1829 ERR("Out of memory\n");
1832 ldata->ulCount = idx;
1833 for (idx = 0; idx < ldata->ulCount; idx++)
1835 ret = MsiEnumProductsW(idx, szProductBuf);
1836 VariantInit(&ldata->pVars[idx]);
1837 V_VT(&ldata->pVars[idx]) = VT_BSTR;
1838 V_BSTR(&ldata->pVars[idx]) = SysAllocString(szProductBuf);
1843 ERR("Failed to create StringList object, hresult 0x%08x\n", hr);
1845 else return DISP_E_MEMBERNOTFOUND;
1848 case DISPID_INSTALLER_RELATEDPRODUCTS:
1849 if (wFlags & DISPATCH_PROPERTYGET)
1851 ListData *ldata = NULL;
1853 WCHAR szProductBuf[GUID_SIZE];
1855 hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
1856 if (FAILED(hr)) return hr;
1858 /* Find number of related products */
1859 while ((ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, szProductBuf)) == ERROR_SUCCESS) idx++;
1860 if (ret != ERROR_NO_MORE_ITEMS)
1862 VariantClear(&varg0);
1863 ERR("MsiEnumRelatedProducts returned %d\n", ret);
1864 return DISP_E_EXCEPTION;
1867 V_VT(pVarResult) = VT_DISPATCH;
1868 if (SUCCEEDED(hr = create_automation_object(0, NULL, (LPVOID*)&pDispatch, &DIID_StringList, ListImpl_Invoke, ListImpl_Free, sizeof(ListData))))
1870 IDispatch_AddRef(pDispatch);
1871 V_DISPATCH(pVarResult) = pDispatch;
1873 /* Save product strings */
1874 ldata = (ListData *)private_data((AutomationObject *)pDispatch);
1875 if (!(ldata->pVars = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(VARIANT)*idx)))
1876 ERR("Out of memory\n");
1879 ldata->ulCount = idx;
1880 for (idx = 0; idx < ldata->ulCount; idx++)
1882 ret = MsiEnumRelatedProductsW(V_BSTR(&varg0), 0, idx, szProductBuf);
1883 VariantInit(&ldata->pVars[idx]);
1884 V_VT(&ldata->pVars[idx]) = VT_BSTR;
1885 V_BSTR(&ldata->pVars[idx]) = SysAllocString(szProductBuf);
1890 ERR("Failed to create StringList object, hresult 0x%08x\n", hr);
1892 else return DISP_E_MEMBERNOTFOUND;
1896 return DISP_E_MEMBERNOTFOUND;
1899 VariantClear(&varg2);
1900 VariantClear(&varg1);
1901 VariantClear(&varg0);
1906 /* Wrapper around create_automation_object to create an installer object. */
1907 HRESULT create_msiserver(IUnknown *pOuter, LPVOID *ppObj)
1909 return create_automation_object(0, pOuter, ppObj, &DIID_Installer, InstallerImpl_Invoke, NULL, 0);
1912 /* Wrapper around create_automation_object to create a session object. */
1913 HRESULT create_session(MSIHANDLE msiHandle, IDispatch *pInstaller, IDispatch **pDispatch)
1915 HRESULT hr = create_automation_object(msiHandle, NULL, (LPVOID)pDispatch, &DIID_Session, SessionImpl_Invoke, NULL, sizeof(SessionData));
1916 if (SUCCEEDED(hr) && pDispatch && *pDispatch)
1917 ((SessionData *)private_data((AutomationObject *)*pDispatch))->pInstaller = pInstaller;