[msi, 2/4, try 7] msi: Add partial, expandable OLE automation support.

Misha Koshelev mk144210 at bcm.tmc.edu
Fri Apr 6 16:34:23 CDT 2007


"Legal" IDL definitions for functions implemented are here now.

Adds partial, expandable OLE automation support (returning DISP_E_MEMBERNOTFOUND for
functions not implemented yet and outputting a FIXME with the method name to the user
so we can implement them). 

Changelog:

	* msi: Add partial, expandable OLE automation support.
-------------- next part --------------
From 68839d8916b43ba53535ecbfa3ec4ab5bd586ad1 Mon Sep 17 00:00:00 2001
From: Misha Koshelev <mk144210 at bcm.tmc.edu>
Date: Fri, 6 Apr 2007 16:05:21 -0500
Subject: msi: Add partial, expandable OLE automation support.
---
 dlls/msi/Makefile.in         |    3 
 dlls/msi/automation.c        | 1013 ++++++++++++++++++++++++++++++++++++++++++
 dlls/msi/msi_main.c          |    6 
 dlls/msi/msipriv.h           |    3 
 dlls/msi/msiserver.idl       |   93 ++++
 dlls/msi/msiserver_dispids.h |   36 +
 dlls/msi/tests/automation.c  |   16 -
 7 files changed, 1156 insertions(+), 14 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..0978198
--- /dev/null
+++ b/dlls/msi/automation.c
@@ -0,0 +1,1013 @@
+/*
+ * 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);
+}
+
+/* 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 = (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 (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 WCHAR szComma[] = { ',',0 };
+        static 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 = szExceptionSource;
+            pExcepInfo->bstrDescription = 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 */
+    if (bstrName == NULL) SysFreeString(bstrName);
+
+    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
+		{
+		    ERR("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)
+                {
+                    ERR("MsiRecordSetString returned %d\n", ret);
+                    return DISP_E_EXCEPTION;
+                }
+	    }
+	    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) && V_DISPATCH(&varg0) != NULL)
+                    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);
+                        V_DISPATCH(pVarResult) = pDispatch;
+                    }
+                }
+		else if (ret == ERROR_NO_MORE_ITEMS)
+                    V_DISPATCH(pVarResult) = NULL;
+                else
+                {
+                    ERR("MsiViewFetch returned %d\n", ret);
+                    return DISP_E_EXCEPTION;
+                }
+	    }
+	    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);
+                        V_DISPATCH(pVarResult) = pDispatch;
+                    }
+                }
+		else 
+                {
+                    ERR("MsiDatabaseOpenView returned %d\n", ret);
+                    return DISP_E_EXCEPTION;
+                }
+	    }
+	    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) 
+                {
+                    ERR("MsiSetProperty returned %d\n", ret);
+                    return DISP_E_EXCEPTION;
+                }
+	    }
+	    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)
+                {
+                    ERR("MsiSetMode returned %d\n", ret);
+                    return DISP_E_EXCEPTION;
+                }
+	    }
+	    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);
+                        V_DISPATCH(pVarResult) = pDispatch;
+                    }
+                }
+		else 
+                {
+                    ERR("MsiGetActiveDatabase failed\n");
+                    return DISP_E_EXCEPTION;
+                }
+	    }
+	    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:
+                        FIXME("MsiDoAction returned unhandled value %d\n", ret);
+                        return DISP_E_EXCEPTION;
+                }    
+            }
+            break;
+
+        case DISPID_SESSION_SETINSTALLLEVEL:
+            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;
+            }
+            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;
+		}
+	    } 
+	    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, 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)
+                {
+                    ERR("MsiSetFeatureState returned %d\n", ret);
+                    return DISP_E_EXCEPTION;
+                }
+	    }
+	    break;
+
+         default:
+            return DISP_E_MEMBERNOTFOUND; 
+    }
+
+    return S_OK;
+}
+
+HRESULT WINAPI InstallerImpl_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_INSTALLER_OPENPACKAGE:
+	    if (wFlags & DISPATCH_METHOD)
+	    { 
+                hr = DispGetParam(pDispParams, 0, VT_BSTR, &varg0, puArgErr);
+                if (FAILED(hr)) return hr;
+                hr = DispGetParam(pDispParams, 1, VT_I4, &varg1, puArgErr);
+                if (FAILED(hr)) return hr;
+                V_VT(pVarResult) = VT_DISPATCH;
+		if ((ret = MsiOpenPackageExW(V_BSTR(&varg0), V_I4(&varg1), &msiHandle)) == ERROR_SUCCESS) 
+                {
+		    if (SUCCEEDED(create_automation_object(msiHandle, NULL, (LPVOID)&pDispatch, &DIID_Session, SessionImpl_Invoke)))
+                    {
+                        IDispatch_AddRef(pDispatch);
+                        V_DISPATCH(pVarResult) = pDispatch;
+                    }
+                }
+		else 
+                {
+                    ERR("MsiOpenPackageEx returned %d\n", ret);
+                    return DISP_E_EXCEPTION;
+                }
+	    }
+	    break;
+            
+         default:
+            return DISP_E_MEMBERNOTFOUND; 
+    }
+
+    return S_OK;
+}
+
+/* Wrapper around create_automation_object to create an installer object. */
+HRESULT create_msiserver(IUnknown *pOuter, LPVOID *ppObj)
+{
+    return create_automation_object(0, pOuter, ppObj, &DIID_Installer, InstallerImpl_Invoke);
+}
diff --git a/dlls/msi/msi_main.c b/dlls/msi/msi_main.c
index a3dac7f..402e173 100644
--- a/dlls/msi/msi_main.c
+++ b/dlls/msi/msi_main.c
@@ -115,12 +115,6 @@ ITypeLib *get_msi_typelib( LPWSTR *path 
     return msi_typelib;
 }
 
