[final, sorry] msi: Add partial, expandable OLE automation support.

Misha Koshelev mk144210 at bcm.tmc.edu
Thu Mar 1 09:40:06 CST 2007


Changes: I have cleaned up some comments as per James' suggestions and
used DispGetParam as per Rob's suggestion to get parameters in a more
proper fashion.

As a reminder this is part 3 of 4 of my patchset:

1.
http://www.winehq.org/pipermail/wine-patches/2007-February/036359.html
2. Previous patch
3. This patch
4.
http://www.winehq.org/pipermail/wine-patches/2007-February/036362.html

This patch provides a currently small (sufficient to fix bug #7357) but
expandable/scalable OLE automation support for MSI.

Changelog:

	* msi: Add partial, expandable OLE automation support.
-------------- next part --------------
From be2db4037f9f0ed32a76f1a6e08f73ea492317be Mon Sep 17 00:00:00 2001
From: Misha Koshelev <mk144210 at bcm.tmc.edu>
Date: Thu, 1 Mar 2007 08:27:47 -0600
Subject: msi: Add partial, expandable OLE automation support.
---
 dlls/msi/Makefile.in  |    3 
 dlls/msi/automation.c |  844 +++++++++++++++++++++++++++++++++++++++++++++++++
 dlls/msi/msipriv.h    |    4 
 3 files changed, 851 insertions(+), 0 deletions(-)

diff --git a/dlls/msi/Makefile.in b/dlls/msi/Makefile.in
index 5fb0941..3418fb5 100644
--- a/dlls/msi/Makefile.in
+++ b/dlls/msi/Makefile.in
@@ -12,6 +12,7 @@ C_SRCS = \
 	action.c \
 	alter.c \
 	appsearch.c \
+	automation.c \
 	classes.c \
 	create.c \
 	custom.c \
@@ -47,6 +48,8 @@ C_SRCS = \
 	upgrade.c \
 	where.c
 
+IDL_H_SRCS = msiserver.idl
+IDL_I_SRCS = msiserver.idl
 IDL_TLB_SRCS = msiserver.idl
 
 BISON_SRCS = \
diff --git a/dlls/msi/automation.c b/dlls/msi/automation.c
new file mode 100644
index 0000000..eb6a6b5
--- /dev/null
+++ b/dlls/msi/automation.c
@@ -0,0 +1,844 @@
+/*
+ * 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 "msidefs.h"
+#include "msipriv.h"
+#include "activscp.h"
+#include "oleauto.h"
+#include "wine/debug.h"
+#include "wine/unicode.h"
+
+#include "msiserver.h"
+#include "msiserver_dispids.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+/* FIXME: I don't know how big this should be */
+#define MAX_MSI_STRING 1000
+
+/*
+ * AutomationObject - "base" class for all automation objects. For each interface, we implement Invoke function
+ *                    called from AutomationObject::Invoke, and pass this function to create_automation_object.
+ */
+
+typedef interface AutomationObject AutomationObject;
+
+interface AutomationObject {
+    /*
+     * VTables - We provide IDispatch, IProvideClassInfo, IProvideClassInfo2, IProvideMultipleClassInfo
+     */
+    const IDispatchVtbl *lpVtbl;
+    const IProvideClassInfoVtbl *lpvtblIProvideClassInfo;
+    const IProvideClassInfo2Vtbl *lpvtblIProvideClassInfo2;
+    const IProvideMultipleClassInfoVtbl *lpvtblIProvideMultipleClassInfo;
+    
+    /* Object reference count */
+    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. */
+    HRESULT (STDMETHODCALLTYPE *funcInvoke)(
+        AutomationObject* This,
+        DISPID dispIdMember,
+        REFIID riid,
+        LCID lcid,
+        WORD wFlags,
+        DISPPARAMS* pDispParams,
+        VARIANT* pVarResult,
+        EXCEPINFO* pExcepInfo,
+        UINT* puArgErr);
+};
+
+/* VTables */
+static const struct IDispatchVtbl AutomationObject_Vtbl; 
+static const struct IProvideClassInfoVtbl AutomationObject_IProvideClassInfo_Vtbl; 
+static const struct IProvideClassInfo2Vtbl AutomationObject_IProvideClassInfo2_Vtbl; 
+static const struct IProvideMultipleClassInfoVtbl AutomationObject_IProvideMultipleClassInfo_Vtbl; 
+
+/* Load type info so we don't have to process GetIDsOfNames */
+HRESULT WINAPI LoadTypeInfo(IDispatch *iface, ITypeInfo **pptinfo, REFIID clsid, LCID lcid)
+{
+    HRESULT hr;
+    LPTYPELIB pLib = NULL;
+    LPTYPEINFO pInfo = NULL;
+    WCHAR szMsiServer[] = {'m','s','i','s','e','r','v','e','r','.','t','l','b'};
+
+    TRACE("(%p)->(%s,%d)\n", iface, debugstr_guid(clsid), lcid);    
+    
+    /* Load registered type library */
+    hr = LoadRegTypeLib(&LIBID_WindowsInstaller, 1, 0, lcid, &pLib);
+    if (FAILED(hr)) {
+	hr = LoadTypeLib(szMsiServer, &pLib);
+	if (FAILED(hr)) {
+	    ERR("Could not load msiserver.tlb\n");
+	    return hr;
+	}
+    }
+
+    /* Get type information for object */
+    hr = ITypeLib_GetTypeInfoOfGuid(pLib, clsid, &pInfo);
+    ITypeLib_Release(pLib);
+    if (FAILED(hr)) {
+	ERR("Could not load ITypeInfo for %s\n", debugstr_guid(clsid));
+	return hr;
+    }
+    *pptinfo = pInfo;
+    return S_OK;
+}
+
+/* Create the automation object, placing the result in the pointer ppObj. The automation object is created
+ * with the appropriate clsid and invocation function. */
+HRESULT create_automation_object(MSIHANDLE msiHandle, IUnknown *pUnkOuter, LPVOID *ppObj, REFIID clsid, 
+	    HRESULT (STDMETHODCALLTYPE *funcInvoke)(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,
+						    VARIANT*,EXCEPINFO*,UINT*))
+{
+    AutomationObject *object;
+    HRESULT hr;
+
+    TRACE("(%ld,%p,%p,%s,%p)\n", (unsigned long)msiHandle, pUnkOuter, ppObj, debugstr_guid(clsid), funcInvoke);
+
+    if( pUnkOuter )
+	return CLASS_E_NOAGGREGATION;
+
+    object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AutomationObject));
+
+    /* Set all the VTable references */
+    object->lpVtbl = &AutomationObject_Vtbl;
+    object->lpvtblIProvideClassInfo = &AutomationObject_IProvideClassInfo_Vtbl;
+    object->lpvtblIProvideClassInfo2 = &AutomationObject_IProvideClassInfo2_Vtbl;
+    object->lpvtblIProvideMultipleClassInfo = &AutomationObject_IProvideMultipleClassInfo_Vtbl;
+    object->ref = 1;
+
+    /* Store data that was passed */
+    object->msiHandle = msiHandle;
+    object->clsid = (LPCLSID)clsid;
+    object->funcInvoke = funcInvoke;
+
+    /* Load our TypeInfo so we don't have to process GetIDsOfNames */
+    object->iTypeInfo = NULL;
+    hr = LoadTypeInfo((IDispatch *)object, &object->iTypeInfo, clsid, 0x0);
+    if (FAILED(hr)) { 
+	HeapFree(GetProcessHeap(), 0, object);
+	return hr;
+    }
+
+    *ppObj = object;
+
+    return S_OK;
+}
+
+/* Macros to get pointer to AutomationObject from the other VTables. */
+static inline AutomationObject *obj_from_IProvideClassInfo( IProvideClassInfo *iface )
+{
+    return (AutomationObject *)((char*)iface - FIELD_OFFSET(AutomationObject, lpvtblIProvideClassInfo));
+}
+
+static inline AutomationObject *obj_from_IProvideClassInfo2( IProvideClassInfo2 *iface )
+{
+    return (AutomationObject *)((char*)iface - FIELD_OFFSET(AutomationObject, lpvtblIProvideClassInfo2));
+}
+
+static inline AutomationObject *obj_from_IProvideMultipleClassInfo( IProvideMultipleClassInfo *iface )
+{
+    return (AutomationObject *)((char*)iface - FIELD_OFFSET(AutomationObject, lpvtblIProvideMultipleClassInfo));
+}
+
+/*
+ * AutomationObject methods
+ */
+
+/*** IUnknown methods ***/
+static HRESULT WINAPI AutomationObject_QueryInterface(IDispatch* iface, REFIID riid, void** ppvObject)
+{
+    AutomationObject *This = (AutomationObject *)iface;
+
+    TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject); 
+
+    if ( (This==0) || (ppvObject==0) )
+      return E_INVALIDARG;
+
+    *ppvObject = 0;
+
+    if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDispatch) || IsEqualGUID(riid, This->clsid))
+        *ppvObject = This;
+    else if (IsEqualGUID(riid, &IID_IProvideClassInfo))
+	*ppvObject = (IProvideClassInfo*)&(This->lpvtblIProvideClassInfo);
+    else if (IsEqualGUID(riid, &IID_IProvideClassInfo2))
+	*ppvObject = (IProvideClassInfo2*)&(This->lpvtblIProvideClassInfo2);
+    else if (IsEqualGUID(riid, &IID_IProvideMultipleClassInfo))
+	*ppvObject = (IProvideMultipleClassInfo*)&(This->lpvtblIProvideMultipleClassInfo);
+
+    if ((*ppvObject)==0)
+    {
+	TRACE("() : asking for unsupported interface %s\n",debugstr_guid(riid));
+	return E_NOINTERFACE;
+    }
+
+    /*
+     * Query Interface always increases the reference count by one when it is
+     * successful
+     */
+    IClassFactory_AddRef(iface);
+
+    return S_OK;
+}
+
+static ULONG WINAPI AutomationObject_AddRef(IDispatch* iface)
+{
+    AutomationObject *This = (AutomationObject *)iface;
+
+    TRACE("(%p/%p)\n", iface, This);
+
+    return InterlockedIncrement(&This->ref);
+}
+
+static ULONG WINAPI AutomationObject_Release(IDispatch* iface)
+{
+    AutomationObject *This = (AutomationObject *)iface;
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p/%p)\n", iface, This);
+
+    if (!ref) 
+    {
+	MsiCloseHandle(This->msiHandle);
+        HeapFree(GetProcessHeap(), 0, This);
+    }
+
+    return ref;
+}
+
+/*** IDispatch methods ***/
+static HRESULT WINAPI AutomationObject_GetTypeInfoCount(
+        IDispatch* iface,
+        UINT* pctinfo)
+{
+    AutomationObject *This = (AutomationObject *)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 = (AutomationObject *)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 = (AutomationObject *)iface;
+    TRACE("(%p/%p)->(%p,%p,%d,%d,%p)\n", iface, This, riid, rgszNames, cNames, lcid, rgDispId);
+
+    if (!IsEqualGUID(riid, &IID_NULL)) return E_INVALIDARG;
+    return ITypeInfo_GetIDsOfNames(This->iTypeInfo, rgszNames, cNames, rgDispId);
+}
+
+/* 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 = (AutomationObject *)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 (!pDispParams)
+    {
+	ERR("NULL pDispParams not allowed\n");
+	return DISP_E_PARAMNOTOPTIONAL;
+    }
+
+    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));
+    }
+
+    /* Make sure we free the return variant if it is our dummy variant */
+    if (pVarResult == &varResultDummy) VariantClear(pVarResult);
+
+    TRACE("Returning 0x%08lx, %s\n", (unsigned long int)hr, SUCCEEDED(hr) ? "ok" : "not ok");
+
+    return hr;
+}
+
+static const struct IDispatchVtbl AutomationObject_Vtbl = 
+{
+    AutomationObject_QueryInterface,
+    AutomationObject_AddRef,
+    AutomationObject_Release,
+    AutomationObject_GetTypeInfoCount,
+    AutomationObject_GetTypeInfo,
+    AutomationObject_GetIDsOfNames,
+    AutomationObject_Invoke
+};
+
+/*
+ * IProvideClassInfo methods 
+ */
+
+static HRESULT WINAPI AutomationObject_IProvideClassInfo_QueryInterface(
+  IProvideClassInfo* iface,
+  REFIID     riid,
+  VOID**     ppvoid)
+{
+    AutomationObject *This = obj_from_IProvideClassInfo(iface);
+    return AutomationObject_QueryInterface((IDispatch *)This, riid, ppvoid);
+}
+
+static ULONG WINAPI AutomationObject_IProvideClassInfo_AddRef(IProvideClassInfo* iface)
+{
+    AutomationObject *This = obj_from_IProvideClassInfo(iface);
+    return AutomationObject_AddRef((IDispatch *)This);
+}
+
+static ULONG WINAPI AutomationObject_IProvideClassInfo_Release(IProvideClassInfo* iface)
+{
+    AutomationObject *This = obj_from_IProvideClassInfo(iface);
+    return AutomationObject_Release((IDispatch *)This);
+}
+
+static HRESULT WINAPI AutomationObject_GetClassInfo(IProvideClassInfo* iface, ITypeInfo** ppTI)
+{
+    AutomationObject *This = obj_from_IProvideClassInfo(iface);
+
+    TRACE("(%p/%p)->(%p)\n", iface, This, ppTI);
+    return LoadTypeInfo((IDispatch *)This, ppTI, This->clsid, 0);
+}
+
+static const IProvideClassInfoVtbl AutomationObject_IProvideClassInfo_Vtbl =
+{
+    AutomationObject_IProvideClassInfo_QueryInterface,
+    AutomationObject_IProvideClassInfo_AddRef,
+    AutomationObject_IProvideClassInfo_Release,    
+    AutomationObject_GetClassInfo
+};
+
+/*
+ * IProvideClassInfo2 methods
+ */
+
+static HRESULT WINAPI AutomationObject_IProvideClassInfo2_QueryInterface(
+  IProvideClassInfo2* iface,
+  REFIID     riid,
+  VOID**     ppvoid)
+{
+    AutomationObject *This = obj_from_IProvideClassInfo2(iface);
+    return AutomationObject_QueryInterface((IDispatch *)This, riid, ppvoid);
+}
+
+static ULONG WINAPI AutomationObject_IProvideClassInfo2_AddRef(IProvideClassInfo2* iface)
+{
+    AutomationObject *This = obj_from_IProvideClassInfo2(iface);
+    return AutomationObject_AddRef((IDispatch *)This);
+}
+
+static ULONG WINAPI AutomationObject_IProvideClassInfo2_Release(IProvideClassInfo2* iface)
+{
+    AutomationObject *This = obj_from_IProvideClassInfo2(iface);
+    return AutomationObject_Release((IDispatch *)This);
+}
+
+static HRESULT WINAPI AutomationObject_IProvideClassInfo2_GetClassInfo(IProvideClassInfo2* iface, ITypeInfo** ppTI)
+{
+    AutomationObject *This = obj_from_IProvideClassInfo2(iface);
+    return AutomationObject_GetClassInfo((IProvideClassInfo*)&(This->lpvtblIProvideClassInfo), ppTI);    
+}
+
+static HRESULT WINAPI AutomationObject_GetGUID(IProvideClassInfo2* iface, DWORD dwGuidKind, GUID* pGUID)
+{
+    AutomationObject *This = obj_from_IProvideClassInfo2(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 const IProvideClassInfo2Vtbl AutomationObject_IProvideClassInfo2_Vtbl =
+{
+    AutomationObject_IProvideClassInfo2_QueryInterface,
+    AutomationObject_IProvideClassInfo2_AddRef,
+    AutomationObject_IProvideClassInfo2_Release,    
+    AutomationObject_IProvideClassInfo2_GetClassInfo,    
+    AutomationObject_GetGUID
+};
+
+/* 
+ * IProvideMultipleClassInfo methods
+ */
+
+static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_QueryInterface(
+  IProvideMultipleClassInfo* iface,
+  REFIID     riid,
+  VOID**     ppvoid)
+{
+    AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
+    return AutomationObject_QueryInterface((IDispatch *)This, riid, ppvoid);
+}
+
+static ULONG WINAPI AutomationObject_IProvideMultipleClassInfo_AddRef(IProvideMultipleClassInfo* iface)
+{
+    AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
+    return AutomationObject_AddRef((IDispatch *)This);
+}
+
+static ULONG WINAPI AutomationObject_IProvideMultipleClassInfo_Release(IProvideMultipleClassInfo* iface)
+{
+    AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
+    return AutomationObject_Release((IDispatch *)This);
+}
+
+static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_GetClassInfo(IProvideMultipleClassInfo* iface, ITypeInfo** ppTI)
+{
+    AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
+    return AutomationObject_GetClassInfo((IProvideClassInfo*)&(This->lpvtblIProvideClassInfo), ppTI);    
+}
+
+static HRESULT WINAPI AutomationObject_IProvideMultipleClassInfo_GetGUID(IProvideMultipleClassInfo* iface, DWORD dwGuidKind, GUID* pGUID)
+{
+    AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
+    return AutomationObject_GetGUID((IProvideClassInfo2*)&(This->lpvtblIProvideClassInfo2), dwGuidKind, pGUID);
+}
+
+static HRESULT WINAPI AutomationObject_GetMultiTypeInfoCount(IProvideMultipleClassInfo* iface, ULONG* pcti)
+{
+    AutomationObject *This = obj_from_IProvideMultipleClassInfo(iface);
+
+    TRACE("(%p/%p)->(%p)\n", iface, This, pcti);
+    *pcti = 1;
+    return S_OK;
+}
+
+static HRESULT WINAPI AutomationObject_GetInfoOfIndex(IProvideMultipleClassInfo* iface,
+        ULONG iti,
+        DWORD dwFlags,
+        ITypeInfo** pptiCoClass,
+        DWORD* pdwTIFlags,
+        ULONG* pcdispidReserved,
+        IID* piidPrimary,
+        IID* piidSource)
+{
+    AutomationObject *This = obj_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)
+	LoadTypeInfo((IDispatch *)This, 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 AutomationObject_IProvideMultipleClassInfo_Vtbl =
+{
+    AutomationObject_IProvideMultipleClassInfo_QueryInterface,
+    AutomationObject_IProvideMultipleClassInfo_AddRef,
+    AutomationObject_IProvideMultipleClassInfo_Release,    
+    AutomationObject_IProvideMultipleClassInfo_GetClassInfo,
+    AutomationObject_IProvideMultipleClassInfo_GetGUID,
+    AutomationObject_GetMultiTypeInfoCount,
+    AutomationObject_GetInfoOfIndex
+};
+
+/*
+ * Individual Object Invocation Functions
+ */
+
+HRESULT WINAPI RecordImpl_Invoke(
+        AutomationObject* This,
+        DISPID dispIdMember,
+        REFIID riid,
+        LCID lcid,
+        WORD wFlags,
+        DISPPARAMS* pDispParams,
+        VARIANT* pVarResult,
+        EXCEPINFO* pExcepInfo,
+        UINT* puArgErr)
+{
+    WCHAR szString[MAX_MSI_STRING];
+    DWORD dwLen = MAX_MSI_STRING;
+    UINT ret;
+    VARIANTARG varg0, varg1;
+    HRESULT hr;
+
+    VariantInit(&varg0);
+    VariantInit(&varg1);
+
+    switch (dispIdMember) 
+    {
+	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;
+		if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&varg0), szString, &dwLen)) == ERROR_SUCCESS)
+                    V_BSTR(pVarResult) = SysAllocString(szString);
+		else
+		{
+		    TRACE("MsiRecordGetString returned %d\n", ret);
+                    V_BSTR(pVarResult) = NULL;
+		}
+	    } else if (wFlags & DISPATCH_PROPERTYPUT) {
+                hr = DispGetParam(pDispParams, 0, VT_I4, &varg0, puArgErr);
+                if (FAILED(hr)) return hr;
+                hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BSTR, &varg1, puArgErr);
+                if (FAILED(hr)) return hr;
+		if ((ret = MsiRecordSetStringW(This->msiHandle, V_I4(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS)
+                    TRACE("MsiRecordSetString returned %d\n", ret);
+	    }
+	    break;
+            
+         default:
+            return DISP_E_MEMBERNOTFOUND; 
+    }
+
+    return S_OK;
+}
+
+HRESULT WINAPI ViewImpl_Invoke(
+        AutomationObject* This,
+        DISPID dispIdMember,
+        REFIID riid,
+        LCID lcid,
+        WORD wFlags,
+        DISPPARAMS* pDispParams,
+        VARIANT* pVarResult,
+        EXCEPINFO* pExcepInfo,
+        UINT* puArgErr)
+{
+    MSIHANDLE msiHandle;
+    IDispatch *pDispatch = NULL;
+    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))
+                    MsiViewExecute(This->msiHandle, ((AutomationObject *)V_DISPATCH(&varg0))->msiHandle);
+                else
+                    MsiViewExecute(This->msiHandle, 0);
+	    }
+	    break;
+
+	case DISPID_VIEW_FETCH:
+	    if (wFlags & DISPATCH_METHOD)
+	    { 
+                V_VT(pVarResult) = VT_DISPATCH;
+		if ((ret = MsiViewFetch(This->msiHandle, &msiHandle)) == ERROR_SUCCESS) 
+                {
+		    if (SUCCEEDED(create_automation_object(msiHandle, NULL, (LPVOID)&pDispatch, &DIID_Record, RecordImpl_Invoke)))
+                        IDispatch_AddRef(pDispatch);
+                }
+		else TRACE("MsiViewFetch returned %d\n", ret);
+                V_DISPATCH(pVarResult) = pDispatch;
+	    }
+	    break;
+
+	case DISPID_VIEW_CLOSE:
+	    if (wFlags & DISPATCH_METHOD)
+	    { 
+		MsiViewClose(This->msiHandle);
+	    }
+	    break;
+
+         default:
+            return DISP_E_MEMBERNOTFOUND; 
+    }
+
+    return S_OK;
+}
+
+HRESULT WINAPI DatabaseImpl_Invoke(
+        AutomationObject* This,
+        DISPID dispIdMember,
+        REFIID riid,
+        LCID lcid,
+        WORD wFlags,
+        DISPPARAMS* pDispParams,
+        VARIANT* pVarResult,
+        EXCEPINFO* pExcepInfo,
+        UINT* puArgErr)
+{
+    MSIHANDLE msiHandle;
+    IDispatch *pDispatch = NULL;
+    UINT ret;
+    VARIANTARG varg0, varg1;
+    HRESULT hr;
+
+    VariantInit(&varg0);
+    VariantInit(&varg1);
+
+    switch (dispIdMember) 
+    {
+	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(create_automation_object(msiHandle, NULL, (LPVOID)&pDispatch, &DIID_View, ViewImpl_Invoke)))
+                        IDispatch_AddRef(pDispatch);
+                }
+		else TRACE("MsiDatabaseOpenView returned %d\n", ret);
+	        V_DISPATCH(pVarResult) = pDispatch;
+	    }
+	    break;
+            
+         default:
+            return DISP_E_MEMBERNOTFOUND; 
+    }
+
+    return S_OK;
+}
+
+HRESULT WINAPI SessionImpl_Invoke(
+        AutomationObject* This,
+        DISPID dispIdMember,
+        REFIID riid,
+        LCID lcid,
+        WORD wFlags,
+        DISPPARAMS* pDispParams,
+        VARIANT* pVarResult,
+        EXCEPINFO* pExcepInfo,
+        UINT* puArgErr)
+{
+    WCHAR szString[MAX_MSI_STRING];
+    DWORD dwLen = MAX_MSI_STRING;
+    IDispatch *pDispatch = NULL;
+    MSIHANDLE msiHandle;
+    LANGID langId;
+    UINT ret;
+    INSTALLSTATE iInstalled, iAction;
+    VARIANTARG varg0, varg1;
+    HRESULT hr;
+
+    VariantInit(&varg0);
+    VariantInit(&varg1);
+
+    switch (dispIdMember)
+    {
+	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;
+		if (MsiGetPropertyW(This->msiHandle, V_BSTR(&varg0), szString, &dwLen) == ERROR_SUCCESS)
+                    V_BSTR(pVarResult) = SysAllocString(szString);
+                else
+                    V_BSTR(pVarResult) = NULL;
+	    } else if (wFlags & DISPATCH_PROPERTYPUT) {
+                hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
+                if (FAILED(hr)) return hr;
+                hr = DispGetParam(pDispParams, DISPID_PROPERTYPUT, VT_BSTR, &varg1, puArgErr);
+                if (FAILED(hr)) {
+                    VariantClear(&varg0);
+                    return hr;
+                }
+		if ((ret = MsiSetPropertyW(This->msiHandle, V_BSTR(&varg0), V_BSTR(&varg1))) != ERROR_SUCCESS) 
+                    TRACE("MsiSetProperty returned %d\n", ret);
+	    }
+	    break;
+
+	case DISPID_SESSION_LANGUAGE:
+	    if (wFlags & DISPATCH_PROPERTYGET) {
+		langId = MsiGetLanguage(This->msiHandle);
+                V_VT(pVarResult) = VT_I4;
+                V_I4(pVarResult) = langId;
+	    } 
+	    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, DISPID_PROPERTYPUT, VT_BOOL, &varg1, puArgErr);
+                if (FAILED(hr)) return hr;
+		if ((ret = MsiSetMode(This->msiHandle, V_I4(&varg0), V_BOOL(&varg1))) != ERROR_SUCCESS)
+                    TRACE("MsiSetMode returned %d\n", ret);
+	    }
+	    break;
+
+	case DISPID_SESSION_DATABASE:
+	    if (wFlags & DISPATCH_PROPERTYGET) {
+                V_VT(pVarResult) = VT_DISPATCH;
+		if ((msiHandle = MsiGetActiveDatabase(This->msiHandle))) 
+                {
+		    if (SUCCEEDED(create_automation_object(msiHandle, NULL, (LPVOID)&pDispatch, &DIID_Database, DatabaseImpl_Invoke)))
+                        IDispatch_AddRef(pDispatch);
+                }
+		else TRACE("MsiGetActiveDatabase failed\n");
+                V_DISPATCH(pVarResult) = pDispatch;
+	    }
+	    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 
+		{
+		    TRACE("MsiGetFeatureState returned %d\n", ret);
+                    V_I4(pVarResult) = msiInstallStateUnknown;
+		}
+	    } 
+	    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 
+		{
+		    TRACE("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, DISPID_PROPERTYPUT, VT_I4, &varg1, puArgErr);
+                if (FAILED(hr)) {
+                    VariantClear(&varg0);
+                    return hr;
+                }
+		if ((ret = MsiSetFeatureStateW(This->msiHandle, V_BSTR(&varg0), V_I4(&varg1))) != ERROR_SUCCESS)
+                    TRACE("MsiSetFeatureState returned %d\n", ret);
+	    }
+	    break;
+
+         default:
+            return DISP_E_MEMBERNOTFOUND; 
+    }
+
+    return S_OK;
+}
+
+/* Wrapper around create_automation_object to create a session object. */
+HRESULT create_session(MSIHANDLE msiHandle, IDispatch **pDispatch)
+{
+    return create_automation_object(msiHandle, NULL, (LPVOID)pDispatch, &DIID_Session, SessionImpl_Invoke);
+}
diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h
index 971f71e..23768c0 100644
--- a/dlls/msi/msipriv.h
+++ b/dlls/msi/msipriv.h
@@ -788,6 +788,10 @@ extern VOID ControlEvent_SubscribeToEven
 extern VOID ControlEvent_UnSubscribeToEvent( MSIPACKAGE *package, LPCWSTR event,
                                       LPCWSTR control, LPCWSTR attribute );
 
+/* OLE automation */
+extern HRESULT create_session(MSIHANDLE msiHandle, IDispatch **pDispatch);
+extern HRESULT WINAPI LoadTypeInfo(IDispatch *iface, ITypeInfo **pptinfo, REFIID clsid, LCID lcid);
+
 /* User Interface messages from the actions */
 extern void ui_progress(MSIPACKAGE *, int, int, int, int);
 extern void ui_actiondata(MSIPACKAGE *, LPCWSTR, MSIRECORD *);
-- 
1.4.1



More information about the wine-patches mailing list