msi: Add full JScript/VBScript support and partial expandable OLE automation support. [PATCH 3/3]

Misha Koshelev mk144210 at bcm.tmc.edu
Sun Feb 25 22:50:37 CST 2007


On Sun, 2007-02-25 at 13:00 +0000, Robert Shearman wrote:
> Misha Koshelev wrote:
> > +/* Macros to get pointer to AutomationObject) from the other VTables. */
> >   
> 
> Typo with extra ")" here.
> 
> > +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 *iDispatch = NULL;
> > +    MSIHANDLE msiHandle;
> > +    LANGID langId;
> > +    UINT ret;
> > +    INSTALLSTATE iInstalled, iAction;
> >   
> 
> Some error checking here would be good, like you do in 
> AutomationObject_Invoke.
> 
> > +
> > +    switch (dispIdMember)
> > +    {
> >   
> ...
> > +/*
> > + * AutomationObject - "base" class for all automation objects so we don't have to repeat functions. Just
> > + *                    need to implement Invoke function for each dispinterface and pass the new function
> > + *                    to create_automation_object.
> > + */
> > +
> > +typedef struct {
> > +    /*
> > +     * 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 IDispatch::Invoke, specific to this type of object */
> > +    LPVOID funcInvoke;
> > +} AutomationObject;
> >   
> 
> You shouldn't need to expose the implementation details of 
> AutomationObject outside of automation.c.
> 
> > +
> > +/* This is the function that one needs to call to create an automation object. */
> > +extern HRESULT create_automation_object(MSIHANDLE msiHandle, IUnknown *pUnkOuter, LPVOID *ppObj, REFIID clsid, LPVOID funcInvoke);
> >   
> 
> It is dangerous to use LPVOID as the type to pass a function in.
> 
> > +
> > +/* We need to expose these functions because our IActiveScriptSite calls it */
> > +extern HRESULT WINAPI LoadTypeInfo(IDispatch *iface, ITypeInfo **pptinfo, REFIID clsid, LCID lcid);
> > +extern HRESULT WINAPI SessionImpl_Invoke(AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*);
> > +
> > +/* Disp Ids 
> > + * (not complete, look in msiserver.idl to add more) */
> > +typedef enum {
> > +    RecordDispId_StringData=1,
> > +    RecordDispId_IntegerData,
> > +    RecordDispId_SetStream,
> > +    RecordDispId_ReadStream,
> > +    RecordDispId_FieldCount,
> > +    RecordDispId_IsNull,
> > +    RecordDispId_DataSize,
> > +    RecordDispId_ClearData,
> > +    RecordDispId_FormatText
> > +} RecordDispId;
> > +
> > +typedef enum {
> > +    ViewDispId_Execute=1,
> > +    ViewDispId_Fetch,
> > +    ViewDispId_Modify,
> > +    ViewDispId_Close,
> > +    ViewDispId_ColumnInfo,
> > +    ViewDispId_GetError
> > +} ViewDispId;
> > +
> > +typedef enum {
> > +    DatabaseDispId_DatabaseState=1,
> > +    DatabaseDispId_SummaryInformation,
> > +    DatabaseDispId_OpenView,
> > +    DatabaseDispId_Commit,
> > +    DatabaseDispId_PrimaryKeys,
> > +    DatabaseDispId_Import,
> > +    DatabaseDispId_Export,
> > +    DatabaseDispId_Merge,
> > +    DatabaseDispId_GenerateTransform,
> > +    DatabaseDispId_ApplyTransform,
> > +    DatabaseDispId_EnableUIPreview,
> > +    DatabaseDispId_TablePersistent,
> > +    DatabaseDispId_CreateTransformSummaryInfo
> > +} DatabaseDispId;
> > +
> > +typedef enum {
> > +    SessionDispId_Installer=1,
> > +    SessionDispId_Property,
> > +    SessionDispId_Language,
> > +    SessionDispId_Mode,
> > +    SessionDispId_Database,
> > +    SessionDispId_SourcePath,
> > +    SessionDispId_TargetPath,
> > +    SessionDispId_DoAction,
> > +    SessionDispId_Sequence,
> > +    SessionDispId_EvaluateCondition,
> > +    SessionDispId_FormatRecord,
> > +    SessionDispId_Message,
> > +    SessionDispId_FeatureCurrentState,
> > +    SessionDispId_FeatureRequestState,
> > +    SessionDispId_FeatureValidStates,
> > +    SessionDispId_FeatureCost,
> > +    SessionDispId_ComponentCurrentState,
> > +    SessionDispId_ComponentRequestState,
> > +    SessionDispId_SetInstallLevel,
> > +    SessionDispId_VerifyDiskSpace,
> > +    SessionDispId_ProductProperty,
> > +    SessionDispId_FeatureInfo,
> > +    SessionDispId_ComponentCost
> > +} SessionDispId;
> >   
> 
> See dlls/oleaut32/tests/tmarshal_dispids.h and 
> dlls/oleaut32/tests/tmarshal.idl for how to use DISPIDs properly.
> 
> > +typedef struct {
> > +    IActiveScriptSite lpVtbl;
> > +    AutomationObject *session;
> >   
> 
> You don't actually access this as anything other than an IDispatch 
> object, so you might as well change to "IDispatch *session".
> 
> > +LPCWSTR read_script_from_file(LPCWSTR szFile, INT type)
> >   
> 
> Should be static.
> 
> > +/* JScript or VBScript? */
> > +LPCWSTR progid_from_type(INT type)
> >   
> 
> Should also be static.
> 
> > +
> > +/*
> > + * Call a script. This is our meat and potatoes. 
> > + *     - Currently, since the function is relatively new, it will always end up returning S_OK.
> > + *       Think of it like a bonus feature, we can run the script - great. If we have a problem,
> > + *       we are no worse off than if this function had not been called.
> > + */
> > +DWORD call_script(MSIHANDLE hPackage, INT type, LPCWSTR filename, LPCWSTR function, LPCWSTR action)
> > +{
> > +    LPCWSTR script = NULL, progId = NULL;
> > +    HRESULT hr;
> > +    IActiveScript *iActiveScript = NULL;
> > +    IActiveScriptParse *iActiveScriptParse = NULL;
> >   
> 
> I haven't seen this variable notation style before. In Hungarian 
> notation "p" is used instead of "i" to show a pointer to an object 
> exposing the interface declared.
> 

I have implemented all the changes you outlined (thanks a lot) in this
and your other email, with the exception of the extra error checking in
each of the individual Invoke functions as they are called from within
AutomationObject::Invoke after the error checking already occurs. What
do you think?

Thanks
Misha

p.s. The 5th patch is not a part of my submission, but is just a hack I
used to make the IDL file with the dispids using oleview. This patch
will make oleview use the DISPID_PARENT_MEMBER notation for ids and will
output the include file to standard output. Thought maybe it would be
useful for someone.
-------------- next part --------------
From bfde4dd7c028bf9e708d12b92a8e8439cb3358f1 Mon Sep 17 00:00:00 2001
From: Misha Koshelev <mk144210 at bcm.tmc.edu>
Date: Sun, 25 Feb 2007 22:19:22 -0600
Subject: msi: Added handlers for JScript/VBScript actions that call one script function.
---
 dlls/msi/custom.c |  252 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 252 insertions(+), 0 deletions(-)

diff --git a/dlls/msi/custom.c b/dlls/msi/custom.c
index ba5c825..7cbbf40 100644
--- a/dlls/msi/custom.c
+++ b/dlls/msi/custom.c
@@ -58,6 +58,14 @@ static UINT HANDLE_CustomType50(MSIPACKA
                                 LPCWSTR target, const INT type, LPCWSTR action);
 static UINT HANDLE_CustomType34(MSIPACKAGE *package, LPCWSTR source,
                                 LPCWSTR target, const INT type, LPCWSTR action);
+static UINT HANDLE_CustomType37_38(MSIPACKAGE *package, LPCWSTR source,
+                                LPCWSTR target, const INT type, LPCWSTR action);
+static UINT HANDLE_CustomType5_6(MSIPACKAGE *package, LPCWSTR source,
+                                LPCWSTR target, const INT type, LPCWSTR action);
+static UINT HANDLE_CustomType21_22(MSIPACKAGE *package, LPCWSTR source,
+                                LPCWSTR target, const INT type, LPCWSTR action);
+static UINT HANDLE_CustomType53_54(MSIPACKAGE *package, LPCWSTR source,
+                                LPCWSTR target, const INT type, LPCWSTR action);
 
 typedef UINT (WINAPI *MsiCustomActionEntryPoint)( MSIHANDLE );
 
@@ -266,6 +274,22 @@ UINT ACTION_CustomAction(MSIPACKAGE *pac
             rc = MSI_SetPropertyW(package,source,deformated);
             msi_free(deformated);
             break;
+	case 37: /* JScript/VBScript text stored in target column. */
+	case 38:
+	    rc = HANDLE_CustomType37_38(package,source,target,type,action);
+	    break;
+	case 5:
+	case 6: /* JScript/VBScript file stored in a Binary table stream. */
+	    rc = HANDLE_CustomType5_6(package,source,target,type,action);
+	    break;
+	case 21: /* JScript/VBScript file installed with the product. */
+	case 22:
+	    rc = HANDLE_CustomType21_22(package,source,target,type,action);
+	    break;
+	case 53: /* JScript/VBScript text specified by a property value. */
+	case 54:
+	    rc = HANDLE_CustomType53_54(package,source,target,type,action);
+	    break;
         default:
             FIXME("UNHANDLED ACTION TYPE %i (%s %s)\n",
              type & CUSTOM_ACTION_TYPE_MASK, debugstr_w(source),
@@ -855,6 +879,234 @@ static UINT HANDLE_CustomType34(MSIPACKA
     return wait_process_handle(package, type, info.hProcess, action);
 }
 
+static DWORD WINAPI ACTION_CallScript( const LPGUID guid )
+{
+    msi_custom_action_info *info;
+    MSIHANDLE hPackage;
+    UINT r = ERROR_FUNCTION_FAILED;
+
+    info = find_action_by_guid( guid );
+    if (!info)
+    {
+        ERR("failed to find action %s\n", debugstr_guid( guid) );
+        return r;
+    }
+
+    FIXME("function %s, script %s\n", debugstr_w( info->function ), debugstr_w( info->dllname ) );
+
+    hPackage = alloc_msihandle( &info->package->hdr );
+    if (hPackage)
+    {
+	r = S_OK;
+        MsiCloseHandle( hPackage );
+    }
+    else
+        ERR("failed to create handle for %p\n", info->package );
+
+    return r;
+}
+
+static DWORD WINAPI ScriptThread( LPVOID arg )
+{
+    LPGUID guid = arg;
+    DWORD rc = 0;
+
+    TRACE("custom action (%x) started\n", GetCurrentThreadId() );
+
+    rc = ACTION_CallScript( guid );
+
+    TRACE("custom action (%x) returned %i\n", GetCurrentThreadId(), rc );
+
+    MsiCloseAllHandles();
+    return rc;
+}
+
+static msi_custom_action_info *do_msidbCustomActionTypeScript(
+    MSIPACKAGE *package, INT type, LPCWSTR script, LPCWSTR function, LPCWSTR action )
+{
+    msi_custom_action_info *info;
+
+    info = msi_alloc( sizeof *info );
+    if (!info)
+        return NULL;
+
+    msiobj_addref( &package->hdr );
+    info->package = package;
+    info->type = type;
+    info->function = strdupW( function );
+    info->dllname = strdupW( script );
+    info->action = strdupW( action );
+    CoCreateGuid( &info->guid );
+
+    EnterCriticalSection( &msi_custom_action_cs );
+    list_add_tail( &msi_pending_custom_actions, &info->entry );
+    LeaveCriticalSection( &msi_custom_action_cs );
+
+    info->handle = CreateThread( NULL, 0, ScriptThread, &info->guid, 0, NULL );
+    if (!info->handle)
+    {
+        free_custom_action_data( info );
+        return NULL;
+    }
+
+    return info;
+}
+
+static UINT HANDLE_CustomType37_38(MSIPACKAGE *package, LPCWSTR source,
+                               LPCWSTR target, const INT type, LPCWSTR action)
+{
+    msi_custom_action_info *info;
+
+    TRACE("%s %s\n", debugstr_w(source), debugstr_w(target));
+    
+    info = do_msidbCustomActionTypeScript( package, type, target, NULL, action );
+
+    return wait_thread_handle( info );
+}
+
+static UINT HANDLE_CustomType5_6(MSIPACKAGE *package, LPCWSTR source,
+                               LPCWSTR target, const INT type, LPCWSTR action)
+{
+    static const WCHAR query[] = {
+        'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
+        '`','B','i' ,'n','a','r','y','`',' ','W','H','E','R','E',' ',
+        '`','N','a','m','e','`',' ','=',' ','\'','%','s','\'',0};
+    MSIRECORD *row = 0;
+    msi_custom_action_info *info;
+    CHAR *buffer = NULL;
+    WCHAR *bufferw = NULL;
+    DWORD sz = 0, szw = 0;
+    UINT r;
+
+    TRACE("%s %s\n", debugstr_w(source), debugstr_w(target));
+
+    row = MSI_QueryGetRecord(package->db, query, source);
+    if (!row)
+        return ERROR_FUNCTION_FAILED;
+
+    r = MSI_RecordReadStream(row, 2, NULL, &sz);
+    if (r != ERROR_SUCCESS)
+	return r;
+
+    buffer = msi_alloc(sizeof(CHAR)*(sz+1));
+    if (!buffer)
+	return ERROR_FUNCTION_FAILED;
+
+    r = MSI_RecordReadStream(row, 2, buffer, &sz);
+    if (r != ERROR_SUCCESS)
+    {
+	msi_free(buffer);
+	return r;
+    }
+
+    buffer[sz] = 0;
+    szw = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, buffer, -1, bufferw, 0);
+    bufferw = msi_alloc(sizeof(WCHAR)*szw);
+    if (!szw)
+    {
+	msi_free(bufferw);
+	return ERROR_FUNCTION_FAILED;
+    }
+
+    r = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, buffer, -1, bufferw, szw);
+    msi_free(buffer);    
+    if (!r)
+    {
+	msi_free(bufferw);
+	return ERROR_FUNCTION_FAILED;
+    }
+
+    info = do_msidbCustomActionTypeScript( package, type, bufferw, target, action );
+    msi_free(bufferw);
+    return wait_thread_handle( info );
+}
+
+static UINT HANDLE_CustomType21_22(MSIPACKAGE *package, LPCWSTR source,
+                               LPCWSTR target, const INT type, LPCWSTR action)
+{
+    msi_custom_action_info *info;
+    MSIFILE *file;
+    HANDLE hFile;
+    DWORD sz, szw, szHighWord = 0, read;
+    CHAR *buffer=NULL;
+    WCHAR *bufferw=NULL;
+    BOOL bRet;
+    UINT r;
+
+    TRACE("%s %s\n", debugstr_w(source), debugstr_w(target));
+
+    file = get_loaded_file(package,source);
+    if (!file)
+    {
+	ERR("invalid file key %s\n", debugstr_w(source));
+	return ERROR_FUNCTION_FAILED;
+    }
+ 
+    hFile = CreateFileW(file->TargetPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+    if (hFile == INVALID_HANDLE_VALUE) 
+	return ERROR_FUNCTION_FAILED;
+ 
+    sz = GetFileSize(hFile, &szHighWord);
+    if (sz == INVALID_FILE_SIZE || szHighWord != 0) 
+    {
+	CloseHandle(hFile);
+	return ERROR_FUNCTION_FAILED;
+    }
+ 
+    buffer = msi_alloc(sizeof(CHAR)*(sz+1));
+    if (!buffer) 
+    {
+	CloseHandle(hFile);
+ 	return ERROR_FUNCTION_FAILED;
+    }
+   
+    bRet = ReadFile(hFile, (LPVOID)buffer, sz, &read, NULL);
+    CloseHandle(hFile);
+    if (!bRet);
+    {
+        msi_free(buffer);
+ 	return ERROR_FUNCTION_FAILED;
+    }
+
+    buffer[read] = 0;
+    szw = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, buffer, -1, bufferw, 0);
+    bufferw = msi_alloc(sizeof(WCHAR)*szw);
+    if (!szw)
+    {
+	msi_free(bufferw);
+	return ERROR_FUNCTION_FAILED;
+    }
+
+    r = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, buffer, -1, bufferw, szw);
+    msi_free(buffer);    
+    if (!r)
+    {
+	msi_free(bufferw);
+	return ERROR_FUNCTION_FAILED;
+    }
+
+    info = do_msidbCustomActionTypeScript( package, type, bufferw, target, action );
+    msi_free(bufferw);
+    return wait_thread_handle( info );
+}
+
+static UINT HANDLE_CustomType53_54(MSIPACKAGE *package, LPCWSTR source,
+                               LPCWSTR target, const INT type, LPCWSTR action)
+{
+    msi_custom_action_info *info;
+    WCHAR *prop;
+
+    TRACE("%s %s\n", debugstr_w(source), debugstr_w(target));
+
+    prop = msi_dup_property(package,source);
+    if (!prop)
+	return ERROR_SUCCESS;
+      
+    info = do_msidbCustomActionTypeScript( package, type, prop, NULL, action );
+    msi_free(prop);
+    return wait_thread_handle( info );
+}
+
 void ACTION_FinishCustomActions(MSIPACKAGE* package)
 {
     struct list *item;
-- 
1.4.1

-------------- next part --------------
From e46996893110b24d0e8a15ef7df158563bc56a1c Mon Sep 17 00:00:00 2001
From: Misha Koshelev <mk144210 at bcm.tmc.edu>
Date: Sun, 25 Feb 2007 22:22:02 -0600
Subject: msi: Expand IDL file to contain all OLE automation interfaces.
---
 dlls/msi/msiserver.idl       |  721 ++++++++++++++++++++++++++++++++++++++----
 dlls/msi/msiserver_dispids.h |  140 ++++++++
 2 files changed, 798 insertions(+), 63 deletions(-)

diff --git a/dlls/msi/msiserver.idl b/dlls/msi/msiserver.idl
index 9966d90..d5b140c 100644
--- a/dlls/msi/msiserver.idl
+++ b/dlls/msi/msiserver.idl
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2007 Mike McCormack
+ *                    Misha Koshelev
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -16,14 +17,21 @@
  * 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";
 import "oaidl.idl";
 
-[ uuid(000C1092-0000-0000-C000-000000000046), version(1.0) ]
+[
+    uuid(000C1092-0000-0000-C000-000000000046),
+    version(1.0),
+    helpstring("Microsoft Windows Installer Object Library")
+]
 library WindowsInstaller
 {
+    /* TLib :
+     * Forward declare all types defined in this typelib */
     dispinterface Installer;
     dispinterface Record;
     dispinterface Session;
@@ -34,90 +42,677 @@ library WindowsInstaller
     dispinterface FeatureInfo;
     dispinterface RecordList;
     dispinterface StringList;
-    dispinterface Product;
-    dispinterface Patch;
-
-    [ uuid(000C1090-0000-0000-C000-000000000046) ]
-    dispinterface Installer
-    {
-    properties:
-    methods:
-    }
-
-    [ uuid(000C1093-0000-0000-C000-000000000046) ]
-    dispinterface Record
-    {
-    properties:
-    methods:
-    }
-
-    [ uuid(000C1095-0000-0000-C000-000000000046) ]
-    dispinterface StringList
-    {
+
+    typedef enum {
+        msiUILevelNoChange = 0,
+        msiUILevelDefault = 1,
+        msiUILevelNone = 2,
+        msiUILevelBasic = 3,
+        msiUILevelReduced = 4,
+        msiUILevelFull = 5,
+        msiUILevelHideCancel = 32,
+        msiUILevelProgressOnly = 64,
+        msiUILevelEndDialog = 128
+    } MsiUILevel;
+
+    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;
+
+    typedef enum {
+        msiReinstallModeFileMissing = 2,
+        msiReinstallModeFileOlderVersion = 4,
+        msiReinstallModeFileEqualVersion = 8,
+        msiReinstallModeFileExact = 16,
+        msiReinstallModeFileVerify = 32,
+        msiReinstallModeFileReplace = 64,
+        msiReinstallModeMachineData = 128,
+        msiReinstallModeUserData = 256,
+        msiReinstallModeShortcut = 512,
+        msiReinstallModePackage = 1024
+    } MsiReinstallMode;
+
+    typedef enum {
+        msiInstallTypeDefault = 0,
+        msiInstallTypeNetworkImage = 1
+    } MsiInstallType;
+
+    typedef enum {
+        msiInstallModeNoSourceResolution = -3,
+        msiInstallModeNoDetection = -2,
+        msiInstallModeExisting = -1,
+        msiInstallModeDefault = 0
+    } MsiInstallMode;
+
+    typedef enum {
+        msiSignatureInfoCertificate = 0,
+        msiSignatureInfoHash = 1
+    } MsiSignatureInfo;
+
+    typedef enum {
+        msiReadStreamInteger = 0,
+        msiReadStreamBytes = 1,
+        msiReadStreamAnsi = 2,
+        msiReadStreamDirect = 3
+    } MsiReadStream;
+
+    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;
+
+    [
+        uuid(000C1090-0000-0000-C000-000000000046),
+        helpcontext(0x00002328)
+    ]
+    dispinterface Installer {
         properties:
+            [id(DISPID_INSTALLER_UILEVEL)]
+            MsiUILevel UILevel;
         methods:
-    }
+            [id(DISPID_INSTALLER_CREATERECORD)]
+            Record* CreateRecord([in] long Count);
+            [id(DISPID_INSTALLER_OPENPACKAGE)]
+            Session* OpenPackage([in] VARIANT PackagePath);
+            [id(DISPID_INSTALLER_OPENPRODUCT)]
+            Session* OpenProduct([in] BSTR ProductCode);
+            [id(DISPID_INSTALLER_OPENDATABASE)]
+            Database* OpenDatabase(
+                                                          [in] BSTR DatabasePath,
+                                                          [in] VARIANT OpenMode);
+            [id(DISPID_INSTALLER_SUMMARYINFORMATION), propget]
+            SummaryInfo* SummaryInformation(
+                                                                            [in] BSTR PackagePath,
+                                                                            [in, optional, defaultvalue(0)] long UpdateCount);
+            [id(DISPID_INSTALLER_ENABLELOG)]
+            void EnableLog(
+                                                  [in] BSTR LogMode,
+                                                  [in] BSTR LogFile);
+            [id(DISPID_INSTALLER_INSTALLPRODUCT)]
+            void InstallProduct(
+                                                       [in] BSTR PackagePath,
+                                                       [in, optional, defaultvalue("0")] BSTR PropertyValues);
+            [id(DISPID_INSTALLER_VERSION), propget]
+            BSTR Version();
+            [id(DISPID_INSTALLER_LASTERRORRECORD)]
+            Record* LastErrorRecord();
+            [id(DISPID_INSTALLER_REGISTRYVALUE)]
+            BSTR RegistryValue(
+                                                      [in] VARIANT Root,
+                                                      [in] BSTR Key,
+                                                      [in, optional] VARIANT Value);
+            [id(DISPID_INSTALLER_FILEATTRIBUTES)]
+            long FileAttributes([in] BSTR FilePath);
+            [id(DISPID_INSTALLER_FILESIZE)]
+            long FileSize([in] BSTR FilePath);
+            [id(DISPID_INSTALLER_FILEVERSION)]
+            BSTR FileVersion(
+                                                    [in] BSTR FilePath,
+                                                    [in, optional] VARIANT Language);
+            [id(DISPID_INSTALLER_ENVIRONMENT), propget]
+            BSTR Environment([in] BSTR Variable);
+            [id(DISPID_INSTALLER_ENVIRONMENT), propput]
+            void Environment(
+                                                             [in] BSTR Variable,
+                                                             [in] BSTR rhs);
+            [id(DISPID_INSTALLER_PRODUCTSTATE), propget]
+            MsiInstallState ProductState([in] BSTR Product);
+            [id(DISPID_INSTALLER_PRODUCTINFO), propget]
+            BSTR ProductInfo(
+                                                             [in] BSTR Product,
+                                                             [in] BSTR Attribute);
+            [id(DISPID_INSTALLER_CONFIGUREPRODUCT)]
+            void ConfigureProduct(
+                                                         [in] BSTR Product,
+                                                         [in] long InstallLevel,
+                                                         [in] MsiInstallState InstallState);
+            [id(DISPID_INSTALLER_REINSTALLPRODUCT)]
+            void ReinstallProduct(
+                                                         [in] BSTR Product,
+                                                         [in] MsiReinstallMode ReinstallMode);
+            [id(DISPID_INSTALLER_COLLECTUSERINFO)]
+            void CollectUserInfo([in] BSTR Product);
+            [id(DISPID_INSTALLER_APPLYPATCH)]
+            void ApplyPatch(
+                                                   [in] BSTR PatchPackage,
+                                                   [in] BSTR InstallPackage,
+                                                   [in] MsiInstallType InstallType,
+                                                   [in] BSTR CommandLine);
+            [id(DISPID_INSTALLER_FEATUREPARENT), propget]
+            BSTR FeatureParent(
+                                                               [in] BSTR Product,
+                                                               [in] BSTR Feature);
+            [id(DISPID_INSTALLER_FEATURESTATE), propget]
+            MsiInstallState FeatureState(
+                                                                         [in] BSTR Product,
+                                                                         [in] BSTR Feature);
+            [id(DISPID_INSTALLER_USEFEATURE)]
+            void UseFeature(
+                                                   [in] BSTR Product,
+                                                   [in] BSTR Feature,
+                                                   [in] MsiInstallMode InstallMode);
+            [id(DISPID_INSTALLER_FEATUREUSAGECOUNT), propget]
+            long FeatureUsageCount(
+                                                                   [in] BSTR Product,
+                                                                   [in] BSTR Feature);
+            [id(DISPID_INSTALLER_FEATUREUSAGEDATE), propget]
+            DATE FeatureUsageDate(
+                                                                  [in] BSTR Product,
+                                                                  [in] BSTR Feature);
+            [id(DISPID_INSTALLER_CONFIGUREFEATURE)]
+            void ConfigureFeature(
+                                                         [in] BSTR Product,
+                                                         [in] BSTR Feature,
+                                                         [in] MsiInstallState InstallState);
+            [id(DISPID_INSTALLER_REINSTALLFEATURE)]
+            void ReinstallFeature(
+                                                         [in] BSTR Product,
+                                                         [in] BSTR Feature,
+                                                         [in] MsiReinstallMode ReinstallMode);
+            [id(DISPID_INSTALLER_PROVIDECOMPONENT)]
+            BSTR ProvideComponent(
+                                                         [in] BSTR Product,
+                                                         [in] BSTR Feature,
+                                                         [in] BSTR Component,
+                                                         [in] long InstallMode);
+            [id(DISPID_INSTALLER_COMPONENTPATH), propget]
+            BSTR ComponentPath(
+                                                               [in] BSTR Product,
+                                                               [in] BSTR Component);
+            [id(DISPID_INSTALLER_PROVIDEQUALIFIEDCOMPONENT)]
+            BSTR ProvideQualifiedComponent(
+                                                                  [in] BSTR Category,
+                                                                  [in] BSTR Qualifier,
+                                                                  [in] long InstallMode);
+            [id(DISPID_INSTALLER_QUALIFIERDESCRIPTION), propget]
+            BSTR QualifierDescription(
+                                                                      [in] BSTR Category,
+                                                                      [in] BSTR Qualifier);
+            [id(DISPID_INSTALLER_COMPONENTQUALIFIERS), propget]
+            StringList* ComponentQualifiers([in] BSTR Category);
+            [id(DISPID_INSTALLER_PRODUCTS), propget]
+            StringList* Products();
+            [id(DISPID_INSTALLER_FEATURES), propget]
+            StringList* Features([in] BSTR Product);
+            [id(DISPID_INSTALLER_COMPONENTS), propget]
+            StringList* Components();
+            [id(DISPID_INSTALLER_COMPONENTCLIENTS), propget]
+            StringList* ComponentClients([in] BSTR Component);
+            [id(DISPID_INSTALLER_PATCHES), propget]
+            StringList* Patches([in] BSTR Product);
+            [id(DISPID_INSTALLER_RELATEDPRODUCTS), propget]
+            StringList* RelatedProducts([in] BSTR UpgradeCode);
+            [id(DISPID_INSTALLER_PATCHINFO), propget]
+            BSTR PatchInfo(
+                                                           [in] BSTR Patch,
+                                                           [in] BSTR Attribute);
+            [id(DISPID_INSTALLER_PATCHTRANSFORMS), propget]
+            BSTR PatchTransforms(
+                                                                 [in] BSTR Product,
+                                                                 [in] BSTR Patch);
+            [id(DISPID_INSTALLER_ADDSOURCE)]
+            void AddSource(
+                                                  [in] BSTR Product,
+                                                  [in] BSTR User,
+                                                  [in] BSTR Source);
+            [id(DISPID_INSTALLER_CLEARSOURCELIST)]
+            void ClearSourceList(
+                                                        [in] BSTR Product,
+                                                        [in] BSTR User);
+            [id(DISPID_INSTALLER_FORCESOURCELISTRESOLUTION)]
+            void ForceSourceListResolution(
+                                                                  [in] BSTR Product,
+                                                                  [in] BSTR User);
+            [id(DISPID_INSTALLER_GETSHORTCUTTARGET), propget]
+            Record* GetShortcutTarget([in] BSTR ShortcutPath);
+            [id(DISPID_INSTALLER_FILEHASH)]
+            Record* FileHash(
+                                                    [in] BSTR FilePath,
+                                                    [in] long Options);
+            [id(DISPID_INSTALLER_FILESIGNATUREINFO)]
+            SAFEARRAY(unsigned char) FileSignatureInfo(
+                                                                              [in] BSTR FilePath,
+                                                                              [in] long Options,
+                                                                              [in] MsiSignatureInfo Format);
+    };
 
-    [ uuid(000C1096-0000-0000-C000-000000000046) ]
-    dispinterface RecordList
-    {
+    [
+        uuid(000C1093-0000-0000-C000-000000000046),
+        helpcontext(0x00002454)
+    ]
+    dispinterface Record {
         properties:
         methods:
-    }
+            [id(DISPID_RECORD_STRINGDATA), propget]
+            BSTR StringData([in] long Field);
+            [id(DISPID_RECORD_STRINGDATA), propput]
+            void StringData(
+                                                         [in] long Field,
+                                                         [in] BSTR rhs);
+            [id(DISPID_RECORD_INTEGERDATA), propget]
+            long IntegerData([in] long Field);
+            [id(DISPID_RECORD_INTEGERDATA), propput]
+            void IntegerData(
+                                                          [in] long Field,
+                                                          [in] long rhs);
+            [id(DISPID_RECORD_SETSTREAM)]
+            void SetStream(
+                                               [in] long Field,
+                                               [in] BSTR FilePath);
+            [id(DISPID_RECORD_READSTREAM)]
+            BSTR ReadStream(
+                                                [in] long Field,
+                                                [in] long Length,
+                                                [in] MsiReadStream Format);
+            [id(DISPID_RECORD_FIELDCOUNT), propget]
+            long FieldCount();
+            [id(DISPID_RECORD_ISNULL), propget]
+            VARIANT_BOOL IsNull([in] long Field);
+            [id(DISPID_RECORD_DATASIZE), propget]
+            long DataSize([in] long Field);
+            [id(DISPID_RECORD_CLEARDATA)]
+            void ClearData();
+            [id(DISPID_RECORD_FORMATTEXT)]
+            BSTR FormatText();
+    };
+
+    typedef enum {
+        msiDoActionStatusNoAction = 0,
+        msiDoActionStatusSuccess = 1,
+        msiDoActionStatusUserExit = 2,
+        msiDoActionStatusFailure = 3,
+        msiDoActionStatusSuspend = 4,
+        msiDoActionStatusFinished = 5,
+        msiDoActionStatusWrongState = 6,
+        msiDoActionStatusBadActionData = 7
+    } MsiDoActionStatus;
+
+    typedef enum {
+        msiEvaluateConditionFalse = 0,
+        msiEvaluateConditionTrue = 1,
+        msiEvaluateConditionNone = 2,
+        msiEvaluateConditionError = 3
+    } _MsiEvaluateCondition; /* Added underscore to avoid conflict with function name */
+
+    typedef enum {
+        msiMessageStatusError = -1,
+        msiMessageStatusNone = 0,
+        msiMessageStatusOk = 1,
+        msiMessageStatusCancel = 2,
+        msiMessageStatusAbort = 3,
+        msiMessageStatusRetry = 4,
+        msiMessageStatusIgnore = 5,
+        msiMessageStatusYes = 6,
+        msiMessageStatusNo = 7
+    } MsiMessageStatus;
+
+    typedef enum {
+        msiMessageTypeFatalExit = 0,
+        msiMessageTypeError = 16777216,
+        msiMessageTypeWarning = 33554432,
+        msiMessageTypeUser = 50331648,
+        msiMessageTypeInfo = 67108864,
+        msiMessageTypeFilesInUse = 83886080,
+        msiMessageTypeResolveSource = 100663296,
+        msiMessageTypeOutOfDiskSpace = 117440512,
+        msiMessageTypeActionStart = 134217728,
+        msiMessageTypeActionData = 150994944,
+        msiMessageTypeProgress = 167772160,
+        msiMessageTypeCommonData = 184549376,
+        msiMessageTypeOk = 0,
+        msiMessageTypeOkCancel = 1,
+        msiMessageTypeAbortRetryIgnore = 2,
+        msiMessageTypeYesNoCancel = 3,
+        msiMessageTypeYesNo = 4,
+        msiMessageTypeRetryCancel = 5,
+        msiMessageTypeDefault1 = 0,
+        msiMessageTypeDefault2 = 256,
+        msiMessageTypeDefault3 = 512
+    } MsiMessageType;
+
+    typedef enum {
+        msiCostTreeSelfOnly = 0,
+        msiCostTreeChildren = 1,
+        msiCostTreeParents = 2
+    } MsiCostTree;
 
-    [ uuid(000C109A-0000-0000-C000-000000000046) ]
-    dispinterface UIPreview
-    {
+    typedef enum {
+        msiDatabaseStateRead = 0,
+        msiDatabaseStateWrite = 1
+    } MsiDatabaseState;
+
+    [
+        uuid(000C109E-0000-0000-C000-000000000046),
+        helpcontext(0x000025e4)
+    ]
+    dispinterface Session {
         properties:
         methods:
-    }
+            [id(DISPID_SESSION_INSTALLER), propget]
+            Installer* Installer();
+            [id(DISPID_SESSION_PROPERTY), propget]
+            BSTR Property([in] BSTR Name);
+            [id(DISPID_SESSION_PROPERTY), propput]
+            void Property(
+                                                        [in] BSTR Name,
+                                                        [in] BSTR rhs);
+            [id(DISPID_SESSION_LANGUAGE), propget]
+            long Language();
+            [id(DISPID_SESSION_MODE), propget]
+            VARIANT_BOOL Mode([in] MsiRunMode Flag);
+            [id(DISPID_SESSION_MODE), propput]
+            void Mode(
+                                                    [in] MsiRunMode Flag,
+                                                    [in] VARIANT_BOOL rhs);
+            [id(DISPID_SESSION_DATABASE), propget]
+            Database* Database();
+            [id(DISPID_SESSION_SOURCEPATH), propget]
+            BSTR SourcePath([in] BSTR Folder);
+            [id(DISPID_SESSION_TARGETPATH), propget]
+            BSTR TargetPath([in] BSTR Folder);
+            [id(DISPID_SESSION_TARGETPATH), propput]
+            void TargetPath(
+                                                          [in] BSTR Folder,
+                                                          [in] BSTR rhs);
+            [id(DISPID_SESSION_DOACTION)]
+            MsiDoActionStatus DoAction([in] BSTR Action);
+            [id(DISPID_SESSION_SEQUENCE)]
+            MsiDoActionStatus Sequence(
+                                                            [in] BSTR Table,
+                                                            [in, optional] VARIANT Mode);
+            [id(DISPID_SESSION_EVALUATECONDITION)]
+            _MsiEvaluateCondition EvaluateCondition([in] BSTR Expression);
+            [id(DISPID_SESSION_FORMATRECORD)]
+            BSTR FormatRecord([in] Record* Record);
+            [id(DISPID_SESSION_MESSAGE)]
+            MsiMessageStatus Message(
+                                                          [in] MsiMessageType Kind,
+                                                          [in] Record* Record);
+            [id(DISPID_SESSION_FEATURECURRENTSTATE), propget]
+            MsiInstallState FeatureCurrentState([in] BSTR Feature);
+            [id(DISPID_SESSION_FEATUREREQUESTSTATE), propget]
+            MsiInstallState FeatureRequestState([in] BSTR Feature);
+            [id(DISPID_SESSION_FEATUREREQUESTSTATE), propput]
+            void FeatureRequestState(
+                                                                   [in] BSTR Feature,
+                                                                   [in] MsiInstallState rhs);
+            [id(DISPID_SESSION_FEATUREVALIDSTATES), propget]
+            long FeatureValidStates([in] BSTR Feature);
+            [id(DISPID_SESSION_FEATURECOST), propget]
+            long FeatureCost(
+                                                           [in] BSTR Feature,
+                                                           [in] MsiCostTree CostTree,
+                                                           [in] MsiInstallState State);
+            [id(DISPID_SESSION_COMPONENTCURRENTSTATE), propget]
+            MsiInstallState ComponentCurrentState([in] BSTR Component);
+            [id(DISPID_SESSION_COMPONENTREQUESTSTATE), propget]
+            MsiInstallState ComponentRequestState([in] BSTR Component);
+            [id(DISPID_SESSION_COMPONENTREQUESTSTATE), propput]
+            void ComponentRequestState(
+                                                                     [in] BSTR Component,
+                                                                     [in] MsiInstallState rhs);
+            [id(DISPID_SESSION_SETINSTALLLEVEL)]
+            void SetInstallLevel([in] long Level);
+            [id(DISPID_SESSION_VERIFYDISKSPACE), propget]
+            VARIANT_BOOL VerifyDiskSpace();
+            [id(DISPID_SESSION_PRODUCTPROPERTY), propget]
+            BSTR ProductProperty([in] BSTR Property);
+            [id(DISPID_SESSION_FEATUREINFO), propget]
+            FeatureInfo* FeatureInfo([in] BSTR Feature);
+            [id(DISPID_SESSION_COMPONENTCOSTS), propget]
+            RecordList* ComponentCosts(
+                                                                     [in] BSTR Component,
+                                                                     [in] MsiInstallState State);
+    };
+
+    typedef enum {
+        msiTransformErrorNone = 0,
+        msiTransformErrorAddExistingRow = 1,
+        msiTransformErrorDeleteNonExistingRow = 2,
+        msiTransformErrorAddExistingTable = 4,
+        msiTransformErrorDeleteNonExistingTable = 8,
+        msiTransformErrorUpdateNonExistingRow = 16,
+        msiTransformErrorChangeCodePage = 32,
+        msiTransformErrorViewTransform = 256
+    } MsiTransformError;
+
+
+    typedef enum {
+        msiTransformValidationNone = 0,
+        msiTransformValidationLanguage = 1,
+        msiTransformValidationProduct = 2,
+        msiTransformValidationPlatform = 4,
+        msiTransformValidationMajorVer = 8,
+        msiTransformValidationMinorVer = 16,
+        msiTransformValidationUpdateVer = 32,
+        msiTransformValidationLess = 64,
+        msiTransformValidationLessOrEqual = 128,
+        msiTransformValidationEqual = 256,
+        msiTransformValidationGreaterOrEqual = 512,
+        msiTransformValidationGreater = 1024,
+        msiTransformValidationUpgradeCode = 2048
+    } MsiTransformValidation;
 
-    [ uuid(000C109B-0000-0000-C000-000000000046) ]
-    dispinterface SummaryInfo
-    {
+    [
+        uuid(000C109D-0000-0000-C000-000000000046),
+        helpcontext(0x0000251c)
+    ]
+    dispinterface Database {
         properties:
         methods:
-    }
+            [id(DISPID_DATABASE_DATABASESTATE), propget]
+            MsiDatabaseState DatabaseState();
+            [id(DISPID_DATABASE_SUMMARYINFORMATION), propget]
+            SummaryInfo* SummaryInformation([in, optional, defaultvalue(0)] long UpdateCount);
+            [id(DISPID_DATABASE_OPENVIEW)]
+            View* OpenView([in] BSTR Sql);
+            [id(DISPID_DATABASE_COMMIT)]
+            void Commit();
+            [id(DISPID_DATABASE_PRIMARYKEYS), propget]
+            Record* PrimaryKeys([in] BSTR Table);
+            [id(DISPID_DATABASE_IMPORT)]
+            void Import(
+                                              [in] BSTR Folder,
+                                              [in] BSTR File);
+            [id(DISPID_DATABASE_EXPORT)]
+            void Export(
+                                              [in] BSTR Table,
+                                              [in] BSTR Folder,
+                                              [in] BSTR File);
+            [id(DISPID_DATABASE_MERGE)]
+            VARIANT_BOOL Merge(
+                                                     [in] Database* Database,
+                                                     [in, optional, defaultvalue("0")] BSTR ErrorTable);
+            [id(DISPID_DATABASE_GENERATETRANSFORM)]
+            VARIANT_BOOL GenerateTransform(
+                                                                 [in] Database* ReferenceDatabase,
+                                                                 [in, optional, defaultvalue("0")] BSTR TransformFile);
+            [id(DISPID_DATABASE_APPLYTRANSFORM)]
+            void ApplyTransform(
+                                                      [in] BSTR TransformFile,
+                                                      [in] MsiTransformError ErrorConditions);
+            [id(DISPID_DATABASE_ENABLEUIPREVIEW)]
+            UIPreview* EnableUIPreview();
+            [id(DISPID_DATABASE_TABLEPERSISTENT), propget]
+            _MsiEvaluateCondition TablePersistent([in] BSTR Table);
+            [id(DISPID_DATABASE_CREATETRANSFORMSUMMARYINFO)]
+            void CreateTransformSummaryInfo(
+                                                                  [in] Database* ReferenceDatabase,
+                                                                  [in] BSTR TransformFile,
+                                                                  [in] MsiTransformError ErrorConditions,
+                                                                  [in] MsiTransformValidation Validation);
+    };
 
-    [ uuid(000C109C-0000-0000-C000-000000000046) ]
-    dispinterface View
-    {
+    [
+        uuid(000C109B-0000-0000-C000-000000000046),
+        helpcontext(0x00002580)
+    ]
+    dispinterface SummaryInfo {
         properties:
         methods:
-    }
+            [id(DISPID_SUMMARYINFO_PROPERTY), propget]
+            VARIANT Property([in] long Pid);
+            [id(DISPID_SUMMARYINFO_PROPERTY), propput]
+            void Property(
+                                                            [in] long Pid,
+                                                            [in] VARIANT rhs);
+            [id(DISPID_SUMMARYINFO_PROPERTYCOUNT), propget]
+            long PropertyCount();
+            [id(DISPID_SUMMARYINFO_PERSIST)]
+            void Persist();
+    };
 
-    [ uuid(000C109D-0000-0000-C000-000000000046) ]
-    dispinterface Database
-    {
+    typedef enum {
+        msiViewModifySeek = -1,
+        msiViewModifyRefresh = 0,
+        msiViewModifyInsert = 1,
+        msiViewModifyUpdate = 2,
+        msiViewModifyAssign = 3,
+        msiViewModifyReplace = 4,
+        msiViewModifyMerge = 5,
+        msiViewModifyDelete = 6,
+        msiViewModifyInsertTemporary = 7,
+        msiViewModifyValidate = 8,
+        msiViewModifyValidateNew = 9,
+        msiViewModifyValidateField = 10,
+        msiViewModifyValidateDelete = 11
+    } _MsiViewModify; /* Added underscore to avoid conflict with MsiViewModify function in msiquery.h */
+
+    typedef enum {
+        msiColumnInfoNames = 0,
+        msiColumnInfoTypes = 1
+    } MsiColumnInfo;
+
+    [
+        uuid(000C109C-0000-0000-C000-000000000046),
+        helpcontext(0x000024b8)
+    ]
+    dispinterface View {
         properties:
         methods:
-    }
-
-    [ uuid(000C109E-0000-0000-C000-000000000046) ]
-    dispinterface Session
-    {
-    properties:
-    methods:
-    }
-
-    [ uuid(000C109F-0000-0000-C000-000000000046) ]
-    dispinterface FeatureInfo
-    {
+            [id(DISPID_VIEW_EXECUTE)]
+            void Execute([in, optional, defaultvalue(0)] Record* Params);
+            [id(DISPID_VIEW_FETCH)]
+            Record* Fetch();
+            [id(DISPID_VIEW_MODIFY)]
+            void Modify(
+                                          [in] _MsiViewModify Mode,
+                                          Record* Record);
+            [id(DISPID_VIEW_COLUMNINFO), propget]
+            Record* ColumnInfo([in] MsiColumnInfo Info);
+            [id(DISPID_VIEW_CLOSE)]
+            void Close();
+            [id(DISPID_VIEW_GETERROR)]
+            BSTR GetError();
+    };
+
+    [
+        uuid(000C109A-0000-0000-C000-000000000046),
+        helpcontext(0x00002648)
+    ]
+    dispinterface UIPreview {
         properties:
         methods:
-    }
+            [id(DISPID_UIPREVIEW_PROPERTY), propget]
+            BSTR Property([in] BSTR Name);
+            [id(DISPID_UIPREVIEW_PROPERTY), propput]
+            void Property(
+                                                          [in] BSTR Name,
+                                                          [in] BSTR rhs);
+            [id(DISPID_UIPREVIEW_VIEWDIALOG)]
+            void ViewDialog([in] BSTR Dialog);
+            [id(DISPID_UIPREVIEW_VIEWBILLBOARD)]
+            void ViewBillboard(
+                                                      [in] BSTR Control,
+                                                      [in] BSTR Billboard);
+    };
 
-    [ uuid(000C10A0-0000-0000-C000-000000000046) ]
-    dispinterface Product
-    {
+    [
+        uuid(000C109F-0000-0000-C000-000000000046),
+        helpcontext(0x0000238c)
+    ]
+    dispinterface FeatureInfo {
         properties:
+            [id(DISPID_FEATUREINFO_ATTRIBUTES)]
+            long Attributes;
         methods:
-    }
+            [id(DISPID_FEATUREINFO_TITLE), propget]
+            BSTR Title();
+            [id(DISPID_FEATUREINFO_DESCRIPTION), propget]
+            BSTR Description();
+    };
 
-    [ uuid(000C10A1-0000-0000-C000-000000000046) ]
-    dispinterface Patch
-    {
+    [
+        uuid(000C1096-0000-0000-C000-000000000046),
+        helpcontext(0x000023f3)
+    ]
+    dispinterface RecordList {
         properties:
         methods:
-    }
-}
+            [id(DISPID_RECORDLIST__NEWENUM)]
+            IUnknown _NewEnum();
+            [id(DISPID_RECORDLIST_ITEM), propget]
+            Record* Item(long Index);
+            [id(DISPID_RECORDLIST_COUNT), propget]
+            long Count();
+    };
+
+    [
+        uuid(000C1095-0000-0000-C000-000000000046),
+        helpcontext(0x000023f0)
+    ]
+    dispinterface StringList {
+        properties:
+        methods:
+            [id(DISPID_STRINGLIST__NEWENUM)]
+            IUnknown _NewEnum();
+            [id(DISPID_STRINGLIST_ITEM), propget]
+            BSTR Item(long Index);
+            [id(DISPID_STRINGLIST_COUNT), propget]
+            long Count();
+    };
+
+    typedef enum {
+        msiDatabaseNullInteger = 0x80000000  /* -2147483648 from oleview, but widl makes it into two "-"'s 
+  				              * which screws up msiserver.h */
+    } Constants;
+
+    typedef enum {
+        msiOpenDatabaseModeReadOnly = 0,
+        msiOpenDatabaseModeTransact = 1,
+        msiOpenDatabaseModeDirect = 2,
+        msiOpenDatabaseModeCreate = 3,
+        msiOpenDatabaseModeCreateDirect = 4,
+        msiOpenDatabaseModePatchFile = 32
+    } MsiOpenDatabaseMode;
+
+    typedef enum {
+        msiSignatureOptionInvalidHashFatal = 1
+    } MsiSignatureOption;
+};
diff --git a/dlls/msi/msiserver_dispids.h b/dlls/msi/msiserver_dispids.h
new file mode 100644
index 0000000..db39ec0
--- /dev/null
+++ b/dlls/msi/msiserver_dispids.h
@@ -0,0 +1,140 @@
+/*
+ * 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_UILEVEL 6
+#define DISPID_INSTALLER_CREATERECORD 1
+#define DISPID_INSTALLER_OPENPACKAGE 2
+#define DISPID_INSTALLER_OPENPRODUCT 3
+#define DISPID_INSTALLER_OPENDATABASE 4
+#define DISPID_INSTALLER_SUMMARYINFORMATION 5
+#define DISPID_INSTALLER_ENABLELOG 7
+#define DISPID_INSTALLER_INSTALLPRODUCT 8
+#define DISPID_INSTALLER_VERSION 9
+#define DISPID_INSTALLER_LASTERRORRECORD 10
+#define DISPID_INSTALLER_REGISTRYVALUE 11
+#define DISPID_INSTALLER_FILEATTRIBUTES 13
+#define DISPID_INSTALLER_FILESIZE 15
+#define DISPID_INSTALLER_FILEVERSION 16
+#define DISPID_INSTALLER_ENVIRONMENT 12
+#define DISPID_INSTALLER_PRODUCTSTATE 17
+#define DISPID_INSTALLER_PRODUCTINFO 18
+#define DISPID_INSTALLER_CONFIGUREPRODUCT 19
+#define DISPID_INSTALLER_REINSTALLPRODUCT 20
+#define DISPID_INSTALLER_COLLECTUSERINFO 21
+#define DISPID_INSTALLER_APPLYPATCH 22
+#define DISPID_INSTALLER_FEATUREPARENT 23
+#define DISPID_INSTALLER_FEATURESTATE 24
+#define DISPID_INSTALLER_USEFEATURE 25
+#define DISPID_INSTALLER_FEATUREUSAGECOUNT 26
+#define DISPID_INSTALLER_FEATUREUSAGEDATE 27
+#define DISPID_INSTALLER_CONFIGUREFEATURE 28
+#define DISPID_INSTALLER_REINSTALLFEATURE 29
+#define DISPID_INSTALLER_PROVIDECOMPONENT 30
+#define DISPID_INSTALLER_COMPONENTPATH 31
+#define DISPID_INSTALLER_PROVIDEQUALIFIEDCOMPONENT 32
+#define DISPID_INSTALLER_QUALIFIERDESCRIPTION 33
+#define DISPID_INSTALLER_COMPONENTQUALIFIERS 34
+#define DISPID_INSTALLER_PRODUCTS 35
+#define DISPID_INSTALLER_FEATURES 36
+#define DISPID_INSTALLER_COMPONENTS 37
+#define DISPID_INSTALLER_COMPONENTCLIENTS 38
+#define DISPID_INSTALLER_PATCHES 39
+#define DISPID_INSTALLER_RELATEDPRODUCTS 40
+#define DISPID_INSTALLER_PATCHINFO 41
+#define DISPID_INSTALLER_PATCHTRANSFORMS 42
+#define DISPID_INSTALLER_ADDSOURCE 43
+#define DISPID_INSTALLER_CLEARSOURCELIST 44
+#define DISPID_INSTALLER_FORCESOURCELISTRESOLUTION 45
+#define DISPID_INSTALLER_GETSHORTCUTTARGET 46
+#define DISPID_INSTALLER_FILEHASH 47
+#define DISPID_INSTALLER_FILESIGNATUREINFO 48
+
+#define DISPID_RECORD_STRINGDATA 1
+#define DISPID_RECORD_INTEGERDATA 2
+#define DISPID_RECORD_SETSTREAM 3
+#define DISPID_RECORD_READSTREAM 4
+#define DISPID_RECORD_FIELDCOUNT 0
+#define DISPID_RECORD_ISNULL 6
+#define DISPID_RECORD_DATASIZE 5
+#define DISPID_RECORD_CLEARDATA 7
+#define DISPID_RECORD_FORMATTEXT 8
+
+#define DISPID_SESSION_INSTALLER 1
+#define DISPID_SESSION_PROPERTY 2
+#define DISPID_SESSION_LANGUAGE 3
+#define DISPID_SESSION_MODE 4
+#define DISPID_SESSION_DATABASE 5
+#define DISPID_SESSION_SOURCEPATH 6
+#define DISPID_SESSION_TARGETPATH 7
+#define DISPID_SESSION_DOACTION 8
+#define DISPID_SESSION_SEQUENCE 9
+#define DISPID_SESSION_EVALUATECONDITION 10
+#define DISPID_SESSION_FORMATRECORD 11
+#define DISPID_SESSION_MESSAGE 12
+#define DISPID_SESSION_FEATURECURRENTSTATE 13
+#define DISPID_SESSION_FEATUREREQUESTSTATE 14
+#define DISPID_SESSION_FEATUREVALIDSTATES 15
+#define DISPID_SESSION_FEATURECOST 16
+#define DISPID_SESSION_COMPONENTCURRENTSTATE 17
+#define DISPID_SESSION_COMPONENTREQUESTSTATE 18
+#define DISPID_SESSION_SETINSTALLLEVEL 19
+#define DISPID_SESSION_VERIFYDISKSPACE 20
+#define DISPID_SESSION_PRODUCTPROPERTY 21
+#define DISPID_SESSION_FEATUREINFO 22
+#define DISPID_SESSION_COMPONENTCOSTS 23
+
+#define DISPID_DATABASE_DATABASESTATE 1
+#define DISPID_DATABASE_SUMMARYINFORMATION 2
+#define DISPID_DATABASE_OPENVIEW 3
+#define DISPID_DATABASE_COMMIT 4
+#define DISPID_DATABASE_PRIMARYKEYS 5
+#define DISPID_DATABASE_IMPORT 6
+#define DISPID_DATABASE_EXPORT 7
+#define DISPID_DATABASE_MERGE 8
+#define DISPID_DATABASE_GENERATETRANSFORM 9
+#define DISPID_DATABASE_APPLYTRANSFORM 10
+#define DISPID_DATABASE_ENABLEUIPREVIEW 11
+#define DISPID_DATABASE_TABLEPERSISTENT 12
+#define DISPID_DATABASE_CREATETRANSFORMSUMMARYINFO 13
+
+#define DISPID_SUMMARYINFO_PROPERTY 1
+#define DISPID_SUMMARYINFO_PROPERTYCOUNT 2
+#define DISPID_SUMMARYINFO_PERSIST 3
+
+#define DISPID_VIEW_EXECUTE 1
+#define DISPID_VIEW_FETCH 2
+#define DISPID_VIEW_MODIFY 3
+#define DISPID_VIEW_COLUMNINFO 5
+#define DISPID_VIEW_CLOSE 4
+#define DISPID_VIEW_GETERROR 6
+
+#define DISPID_UIPREVIEW_PROPERTY 1
+#define DISPID_UIPREVIEW_VIEWDIALOG 2
+#define DISPID_UIPREVIEW_VIEWBILLBOARD 3
+
+#define DISPID_FEATUREINFO_ATTRIBUTES 3
+#define DISPID_FEATUREINFO_TITLE 1
+#define DISPID_FEATUREINFO_DESCRIPTION 2
+
+#define DISPID_RECORDLIST__NEWENUM -4
+#define DISPID_RECORDLIST_ITEM 0
+#define DISPID_RECORDLIST_COUNT 1
+
+#define DISPID_STRINGLIST__NEWENUM -4
+#define DISPID_STRINGLIST_ITEM 0
+#define DISPID_STRINGLIST_COUNT 1
-- 
1.4.1

-------------- next part --------------
From 3c20af7127de00c3bafb859036b17cc221a3fc74 Mon Sep 17 00:00:00 2001
From: Misha Koshelev <mk144210 at bcm.tmc.edu>
Date: Sun, 25 Feb 2007 22:23:15 -0600
Subject: msi: Add partial, expandable OLE automation support.
---
 dlls/msi/Makefile.in  |    3 
 dlls/msi/automation.c |  809 +++++++++++++++++++++++++++++++++++++++++++++++++
 dlls/msi/msipriv.h    |    4 
 3 files changed, 816 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..c7ca30b
--- /dev/null
+++ b/dlls/msi/automation.c
@@ -0,0 +1,809 @@
+/*
+ * 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);
+
+/*
+ * If you would like to implement a new automation function/object, look towards the bottom of this
+ * file for the "meat and potatoes" section.
+ */
+
+/* FIXME: I don't know how big this should be */
+#define MAX_MSI_STRING 1000
+
+/*
+ * AutomationObject - "base" class for all automation objects so we don't have to repeat functions. Just
+ *                    need to implement Invoke function for each dispinterface that is called from within
+ *                    the AutomationObject Invoke function which performs error checking, and pass the new 
+ *                    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 IDispatch::Invoke, specific to this type of object. By the
+     * time this function is called, basic error checking has been done in the AutomationObject
+     * Invoke function */
+    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); 
+
+    /*
+     * Perform a sanity check on the parameters.
+     */
+    if ( (This==0) || (ppvObject==0) )
+      return E_INVALIDARG;
+
+    /*
+     * Initialize the return parameter.
+     */
+    *ppvObject = 0;
+
+    /*
+     * Compare the riid with the interface IDs implemented by this object.
+     */
+    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);
+
+    /*
+     * Check that we obtained an interface.
+     */
+    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);
+}
+
+/* Error checking, etc. 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 (STDMETHODCALLTYPE *Invoke)(
+        AutomationObject*,DISPID,REFIID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*,UINT*) = This->funcInvoke;
+    HRESULT hr;
+    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;
+    }
+
+    /* If there is a result, make default type empty */
+    if (pVarResult) V_VT(pVarResult) = VT_EMPTY;
+
+    /* 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 = Invoke(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));
+    }
+
+    TRACE("Returning %d, %s\n", hr, hr == S_OK ? "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 - Our meat and potatoes
+ *
+ *    - To add a method, just add an appropriate case to an appropriate switch statement
+ *        * Follow syntax here for property get/puts and method calls. Remember, parameters
+ *          are passed IN REVERSE ORDER (last parameter to function is first in array). This got me at first.
+ *        * MSI specs seem to indicate that most functions return an S_OK. If you don't, chances are the
+ *          script will stop running, but check the MSI documentation for your specific function.
+ *    - To add a new object, just add an ObjectImpl_Invoke method and appropriate method call that 
+ *      creates your object. Note that these are not true Invoke methods, but are called from 
+ *      AutomationObject_Invoke with some appropriate parameter error checking, made to ensure that 
+ *      the functions below remain just down to what they need to do.
+ */
+
+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;
+
+    switch (dispIdMember) 
+    {
+	case DISPID_RECORD_STRINGDATA:
+	    if (wFlags & DISPATCH_PROPERTYGET) {
+ 	        V_VT(pVarResult) = VT_BSTR;
+		if ((ret = MsiRecordGetStringW(This->msiHandle, V_I4(&pDispParams->rgvarg[0]),
+				               szString, &dwLen)) == ERROR_SUCCESS)
+		    V_BSTR(pVarResult) = SysAllocString(szString);
+		else
+		{
+		    TRACE("MsiRecordGetString returned %d\n", ret);
+		    V_BSTR(pVarResult) = NULL;
+		}
+		return S_OK;
+	    } else if (wFlags & DISPATCH_PROPERTYPUT) {
+		return (MsiRecordSetStringW(This->msiHandle, V_I4(&pDispParams->rgvarg[1]),
+   				        V_BSTR(&pDispParams->rgvarg[0])) == ERROR_SUCCESS ? S_OK : E_FAIL);
+	    }
+	    break;
+    }
+
+    return DISP_E_MEMBERNOTFOUND;
+}
+
+HRESULT WINAPI ViewImpl_Invoke(
+        AutomationObject* This,
+        DISPID dispIdMember,
+        REFIID riid,
+        LCID lcid,
+        WORD wFlags,
+        DISPPARAMS* pDispParams,
+        VARIANT* pVarResult,
+        EXCEPINFO* pExcepInfo,
+        UINT* puArgErr)
+{
+    MSIHANDLE msiHandle;
+    AutomationObject *obj = NULL;
+    IDispatch *iDispatch = NULL;
+    UINT ret;
+
+    switch (dispIdMember) 
+    {
+	case DISPID_VIEW_EXECUTE:
+	    if (wFlags & DISPATCH_METHOD)
+	    { 
+	        obj = (AutomationObject *)V_DISPATCH(&pDispParams->rgvarg[0]);
+		MsiViewExecute(This->msiHandle, obj == NULL ? 0 : obj->msiHandle);
+		return S_OK;
+	    }
+	    break;
+
+	case DISPID_VIEW_FETCH:
+	    if (wFlags & DISPATCH_METHOD)
+	    { 
+		V_VT(pVarResult) = VT_DISPATCH;
+		if ((ret = MsiViewFetch(This->msiHandle, &msiHandle)) == ERROR_SUCCESS) 
+		    create_automation_object(msiHandle, NULL, (LPVOID)&iDispatch, &DIID_Record, RecordImpl_Invoke);
+		else TRACE("MsiViewFetch returned %d\n", ret);
+		V_DISPATCH(pVarResult) = iDispatch;
+		return S_OK;
+	    }
+	    break;
+
+	case DISPID_VIEW_CLOSE:
+	    if (wFlags & DISPATCH_METHOD)
+	    { 
+		MsiViewClose(This->msiHandle);
+		return S_OK;
+	    }
+	    break;
+    }
+
+    return DISP_E_MEMBERNOTFOUND;
+}
+
+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 *iDispatch = NULL;
+    UINT ret;
+
+    switch (dispIdMember) 
+    {
+	case DISPID_DATABASE_OPENVIEW:
+	    if (wFlags & DISPATCH_METHOD)
+	    { 
+		V_VT(pVarResult) = VT_DISPATCH;
+		if ((ret = MsiDatabaseOpenViewW(This->msiHandle, V_BSTR(&pDispParams->rgvarg[0]), &msiHandle)) == ERROR_SUCCESS) 
+		    create_automation_object(msiHandle, NULL, (LPVOID)&iDispatch, &DIID_View, ViewImpl_Invoke);
+		else TRACE("MsiDatabaseOpenViewW returned %d\n", ret);
+	        V_DISPATCH(pVarResult) = iDispatch;
+		return S_OK;
+	    }
+	    break;
+    }
+
+    return DISP_E_MEMBERNOTFOUND;
+}
+
+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 *iDispatch = NULL;
+    MSIHANDLE msiHandle;
+    LANGID langId;
+    UINT ret;
+    INSTALLSTATE iInstalled, iAction;
+
+    switch (dispIdMember)
+    {
+	case DISPID_SESSION_PROPERTY:
+	    if (wFlags & DISPATCH_PROPERTYGET) {
+		V_VT(pVarResult) = VT_BSTR;
+		V_BSTR(pVarResult) = NULL;
+		if (MsiGetPropertyW(This->msiHandle, V_BSTR(&pDispParams->rgvarg[0]),
+				    szString, &dwLen) == ERROR_SUCCESS)
+		    V_BSTR(pVarResult) = SysAllocString(szString);
+		return S_OK;
+	    } else if (wFlags & DISPATCH_PROPERTYPUT) {
+		return (MsiSetPropertyW(This->msiHandle, V_BSTR(&pDispParams->rgvarg[1]),
+   				        V_BSTR(&pDispParams->rgvarg[0])) == ERROR_SUCCESS ? S_OK : E_FAIL);
+	    }
+	    break;
+
+	case DISPID_SESSION_LANGUAGE:
+	    if (wFlags & DISPATCH_PROPERTYGET) {
+		langId = MsiGetLanguage(This->msiHandle);
+		if (langId != ERROR_INVALID_HANDLE)
+		{
+		    V_VT(pVarResult) = VT_I4;
+		    V_I4(pVarResult) = langId;	
+		    return S_OK;
+		} else return E_FAIL;
+	    } 
+	    break;
+
+	case DISPID_SESSION_MODE:
+	    if (wFlags & DISPATCH_PROPERTYGET) {
+		V_VT(pVarResult) = VT_BOOL;
+		V_BOOL(pVarResult) = MsiGetMode(This->msiHandle, V_I4(&pDispParams->rgvarg[0]));
+		return S_OK;
+	    } else if (wFlags & DISPATCH_PROPERTYPUT) {
+		return (MsiSetMode(This->msiHandle, V_I4(&pDispParams->rgvarg[1]),
+   				   V_BOOL(&pDispParams->rgvarg[0])) == ERROR_SUCCESS ? S_OK : E_FAIL);
+	    }
+	    break;
+
+	case DISPID_SESSION_DATABASE:
+	    if (wFlags & DISPATCH_PROPERTYGET) {
+  	        V_VT(pVarResult) = VT_DISPATCH;
+		msiHandle = MsiGetActiveDatabase(This->msiHandle);
+		if (msiHandle) 
+		    create_automation_object(msiHandle, NULL, (LPVOID)&iDispatch, &DIID_Database, DatabaseImpl_Invoke);
+		else TRACE("MsiGetActiveDatabase failed\n");
+		V_DISPATCH(pVarResult) = iDispatch;
+		return S_OK;
+	    }
+	    break;
+
+	case DISPID_SESSION_FEATURECURRENTSTATE:
+	    if (wFlags & DISPATCH_PROPERTYGET) {
+		V_VT(pVarResult) = VT_I4;
+		if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&pDispParams->rgvarg[0]),
+					      &iInstalled, &iAction)) == ERROR_SUCCESS)
+		    V_I4(pVarResult) = iInstalled;
+		else 
+		{
+		    TRACE("MsiGetFeatureState returned %d\n", ret);
+		    V_I4(pVarResult) = msiInstallStateUnknown;
+		}
+		return S_OK;
+	    } 
+	    break;
+
+	case DISPID_SESSION_FEATUREREQUESTSTATE:
+	    if (wFlags & DISPATCH_PROPERTYGET) {
+		V_VT(pVarResult) = VT_I4;
+		if ((ret = MsiGetFeatureStateW(This->msiHandle, V_BSTR(&pDispParams->rgvarg[0]),
+					      &iInstalled, &iAction)) == ERROR_SUCCESS)
+		    V_I4(pVarResult) = iAction;
+		else 
+		{
+		    TRACE("MsiGetFeatureState returned %d\n", ret);
+		    V_I4(pVarResult) = msiInstallStateUnknown;
+		}
+		return S_OK;
+	    } else if (wFlags & DISPATCH_PROPERTYPUT) {
+		return (MsiSetFeatureStateW(This->msiHandle, V_BSTR(&pDispParams->rgvarg[1]),
+   				   (INSTALLSTATE)V_I4(&pDispParams->rgvarg[0])) == ERROR_SUCCESS ? S_OK : E_FAIL);
+	    }
+	    break;
+    }
+
+    return DISP_E_MEMBERNOTFOUND;
+}
+
+/* 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

-------------- next part --------------
From bea150c6a681acd029ee2c95faab9b77d7e613c6 Mon Sep 17 00:00:00 2001
From: Misha Koshelev <mk144210 at bcm.tmc.edu>
Date: Sun, 25 Feb 2007 22:24:06 -0600
Subject: msi: Add full JScript/VBScript support.
---
 dlls/msi/Makefile.in |    1 
 dlls/msi/custom.c    |    4 -
 dlls/msi/msipriv.h   |    3 
 dlls/msi/script.c    |  369 ++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 375 insertions(+), 2 deletions(-)

diff --git a/dlls/msi/Makefile.in b/dlls/msi/Makefile.in
index 3418fb5..5b7a991 100644
--- a/dlls/msi/Makefile.in
+++ b/dlls/msi/Makefile.in
@@ -38,6 +38,7 @@ C_SRCS = \
 	record.c \
 	registry.c \
 	regsvr.c \
+        script.c \
 	select.c \
 	source.c \
 	string.c \
diff --git a/dlls/msi/custom.c b/dlls/msi/custom.c
index 7cbbf40..bdffe8b 100644
--- a/dlls/msi/custom.c
+++ b/dlls/msi/custom.c
@@ -892,12 +892,12 @@ static DWORD WINAPI ACTION_CallScript( c
         return r;
     }
 
-    FIXME("function %s, script %s\n", debugstr_w( info->function ), debugstr_w( info->dllname ) );
+    TRACE("function %s, script %s\n", debugstr_w( info->function ), debugstr_w( info->dllname ) );
 
     hPackage = alloc_msihandle( &info->package->hdr );
     if (hPackage)
     {
-	r = S_OK;
+        r = call_script( hPackage, info->type, info->dllname, info->function, info->action );
         MsiCloseHandle( hPackage );
     }
     else
diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h
index 23768c0..57f2531 100644
--- a/dlls/msi/msipriv.h
+++ b/dlls/msi/msipriv.h
@@ -792,6 +792,9 @@ extern VOID ControlEvent_UnSubscribeToEv
 extern HRESULT create_session(MSIHANDLE msiHandle, IDispatch **pDispatch);
 extern HRESULT WINAPI LoadTypeInfo(IDispatch *iface, ITypeInfo **pptinfo, REFIID clsid, LCID lcid);
 
+/* Scripting */
+extern DWORD call_script(MSIHANDLE hPackage, INT type, LPCWSTR script, LPCWSTR function, LPCWSTR action);
+
 /* 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/script.c b/dlls/msi/script.c
new file mode 100644
index 0000000..65a937d
--- /dev/null
+++ b/dlls/msi/script.c
@@ -0,0 +1,369 @@
+/*
+ * Implementation of scripting 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"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+const WCHAR szJScript[] = { 'J','S','c','r','i','p','t',0};
+const WCHAR szVBScript[] = { 'V','B','S','c','r','i','p','t',0};
+const WCHAR szSession[] = {'S','e','s','s','i','o','n',0};
+
+/*
+ * MsiActiveScriptSite - Our IActiveScriptSite implementation.
+ */
+
+typedef struct {
+    IActiveScriptSite lpVtbl;
+    IDispatch *pSession;
+    LONG ref;
+} MsiActiveScriptSite;
+
+static const struct IActiveScriptSiteVtbl ASS_Vtbl;
+
+static HRESULT ASS_create(IUnknown *pUnkOuter, LPVOID *ppObj)
+{
+    MsiActiveScriptSite* object; 
+
+    TRACE("(%p,%p)\n", pUnkOuter, ppObj);
+
+    if( pUnkOuter )
+        return CLASS_E_NOAGGREGATION;
+
+    object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MsiActiveScriptSite));
+
+    object->lpVtbl.lpVtbl = &ASS_Vtbl;
+    object->ref = 1;
+    object->pSession = NULL;
+
+    *ppObj = object;
+
+    return S_OK;
+}
+
+/*
+ * Call a script. This is our meat and potatoes. 
+ *     - Currently, since the function is relatively new, it will always end up returning S_OK.
+ *       Think of it like a bonus feature, we can run the script - great. If we have a problem,
+ *       we are no worse off than if this function had not been called.
+ */
+DWORD call_script(MSIHANDLE hPackage, INT type, LPCWSTR script, LPCWSTR function, LPCWSTR action)
+{
+    HRESULT hr;
+    IActiveScript *pActiveScript = NULL;
+    IActiveScriptParse *pActiveScriptParse = NULL;
+    MsiActiveScriptSite *pActiveScriptSite = NULL;
+    IDispatch *pDispatch = NULL;
+    DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
+    DISPID dispid;
+    CLSID clsid;
+    VARIANT var;
+
+    /* Return success by default (if Windows Script not installed) - not native behavior. This
+     * should be here until we implement wine scripting. */
+    DWORD ret = ERROR_SUCCESS;    
+  
+    CoInitialize(NULL);
+
+    /* Create MsiActiveScriptSite object */
+    hr = ASS_create(NULL, (void **)&pActiveScriptSite);
+    if (hr != S_OK) goto done;
+
+    /* Create a session object */
+    hr = create_session(hPackage, &pActiveScriptSite->pSession);
+    if (hr != S_OK) goto done;
+    IUnknown_AddRef((IUnknown *)pActiveScriptSite->pSession);
+
+    /* Create the scripting engine */
+    if (type & msidbCustomActionTypeJScript)
+	hr = CLSIDFromProgID(szJScript, &clsid);
+    else if (type & msidbCustomActionTypeVBScript)
+	hr = CLSIDFromProgID(szVBScript, &clsid);
+    else {
+	ERR("Unknown script type %d\n", type);
+	goto done;
+    }
+    if (FAILED(hr)) {
+	ERR("Could not find CLSID for Windows Script\n");
+	goto done;
+    }
+    hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IActiveScript, (void **)&pActiveScript);
+    if (FAILED(hr)) {
+	ERR("Could not instantiate class for Windows Script\n");
+	goto done;
+    }
+
+    /* If we got this far, Windows Script is installed, so don't return success by default anymore */
+    ret = ERROR_INSTALL_FAILURE; 
+
+    /* Get the IActiveScriptParse engine interface */
+    hr = IActiveScript_QueryInterface(pActiveScript, &IID_IActiveScriptParse, (void **)&pActiveScriptParse);
+    if (FAILED(hr)) goto done;
+
+    /* Give our host to the engine */
+    hr = IActiveScript_SetScriptSite(pActiveScript, (IActiveScriptSite *)pActiveScriptSite);
+    if (FAILED(hr)) goto done;
+
+    /* Initialize the script engine */
+    hr = IActiveScriptParse_InitNew(pActiveScriptParse);
+    if (FAILED(hr)) goto done;
+
+    /* Add the session object */
+    hr = IActiveScript_AddNamedItem(pActiveScript, szSession, SCRIPTITEM_ISVISIBLE);
+
+    /* Pass the script to the engine */
+    hr = IActiveScriptParse_ParseScriptText(pActiveScriptParse, script, NULL, NULL, NULL, 0, 0, 0L, NULL, NULL);
+    if (FAILED(hr)) goto done;
+
+    /* Start processing the script */
+    hr = IActiveScript_SetScriptState(pActiveScript, SCRIPTSTATE_CONNECTED);
+    if (FAILED(hr)) goto done;
+
+    /* Call a function if necessary through the IDispatch interface */
+    if (function != NULL && strlenW(function) > 0) {
+	TRACE("Calling function %s\n", debugstr_w(function));
+
+	hr = IActiveScript_GetScriptDispatch(pActiveScript, NULL, &pDispatch);
+	if (FAILED(hr)) goto done; 
+
+	hr = IDispatch_GetIDsOfNames(pDispatch, &IID_NULL, (WCHAR **)&function, 1,LOCALE_USER_DEFAULT, &dispid);
+	if (FAILED(hr)) goto done;
+  
+	hr = IDispatch_Invoke(pDispatch, dispid, &IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparamsNoArgs, &var, NULL, NULL);
+	if (FAILED(hr)) goto done;
+
+	/* Check return value, if it's not IDOK we failed */
+	hr = VariantChangeType(&var, &var, 0, VT_I4);
+	if (FAILED(hr)) goto done;
+	
+	if (V_I4(&var) == IDOK) 
+	    ret = ERROR_SUCCESS;
+	else ret = ERROR_INSTALL_FAILURE;
+
+	VariantClear(&var);
+    } else {
+	/* If no function to be called, MSI behavior is to succeed */
+	ret = ERROR_SUCCESS;
+    }
+
+done:
+
+    /* Free everything that needs to be freed */
+    if (pDispatch) IDispatch_Release(pDispatch);
+    if (pActiveScript) IActiveScriptSite_Release(pActiveScript);
+    if (pActiveScriptSite &&
+	pActiveScriptSite->pSession) IUnknown_Release((IUnknown *)pActiveScriptSite->pSession);
+    if (pActiveScriptSite) IUnknown_Release((IUnknown *)pActiveScriptSite);
+
+    CoUninitialize();    /* must call even if CoInitialize failed */
+
+/*    return ret;  */
+    return ERROR_SUCCESS;       /* FIXME: Until thoroughly tested, always return success */
+}
+
+/*
+ * MsiActiveScriptSite
+ */
+
+/*** IUnknown methods ***/
+static HRESULT WINAPI MsiActiveScriptSite_QueryInterface(IActiveScriptSite* iface, REFIID riid, void** ppvObject)
+{
+    MsiActiveScriptSite *This = (MsiActiveScriptSite *)iface;
+
+    TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
+
+    if (IsEqualGUID(riid, &IID_IUnknown) ||
+        IsEqualGUID(riid, &IID_IActiveScriptSite))
+    {
+        IClassFactory_AddRef(iface);
+        *ppvObject = This;
+        return S_OK;
+    }
+
+    TRACE("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
+
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI MsiActiveScriptSite_AddRef(IActiveScriptSite* iface)
+{
+    MsiActiveScriptSite *This = (MsiActiveScriptSite *)iface;
+
+    TRACE("(%p/%p)\n", iface, This);
+
+    return InterlockedIncrement(&This->ref);
+}
+
+static ULONG WINAPI MsiActiveScriptSite_Release(IActiveScriptSite* iface)
+{
+    MsiActiveScriptSite *This = (MsiActiveScriptSite *)iface;
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p/%p)\n", iface, This);
+
+    if (!ref)
+        HeapFree(GetProcessHeap(), 0, This);
+
+    return ref;
+}
+
+/*** IActiveScriptSite methods **/
+static HRESULT WINAPI MsiActiveScriptSite_GetLCID(IActiveScriptSite* iface, LCID* plcid)
+{
+    MsiActiveScriptSite *This = (MsiActiveScriptSite *)iface;   
+    TRACE("(%p/%p)->(%p) stub!\n", This, iface, plcid);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI MsiActiveScriptSite_GetItemInfo(IActiveScriptSite* iface, LPCOLESTR pstrName, DWORD dwReturnMask, IUnknown** ppiunkItem, ITypeInfo** ppti)
+{
+    MsiActiveScriptSite *This = (MsiActiveScriptSite *)iface;
+    TRACE("(%p/%p)->(%p,%d,%p,%p)!\n", This, iface, pstrName, dwReturnMask, ppiunkItem, ppti);
+
+    /* Determine the kind of pointer that is requested, and make sure placeholder is valid */
+    if (dwReturnMask & SCRIPTINFO_ITYPEINFO) {
+	if (!ppti) return E_INVALIDARG;
+	*ppti = NULL;
+    }
+    if (dwReturnMask & SCRIPTINFO_IUNKNOWN) {
+	if (!ppiunkItem) return E_INVALIDARG;
+	*ppiunkItem = NULL;
+    }
+
+    /* Are we looking for the session object? */
+    if (!strcmpW(szSession, pstrName)) {
+	if (dwReturnMask & SCRIPTINFO_ITYPEINFO)                
+	    return LoadTypeInfo(This->pSession, ppti, &DIID_Session, 0); 
+	else if (dwReturnMask & SCRIPTINFO_IUNKNOWN) {
+	    IDispatch_QueryInterface(This->pSession, &IID_IUnknown, (void **)ppiunkItem);
+	    return S_OK;
+        }
+    }
+  
+    return TYPE_E_ELEMENTNOTFOUND;
+}
+
+static HRESULT WINAPI MsiActiveScriptSite_GetDocVersionString(IActiveScriptSite* iface, BSTR* pbstrVersion)
+{
+    MsiActiveScriptSite *This = (MsiActiveScriptSite *)iface;
+    TRACE("(%p/%p)->(%p) stub\n", This, iface, pbstrVersion);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI MsiActiveScriptSite_OnScriptTerminate(IActiveScriptSite* iface, const VARIANT* pvarResult, const EXCEPINFO* pexcepinfo)
+{
+    MsiActiveScriptSite *This = (MsiActiveScriptSite *)iface;
+    TRACE("(%p/%p)->(%p,%p) stub\n", This, iface, pvarResult, pexcepinfo);
+    return S_OK;
+}
+
+static HRESULT WINAPI MsiActiveScriptSite_OnStateChange(IActiveScriptSite* iface, SCRIPTSTATE ssScriptState)
+{
+    switch (ssScriptState) {
+	case SCRIPTSTATE_UNINITIALIZED:
+	      TRACE("State: Uninitialized.\n");
+	      break;
+
+	case SCRIPTSTATE_INITIALIZED:
+	      TRACE("State: Initialized.\n");
+	      break;
+
+	case SCRIPTSTATE_STARTED:
+	      TRACE("State: Started.\n");
+	      break;
+
+	case SCRIPTSTATE_CONNECTED:
+	      TRACE("State: Connected.\n");
+	      break;
+
+	case SCRIPTSTATE_DISCONNECTED:
+	      TRACE("State: Disconnected.\n");
+	      break;
+
+	case SCRIPTSTATE_CLOSED:
+	      TRACE("State: Closed.\n");
+	      break;
+
+	default:
+	      ERR("Unknown State: %d\n", ssScriptState);
+	      break;
+    }
+  
+    return S_OK;
+}
+
+static HRESULT WINAPI MsiActiveScriptSite_OnScriptError(IActiveScriptSite* iface, IActiveScriptError* pscripterror)
+{
+    MsiActiveScriptSite *This = (MsiActiveScriptSite *)iface;
+    EXCEPINFO exception;
+    HRESULT hr;
+
+    TRACE("(%p/%p)->(%p)\n", This, iface, pscripterror);
+
+    hr = IActiveScriptError_GetExceptionInfo(pscripterror, &exception);
+    if (SUCCEEDED(hr))
+	ERR("script error: %s\n", debugstr_w(exception.bstrDescription));
+
+    return S_OK;
+}
+
+static HRESULT WINAPI MsiActiveScriptSite_OnEnterScript(IActiveScriptSite* iface)
+{
+    MsiActiveScriptSite *This = (MsiActiveScriptSite *)iface;
+    TRACE("(%p/%p) stub\n", This, iface);
+    return S_OK;
+}
+
+static HRESULT WINAPI MsiActiveScriptSite_OnLeaveScript(IActiveScriptSite* iface)
+{
+    MsiActiveScriptSite *This = (MsiActiveScriptSite *)iface;
+    TRACE("(%p/%p) stub\n", This, iface);
+    return S_OK;
+}
+
+static const struct IActiveScriptSiteVtbl ASS_Vtbl = 
+{
+    MsiActiveScriptSite_QueryInterface,
+    MsiActiveScriptSite_AddRef,
+    MsiActiveScriptSite_Release,
+    MsiActiveScriptSite_GetLCID,
+    MsiActiveScriptSite_GetItemInfo,
+    MsiActiveScriptSite_GetDocVersionString,
+    MsiActiveScriptSite_OnScriptTerminate,
+    MsiActiveScriptSite_OnStateChange,
+    MsiActiveScriptSite_OnScriptError,
+    MsiActiveScriptSite_OnEnterScript,
+    MsiActiveScriptSite_OnLeaveScript    
+};
+
-- 
1.4.1

-------------- next part --------------
From 1be8b9e7543653fe59cee4674a1bd7e8f1fbb1f7 Mon Sep 17 00:00:00 2001
From: Misha Koshelev <mk144210 at bcm.tmc.edu>
Date: Sun, 25 Feb 2007 17:55:32 -0600
Subject: oleview: My private dispid patch.
---
 programs/oleview/typelib.c |   30 ++++++++++++++++++++++++++++--
 1 files changed, 28 insertions(+), 2 deletions(-)

diff --git a/programs/oleview/typelib.c b/programs/oleview/typelib.c
index 4336cf1..d96117a 100644
--- a/programs/oleview/typelib.c
+++ b/programs/oleview/typelib.c
@@ -372,6 +372,28 @@ #define VTADDTOSTR(x) case x:\
     }
 }
 
+void printw(WCHAR *w)
+{
+    int i=0;
+    while (w[i]) { printf("%c", (char)w[i]); i++; }
+}
+
+void dispidhack(ITypeInfo *pTypeInfo, BSTR bstrName, MEMBERID memid, WCHAR *szOut)
+{
+    ITypeLib *pTLib;
+    UINT iTLib;
+    BSTR bstrTypeLibName;
+    WCHAR wformat[] = {'D','I','S','P','I','D','_','%','s','_','%','s',0};
+
+    ITypeInfo_GetContainingTypeLib(pTypeInfo, &pTLib, &iTLib);
+    ITypeLib_GetDocumentation(pTLib, iTLib, &bstrTypeLibName, NULL, NULL, NULL);
+
+    wsprintfW(szOut, wformat, bstrTypeLibName, bstrName);
+    printf("#define ");
+    printw(struprW(szOut));
+    printf(" %d\n", memid);
+}
+
 int EnumVars(ITypeInfo *pTypeInfo, int cVars, HTREEITEM hParent)
 {
     int i;
@@ -403,7 +425,9 @@ int EnumVars(ITypeInfo *pTypeInfo, int c
             AddToTLDataStrW(tld, wszOpenBrackets1);
             AddToTLDataStrW(tld, wszId);
             AddToTLDataStrW(tld, wszOpenBrackets2);
-            wsprintfW(wszText, wszFormat, pVarDesc->memid);
+	    //            wsprintfW(wszText, wszFormat, pVarDesc->memid);
+	    dispidhack(pTypeInfo, bstrName, pVarDesc->memid, wszText);
+
             AddToTLDataStrW(tld, wszText);
             memset(wszText, 0, sizeof(wszText));
             AddToTLDataStrW(tld, wszCloseBrackets2);
@@ -537,7 +561,9 @@ int EnumFuncs(ITypeInfo *pTypeInfo, int 
             bFirst = FALSE;
             AddToTLDataStrW(tld, wszId);
             AddToTLDataStrW(tld, wszOpenBrackets2);
-            wsprintfW(wszText, wszFormat, pFuncDesc->memid);
+//            wsprintfW(wszText, wszFormat, pFuncDesc->memid);
+	    dispidhack(pTypeInfo, bstrName, pFuncDesc->memid, wszText);
+
             AddToTLDataStrW(tld, wszText);
             AddToTLDataStrW(tld, wszCloseBrackets2);
             memset(wszText, 0, sizeof(wszText));
-- 
1.4.1



More information about the wine-devel mailing list