-static HRESULT create_msiserver( IUnknown *pOuter, LPVOID *ppObj )
-{
-    FIXME("\n");
-    return E_FAIL;
-}
-
 typedef struct tagIClassFactoryImpl {
     const IClassFactoryVtbl *lpVtbl;
     HRESULT (*create_object)( IUnknown*, LPVOID* );
diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h
index 55dd2fa..f160e2c 100644
--- a/dlls/msi/msipriv.h
+++ b/dlls/msi/msipriv.h
@@ -788,6 +788,9 @@ extern VOID ControlEvent_SubscribeToEven
 extern VOID ControlEvent_UnSubscribeToEvent( MSIPACKAGE *package, LPCWSTR event,
                                       LPCWSTR control, LPCWSTR attribute );
 
+/* OLE automation */
+extern HRESULT create_msiserver(IUnknown *pOuter, LPVOID *ppObj);
+
 /* User Interface messages from the actions */
 extern void ui_progress(MSIPACKAGE *, int, int, int, int);
 extern void ui_actiondata(MSIPACKAGE *, LPCWSTR, MSIRECORD *);
diff --git a/dlls/msi/msiserver.idl b/dlls/msi/msiserver.idl
index 9966d90..4d6c00b 100644
--- a/dlls/msi/msiserver.idl
+++ b/dlls/msi/msiserver.idl
@@ -16,6 +16,7 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include "msiserver_dispids.h"
 import "unknwn.idl";
 import "wtypes.idl";
 import "objidl.idl";
@@ -42,6 +43,10 @@ library WindowsInstaller
     {
     properties:
     methods:
+        [id(DISPID_INSTALLER_OPENPACKAGE)]
+            Session* OpenPackage(
+                [in] VARIANT Path,
+                [in, optional, defaultvalue(0)] long OptionalOption);
     }
 
     [ uuid(000C1093-0000-0000-C000-000000000046) ]
@@ -49,6 +54,12 @@ library WindowsInstaller
     {
     properties:
     methods:
+        [id(DISPID_RECORD_STRINGDATA), propget]
+            BSTR StringData([in] long FieldNumber);
+        [id(DISPID_RECORD_STRINGDATA), propput]
+            void StringData(
+                [in] long FieldNumber,
+                [in] BSTR rhs);
     }
 
     [ uuid(000C1095-0000-0000-C000-000000000046) ]
@@ -84,6 +95,12 @@ library WindowsInstaller
     {
         properties:
         methods:
+        [id(DISPID_VIEW_EXECUTE)]
+            void Execute([in, optional, defaultvalue(0)] Record *OptionalRecord);
+        [id(DISPID_VIEW_FETCH)]
+            Record* Fetch();
+        [id(DISPID_VIEW_CLOSE)]
+            void Close();
     }
 
     [ uuid(000C109D-0000-0000-C000-000000000046) ]
@@ -91,13 +108,89 @@ library WindowsInstaller
     {
         properties:
         methods:
+        [id(DISPID_DATABASE_OPENVIEW)]
+            View* OpenView([in] BSTR QueryString);
     }
 
+    typedef enum {
+        msiDoActionStatusNoAction = 0,
+        msiDoActionStatusSuccess = 1,
+        msiDoActionStatusUserExit = 2,
+        msiDoActionStatusFailure = 3,
+        msiDoActionStatusSuspend = 4,
+        msiDoActionStatusFinished = 5,
+        msiDoActionStatusWrongState = 6,
+        msiDoActionStatusBadActionData = 7
+    } MsiDoActionStatus;
+
+    typedef enum {
+        msiRunModeAdmin = 0,
+        msiRunModeAdvertise = 1,
+        msiRunModeMaintenance = 2,
+        msiRunModeRollbackEnabled = 3,
+        msiRunModeLogEnabled = 4,
+        msiRunModeOperations = 5,
+        msiRunModeRebootAtEnd = 6,
+        msiRunModeRebootNow = 7,
+        msiRunModeCabinet = 8,
+        msiRunModeSourceShortNames = 9,
+        msiRunModeTargetShortNames = 10,
+        msiRunModeWindows9x = 12,
+        msiRunModeZawEnabled = 13,
+        msiRunModeScheduled = 16,
+        msiRunModeRollback = 17,
+        msiRunModeCommit = 18
+    } MsiRunMode;
+
+    typedef enum {
+        msiInstallStateNotUsed = -7,
+        msiInstallStateBadConfig = -6,
+        msiInstallStateIncomplete = -5,
+        msiInstallStateSourceAbsent = -4,
+        msiInstallStateInvalidArg = -2,
+        msiInstallStateUnknown = -1,
+        msiInstallStateBroken = 0,
+        msiInstallStateAdvertised = 1,
+        msiInstallStateRemoved = 1,
+        msiInstallStateAbsent = 2,
+        msiInstallStateLocal = 3,
+        msiInstallStateSource = 4,
+        msiInstallStateDefault = 5
+    } MsiInstallState;
+
     [ uuid(000C109E-0000-0000-C000-000000000046) ]
     dispinterface Session
     {
     properties:
     methods:
+        [id(DISPID_SESSION_PROPERTY), propget]
+            BSTR Property([in] BSTR PropertyName);
+        [id(DISPID_SESSION_PROPERTY), propput]
+            void Property(
+                [in] BSTR PropertyName,
+                [in] BSTR rhs);
+        [id(DISPID_SESSION_LANGUAGE), propget]
+            long Language();
+        [id(DISPID_SESSION_MODE), propget]
+            VARIANT_BOOL Mode([in] MsiRunMode runMode);
+        [id(DISPID_SESSION_MODE), propput]
+            void Mode(
+                [in] MsiRunMode runMode,
+                [in] VARIANT_BOOL rhs);
+        [id(DISPID_SESSION_DATABASE), propget]
+            Database* Database();
+        [id(DISPID_SESSION_DOACTION)]
+            MsiDoActionStatus DoAction([in] BSTR ActionString);
+        [id(DISPID_SESSION_FEATURECURRENTSTATE), propget]
+            MsiInstallState FeatureCurrentState([in] BSTR FeatureName);
+        [id(DISPID_SESSION_FEATUREREQUESTSTATE), propget]
+            MsiInstallState FeatureRequestState([in] BSTR FeatureName);
+        [id(DISPID_SESSION_FEATUREREQUESTSTATE), propput]
+            void FeatureRequestState(
+                [in] BSTR FeatureName,
+                [in] MsiInstallState rhs);
+        [id(DISPID_SESSION_SETINSTALLLEVEL)]
+            void SetInstallLevel([in] long InstallLevel);
     }
 
     [ uuid(000C109F-0000-0000-C000-000000000046) ]
diff --git a/dlls/msi/msiserver_dispids.h b/dlls/msi/msiserver_dispids.h
new file mode 100644
index 0000000..1c7a17f
--- /dev/null
+++ b/dlls/msi/msiserver_dispids.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 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 DISPID_INSTALLER_OPENPACKAGE 2
+
+#define DISPID_RECORD_STRINGDATA 1
+
+#define DISPID_VIEW_EXECUTE 1
+#define DISPID_VIEW_FETCH 2
+#define DISPID_VIEW_CLOSE 4
+
+#define DISPID_DATABASE_OPENVIEW 3
+
+#define DISPID_SESSION_PROPERTY 2
+#define DISPID_SESSION_LANGUAGE 3
+#define DISPID_SESSION_MODE 4
+#define DISPID_SESSION_DATABASE 5
+#define DISPID_SESSION_DOACTION 8
+#define DISPID_SESSION_FEATURECURRENTSTATE 13
+#define DISPID_SESSION_FEATUREREQUESTSTATE 14
+#define DISPID_SESSION_SETINSTALLLEVEL 19
diff --git a/dlls/msi/tests/automation.c b/dlls/msi/tests/automation.c
index c830efd..ecacaf0 100644
--- a/dlls/msi/tests/automation.c
+++ b/dlls/msi/tests/automation.c
@@ -354,14 +354,14 @@ static void test_dispatch()
 
     /* Try with NULL params */
     hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
-    ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08lx\n", (unsigned long int)hr);
+    todo_wine ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08lx\n", (unsigned long int)hr);
 
     /* Try one empty parameter */
     dispparams.rgvarg = vararg;
     dispparams.cArgs = 1;
     VariantInit(&vararg[0]);
     hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
-    ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08lx\n", (unsigned long int)hr);    
+    todo_wine ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08lx\n", (unsigned long int)hr);    
 
     /* Try one parameter, function requires two */
     VariantInit(&vararg[0]);
@@ -808,16 +808,16 @@ static void test_Session(IDispatch *pSes
     /* Session::Mode, get */
     hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
     ok(SUCCEEDED(hr), "Session_ModeGet failed, hresult 0x%08lx\n", (unsigned long int)hr);
-    ok(!bool, "Reboot at end session mode is %d\n", bool);
+    todo_wine ok(!bool, "Reboot at end session mode is %d\n", bool);
 
     /* Session::Mode, put */
     hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, TRUE);
-    ok(SUCCEEDED(hr), "Session_ModePut failed, hresult 0x%08lx\n", (unsigned long int)hr);
+    todo_wine ok(SUCCEEDED(hr), "Session_ModePut failed, hresult 0x%08lx\n", (unsigned long int)hr);
     hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
     ok(SUCCEEDED(hr), "Session_ModeGet failed, hresult 0x%08lx\n", (unsigned long int)hr);
     ok(bool, "Reboot at end session mode is %d, expected 1\n", bool);    
     hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, FALSE);  /* set it again so we don't reboot */
