summaryrefslogtreecommitdiffstats
path: root/libmsi/automation.c
diff options
context:
space:
mode:
Diffstat (limited to 'libmsi/automation.c')
-rw-r--r--libmsi/automation.c2461
1 files changed, 2461 insertions, 0 deletions
diff --git a/libmsi/automation.c b/libmsi/automation.c
new file mode 100644
index 0000000..e55717a
--- /dev/null
+++ b/libmsi/automation.c
@@ -0,0 +1,2461 @@
+/*
+ * Implementation of OLE Automation for Microsoft Installer (msi.dll)
+ *
+ * Copyright 2007 Misha Koshelev
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define COBJMACROS
+
+#include <stdarg.h>
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "winuser.h"
+#include "winreg.h"
+#include "msidefs.h"
+#include "msipriv.h"
+#include "activscp.h"
+#include "oleauto.h"
+#include "shlwapi.h"
+#include "wine/debug.h"
+#include "wine/unicode.h"
+
+#include "msiserver.h"
+#include "msiserver_dispids.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+#define REG_INDEX_CLASSES_ROOT 0
+#define REG_INDEX_DYN_DATA 6
+
+/*
+ * AutomationObject - "base" class for all automation objects. For each interface, we implement Invoke function
+ * called from AutomationObject::Invoke.
+ */
+
+typedef struct AutomationObject AutomationObject;
+
+typedef HRESULT (*autoInvokeFunc)(AutomationObject* This,
+ DISPID dispIdMember, REFIID riid, LCID lcid, WORD flags, DISPPARAMS* pDispParams,
+ VARIANT* result, EXCEPINFO* ei, UINT* arg_err);
+
+typedef void (*autoFreeFunc)(AutomationObject* This);
+
+struct AutomationObject {
+ IDispatch IDispatch_iface;
+ IProvideMultipleClassInfo IProvideMultipleClassInfo_iface;
+ LONG ref;
+
+ /* Clsid for this class and it's appropriate ITypeInfo object */
+ LPCLSID clsid;
+ ITypeInfo *iTypeInfo;
+
+ /* The MSI handle of the current object */
+ MSIHANDLE msiHandle;
+
+ /* A function that is called from AutomationObject::Invoke, specific to this type of object. */
+ autoInvokeFunc funcInvoke;
+ /* A function that is called from AutomationObject::Release when the object is being freed to free any private
+ * data structures (or NULL) */
+ autoFreeFunc funcFree;
+};
+
+typedef struct {
+ AutomationObject autoobj;
+ int count;
+ VARIANT *data;
+} ListObject;
+
+static HRESULT create_database(MSIHANDLE, IDispatch**);
+static HRESULT create_list_enumerator(ListObject*, void**);
+static HRESULT create_summaryinfo(MSIHANDLE, IDispatch**);
+static HRESULT create_view(MSIHANDLE, IDispatch**);
+
+/* ListEnumerator - IEnumVARIANT implementation for MSI automation lists */
+typedef struct {
+ IEnumVARIANT IEnumVARIANT_iface;
+ LONG ref;
+
+ /* Current position and pointer to AutomationObject that stores actual data */
+ ULONG pos;
+ ListObject *list;
+} ListEnumerator;
+
+typedef struct {
+ AutomationObject autoobj;
+ IDispatch *installer;
+} SessionObject;
+
+static inline AutomationObject *impl_from_IProvideMultipleClassInfo( IProvideMultipleClassInfo *iface )
+{
+ return CONTAINING_RECORD(iface, AutomationObject, IProvideMultipleClassInfo_iface);
+}
+
+static inline AutomationObject *impl_from_IDispatch( IDispatch *iface )
+{
+ return CONTAINING_RECORD(iface, AutomationObject, IDispatch_iface);
+}
+
+/* Load type info so we don't have to process GetIDsOfNames */
+HRESULT load_type_info(IDispatch *iface, ITypeInfo **pptinfo, REFIID clsid, LCID lcid)
+{
+ static const WCHAR msiserverW[] = {'m','s','i','s','e','r','v','e','r','.','t','l','b',0};
+ ITypeInfo *ti = NULL;
+ ITypeLib *lib = NULL;
+ HRESULT hr;
+
+ TRACE("(%p)->(%s, %d)\n", iface, debugstr_guid(clsid), lcid);
+
+ /* Load registered type library */
+ hr = LoadRegTypeLib(&LIBID_WindowsInstaller, 1, 0, lcid, &lib);
+ if (FAILED(hr)) {
+ hr = LoadTypeLib(msiserverW, &lib);
+ if (FAILED(hr)) {
+ ERR("Could not load msiserver.tlb\n");
+ return hr;
+ }
+ }
+
+ /* Get type information for object */
+ hr = ITypeLib_GetTypeInfoOfGuid(lib, clsid, &ti);
+ ITypeLib_Release(lib);
+ if (FAILED(hr)) {
+ ERR("Could not load ITypeInfo for %s\n", debugstr_guid(clsid));
+ return hr;
+ }
+ *pptinfo = ti;
+ return S_OK;
+}
+
+/* AutomationObject methods */
+static HRESULT WINAPI AutomationObject_QueryInterface(IDispatch* iface, REFIID riid, void** ppvObject)
+{
+ AutomationObject *This = impl_from_IDispatch(iface);
+
+ TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
+
+ if (ppvObject == NULL)
+ return E_INVALIDARG;
+
+ *ppvObject = 0;
+
+ if (IsEqualGUID(riid, &IID_IUnknown) ||
+ IsEqualGUID(riid, &IID_IDispatch) ||
+ IsEqualGUID(riid, This->clsid))
+ *ppvObject = &This->IDispatch_iface;
+ else if (IsEqualGUID(riid, &IID_IProvideClassInfo) ||
+ IsEqualGUID(riid, &IID_IProvideClassInfo2) ||
+ IsEqualGUID(riid, &IID_IProvideMultipleClassInfo))
+ *ppvObject = &This->IProvideMultipleClassInfo_iface;
+ else
+ {
+ TRACE("() : asking for unsupported interface %s\n", debugstr_guid(riid));
+ return E_NOINTERFACE;
+ }
+
+ IDispatch_AddRef(iface);
+
+ return S_OK;
+}
+
+static ULONG WINAPI AutomationObject_AddRef(IDispatch* iface)
+{
+ AutomationObject *This = impl_from_IDispatch(iface);
+
+ TRACE("(%p/%p)\n", iface, This);
+
+ return InterlockedIncrement(&This->ref);
+}
+
+static ULONG WINAPI AutomationObject_Release(IDispatch* iface)
+{
+ AutomationObject *This = impl_from_IDispatch(iface);
+ ULONG ref = InterlockedDecrement(&This->ref);
+
+ TRACE("(%p/%p)\n", iface, This);
+
+ if (!ref)
+ {
+ if (This->funcFree) This->funcFree(This);
+ ITypeInfo_Release(This->iTypeInfo);
+ MsiCloseHandle(This->msiHandle);
+ msi_free(This);
+ }
+
+ return ref;
+}
+
+static HRESULT WINAPI AutomationObject_GetTypeInfoCount(
+ IDispatch* iface,
+ UINT* pctinfo)
+{
+ AutomationObject *This = impl_from_IDispatch(iface);
+
+ TRACE("(%p/%p)->(%p)\n", iface, This, pctinfo);
+ *pctinfo = 1;
+ return S_OK;
+}
+
+static HRESULT WINAPI AutomationObject_GetTypeInfo(
+ IDispatch* iface,
+ UINT iTInfo,
+ LCID lcid,
+ ITypeInfo** ppTInfo)
+{
+ AutomationObject *This = impl_from_IDispatch(iface);
+ TRACE("(%p/%p)->(%d,%d,%p)\n", iface, This, iTInfo, lcid, ppTInfo);
+
+ ITypeInfo_AddRef(This->iTypeInfo);
+ *ppTInfo = This->iTypeInfo;
+ return S_OK;
+}
+
+static HRESULT WINAPI AutomationObject_GetIDsOfNames(
+ IDispatch* iface,
+ REFIID riid,
+ LPOLESTR* rgszNames,
+ UINT cNames,
+ LCID lcid,
+ DISPID* rgDispId)
+{
+ AutomationObject *This = impl_from_IDispatch(iface);
+ HRESULT hr;
+ TRACE("(%p/%p)->(%p,%p,%d,%d,%p)\n", iface, This, riid, rgszNames, cNames, lcid, rgDispId);
+
+ if (!IsEqualGUID(riid, &IID_NULL)) return E_INVALIDARG;
+ hr = ITypeInfo_GetIDsOfNames(This->iTypeInfo, rgszNames, cNames, rgDispId);
+ if (hr == DISP_E_UNKNOWNNAME)
+ {
+ UINT idx;
+ for (idx=0; idx<cNames; idx++)
+ {
+ if (rgDispId[idx] == DISPID_UNKNOWN)
+ FIXME("Unknown member %s, clsid %s\n", debugstr_w(rgszNames[idx]), debugstr_guid(This->clsid));
+ }
+ }
+ return hr;
+}
+
+/* Maximum number of allowed function parameters+1 */
+#define MAX_FUNC_PARAMS 20
+
+/* Some error checking is done here to simplify individual object function invocation */
+static HRESULT WINAPI AutomationObject_Invoke(
+ IDispatch* iface,
+ DISPID dispIdMember,
+ REFIID riid,
+ LCID lcid,
+ WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ AutomationObject *This = impl_from_IDispatch(iface);
+ HRESULT hr;
+ unsigned int uArgErr;
+ VARIANT varResultDummy;
+ BSTR bstrName = NULL;
+
+ TRACE("(%p/%p)->(%d,%p,%d,%d,%p,%p,%p,%p)\n", iface, This, dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
+
+ if (!IsEqualIID(riid, &IID_NULL))
+ {
+ ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
+ return DISP_E_UNKNOWNNAME;
+ }
+
+ if (wFlags & DISPATCH_PROPERTYGET && !pVarResult)
+ {
+ ERR("NULL pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
+ return DISP_E_PARAMNOTOPTIONAL;
+ }
+
+ /* This simplifies our individual object invocation functions */
+ if (puArgErr == NULL) puArgErr = &uArgErr;
+ if (pVarResult == NULL) pVarResult = &varResultDummy;
+
+ /* Assume return type is void unless determined otherwise */
+ VariantInit(pVarResult);
+
+ /* If we are tracing, we want to see the name of the member we are invoking */
+ if (TRACE_ON(msi))
+ {
+ ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL);
+ TRACE("Method %d, %s\n", dispIdMember, debugstr_w(bstrName));
+ }
+
+ hr = This->funcInvoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr);
+
+ if (hr == DISP_E_MEMBERNOTFOUND) {
+ if (bstrName == NULL) ITypeInfo_GetDocumentation(This->iTypeInfo, dispIdMember, &bstrName, NULL, NULL, NULL);
+ FIXME("Method %d, %s wflags %d not implemented, clsid %s\n", dispIdMember, debugstr_w(bstrName), wFlags, debugstr_guid(This->clsid));
+ }
+ else if (pExcepInfo &&
+ (hr == DISP_E_PARAMNOTFOUND ||
+ hr == DISP_E_EXCEPTION)) {
+ static const WCHAR szComma[] = { ',',0 };
+ static const WCHAR szExceptionSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
+ WCHAR szExceptionDescription[MAX_PATH];
+ BSTR bstrParamNames[MAX_FUNC_PARAMS];
+ unsigned namesNo, i;
+ BOOL bFirst = TRUE;
+
+ if (FAILED(ITypeInfo_GetNames(This->iTypeInfo, dispIdMember, bstrParamNames,
+ MAX_FUNC_PARAMS, &namesNo)))
+ {
+ TRACE("Failed to retrieve names for dispIdMember %d\n", dispIdMember);
+ }
+ else
+ {
+ memset(szExceptionDescription, 0, sizeof(szExceptionDescription));
+ for (i=0; i<namesNo; i++)
+ {
+ if (bFirst) bFirst = FALSE;
+ else {
+ lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], szComma);
+ }
+ lstrcpyW(&szExceptionDescription[lstrlenW(szExceptionDescription)], bstrParamNames[i]);
+ SysFreeString(bstrParamNames[i]);
+ }
+
+ memset(pExcepInfo, 0, sizeof(EXCEPINFO));
+ pExcepInfo->wCode = 1000;
+ pExcepInfo->bstrSource = SysAllocString(szExceptionSource);
+ pExcepInfo->bstrDescription = SysAllocString(szExceptionDescription);
+ hr = DISP_E_EXCEPTION;
+ }
+ }
+
+ /* Make sure we free the return variant if it is our dummy variant */
+ if (pVarResult == &varResultDummy) VariantClear(pVarResult);
+
+ /* Free function name if we retrieved it */
+ SysFreeString(bstrName);
+
+ TRACE("Returning 0x%08x, %s\n", hr, SUCCEEDED(hr) ? "ok" : "not ok");
+
+ return hr;
+}
+
+static const struct IDispatchVtbl AutomationObjectVtbl =
+{
+ AutomationObject_QueryInterface,
+ AutomationObject_AddRef,
+ AutomationObject_Release,
+ AutomationObject_GetTypeInfoCount,
+ AutomationObject_GetTypeInfo,
+ AutomationObject_GetIDsOfNames,
+ AutomationObject_Invoke
+};
+
+/*
+ * IProvideMultipleClassInfo methods
+ */
+
+static HRESULT WINAPI ProvideMultipleClassInfo_QueryInterface(
+ IProvideMultipleClassInfo* iface,
+ REFIID riid,
+ VOID** ppvoid)
+{
+ AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
+ return IDispatch_QueryInterface(&This->IDispatch_iface, riid, ppvoid);
+}
+
+static ULONG WINAPI ProvideMultipleClassInfo_AddRef(IProvideMultipleClassInfo* iface)
+{
+ AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
+ return IDispatch_AddRef(&This->IDispatch_iface);
+}
+
+static ULONG WINAPI ProvideMultipleClassInfo_Release(IProvideMultipleClassInfo* iface)
+{
+ AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
+ return IDispatch_Release(&This->IDispatch_iface);
+}
+
+static HRESULT WINAPI ProvideMultipleClassInfo_GetClassInfo(IProvideMultipleClassInfo* iface, ITypeInfo** ppTI)
+{
+ AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
+ TRACE("(%p/%p)->(%p)\n", iface, This, ppTI);
+ return load_type_info(&This->IDispatch_iface, ppTI, This->clsid, 0);
+}
+
+static HRESULT WINAPI ProvideMultipleClassInfo_GetGUID(IProvideMultipleClassInfo* iface, DWORD dwGuidKind, GUID* pGUID)
+{
+ AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
+ TRACE("(%p/%p)->(%d,%s)\n", iface, This, dwGuidKind, debugstr_guid(pGUID));
+
+ if (dwGuidKind != GUIDKIND_DEFAULT_SOURCE_DISP_IID)
+ return E_INVALIDARG;
+ else {
+ *pGUID = *This->clsid;
+ return S_OK;
+ }
+}
+
+static HRESULT WINAPI ProvideMultipleClassInfo_GetMultiTypeInfoCount(IProvideMultipleClassInfo* iface, ULONG* pcti)
+{
+ AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
+
+ TRACE("(%p/%p)->(%p)\n", iface, This, pcti);
+ *pcti = 1;
+ return S_OK;
+}
+
+static HRESULT WINAPI ProvideMultipleClassInfo_GetInfoOfIndex(IProvideMultipleClassInfo* iface,
+ ULONG iti,
+ DWORD dwFlags,
+ ITypeInfo** pptiCoClass,
+ DWORD* pdwTIFlags,
+ ULONG* pcdispidReserved,
+ IID* piidPrimary,
+ IID* piidSource)
+{
+ AutomationObject *This = impl_from_IProvideMultipleClassInfo(iface);
+
+ TRACE("(%p/%p)->(%d,%d,%p,%p,%p,%p,%p)\n", iface, This, iti, dwFlags, pptiCoClass, pdwTIFlags, pcdispidReserved, piidPrimary, piidSource);
+
+ if (iti != 0)
+ return E_INVALIDARG;
+
+ if (dwFlags & MULTICLASSINFO_GETTYPEINFO)
+ load_type_info(&This->IDispatch_iface, pptiCoClass, This->clsid, 0);
+
+ if (dwFlags & MULTICLASSINFO_GETNUMRESERVEDDISPIDS)
+ {
+ *pdwTIFlags = 0;
+ *pcdispidReserved = 0;
+ }
+
+ if (dwFlags & MULTICLASSINFO_GETIIDPRIMARY){
+ *piidPrimary = *This->clsid;
+ }
+
+ if (dwFlags & MULTICLASSINFO_GETIIDSOURCE){
+ *piidSource = *This->clsid;
+ }
+
+ return S_OK;
+}
+
+static const IProvideMultipleClassInfoVtbl ProvideMultipleClassInfoVtbl =
+{
+ ProvideMultipleClassInfo_QueryInterface,
+ ProvideMultipleClassInfo_AddRef,
+ ProvideMultipleClassInfo_Release,
+ ProvideMultipleClassInfo_GetClassInfo,
+ ProvideMultipleClassInfo_GetGUID,
+ ProvideMultipleClassInfo_GetMultiTypeInfoCount,
+ ProvideMultipleClassInfo_GetInfoOfIndex
+};
+
+static HRESULT init_automation_object(AutomationObject *This, MSIHANDLE msiHandle, REFIID clsid,
+ autoInvokeFunc invokeFunc, autoFreeFunc freeFunc)
+{
+ TRACE("(%p, %d, %s, %p, %p)\n", This, msiHandle, debugstr_guid(clsid), invokeFunc, freeFunc);
+
+ This->IDispatch_iface.lpVtbl = &AutomationObjectVtbl;
+ This->IProvideMultipleClassInfo_iface.lpVtbl = &ProvideMultipleClassInfoVtbl;
+ This->ref = 1;
+
+ This->msiHandle = msiHandle;
+ This->clsid = (LPCLSID)clsid;
+ This->funcInvoke = invokeFunc;
+ This->funcFree = freeFunc;
+
+ /* Load our TypeInfo so we don't have to process GetIDsOfNames */
+ This->iTypeInfo = NULL;
+ return load_type_info(&This->IDispatch_iface, &This->iTypeInfo, clsid, 0);
+}
+
+/*
+ * ListEnumerator methods
+ */
+
+static inline ListEnumerator *impl_from_IEnumVARIANT(IEnumVARIANT* iface)
+{
+ return CONTAINING_RECORD(iface, ListEnumerator, IEnumVARIANT_iface);
+}
+
+static HRESULT WINAPI ListEnumerator_QueryInterface(IEnumVARIANT* iface, REFIID riid,
+ void** ppvObject)
+{
+ ListEnumerator *This = impl_from_IEnumVARIANT(iface);
+
+ TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
+
+ if (ppvObject == NULL)
+ return E_INVALIDARG;
+
+ *ppvObject = 0;
+
+ if (IsEqualGUID(riid, &IID_IUnknown) ||
+ IsEqualGUID(riid, &IID_IEnumVARIANT))
+ {
+ *ppvObject = &This->IEnumVARIANT_iface;
+ }
+ else
+ {
+ TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid));
+ return E_NOINTERFACE;
+ }
+
+ IEnumVARIANT_AddRef(iface);
+ return S_OK;
+}
+
+static ULONG WINAPI ListEnumerator_AddRef(IEnumVARIANT* iface)
+{
+ ListEnumerator *This = impl_from_IEnumVARIANT(iface);
+
+ TRACE("(%p/%p)\n", iface, This);
+
+ return InterlockedIncrement(&This->ref);
+}
+
+static ULONG WINAPI ListEnumerator_Release(IEnumVARIANT* iface)
+{
+ ListEnumerator *This = impl_from_IEnumVARIANT(iface);
+ ULONG ref = InterlockedDecrement(&This->ref);
+
+ TRACE("(%p/%p)\n", iface, This);
+
+ if (!ref)
+ {
+ if (This->list) IDispatch_Release(&This->list->autoobj.IDispatch_iface);
+ msi_free(This);
+ }
+
+ return ref;
+}
+
+static HRESULT WINAPI ListEnumerator_Next(IEnumVARIANT* iface, ULONG celt, VARIANT* rgVar,
+ ULONG* fetched)
+{
+ ListEnumerator *This = impl_from_IEnumVARIANT(iface);
+ ULONG i, local;
+
+ TRACE("(%p, %uld, %p, %p)\n", iface, celt, rgVar, fetched);
+
+ if (fetched) *fetched = 0;
+
+ if (!rgVar)
+ return S_FALSE;
+
+ for (local = 0; local < celt; local++)
+ VariantInit(&rgVar[local]);
+
+ for (i = This->pos, local = 0; i < This->list->count && local < celt; i++, local++)
+ VariantCopy(&rgVar[local], &This->list->data[i]);
+
+ if (fetched) *fetched = local;
+ This->pos = i;
+
+ return (local < celt) ? S_FALSE : S_OK;
+}
+
+static HRESULT WINAPI ListEnumerator_Skip(IEnumVARIANT* iface, ULONG celt)
+{
+ ListEnumerator *This = impl_from_IEnumVARIANT(iface);
+
+ TRACE("(%p,%uld)\n", iface, celt);
+
+ This->pos += celt;
+ if (This->pos >= This->list->count)
+ {
+ This->pos = This->list->count;
+ return S_FALSE;
+ }
+
+ return S_OK;
+}
+
+static HRESULT WINAPI ListEnumerator_Reset(IEnumVARIANT* iface)
+{
+ ListEnumerator *This = impl_from_IEnumVARIANT(iface);
+
+ TRACE("(%p)\n", iface);
+
+ This->pos = 0;
+ return S_OK;
+}
+
+static HRESULT WINAPI ListEnumerator_Clone(IEnumVARIANT* iface, IEnumVARIANT **ppEnum)
+{
+ ListEnumerator *This = impl_from_IEnumVARIANT(iface);
+ HRESULT hr;
+
+ TRACE("(%p,%p)\n", iface, ppEnum);
+
+ if (ppEnum == NULL)
+ return S_FALSE;
+
+ *ppEnum = NULL;
+ hr = create_list_enumerator(This->list, (LPVOID *)ppEnum);
+ if (FAILED(hr))
+ {
+ if (*ppEnum) IEnumVARIANT_Release(*ppEnum);
+ return hr;
+ }
+
+ return S_OK;
+}
+
+static const struct IEnumVARIANTVtbl ListEnumerator_Vtbl =
+{
+ ListEnumerator_QueryInterface,
+ ListEnumerator_AddRef,
+ ListEnumerator_Release,
+ ListEnumerator_Next,
+ ListEnumerator_Skip,
+ ListEnumerator_Reset,
+ ListEnumerator_Clone
+};
+
+/* Create a list enumerator, placing the result in the pointer ppObj. */
+static HRESULT create_list_enumerator(ListObject *list, void **ppObj)
+{
+ ListEnumerator *object;
+
+ TRACE("(%p, %p)\n", list, ppObj);
+
+ object = msi_alloc(sizeof(ListEnumerator));
+
+ /* Set all the VTable references */
+ object->IEnumVARIANT_iface.lpVtbl = &ListEnumerator_Vtbl;
+ object->ref = 1;
+
+ /* Store data that was passed */
+ object->pos = 0;
+ object->list = list;
+ if (list) IDispatch_AddRef(&list->autoobj.IDispatch_iface);
+
+ *ppObj = object;
+ return S_OK;
+}
+
+/*
+ * Individual Object Invocation Functions
+ */
+
+/* Helper function that copies a passed parameter instead of using VariantChangeType like the actual DispGetParam.
+ This function is only for VARIANT type parameters that have several types that cannot be properly discriminated
+ using DispGetParam/VariantChangeType. */
+static HRESULT DispGetParam_CopyOnly(
+ DISPPARAMS *pdispparams, /* [in] Parameter list */
+ UINT *position, /* [in] Position of parameter to copy in pdispparams; on return will contain calculated position */
+ VARIANT *pvarResult) /* [out] Destination for resulting variant */
+{
+ /* position is counted backwards */
+ UINT pos;
+
+ TRACE("position=%d, cArgs=%d, cNamedArgs=%d\n",
+ *position, pdispparams->cArgs, pdispparams->cNamedArgs);
+ if (*position < pdispparams->cArgs) {
+ /* positional arg? */
+ pos = pdispparams->cArgs - *position - 1;
+ } else {
+ /* FIXME: is this how to handle named args? */
+ for (pos=0; pos<pdispparams->cNamedArgs; pos++)
+ if (pdispparams->rgdispidNamedArgs[pos] == *position) break;
+
+ if (pos==pdispparams->cNamedArgs)
+ return DISP_E_PARAMNOTFOUND;
+ }
+ *position = pos;
+ return VariantCopyInd(pvarResult,
+ &pdispparams->rgvarg[pos]);
+}
+
+static HRESULT SummaryInfoImpl_Invoke(
+ AutomationObject* This,
+ DISPID dispIdMember,
+ REFIID riid,
+ LCID lcid,
+ WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ UINT ret;
+ VARIANTARG varg0, varg1;
+ FILETIME ft, ftlocal;
+ SYSTEMTIME st;
+ HRESULT hr;
+
+ VariantInit(&varg0);
+ VariantInit(&varg1);
+
+ switch (dispIdMember)
+ {
+ case DISPID_SUMMARYINFO_PROPERTY:
+ if (wFlags & DISPATCH_PROPERTYGET)
+ {
+ UINT type;
+ INT value;
+ DWORD size = 0;
+ DATE date;
+ LPWSTR str;
+
+ static WCHAR szEmpty[] = {0};
+
+ hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
+ if (FAILED(hr)) return hr;
+ ret = MsiSummaryInfoGetPropertyW(This->msiHandle, V_I4(&varg0), &type, &value,
+ &ft, szEmpty, &size);
+ if (ret != ERROR_SUCCESS &&
+ ret != ERROR_MORE_DATA)
+ {
+ ERR("MsiSummaryInfoGetProperty returned %d\n", ret);
+ return DISP_E_EXCEPTION;
+ }
+
+ switch (type)
+ {
+ case VT_EMPTY:
+ break;
+
+ case VT_I2:
+ case VT_I4:
+ V_VT(pVarResult) = VT_I4;
+ V_I4(pVarResult) = value;
+ break;
+
+ case VT_LPSTR:
+ if (!(str = msi_alloc(++size * sizeof(WCHAR))))
+ ERR("Out of memory\n");
+ else if ((ret = MsiSummaryInfoGetPropertyW(This->msiHandle, V_I4(&varg0), &type, NULL,
+ NULL, str, &size)) != ERROR_SUCCESS)
+ ERR("MsiSummaryInfoGetProperty returned %d\n", ret);
+ else
+ {
+ V_VT(pVarResult) = VT_BSTR;
+ V_BSTR(pVarResult) = SysAllocString(str);
+ }
+ msi_free(str);
+ break;
+
+ case VT_FILETIME:
+ FileTimeToLocalFileTime(&ft, &ftlocal);
+ FileTimeToSystemTime(&ftlocal, &st);
+ SystemTimeToVariantTime(&st, &date);
+
+ V_VT(pVarResult) = VT_DATE;
+ V_DATE(pVarResult) = date;
+ break;
+
+ default:
+ ERR("Unhandled variant type %d\n", type);
+ }
+ }
+ else if (wFlags & DISPATCH_PROPERTYPUT)
+ {
+ UINT posValue = DISPID_PROPERTYPUT;
+
+ hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
+ if (FAILED(hr)) return hr;
+ hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg1);
+ if (FAILED(hr))
+ {
+ *puArgErr = posValue;
+ return hr;
+ }
+
+ switch (V_VT(&varg1))
+ {
+ case VT_I2:
+ case VT_I4:
+ ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), V_VT(&varg1), V_I4(&varg1), NULL, NULL);
+ break;
+
+ case VT_DATE:
+ VariantTimeToSystemTime(V_DATE(&varg1), &st);
+ SystemTimeToFileTime(&st, &ftlocal);
+ LocalFileTimeToFileTime(&ftlocal, &ft);
+ ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), VT_FILETIME, 0, &ft, NULL);
+ break;
+
+ case VT_BSTR:
+ ret = MsiSummaryInfoSetPropertyW(This->msiHandle, V_I4(&varg0), VT_LPSTR, 0, NULL, V_BSTR(&varg1));
+ break;
+
+ default:
+ FIXME("Unhandled variant type %d\n", V_VT(&varg1));
+ VariantClear(&varg1);
+ return DISP_E_EXCEPTION;
+ }
+
+ if (ret != ERROR_SUCCESS)
+ {
+ ERR("MsiSummaryInfoSetPropertyW returned %d\n", ret);
+ return DISP_E_EXCEPTION;
+ }
+ }
+ else return DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_SUMMARYINFO_PROPERTYCOUNT:
+ if (wFlags & DISPATCH_PROPERTYGET) {
+ UINT count;
+ if ((ret = MsiSummaryInfoGetPropertyCount(This->msiHandle, &count)) != ERROR_SUCCESS)
+ ERR("MsiSummaryInfoGetPropertyCount returned %d\n", ret);
+ else
+ {
+ V_VT(pVarResult) = VT_I4;
+ V_I4(pVarResult) = count;
+ }
+ }
+ else return DISP_E_MEMBERNOTFOUND;
+ break;
+
+ default:
+ return DISP_E_MEMBERNOTFOUND;
+ }
+
+ VariantClear(&varg1);
+ VariantClear(&varg0);
+
+ return S_OK;
+}
+
+static HRESULT RecordImpl_Invoke(
+ AutomationObject* This,
+ DISPID dispIdMember,
+ REFIID riid,
+ LCID lcid,
+ WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ WCHAR *szString;
+ DWORD dwLen;
+ UINT ret;
+ VARIANTARG varg0, varg1;
+ HRESULT hr;
+
+ VariantInit(&varg0);
+ VariantInit(&varg1);
+
+ switch (dispIdMember)
+ {
+ case DISPID_RECORD_FIELDCOUNT:
+ if (wFlags & DISPATCH_PROPERTYGET) {
+ V_VT(pVarResult) = VT_I4;
+ V_I4(pVarResult) = MsiRecordGetFieldCount(This->msiHandle);
+ }
+ else return DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_RECORD_STRINGDATA:
+ if (wFlags & DISPATCH_PROPERTYGET) {
+ hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
+ if (FAILED(hr)) return hr;
+ V_VT(pVarResult) = VT_BSTR;
+ V_BSTR(pVarResult) = NULL;
+ if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
+ {
+ if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
+ ERR("Out of memory\n");
+ else if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
+ V_BSTR(pVarResult) = SysAllocString(szString);
+ msi_free(szString);
+ }
+ if (ret != ERROR_SUCCESS)
+ ERR("MsiRecordGetString returned %d\n", ret);
+ } else if (wFlags & DISPATCH_PROPERTYPUT) {
+ hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
+ if (FAILED(hr)) return hr;
+ hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
+ if (FAILED(hr)) return hr;
+ if ((ret = MsiRecordSetStringW(This->msiHandle, V_I4(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
+ {
+ VariantClear(&varg1);
+ ERR("MsiRecordSetString returned %d\n", ret);
+ return DISP_E_EXCEPTION;
+ }
+ }
+ else return DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_RECORD_INTEGERDATA:
+ if (wFlags & DISPATCH_PROPERTYGET) {
+ hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
+ if (FAILED(hr)) return hr;
+ V_VT(pVarResult) = VT_I4;
+ V_I4(pVarResult) = MsiRecordGetInteger(This->msiHandle, V_I4(&varg0));
+ } else if (wFlags & DISPATCH_PROPERTYPUT) {
+ hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
+ if (FAILED(hr)) return hr;
+ hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
+ if (FAILED(hr)) return hr;
+ if ((ret = MsiRecordSetInteger(This->msiHandle, V_I4(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
+ {
+ ERR("MsiRecordSetInteger returned %d\n", ret);
+ return DISP_E_EXCEPTION;
+ }
+ }
+ else return DISP_E_MEMBERNOTFOUND;
+ break;
+
+ default:
+ return DISP_E_MEMBERNOTFOUND;
+ }
+
+ VariantClear(&varg1);
+ VariantClear(&varg0);
+
+ return S_OK;
+}
+
+static HRESULT create_record(MSIHANDLE msiHandle, IDispatch **disp)
+{
+ AutomationObject *record;
+ HRESULT hr;
+
+ record = msi_alloc(sizeof(*record));
+ if (!record) return E_OUTOFMEMORY;
+
+ hr = init_automation_object(record, msiHandle, &DIID_Record, RecordImpl_Invoke, NULL);
+ if (hr != S_OK)
+ {
+ msi_free(record);
+ return hr;
+ }
+
+ *disp = &record->IDispatch_iface;
+
+ return hr;
+}
+
+static HRESULT ListImpl_Invoke(
+ AutomationObject* This,
+ DISPID dispIdMember,
+ REFIID riid,
+ LCID lcid,
+ WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ ListObject *list = (ListObject*)This;
+ IUnknown *pUnk = NULL;
+ HRESULT hr;
+
+ switch (dispIdMember)
+ {
+ case DISPID_LIST__NEWENUM:
+ if (wFlags & DISPATCH_METHOD) {
+ V_VT(pVarResult) = VT_UNKNOWN;
+ if (SUCCEEDED(hr = create_list_enumerator(list, (LPVOID *)&pUnk)))
+ V_UNKNOWN(pVarResult) = pUnk;
+ else
+ ERR("Failed to create IEnumVARIANT object, hresult 0x%08x\n", hr);
+ }
+ else return DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_LIST_ITEM:
+ if (wFlags & DISPATCH_PROPERTYGET) {
+ VARIANTARG index;
+
+ VariantInit(&index);
+ hr = DispGetParam(pDispParams, 0, VT_I4, &index, puArgErr);
+ if (FAILED(hr)) return hr;
+ if (V_I4(&index) < 0 || V_I4(&index) >= list->count)
+ return DISP_E_BADINDEX;
+ VariantCopy(pVarResult, &list->data[V_I4(&index)]);
+ }
+ else return DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_LIST_COUNT:
+ if (wFlags & DISPATCH_PROPERTYGET) {
+ V_VT(pVarResult) = VT_I4;
+ V_I4(pVarResult) = list->count;
+ }
+ else return DISP_E_MEMBERNOTFOUND;
+ break;
+
+ default:
+ return DISP_E_MEMBERNOTFOUND;
+ }
+
+ return S_OK;
+}
+
+static void ListImpl_Free(AutomationObject *This)
+{
+ ListObject *list = (ListObject*)This;
+ int i;
+
+ for (i = 0; i < list->count; i++)
+ VariantClear(&list->data[i]);
+ msi_free(list->data);
+}
+
+static HRESULT get_products_count(const WCHAR *product, int *len)
+{
+ int i = 0;
+
+ while (1)
+ {
+ WCHAR dataW[GUID_SIZE];
+ UINT ret;
+
+ /* all or related only */
+ if (product)
+ ret = MsiEnumRelatedProductsW(product, 0, i, dataW);
+ else
+ ret = MsiEnumProductsW(i, dataW);
+
+ if (ret == ERROR_NO_MORE_ITEMS) break;
+
+ if (ret != ERROR_SUCCESS)
+ return DISP_E_EXCEPTION;
+
+ i++;
+ }
+
+ *len = i;
+
+ return S_OK;
+}
+
+static HRESULT create_list(const WCHAR *product, IDispatch **dispatch)
+{
+ ListObject *list;
+ HRESULT hr;
+ int i;
+
+ list = msi_alloc_zero(sizeof(ListObject));
+ if (!list) return E_OUTOFMEMORY;
+
+ hr = init_automation_object(&list->autoobj, 0, &DIID_StringList, ListImpl_Invoke, ListImpl_Free);
+ if (hr != S_OK)
+ {
+ msi_free(list);
+ return hr;
+ }
+
+ *dispatch = &list->autoobj.IDispatch_iface;
+
+ hr = get_products_count(product, &list->count);
+ if (hr != S_OK)
+ {
+ IDispatch_Release(*dispatch);
+ return hr;
+ }
+
+ list->data = msi_alloc(list->count*sizeof(VARIANT));
+ if (!list->data)
+ {
+ IDispatch_Release(*dispatch);
+ return E_OUTOFMEMORY;
+ }
+
+ for (i = 0; i < list->count; i++)
+ {
+ WCHAR dataW[GUID_SIZE];
+ UINT ret;
+
+ /* all or related only */
+ if (product)
+ ret = MsiEnumRelatedProductsW(product, 0, i, dataW);
+ else
+ ret = MsiEnumProductsW(i, dataW);
+
+ if (ret == ERROR_NO_MORE_ITEMS) break;
+
+ V_VT(&list->data[i]) = VT_BSTR;
+ V_BSTR(&list->data[i]) = SysAllocString(dataW);
+ }
+
+ return S_OK;
+}
+
+static HRESULT ViewImpl_Invoke(
+ AutomationObject* This,
+ DISPID dispIdMember,
+ REFIID riid,
+ LCID lcid,
+ WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ MSIHANDLE msiHandle;
+ UINT ret;
+ VARIANTARG varg0, varg1;
+ HRESULT hr;
+
+ VariantInit(&varg0);
+ VariantInit(&varg1);
+
+ switch (dispIdMember)
+ {
+ case DISPID_VIEW_EXECUTE:
+ if (wFlags & DISPATCH_METHOD)
+ {
+ hr = DispGetParam(pDispParams, 0, VT_DISPATCH, &varg0, puArgErr);
+ if (SUCCEEDED(hr) && V_DISPATCH(&varg0) != NULL)
+ MsiViewExecute(This->msiHandle, ((AutomationObject *)V_DISPATCH(&varg0))->msiHandle);
+ else
+ MsiViewExecute(This->msiHandle, 0);
+ }
+ else return DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_VIEW_FETCH:
+ if (wFlags & DISPATCH_METHOD)
+ {
+ V_VT(pVarResult) = VT_DISPATCH;
+ if ((ret = MsiViewFetch(This->msiHandle, &msiHandle)) == ERROR_SUCCESS)
+ {
+ IDispatch *dispatch = NULL;
+
+ if (SUCCEEDED(hr = create_record(msiHandle, &dispatch)))
+ V_DISPATCH(pVarResult) = dispatch;
+ else
+ ERR("Failed to create Record object, hresult 0x%08x\n", hr);
+ }
+ else if (ret == ERROR_NO_MORE_ITEMS)
+ V_DISPATCH(pVarResult) = NULL;
+ else
+ {
+ ERR("MsiViewFetch returned %d\n", ret);
+ return DISP_E_EXCEPTION;
+ }
+ }
+ else return DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_VIEW_MODIFY:
+ if (wFlags & DISPATCH_METHOD)
+ {
+ hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
+ if (FAILED(hr)) return hr;
+ hr = DispGetParam(pDispParams, 1, VT_DISPATCH, &varg1, puArgErr);
+ if (FAILED(hr)) return hr;
+ if (!V_DISPATCH(&varg1)) return DISP_E_EXCEPTION;
+ if ((ret = MsiViewModify(This->msiHandle, V_I4(&varg0), ((AutomationObject *)V_DISPATCH(&varg1))->msiHandle)) != ERROR_SUCCESS)
+ {
+ VariantClear(&varg1);
+ ERR("MsiViewModify returned %d\n", ret);
+ return DISP_E_EXCEPTION;
+ }
+ }
+ else return DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_VIEW_CLOSE:
+ if (wFlags & DISPATCH_METHOD)
+ {
+ MsiViewClose(This->msiHandle);
+ }
+ else return DISP_E_MEMBERNOTFOUND;
+ break;
+
+ default:
+ return DISP_E_MEMBERNOTFOUND;
+ }
+
+ VariantClear(&varg1);
+ VariantClear(&varg0);
+
+ return S_OK;
+}
+
+static HRESULT DatabaseImpl_LastErrorRecord(WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ if (!(wFlags & DISPATCH_METHOD))
+ return DISP_E_MEMBERNOTFOUND;
+
+ FIXME("\n");
+
+ VariantInit(pVarResult);
+ return S_OK;
+}
+
+static HRESULT DatabaseImpl_Invoke(
+ AutomationObject* This,
+ DISPID dispIdMember,
+ REFIID riid,
+ LCID lcid,
+ WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ IDispatch *dispatch = NULL;
+ MSIHANDLE msiHandle;
+ UINT ret;
+ VARIANTARG varg0, varg1;
+ HRESULT hr;
+
+ VariantInit(&varg0);
+ VariantInit(&varg1);
+
+ switch (dispIdMember)
+ {
+ case DISPID_DATABASE_SUMMARYINFORMATION:
+ if (wFlags & DISPATCH_PROPERTYGET)
+ {
+ hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
+ if (FAILED(hr))
+ V_I4(&varg0) = 0;
+
+ V_VT(pVarResult) = VT_DISPATCH;
+ if ((ret = MsiGetSummaryInformationW(This->msiHandle, NULL, V_I4(&varg0), &msiHandle)) == ERROR_SUCCESS)
+ {
+ hr = create_summaryinfo(msiHandle, &dispatch);
+ if (SUCCEEDED(hr))
+ V_DISPATCH(pVarResult) = dispatch;
+ else
+ ERR("Failed to create SummaryInfo object: 0x%08x\n", hr);
+ }
+ else
+ {
+ ERR("MsiGetSummaryInformation returned %d\n", ret);
+ return DISP_E_EXCEPTION;
+ }
+ }
+ else return DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_DATABASE_OPENVIEW:
+ if (wFlags & DISPATCH_METHOD)
+ {
+ hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
+ if (FAILED(hr)) return hr;
+ V_VT(pVarResult) = VT_DISPATCH;
+ if ((ret = MsiDatabaseOpenViewW(This->msiHandle, V_BSTR(&varg0), &msiHandle)) == ERROR_SUCCESS)
+ {
+ if (SUCCEEDED(hr = create_view(msiHandle, &dispatch)))
+ V_DISPATCH(pVarResult) = dispatch;
+ else
+ ERR("Failed to create View object, hresult 0x%08x\n", hr);
+ }
+ else
+ {
+ VariantClear(&varg0);
+ ERR("MsiDatabaseOpenView returned %d\n", ret);
+ return DISP_E_EXCEPTION;
+ }
+ }
+ else return DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_INSTALLER_LASTERRORRECORD:
+ return DatabaseImpl_LastErrorRecord(wFlags, pDispParams,
+ pVarResult, pExcepInfo,
+ puArgErr);
+
+ default:
+ return DISP_E_MEMBERNOTFOUND;
+ }
+
+ VariantClear(&varg1);
+ VariantClear(&varg0);
+
+ return S_OK;
+}
+
+static HRESULT SessionImpl_Invoke(
+ AutomationObject* This,
+ DISPID dispIdMember,
+ REFIID riid,
+ LCID lcid,
+ WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ SessionObject *session = (SessionObject*)This;
+ WCHAR *szString;
+ DWORD dwLen;
+ MSIHANDLE msiHandle;
+ LANGID langId;
+ UINT ret;
+ INSTALLSTATE iInstalled, iAction;
+ VARIANTARG varg0, varg1;
+ HRESULT hr;
+
+ VariantInit(&varg0);
+ VariantInit(&varg1);
+
+ switch (dispIdMember)
+ {
+ case DISPID_SESSION_INSTALLER:
+ if (wFlags & DISPATCH_PROPERTYGET) {
+ V_VT(pVarResult) = VT_DISPATCH;
+ IDispatch_AddRef(session->installer);
+ V_DISPATCH(pVarResult) = session->installer;
+ }
+ else return DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_SESSION_PROPERTY:
+ if (wFlags & DISPATCH_PROPERTYGET) {
+ hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
+ if (FAILED(hr)) return hr;
+ V_VT(pVarResult) = VT_BSTR;
+ V_BSTR(pVarResult) = NULL;
+ if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), NULL, &dwLen)) == ERROR_SUCCESS)
+ {
+ if (!(szString = msi_alloc((++dwLen)*sizeof(WCHAR))))
+ ERR("Out of memory\n");
+ else if ((ret = MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
+ V_BSTR(pVarResult) = SysAllocString(szString);
+ msi_free(szString);
+ }
+ if (ret != ERROR_SUCCESS)
+ ERR("MsiGetProperty returned %d\n", ret);
+ } else if (wFlags & DISPATCH_PROPERTYPUT) {
+ hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
+ if (FAILED(hr)) return hr;
+ hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
+ if (FAILED(hr)) {
+ VariantClear(&varg0);
+ return hr;
+ }
+ if ((ret = MsiSetPropertyW(This->msiHandle, V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
+ {
+ VariantClear(&varg0);
+ VariantClear(&varg1);
+ ERR("MsiSetProperty returned %d\n", ret);
+ return DISP_E_EXCEPTION;
+ }
+ }
+ else return DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_SESSION_LANGUAGE:
+ if (wFlags & DISPATCH_PROPERTYGET) {
+ langId = MsiGetLanguage(This->msiHandle);
+ V_VT(pVarResult) = VT_I4;
+ V_I4(pVarResult) = langId;
+ }
+ else return DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_SESSION_MODE:
+ if (wFlags & DISPATCH_PROPERTYGET) {
+ hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
+ if (FAILED(hr)) return hr;
+ V_VT(pVarResult) = VT_BOOL;
+ V_BOOL(pVarResult) = MsiGetMode(This->msiHandle, V_I4(&varg0));
+ } else if (wFlags & DISPATCH_PROPERTYPUT) {
+ hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
+ if (FAILED(hr)) return hr;
+ hr = DispGetParam(pDispParams, 1, VT_BOOL, &varg1, puArgErr);
+ if (FAILED(hr)) return hr;
+ if ((ret = MsiSetMode(This->msiHandle, V_I4(&varg0), V_BOOL(&varg1))) != ERROR_SUCCESS)
+ {
+ ERR("MsiSetMode returned %d\n", ret);
+ return DISP_E_EXCEPTION;
+ }
+ }
+ else return DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_SESSION_DATABASE:
+ if (wFlags & DISPATCH_PROPERTYGET) {
+ V_VT(pVarResult) = VT_DISPATCH;
+ if ((msiHandle = MsiGetActiveDatabase(This->msiHandle)))
+ {
+ IDispatch *dispatch;
+
+ if (SUCCEEDED(hr = create_database(msiHandle, &dispatch)))
+ V_DISPATCH(pVarResult) = dispatch;
+ else
+ ERR("Failed to create Database object, hresult 0x%08x\n", hr);
+ }
+ else
+ {
+ ERR("MsiGetActiveDatabase failed\n");
+ return DISP_E_EXCEPTION;
+ }
+ }
+ else return DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_SESSION_DOACTION:
+ if (wFlags & DISPATCH_METHOD) {
+ hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
+ if (FAILED(hr)) return hr;
+ ret = MsiDoActionW(This->msiHandle, V_BSTR(&varg0));
+ V_VT(pVarResult) = VT_I4;
+ switch (ret)
+ {
+ case ERROR_FUNCTION_NOT_CALLED:
+ V_I4(pVarResult) = msiDoActionStatusNoAction;
+ break;
+ case ERROR_SUCCESS:
+ V_I4(pVarResult) = msiDoActionStatusSuccess;
+ break;
+ case ERROR_INSTALL_USEREXIT:
+ V_I4(pVarResult) = msiDoActionStatusUserExit;
+ break;
+ case ERROR_INSTALL_FAILURE:
+ V_I4(pVarResult) = msiDoActionStatusFailure;
+ break;
+ case ERROR_INSTALL_SUSPEND:
+ V_I4(pVarResult) = msiDoActionStatusSuspend;
+ break;
+ case ERROR_MORE_DATA:
+ V_I4(pVarResult) = msiDoActionStatusFinished;
+ break;
+ case ERROR_INVALID_HANDLE_STATE:
+ V_I4(pVarResult) = msiDoActionStatusWrongState;
+ break;
+ case ERROR_INVALID_DATA:
+ V_I4(pVarResult) = msiDoActionStatusBadActionData;
+ break;
+ default:
+ VariantClear(&varg0);
+ FIXME("MsiDoAction returned unhandled value %d\n", ret);
+ return DISP_E_EXCEPTION;
+ }
+ }
+ else return DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_SESSION_EVALUATECONDITION:
+ if (wFlags & DISPATCH_METHOD) {
+ hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
+ if (FAILED(hr)) return hr;
+ V_VT(pVarResult) = VT_I4;
+ V_I4(pVarResult) = MsiEvaluateConditionW(This->msiHandle, V_BSTR(&varg0));
+ }
+ else return DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_SESSION_MESSAGE:
+ if(!(wFlags & DISPATCH_METHOD))
+ return DISP_E_MEMBERNOTFOUND;
+
+ hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
+ if (FAILED(hr)) return hr;
+ hr = DispGetParam(pDispParams, 1, VT_DISPATCH, &varg1, puArgErr);
+ if (FAILED(hr)) return hr;
+
+ V_VT(pVarResult) = VT_I4;
+ V_I4(pVarResult) =
+ MsiProcessMessage(This->msiHandle, V_I4(&varg0), ((AutomationObject *)V_DISPATCH(&varg1))->msiHandle);
+ break;
+
+ case DISPID_SESSION_SETINSTALLLEVEL:
+ if (wFlags & DISPATCH_METHOD) {
+ hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
+ if (FAILED(hr)) return hr;
+ if ((ret = MsiSetInstallLevel(This->msiHandle, V_I4(&varg0))) != ERROR_SUCCESS)
+ {
+ ERR("MsiSetInstallLevel returned %d\n", ret);
+ return DISP_E_EXCEPTION;
+ }
+ }
+ else return DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_SESSION_FEATURECURRENTSTATE:
+ if (wFlags & DISPATCH_PROPERTYGET) {
+ hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
+ if (FAILED(hr)) return hr;
+ V_VT(pVarResult) = VT_I4;
+ if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
+ V_I4(pVarResult) = iInstalled;
+ else
+ {
+ ERR("MsiGetFeatureState returned %d\n", ret);
+ V_I4(pVarResult) = msiInstallStateUnknown;
+ }
+ }
+ else return DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_SESSION_FEATUREREQUESTSTATE:
+ if (wFlags & DISPATCH_PROPERTYGET) {
+ hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
+ if (FAILED(hr)) return hr;
+ V_VT(pVarResult) = VT_I4;
+ if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&varg0), &iInstalled, &iAction)) == ERROR_SUCCESS)
+ V_I4(pVarResult) = iAction;
+ else
+ {
+ ERR("MsiGetFeatureState returned %d\n", ret);
+ V_I4(pVarResult) = msiInstallStateUnknown;
+ }
+ } else if (wFlags & DISPATCH_PROPERTYPUT) {
+ hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
+ if (FAILED(hr)) return hr;
+ hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
+ if (FAILED(hr)) {
+ VariantClear(&varg0);
+ return hr;
+ }
+ if ((ret = MsiSetFeatureStateW(This->msiHandle, V_BSTR(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
+ {
+ VariantClear(&varg0);
+ ERR("MsiSetFeatureState returned %d\n", ret);
+ return DISP_E_EXCEPTION;
+ }
+ }
+ else return DISP_E_MEMBERNOTFOUND;
+ break;
+
+ default:
+ return DISP_E_MEMBERNOTFOUND;
+ }
+
+ VariantClear(&varg1);
+ VariantClear(&varg0);
+
+ return S_OK;
+}
+
+/* Fill the variant pointed to by pVarResult with the value & size returned by RegQueryValueEx as dictated by the
+ * registry value type. Used by Installer::RegistryValue. */
+static void variant_from_registry_value(VARIANT *pVarResult, DWORD dwType, LPBYTE lpData, DWORD dwSize)
+{
+ static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
+ static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
+ WCHAR *szString = (WCHAR *)lpData;
+ LPWSTR szNewString = NULL;
+ DWORD dwNewSize = 0;
+ int idx;
+
+ switch (dwType)
+ {
+ /* Registry strings may not be null terminated so we must use SysAllocStringByteLen/Len */
+ case REG_MULTI_SZ: /* Multi SZ change internal null characters to newlines */
+ idx = (dwSize/sizeof(WCHAR))-1;
+ while (idx >= 0 && !szString[idx]) idx--;
+ for (; idx >= 0; idx--)
+ if (!szString[idx]) szString[idx] = '\n';
+ /* fall through */
+ case REG_SZ:
+ V_VT(pVarResult) = VT_BSTR;
+ V_BSTR(pVarResult) = SysAllocStringByteLen((LPCSTR)szString, dwSize);
+ break;
+
+ case REG_EXPAND_SZ:
+ if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
+ ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
+ else if (!(szNewString = msi_alloc(dwNewSize * sizeof(WCHAR))))
+ ERR("Out of memory\n");
+ else if (!(dwNewSize = ExpandEnvironmentStringsW(szString, szNewString, dwNewSize)))
+ ERR("ExpandEnvironmentStrings returned error %d\n", GetLastError());
+ else
+ {
+ V_VT(pVarResult) = VT_BSTR;
+ V_BSTR(pVarResult) = SysAllocStringLen(szNewString, dwNewSize);
+ }
+ msi_free(szNewString);
+ break;
+
+ case REG_DWORD:
+ V_VT(pVarResult) = VT_I4;
+ V_I4(pVarResult) = *((DWORD *)lpData);
+ break;
+
+ case REG_QWORD:
+ V_VT(pVarResult) = VT_BSTR;
+ V_BSTR(pVarResult) = SysAllocString(szREG_); /* Weird string, don't know why native returns it */
+ break;
+
+ case REG_BINARY:
+ V_VT(pVarResult) = VT_BSTR;
+ V_BSTR(pVarResult) = SysAllocString(szREG_BINARY);
+ break;
+
+ case REG_NONE:
+ V_VT(pVarResult) = VT_EMPTY;
+ break;
+
+ default:
+ FIXME("Unhandled registry value type %d\n", dwType);
+ }
+}
+
+static HRESULT InstallerImpl_CreateRecord(WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ HRESULT hr;
+ VARIANTARG varg0;
+ MSIHANDLE hrec;
+ IDispatch* dispatch;
+
+ if (!(wFlags & DISPATCH_METHOD))
+ return DISP_E_MEMBERNOTFOUND;
+
+ VariantInit(&varg0);
+ hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
+ if (FAILED(hr))
+ return hr;
+
+ V_VT(pVarResult) = VT_DISPATCH;
+
+ hrec = MsiCreateRecord(V_I4(&varg0));
+ if (!hrec)
+ return DISP_E_EXCEPTION;
+
+ hr = create_record(hrec, &dispatch);
+ if (SUCCEEDED(hr))
+ V_DISPATCH(pVarResult) = dispatch;
+
+ return hr;
+}
+
+static HRESULT InstallerImpl_OpenPackage(AutomationObject* This,
+ WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ UINT ret;
+ HRESULT hr;
+ MSIHANDLE hpkg;
+ IDispatch* dispatch;
+ VARIANTARG varg0, varg1;
+
+ if (!(wFlags & DISPATCH_METHOD))
+ return DISP_E_MEMBERNOTFOUND;
+
+ if (pDispParams->cArgs == 0)
+ return DISP_E_TYPEMISMATCH;
+
+ if (V_VT(&pDispParams->rgvarg[pDispParams->cArgs - 1]) != VT_BSTR)
+ return DISP_E_TYPEMISMATCH;
+
+ VariantInit(&varg0);
+ hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
+ if (FAILED(hr))
+ return hr;
+
+ VariantInit(&varg1);
+ if (pDispParams->cArgs == 2)
+ {
+ hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
+ if (FAILED(hr))
+ goto done;
+ }
+ else
+ {
+ V_VT(&varg1) = VT_I4;
+ V_I4(&varg1) = 0;
+ }
+
+ V_VT(pVarResult) = VT_DISPATCH;
+
+ ret = MsiOpenPackageExW(V_BSTR(&varg0), V_I4(&varg1), &hpkg);
+ if (ret != ERROR_SUCCESS)
+ {
+ hr = DISP_E_EXCEPTION;
+ goto done;
+ }
+
+ hr = create_session(hpkg, &This->IDispatch_iface, &dispatch);
+ if (SUCCEEDED(hr))
+ V_DISPATCH(pVarResult) = dispatch;
+
+done:
+ VariantClear(&varg0);
+ VariantClear(&varg1);
+ return hr;
+}
+
+static HRESULT InstallerImpl_OpenProduct(WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ HRESULT hr;
+ VARIANTARG varg0;
+
+ if (!(wFlags & DISPATCH_METHOD))
+ return DISP_E_MEMBERNOTFOUND;
+
+ VariantInit(&varg0);
+ hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
+ if (FAILED(hr))
+ return hr;
+
+ FIXME("%s\n", debugstr_w(V_BSTR(&varg0)));
+
+ VariantInit(pVarResult);
+
+ VariantClear(&varg0);
+ return S_OK;
+}
+
+static HRESULT InstallerImpl_OpenDatabase(WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ UINT ret;
+ HRESULT hr;
+ MSIHANDLE hdb;
+ IDispatch* dispatch;
+ VARIANTARG varg0, varg1;
+
+ if (!(wFlags & DISPATCH_METHOD))
+ return DISP_E_MEMBERNOTFOUND;
+
+ VariantInit(&varg0);
+ hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
+ if (FAILED(hr))
+ return hr;
+
+ VariantInit(&varg1);
+ hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
+ if (FAILED(hr))
+ goto done;
+
+ V_VT(pVarResult) = VT_DISPATCH;
+
+ ret = MsiOpenDatabaseW(V_BSTR(&varg0), V_BSTR(&varg1), &hdb);
+ if (ret != ERROR_SUCCESS)
+ {
+ hr = DISP_E_EXCEPTION;
+ goto done;
+ }
+
+ hr = create_database(hdb, &dispatch);
+ if (SUCCEEDED(hr))
+ V_DISPATCH(pVarResult) = dispatch;
+
+done:
+ VariantClear(&varg0);
+ VariantClear(&varg1);
+ return hr;
+}
+
+static HRESULT InstallerImpl_SummaryInformation(WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ if (!(wFlags & DISPATCH_METHOD))
+ return DISP_E_MEMBERNOTFOUND;
+
+ FIXME("\n");
+
+ VariantInit(pVarResult);
+ return S_OK;
+}
+
+static HRESULT InstallerImpl_UILevel(WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ HRESULT hr;
+ VARIANTARG varg0;
+ INSTALLUILEVEL ui;
+
+ if (!(wFlags & DISPATCH_PROPERTYPUT) && !(wFlags & DISPATCH_PROPERTYGET))
+ return DISP_E_MEMBERNOTFOUND;
+
+ if (wFlags & DISPATCH_PROPERTYPUT)
+ {
+ VariantInit(&varg0);
+ hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
+ if (FAILED(hr))
+ return hr;
+
+ ui = MsiSetInternalUI(V_I4(&varg0), NULL);
+ if (ui == INSTALLUILEVEL_NOCHANGE)
+ return DISP_E_EXCEPTION;
+ }
+ else if (wFlags & DISPATCH_PROPERTYGET)
+ {
+ ui = MsiSetInternalUI(INSTALLUILEVEL_NOCHANGE, NULL);
+ if (ui == INSTALLUILEVEL_NOCHANGE)
+ return DISP_E_EXCEPTION;
+
+ V_VT(pVarResult) = VT_I4;
+ V_I4(pVarResult) = ui;
+ }
+
+ return S_OK;
+}
+
+static HRESULT InstallerImpl_EnableLog(WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ if (!(wFlags & DISPATCH_METHOD))
+ return DISP_E_MEMBERNOTFOUND;
+
+ FIXME("\n");
+
+ VariantInit(pVarResult);
+ return S_OK;
+}
+
+static HRESULT InstallerImpl_InstallProduct(WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ UINT ret;
+ HRESULT hr;
+ VARIANTARG varg0, varg1;
+
+ if (!(wFlags & DISPATCH_METHOD))
+ return DISP_E_MEMBERNOTFOUND;
+
+ VariantInit(&varg0);
+ hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
+ if (FAILED(hr))
+ return hr;
+
+ VariantInit(&varg1);
+ hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
+ if (FAILED(hr))
+ goto done;
+
+ ret = MsiInstallProductW(V_BSTR(&varg0), V_BSTR(&varg1));
+ if (ret != ERROR_SUCCESS)
+ {
+ hr = DISP_E_EXCEPTION;
+ goto done;
+ }
+
+done:
+ VariantClear(&varg0);
+ VariantClear(&varg1);
+ return hr;
+}
+
+static HRESULT InstallerImpl_Version(WORD wFlags,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ HRESULT hr;
+ DLLVERSIONINFO verinfo;
+ WCHAR version[MAX_PATH];
+
+ static const WCHAR format[] = {
+ '%','d','.','%','d','.','%','d','.','%','d',0};
+
+ if (!(wFlags & DISPATCH_PROPERTYGET))
+ return DISP_E_MEMBERNOTFOUND;
+
+ verinfo.cbSize = sizeof(DLLVERSIONINFO);
+ hr = DllGetVersion(&verinfo);
+ if (FAILED(hr))
+ return hr;
+
+ sprintfW(version, format, verinfo.dwMajorVersion, verinfo.dwMinorVersion,
+ verinfo.dwBuildNumber, verinfo.dwPlatformID);
+
+ V_VT(pVarResult) = VT_BSTR;
+ V_BSTR(pVarResult) = SysAllocString(version);
+ return S_OK;
+}
+
+static HRESULT InstallerImpl_LastErrorRecord(WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ if (!(wFlags & DISPATCH_METHOD))
+ return DISP_E_MEMBERNOTFOUND;
+
+ FIXME("\n");
+
+ VariantInit(pVarResult);
+ return S_OK;
+}
+
+static HRESULT InstallerImpl_RegistryValue(WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ UINT ret;
+ HKEY hkey = NULL;
+ HRESULT hr;
+ UINT posValue;
+ DWORD type, size;
+ LPWSTR szString = NULL;
+ VARIANTARG varg0, varg1, varg2;
+
+ if (!(wFlags & DISPATCH_METHOD))
+ return DISP_E_MEMBERNOTFOUND;
+
+ VariantInit(&varg0);
+ hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
+ if (FAILED(hr))
+ return hr;
+
+ VariantInit(&varg1);
+ hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
+ if (FAILED(hr))
+ goto done;
+
+ /* Save valuePos so we can save puArgErr if we are unable to do our type
+ * conversions.
+ */
+ posValue = 2;
+ VariantInit(&varg2);
+ hr = DispGetParam_CopyOnly(pDispParams, &posValue, &varg2);
+ if (FAILED(hr))
+ goto done;
+
+ if (V_I4(&varg0) >= REG_INDEX_CLASSES_ROOT &&
+ V_I4(&varg0) <= REG_INDEX_DYN_DATA)
+ {
+ V_I4(&varg0) |= (UINT_PTR)HKEY_CLASSES_ROOT;
+ }
+
+ ret = RegOpenKeyW((HKEY)(UINT_PTR)V_I4(&varg0), V_BSTR(&varg1), &hkey);
+
+ /* Only VT_EMPTY case can do anything if the key doesn't exist. */
+ if (ret != ERROR_SUCCESS && V_VT(&varg2) != VT_EMPTY)
+ {
+ hr = DISP_E_BADINDEX;
+ goto done;
+ }
+
+ /* Third parameter can be VT_EMPTY, VT_I4, or VT_BSTR */
+ switch (V_VT(&varg2))
+ {
+ /* Return VT_BOOL clarifying whether registry key exists or not. */
+ case VT_EMPTY:
+ V_VT(pVarResult) = VT_BOOL;
+ V_BOOL(pVarResult) = (ret == ERROR_SUCCESS);
+ break;
+
+ /* Return the value of specified key if it exists. */
+ case VT_BSTR:
+ ret = RegQueryValueExW(hkey, V_BSTR(&varg2),
+ NULL, NULL, NULL, &size);
+ if (ret != ERROR_SUCCESS)
+ {
+ hr = DISP_E_BADINDEX;
+ goto done;
+ }
+
+ szString = msi_alloc(size);
+ if (!szString)
+ {
+ hr = E_OUTOFMEMORY;
+ goto done;
+ }
+
+ ret = RegQueryValueExW(hkey, V_BSTR(&varg2), NULL,
+ &type, (LPBYTE)szString, &size);
+ if (ret != ERROR_SUCCESS)
+ {
+ msi_free(szString);
+ hr = DISP_E_BADINDEX;
+ goto done;
+ }
+
+ variant_from_registry_value(pVarResult, type,
+ (LPBYTE)szString, size);
+ msi_free(szString);
+ break;
+
+ /* Try to make it into VT_I4, can use VariantChangeType for this. */
+ default:
+ hr = VariantChangeType(&varg2, &varg2, 0, VT_I4);
+ if (FAILED(hr))
+ {
+ if (hr == DISP_E_TYPEMISMATCH)
+ *puArgErr = posValue;
+
+ goto done;
+ }
+
+ /* Retrieve class name or maximum value name or subkey name size. */
+ if (!V_I4(&varg2))
+ ret = RegQueryInfoKeyW(hkey, NULL, &size, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ else if (V_I4(&varg2) > 0)
+ ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, &size, NULL, NULL, NULL);
+ else /* V_I4(&varg2) < 0 */
+ ret = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, &size,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+
+ if (ret != ERROR_SUCCESS)
+ goto done;
+
+ szString = msi_alloc(++size * sizeof(WCHAR));
+ if (!szString)
+ {
+ hr = E_OUTOFMEMORY;
+ goto done;
+ }
+
+ if (!V_I4(&varg2))
+ ret = RegQueryInfoKeyW(hkey, szString, &size,NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ else if (V_I4(&varg2) > 0)
+ ret = RegEnumValueW(hkey, V_I4(&varg2)-1, szString,
+ &size, 0, 0, NULL, NULL);
+ else /* V_I4(&varg2) < 0 */
+ ret = RegEnumKeyW(hkey, -1 - V_I4(&varg2), szString, size);
+
+ if (ret == ERROR_SUCCESS)
+ {
+ V_VT(pVarResult) = VT_BSTR;
+ V_BSTR(pVarResult) = SysAllocString(szString);
+ }
+
+ msi_free(szString);
+ }
+
+done:
+ VariantClear(&varg0);
+ VariantClear(&varg1);
+ VariantClear(&varg2);
+ RegCloseKey(hkey);
+ return hr;
+}
+
+static HRESULT InstallerImpl_Environment(WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ if (!(wFlags & DISPATCH_METHOD))
+ return DISP_E_MEMBERNOTFOUND;
+
+ FIXME("\n");
+
+ VariantInit(pVarResult);
+ return S_OK;
+}
+
+static HRESULT InstallerImpl_FileAttributes(WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ if (!(wFlags & DISPATCH_METHOD))
+ return DISP_E_MEMBERNOTFOUND;
+
+ FIXME("\n");
+
+ VariantInit(pVarResult);
+ return S_OK;
+}
+
+static HRESULT InstallerImpl_FileSize(WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ if (!(wFlags & DISPATCH_METHOD))
+ return DISP_E_MEMBERNOTFOUND;
+
+ FIXME("\n");
+
+ VariantInit(pVarResult);
+ return S_OK;
+}
+
+static HRESULT InstallerImpl_FileVersion(WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ if (!(wFlags & DISPATCH_METHOD))
+ return DISP_E_MEMBERNOTFOUND;
+
+ FIXME("\n");
+
+ VariantInit(pVarResult);
+ return S_OK;
+}
+
+static HRESULT InstallerImpl_ProductState(WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ HRESULT hr;
+ VARIANTARG varg0;
+
+ if (!(wFlags & DISPATCH_PROPERTYGET))
+ return DISP_E_MEMBERNOTFOUND;
+
+ VariantInit(&varg0);
+ hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
+ if (FAILED(hr))
+ return hr;
+
+ V_VT(pVarResult) = VT_I4;
+ V_I4(pVarResult) = MsiQueryProductStateW(V_BSTR(&varg0));
+
+ VariantClear(&varg0);
+ return S_OK;
+}
+
+static HRESULT InstallerImpl_ProductInfo(WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ UINT ret;
+ HRESULT hr;
+ DWORD size;
+ LPWSTR str = NULL;
+ VARIANTARG varg0, varg1;
+
+ if (!(wFlags & DISPATCH_PROPERTYGET))
+ return DISP_E_MEMBERNOTFOUND;
+
+ VariantInit(&varg0);
+ hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
+ if (FAILED(hr))
+ return hr;
+
+ VariantInit(&varg1);
+ hr = DispGetParam(pDispParams, 1, VT_BSTR, &varg1, puArgErr);
+ if (FAILED(hr))
+ goto done;
+
+ V_VT(pVarResult) = VT_BSTR;
+ V_BSTR(pVarResult) = NULL;
+
+ ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), NULL, &size);
+ if (ret != ERROR_SUCCESS)
+ {
+ hr = DISP_E_EXCEPTION;
+ goto done;
+ }
+
+ str = msi_alloc(++size * sizeof(WCHAR));
+ if (!str)
+ {
+ hr = E_OUTOFMEMORY;
+ goto done;
+ }
+
+ ret = MsiGetProductInfoW(V_BSTR(&varg0), V_BSTR(&varg1), str, &size);
+ if (ret != ERROR_SUCCESS)
+ {
+ hr = DISP_E_EXCEPTION;
+ goto done;
+ }
+
+ V_BSTR(pVarResult) = SysAllocString(str);
+ hr = S_OK;
+
+done:
+ msi_free(str);
+ VariantClear(&varg0);
+ VariantClear(&varg1);
+ return hr;
+}
+
+static HRESULT InstallerImpl_Products(WORD flags,
+ DISPPARAMS* pDispParams,
+ VARIANT* result,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ IDispatch *dispatch;
+ HRESULT hr;
+
+ if (!(flags & DISPATCH_PROPERTYGET))
+ return DISP_E_MEMBERNOTFOUND;
+
+ hr = create_list(NULL, &dispatch);
+ if (FAILED(hr))
+ return hr;
+
+ V_VT(result) = VT_DISPATCH;
+ V_DISPATCH(result) = dispatch;
+
+ return hr;
+}
+
+static HRESULT InstallerImpl_RelatedProducts(WORD flags,
+ DISPPARAMS* pDispParams,
+ VARIANT* result,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ IDispatch* dispatch;
+ VARIANTARG related;
+ HRESULT hr;
+
+ if (!(flags & DISPATCH_PROPERTYGET))
+ return DISP_E_MEMBERNOTFOUND;
+
+ VariantInit(&related);
+ hr = DispGetParam(pDispParams, 0, VT_BSTR, &related, puArgErr);
+ if (FAILED(hr))
+ return hr;
+
+ hr = create_list(V_BSTR(&related), &dispatch);
+ VariantClear(&related);
+
+ V_VT(result) = VT_DISPATCH;
+ V_DISPATCH(result) = dispatch;
+
+ return hr;
+}
+
+static HRESULT InstallerImpl_Invoke(
+ AutomationObject* This,
+ DISPID dispIdMember,
+ REFIID riid,
+ LCID lcid,
+ WORD wFlags,
+ DISPPARAMS* pDispParams,
+ VARIANT* pVarResult,
+ EXCEPINFO* pExcepInfo,
+ UINT* puArgErr)
+{
+ switch (dispIdMember)
+ {
+ case DISPID_INSTALLER_CREATERECORD:
+ return InstallerImpl_CreateRecord(wFlags, pDispParams,
+ pVarResult, pExcepInfo, puArgErr);
+
+ case DISPID_INSTALLER_OPENPACKAGE:
+ return InstallerImpl_OpenPackage(This, wFlags, pDispParams,
+ pVarResult, pExcepInfo, puArgErr);
+
+ case DISPID_INSTALLER_OPENPRODUCT:
+ return InstallerImpl_OpenProduct(wFlags, pDispParams,
+ pVarResult, pExcepInfo, puArgErr);
+
+ case DISPID_INSTALLER_OPENDATABASE:
+ return InstallerImpl_OpenDatabase(wFlags, pDispParams,
+ pVarResult, pExcepInfo, puArgErr);
+
+ case DISPID_INSTALLER_SUMMARYINFORMATION:
+ return InstallerImpl_SummaryInformation(wFlags, pDispParams,
+ pVarResult, pExcepInfo,
+ puArgErr);
+
+ case DISPID_INSTALLER_UILEVEL:
+ return InstallerImpl_UILevel(wFlags, pDispParams,
+ pVarResult, pExcepInfo, puArgErr);
+
+ case DISPID_INSTALLER_ENABLELOG:
+ return InstallerImpl_EnableLog(wFlags, pDispParams,
+ pVarResult, pExcepInfo, puArgErr);
+
+ case DISPID_INSTALLER_INSTALLPRODUCT:
+ return InstallerImpl_InstallProduct(wFlags, pDispParams,
+ pVarResult, pExcepInfo,
+ puArgErr);
+
+ case DISPID_INSTALLER_VERSION:
+ return InstallerImpl_Version(wFlags, pVarResult,
+ pExcepInfo, puArgErr);
+
+ case DISPID_INSTALLER_LASTERRORRECORD:
+ return InstallerImpl_LastErrorRecord(wFlags, pDispParams,
+ pVarResult, pExcepInfo,
+ puArgErr);
+
+ case DISPID_INSTALLER_REGISTRYVALUE:
+ return InstallerImpl_RegistryValue(wFlags, pDispParams,
+ pVarResult, pExcepInfo,
+ puArgErr);
+
+ case DISPID_INSTALLER_ENVIRONMENT:
+ return InstallerImpl_Environment(wFlags, pDispParams,
+ pVarResult, pExcepInfo, puArgErr);
+
+ case DISPID_INSTALLER_FILEATTRIBUTES:
+ return InstallerImpl_FileAttributes(wFlags, pDispParams,
+ pVarResult, pExcepInfo,
+ puArgErr);
+
+ case DISPID_INSTALLER_FILESIZE:
+ return InstallerImpl_FileSize(wFlags, pDispParams,
+ pVarResult, pExcepInfo, puArgErr);
+
+ case DISPID_INSTALLER_FILEVERSION:
+ return InstallerImpl_FileVersion(wFlags, pDispParams,
+ pVarResult, pExcepInfo, puArgErr);
+
+ case DISPID_INSTALLER_PRODUCTSTATE:
+ return InstallerImpl_ProductState(wFlags, pDispParams,
+ pVarResult, pExcepInfo, puArgErr);
+
+ case DISPID_INSTALLER_PRODUCTINFO:
+ return InstallerImpl_ProductInfo(wFlags, pDispParams,
+ pVarResult, pExcepInfo, puArgErr);
+
+ case DISPID_INSTALLER_PRODUCTS:
+ return InstallerImpl_Products(wFlags, pDispParams,
+ pVarResult, pExcepInfo, puArgErr);
+
+ case DISPID_INSTALLER_RELATEDPRODUCTS:
+ return InstallerImpl_RelatedProducts(wFlags, pDispParams,
+ pVarResult, pExcepInfo,
+ puArgErr);
+
+ default:
+ return DISP_E_MEMBERNOTFOUND;
+ }
+}
+
+HRESULT create_msiserver(IUnknown *outer, void **ppObj)
+{
+ AutomationObject *installer;
+ HRESULT hr;
+
+ TRACE("(%p %p)\n", outer, ppObj);
+
+ if (outer)
+ return CLASS_E_NOAGGREGATION;
+
+ installer = msi_alloc(sizeof(AutomationObject));
+ if (!installer) return E_OUTOFMEMORY;
+
+ hr = init_automation_object(installer, 0, &DIID_Installer, InstallerImpl_Invoke, NULL);
+ if (hr != S_OK)
+ {
+ msi_free(installer);
+ return hr;
+ }
+
+ *ppObj = &installer->IDispatch_iface;
+
+ return hr;
+}
+
+HRESULT create_session(MSIHANDLE msiHandle, IDispatch *installer, IDispatch **disp)
+{
+ SessionObject *session;
+ HRESULT hr;
+
+ session = msi_alloc(sizeof(SessionObject));
+ if (!session) return E_OUTOFMEMORY;
+
+ hr = init_automation_object(&session->autoobj, msiHandle, &DIID_Session, SessionImpl_Invoke, NULL);
+ if (hr != S_OK)
+ {
+ msi_free(session);
+ return hr;
+ }
+
+ session->installer = installer;
+ *disp = &session->autoobj.IDispatch_iface;
+
+ return hr;
+}
+
+static HRESULT create_database(MSIHANDLE msiHandle, IDispatch **dispatch)
+{
+ AutomationObject *database;
+ HRESULT hr;
+
+ TRACE("(%d %p)\n", msiHandle, dispatch);
+
+ database = msi_alloc(sizeof(AutomationObject));
+ if (!database) return E_OUTOFMEMORY;
+
+ hr = init_automation_object(database, msiHandle, &DIID_Database, DatabaseImpl_Invoke, NULL);
+ if (hr != S_OK)
+ {
+ msi_free(database);
+ return hr;
+ }
+
+ *dispatch = &database->IDispatch_iface;
+
+ return hr;
+}
+
+static HRESULT create_view(MSIHANDLE msiHandle, IDispatch **dispatch)
+{
+ AutomationObject *view;
+ HRESULT hr;
+
+ TRACE("(%d %p)\n", msiHandle, dispatch);
+
+ view = msi_alloc(sizeof(AutomationObject));
+ if (!view) return E_OUTOFMEMORY;
+
+ hr = init_automation_object(view, msiHandle, &DIID_View, ViewImpl_Invoke, NULL);
+ if (hr != S_OK)
+ {
+ msi_free(view);
+ return hr;
+ }
+
+ *dispatch = &view->IDispatch_iface;
+
+ return hr;
+}
+
+static HRESULT create_summaryinfo(MSIHANDLE msiHandle, IDispatch **disp)
+{
+ AutomationObject *info;
+ HRESULT hr;
+
+ info = msi_alloc(sizeof(*info));
+ if (!info) return E_OUTOFMEMORY;
+
+ hr = init_automation_object(info, msiHandle, &DIID_SummaryInfo, SummaryInfoImpl_Invoke, NULL);
+ if (hr != S_OK)
+ {
+ msi_free(info);
+ return hr;
+ }
+
+ *disp = &info->IDispatch_iface;
+
+ return hr;
+}