-    ok(SUCCEEDED(hr), "Session_ModePut failed, hresult 0x%08lx\n", (unsigned long int)hr);
+    todo_wine ok(SUCCEEDED(hr), "Session_ModePut failed, hresult 0x%08lx\n", (unsigned long int)hr);
 
     /* Session::Database, get */
     hr = Session_Database(pSession, &pDatabase);
@@ -904,15 +904,15 @@ START_TEST(automation)
     hr = CLSIDFromProgID(szProgId, &clsid);
     ok (SUCCEEDED(hr), "CLSIDFromProgID returned 0x%08lx\n", (unsigned long int)hr);
     hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
-    todo_wine ok(SUCCEEDED(hr), "CoCreateInstance returned 0x%08lx\n", (unsigned long int)hr);
+    ok(SUCCEEDED(hr), "CoCreateInstance returned 0x%08lx\n", (unsigned long int)hr);
 
     if (pUnk) 
     {
         hr = IUnknown_QueryInterface(pUnk, &IID_IDispatch, (void **)&pInstaller);
         ok (SUCCEEDED(hr), "IUnknown::QueryInterface returned 0x%08lx\n", (unsigned long int)hr);
 
-        todo_wine test_dispatch();
-        todo_wine test_Installer();
+        test_dispatch();
+        test_Installer();
 
         hr = IUnknown_Release(pUnk);
         ok (SUCCEEDED(hr), "IUnknown::Release returned 0x%08lx\n", (unsigned long int)hr);
-- 
1.4.1



More information about the wine-patches mailing list