Update on msi JScript/VBScript support functions

Misha Koshelev mk144210 at bcm.tmc.edu
Fri Feb 23 20:15:27 CST 2007


On Fri, 2007-02-23 at 19:22 -0600, Misha Koshelev wrote:
> On Fri, 2007-02-23 at 19:20 -0600, Misha Koshelev wrote:
> > Hi, just wanted to update everybody on my work with this, sorry I have
> > not been good at replying to personal emails lately. I am not currently
> > attaching any code but will clean things up and then submit my patches
> > to wine-patches soon.
> > 
> > So, the good news is that, as a proof of concept, I have gotten the
> > Vector NTI installer to work successfully, which requires the JScript
> > functionality. Specifically, this tests custom actions 5/6 and 37/38,
> > there are two other sets that would be nice to test (but it is all the
> > same script handler so it should work).
> > 
> > Also, to make this work, I had to implement the OLE automation
> > interface. Now, I have not implemented the entire interface yet, but I
> > have made the entire .tlb file for this and made a framework which makes
> > implementing everything fairly straightforward (and everything is a
> > wrapper around the existing MSI database functions, so there is no
> > actual functionality, it is just adding new cases to the switch
> > statements that call the MSI database functions appropriately). 
> > 
> > Basically, because of the MSI design where everything that is an object
> > has an MSIHANDLE, I have made one Automation Object that each specific
> > object "inherits" from by implementing its invoke function (minus basic
> > parameter checking, etc. which is all done by the automation object) and
> > passing it to create_automation_object with its CLSID. It is pretty easy
> > to implement more functions, and I will try to keep on adding more,
> > probably as patches that I will periodically send to wine-patches.
> > 
> > Anyhow, look for my first patches in the next couple of days.
> > 
> > Misha
> 
> Almost forgot, one big caveat is right now for some reason Microsoft
> Script 5.6 does not install properly on wine either (bummer), it looks
> for some Scriptable.Dictionary (I am writing this from memory) object,
> doesn't find it, and then doesn't want to run the script, so currently
> one needs to install IE6 first to get Microsoft Script to work properly.
> But in any case IE6 < IE6+native MSI which was required before, and I
> think tracking down the Microsoft Script installation problem should not
> be too bad.
> 
> Misha

Okay, even though I said no code yet I actually didn't have that much
cleaning to do, and here are the patches I am thinking of submitting. I
would like to test these with an MSI file that has the other two
scripting custom action types (script in an installed file and script in
a property, already tested script in an MSI binary and script in the
target field of the custom action table) though. Let me know what ppl
think.

Also, just to comment on the IE6 requirement with the Microsoft Script
5.6, it actually is not just a requirement of my patches to the wine
MSI, but is required by native MSI as well, at least to install Vector
NTI (native MSI complains about scripting and does not finish installing
if I install Microsoft Script from the MS website or with the MS script
that it comes bundled with and installed; however ,with IE6 it installs
fine, and, as I said previously, there is something about a missing
Dictionary entry in the registry in the logs, so I will have to look
into it).

In any case, the first patch can be applied by itself, but the other two
must be applied together. Look at the bottom of automation.c to see how
easy it will be to fill in all the other OLE automation functions (easy
but a little tedious, mostly because of time checking things on MSDN;
also QA is hard to do as all the tests would have to be wine_todo since
wine has no native scripting engine) - I think these would be separate
patches though.

Anyhow, let me stress that these patches fix bug #7357 and possibly
other installer bugs that require scripting or allow them to be easily
fixed by implementing a few more OLE automation functions (when an
unhandled function is called this triggers a FIXME with the function
name and CLSID of the object, and as I mentioned they are all wrappers
around already implemented functions anyway).

Misha
-------------- next part --------------
From ace5c7ed5707a03a47bfd4c6387c1c704689a501 Mon Sep 17 00:00:00 2001
From: Misha Koshelev <mk144210 at bcm.tmc.edu>
Date: Fri, 23 Feb 2007 20:02:01 -0600
Subject: msi: Expand IDL file to contain all OLE automation interfaces.
---
 dlls/msi/msiserver.idl |  917 +++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 857 insertions(+), 60 deletions(-)

diff --git a/dlls/msi/msiserver.idl b/dlls/msi/msiserver.idl
index 9966d90..02def8e 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
@@ -21,9 +22,16 @@ 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)
+]
 library WindowsInstaller
 {
+    /* TLib : */    /* TLib : OLE Automation : {00020430-0000-0000-C000-000000000046} */
+    importlib("stdole2.tlb");
+
+    /* Forward declare all types defined in this typelib */
     dispinterface Installer;
     dispinterface Record;
     dispinterface Session;
@@ -37,87 +45,876 @@ library WindowsInstaller
     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
-    {
+    /* All enumerations */
+
+    typedef
+    enum {
+        msiUILevelNoChange = 0,
+        msiUILevelDefault = 1,
+        msiUILevelNone = 2,
+        msiUILevelBasic = 3,
+        msiUILevelReduced = 4,
+        msiUILevelFull = 5,
+        msiUILevelHideCancel = 32,
+        msiUILevelProgressOnly = 64,
+        msiUILevelEndDialog = 128,
+        msiUILevelSourceResOnly = 256
+    } MsiUILevel;
+
+    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;
+
+    typedef
+    enum {
+        msiDatabaseStateRead = 0,
+        msiDatabaseStateWrite = 1
+    } MsiDatabaseState;
+
+    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;
+
+    typedef
+    enum {
+        msiTransformErrorNone = 0,
+        msiTransformErrorAddExistingRow = 1,
+        msiTransformErrorDeleteNonExistingRow = 2,
+        msiTransformErrorAddExistingTable = 4,
+        msiTransformErrorDeleteNonExistingTable = 8,
+        msiTransformErrorUpdateNonExistingRow = 16,
+        msiTransformErrorChangeCodePage = 32,
+        msiTransformErrorViewTransform = 256
+    } MsiTransformError;
+
+    typedef
+    enum {
+        msiEvaluateConditionFalse = 0,
+        msiEvaluateConditionTrue = 1,
+        msiEvaluateConditionNone = 2,
+        msiEvaluateConditionError = 3
+    } _MsiEvaluateCondition;  /* Added underscore to avoid conflict with function name */
+
+    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;
+
+    typedef
+    enum {
+        msiDoActionStatusNoAction = 0,
+        msiDoActionStatusSuccess = 1,
+        msiDoActionStatusUserExit = 2,
+        msiDoActionStatusFailure = 3,
+        msiDoActionStatusSuspend = 4,
+        msiDoActionStatusFinished = 5,
+        msiDoActionStatusWrongState = 6,
+        msiDoActionStatusBadActionData = 7
+    } MsiDoActionStatus;
+
+    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 {
+        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 {
+        msiCostTreeSelfOnly = 0,
+        msiCostTreeChildren = 1,
+        msiCostTreeParents = 2
+    } MsiCostTree;
+
+    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,
+        msiInstallTypeSingleInstance = 2
+    } MsiInstallType;
+
+    typedef
+    enum {
+        msiInstallModeNoSourceResolution = -3,
+        msiInstallModeNoDetection = -2,
+        msiInstallModeExisting = -1,
+        msiInstallModeDefault = 0
+    } MsiInstallMode;
+
+    typedef
+    enum {
+        msiSignatureInfoCertificate = 0,
+        msiSignatureInfoHash = 1
+    } MsiSignatureInfo;
+
+    typedef
+    enum {
+        msiInstallContextFirstVisible = 0,
+        msiInstallContextUserManaged = 1,
+        msiInstallContextUser = 2,
+        msiInstallContextMachine = 4,
+        msiInstallContextAllUserManaged = 8
+    } MsiInstallContext;
+
+    typedef
+    enum {
+        msiInstallSourceTypeUnknown = 0,
+        msiInstallSourceTypeNetwork = 1,
+        msiInstallSourceTypeURL = 2,
+        msiInstallSourceTypeMedia = 4
+    } MsiInstallSourceType;
+
+    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;
+
+    /*
+     * Now the interfaces.
+     */
+
+    [
+      uuid(000C1090-0000-0000-C000-000000000046),
+    ]
+    dispinterface Installer {
+        properties:
+            [id(0x00000006)]
+            MsiUILevel UILevel;
+        methods:
+            [id(0x00000001)]
+            Record* CreateRecord([in] long Count);
+            [id(0x00000002)]
+            Session* OpenPackage(
+                            [in] VARIANT PackagePath, 
+                            [in, optional, defaultvalue(0)] long Options);
+            [id(0x00000003)]
+            Session* OpenProduct([in] BSTR ProductCode);
+            [id(0x00000004)]
+            Database* OpenDatabase(
+                            [in] BSTR DatabasePath, 
+                            [in] VARIANT OpenMode);
+            [id(0x00000005), propget]
+            SummaryInfo* SummaryInformation(
+                            [in] BSTR PackagePath, 
+                            [in, optional, defaultvalue(0)] long UpdateCount);
+            [id(0x00000007)]
+            void EnableLog(
+                            [in] BSTR LogMode, 
+                            [in] BSTR LogFile);
+            [id(0x00000008)]
+            void InstallProduct(
+                            [in] BSTR PackagePath, 
+                            [in, optional, defaultvalue("0")] BSTR PropertyValues);
+            [id(0x00000009), propget]
+            BSTR Version();
+            [id(0x0000000a)]
+            Record* LastErrorRecord();
+            [id(0x0000000b)]
+            BSTR RegistryValue(
+                            [in] VARIANT Root, 
+                            [in] BSTR Key, 
+                            [in, optional] VARIANT Value);
+            [id(0x0000000d)]
+            long FileAttributes([in] BSTR FilePath);
+            [id(0x0000000f)]
+            long FileSize([in] BSTR FilePath);
+            [id(0x00000010)]
+            BSTR FileVersion(
+                            [in] BSTR FilePath, 
+                            [in, optional] VARIANT Language);
+            [id(0x0000000c), propget]
+            BSTR Environment([in] BSTR Variable);
+            [id(0x0000000c), propput]
+            void Environment(
+                            [in] BSTR Variable, 
+                            [in] BSTR rhs);
+            [id(0x00000011), propget]
+            MsiInstallState ProductState([in] BSTR Product);
+            [id(0x00000012), propget]
+            BSTR ProductInfo(
+                            [in] BSTR Product, 
+                            [in] BSTR Attribute);
+            [id(0x00000013)]
+            void ConfigureProduct(
+                            [in] BSTR Product, 
+                            [in] long InstallLevel, 
+                            [in] MsiInstallState InstallState);
+            [id(0x00000014)]
+            void ReinstallProduct(
+                            [in] BSTR Product, 
+                            [in] MsiReinstallMode ReinstallMode);
+            [id(0x00000015)]
+            void CollectUserInfo([in] BSTR Product);
+            [id(0x00000016)]
+            void ApplyPatch(
+                            [in] BSTR PatchPackage, 
+                            [in] BSTR InstallPackage, 
+                            [in] MsiInstallType InstallType, 
+                            [in] BSTR CommandLine);
+            [id(0x00000017), propget]
+            BSTR FeatureParent(
+                            [in] BSTR Product, 
+                            [in] BSTR Feature);
+            [id(0x00000018), propget]
+            MsiInstallState FeatureState(
+                            [in] BSTR Product, 
+                            [in] BSTR Feature);
+            [id(0x00000019)]
+            void UseFeature(
+                            [in] BSTR Product, 
+                            [in] BSTR Feature, 
+                            [in] MsiInstallMode InstallMode);
+            [id(0x0000001a), propget]
+            long FeatureUsageCount(
+                            [in] BSTR Product, 
+                            [in] BSTR Feature);
+            [id(0x0000001b), propget]
+            DATE FeatureUsageDate(
+                            [in] BSTR Product, 
+                            [in] BSTR Feature);
+            [id(0x0000001c)]
+            void ConfigureFeature(
+                            [in] BSTR Product, 
+                            [in] BSTR Feature, 
+                            [in] MsiInstallState InstallState);
+            [id(0x0000001d)]
+            void ReinstallFeature(
+                            [in] BSTR Product, 
+                            [in] BSTR Feature, 
+                            [in] MsiReinstallMode ReinstallMode);
+            [id(0x0000001e)]
+            BSTR ProvideComponent(
+                            [in] BSTR Product, 
+                            [in] BSTR Feature, 
+                            [in] BSTR Component, 
+                            [in] long InstallMode);
+            [id(0x0000001f), propget]
+            BSTR ComponentPath(
+                            [in] BSTR Product, 
+                            [in] BSTR Component);
+            [id(0x00000020)]
+            BSTR ProvideQualifiedComponent(
+                            [in] BSTR Category, 
+                            [in] BSTR Qualifier, 
+                            [in] long InstallMode);
+            [id(0x00000021), propget]
+            BSTR QualifierDescription(
+                            [in] BSTR Category, 
+                            [in] BSTR Qualifier);
+            [id(0x00000022), propget]
+            StringList* ComponentQualifiers([in] BSTR Category);
+            [id(0x00000023), propget]
+            StringList* Products();
+            [id(0x00000024), propget]
+            StringList* Features([in] BSTR Product);
+            [id(0x00000025), propget]
+            StringList* Components();
+            [id(0x00000026), propget]
+            StringList* ComponentClients([in] BSTR Component);
+            [id(0x00000027), propget]
+            StringList* Patches([in] BSTR Product);
+            [id(0x00000028), propget]
+            StringList* RelatedProducts([in] BSTR UpgradeCode);
+            [id(0x00000029), propget]
+            BSTR PatchInfo(
+                            [in] BSTR Patch, 
+                            [in] BSTR Attribute);
+            [id(0x0000002a), propget]
+            BSTR PatchTransforms(
+                            [in] BSTR Product, 
+                            [in] BSTR Patch);
+            [id(0x0000002b)]
+            void AddSource(
+                            [in] BSTR Product, 
+                            [in] BSTR User, 
+                            [in] BSTR Source);
+            [id(0x0000002c)]
+            void ClearSourceList(
+                            [in] BSTR Product, 
+                            [in] BSTR User);
+            [id(0x0000002d)]
+            void ForceSourceListResolution(
+                            [in] BSTR Product, 
+                            [in] BSTR User);
+            [id(0x0000002e), propget]
+            Record* GetShortcutTarget([in] BSTR ShortcutPath);
+            [id(0x0000002f)]
+            Record* FileHash(
+                            [in] BSTR FilePath, 
+                            [in] long Options);
+            [id(0x00000030)]
+            SAFEARRAY(unsigned char) FileSignatureInfo(
+                            [in] BSTR FilePath, 
+                            [in] long Options, 
+                            [in] MsiSignatureInfo Format);
+            [id(0x00000031)]
+            void RemovePatches(
+                            [in] BSTR PatchList, 
+                            [in] BSTR Product, 
+                            [in] MsiInstallType UninstallType, 
+                            [in, optional, defaultvalue("0")] BSTR PropertyList);
+            [id(0x00000033)]
+            void ApplyMultiplePatches(
+                            [in] BSTR PatchPackage, 
+                            [in] BSTR Product, 
+                            [in] BSTR PropertiesList);
+            [id(0x00000035), propget]
+            HRESULT Product(
+                            [in] BSTR Product, 
+                            [in] BSTR UserSid, 
+                            [in] MsiInstallContext iContext, 
+                            [out, retval] Product** retval);
+            [id(0x00000038), propget]
+            HRESULT Patch(
+                            [in] BSTR PatchCode, 
+                            [in] BSTR ProductCode, 
+                            [in] BSTR UserSid, 
+                            [in] MsiInstallContext iContext, 
+                            [out, retval] Patch** retval);
+            [id(0x00000034), propget]
+            RecordList* ProductsEx(
+                            [in] BSTR Product, 
+                            [in] BSTR UserSid, 
+                            [in] long Contexts);
+            [id(0x00000037), propget]
+            RecordList* PatchesEx(
+                            [in] BSTR Product, 
+                            [in] BSTR UserSid, 
+                            [in] long Contexts, 
+                            [in] long filter);
+            [id(0x00000039)]
+            BSTR ExtractPatchXMLData([in] BSTR PatchPath);
+    };
+
+
+    [
+      uuid(000C1093-0000-0000-C000-000000000046)
+    ]
+    dispinterface Record {
+        properties:
+        methods:
+            [id(0x00000001), propget]
+            BSTR StringData([in] long Field);
+            [id(0x00000001), propput]
+            void StringData(
+                            [in] long Field, 
+                            [in] BSTR rhs);
+            [id(0x00000002), propget]
+            long IntegerData([in] long Field);
+            [id(0x00000002), propput]
+            void IntegerData(
+                            [in] long Field, 
+                            [in] long rhs);
+            [id(0x00000003)]
+            void SetStream(
+                            [in] long Field, 
+                            [in] BSTR FilePath);
+            [id(0x00000004)]
+            BSTR ReadStream(
+                            [in] long Field, 
+                            [in] long Length, 
+                            [in] MsiReadStream Format);
+            [id(00000000), propget]
+            long FieldCount();
+            [id(0x00000006), propget]
+            VARIANT_BOOL IsNull([in] long Field);
+            [id(0x00000005), propget]
+            long DataSize([in] long Field);
+            [id(0x00000007)]
+            void ClearData();
+            [id(0x00000008)]
+            BSTR FormatText();
+    };
+
+
+    [
+      uuid(000C109E-0000-0000-C000-000000000046)
+    ]
+    dispinterface Session {
         properties:
         methods:
-    }
+            [id(0x00000001), propget]
+            Installer* Installer();
+            [id(0x00000002), propget]
+            BSTR Property([in] BSTR Name);
+            [id(0x00000002), propput]
+            void Property(
+                            [in] BSTR Name, 
+                            [in] BSTR rhs);
+            [id(0x00000003), propget]
+            long Language();
+            [id(0x00000004), propget]
+            VARIANT_BOOL Mode([in] MsiRunMode Flag);
+            [id(0x00000004), propput]
+            void Mode(
+                            [in] MsiRunMode Flag, 
+                            [in] VARIANT_BOOL rhs);
+            [id(0x00000005), propget]
+            Database* Database();
+            [id(0x00000006), propget]
+            BSTR SourcePath([in] BSTR Folder);
+            [id(0x00000007), propget]
+            BSTR TargetPath([in] BSTR Folder);
+            [id(0x00000007), propput]
+            void TargetPath(
+                            [in] BSTR Folder, 
+                            [in] BSTR rhs);
+            [id(0x00000008)]
+            MsiDoActionStatus DoAction([in] BSTR Action);
+            [id(0x00000009)]
+            MsiDoActionStatus Sequence(
+                            [in] BSTR Table, 
+                            [in, optional] VARIANT Mode);
+            [id(0x0000000a)]
+            _MsiEvaluateCondition EvaluateCondition([in] BSTR Expression);
+            [id(0x0000000b)]
+            BSTR FormatRecord([in] Record* Record);
+            [id(0x0000000c)]
+            MsiMessageStatus Message(
+                            [in] MsiMessageType Kind, 
+                            [in] Record* Record);
+            [id(0x0000000d), propget]
+            MsiInstallState FeatureCurrentState([in] BSTR Feature);
+            [id(0x0000000e), propget]
+            MsiInstallState FeatureRequestState([in] BSTR Feature);
+            [id(0x0000000e), propput]
+            void FeatureRequestState(
+                            [in] BSTR Feature, 
+                            [in] MsiInstallState rhs);
+            [id(0x0000000f), propget]
+            long FeatureValidStates([in] BSTR Feature);
+            [id(0x00000010), propget]
+            long FeatureCost(
+                            [in] BSTR Feature, 
+                            [in] MsiCostTree CostTree, 
+                            [in] MsiInstallState State);
+            [id(0x00000011), propget]
+            MsiInstallState ComponentCurrentState([in] BSTR Component);
+            [id(0x00000012), propget]
+            MsiInstallState ComponentRequestState([in] BSTR Component);
+            [id(0x00000012), propput]
+            void ComponentRequestState(
+                            [in] BSTR Component, 
+                            [in] MsiInstallState rhs);
+            [id(0x00000013)]
+            void SetInstallLevel([in] long Level);
+            [id(0x00000014), propget]
+            VARIANT_BOOL VerifyDiskSpace();
+            [id(0x00000015), propget]
+            BSTR ProductProperty([in] BSTR Property);
+            [id(0x00000016), propget]
+            FeatureInfo* FeatureInfo([in] BSTR Feature);
+            [id(0x00000017), propget]
+            RecordList* ComponentCosts(
+                            [in] BSTR Component, 
+                            [in] MsiInstallState State);
+    };
 
-    [ uuid(000C1096-0000-0000-C000-000000000046) ]
-    dispinterface RecordList
-    {
+
+    [
+      uuid(000C109D-0000-0000-C000-000000000046)
+    ]
+    dispinterface Database {
         properties:
         methods:
-    }
+            [id(0x00000001), propget]
+            MsiDatabaseState DatabaseState();
+            [id(0x00000002), propget]
+            SummaryInfo* SummaryInformation([in, optional, defaultvalue(0)] long UpdateCount);
+            [id(0x00000003)]
+            View* OpenView([in] BSTR Sql);
+            [id(0x00000004)]
+            void Commit();
+            [id(0x00000005), propget]
+            Record* PrimaryKeys([in] BSTR Table);
+            [id(0x00000006)]
+            void Import(
+                            [in] BSTR Folder, 
+                            [in] BSTR File);
+            [id(0x00000007)]
+            void Export(
+                            [in] BSTR Table, 
+                            [in] BSTR Folder, 
+                            [in] BSTR File);
+            [id(0x00000008)]
+            VARIANT_BOOL Merge(
+                            [in] Database* Database, 
+                            [in, optional, defaultvalue("0")] BSTR ErrorTable);
+            [id(0x00000009)]
+            VARIANT_BOOL GenerateTransform(
+                            [in] Database* ReferenceDatabase, 
+                            [in, optional, defaultvalue("0")] BSTR TransformFile);
+            [id(0x0000000a)]
+            void ApplyTransform(
+                            [in] BSTR TransformFile, 
+                            [in] MsiTransformError ErrorConditions);
+            [id(0x0000000b)]
+            UIPreview* EnableUIPreview();
+            [id(0x0000000c), propget]
+            _MsiEvaluateCondition TablePersistent([in] BSTR Table);
+            [id(0x0000000d)]
+            void CreateTransformSummaryInfo(
+                            [in] Database* ReferenceDatabase, 
+                            [in] BSTR TransformFile, 
+                            [in] MsiTransformError ErrorConditions, 
+                            [in] MsiTransformValidation Validation);
+    };
+
 
-    [ uuid(000C109A-0000-0000-C000-000000000046) ]
-    dispinterface UIPreview
-    {
+    [
+      uuid(000C109B-0000-0000-C000-000000000046)
+    ]
+    dispinterface SummaryInfo {
         properties:
         methods:
-    }
+            [id(0x00000001), propget]
+            VARIANT Property([in] long Pid);
+            [id(0x00000001), propput]
+            void Property(
+                            [in] long Pid, 
+                            [in] VARIANT rhs);
+            [id(0x00000002), propget]
+            long PropertyCount();
+            [id(0x00000003)]
+            void Persist();
+    };
 
-    [ uuid(000C109B-0000-0000-C000-000000000046) ]
-    dispinterface SummaryInfo
-    {
+    [
+      uuid(000C109C-0000-0000-C000-000000000046)
+    ]
+    dispinterface View {
         properties:
         methods:
-    }
+            [id(0x00000001)]
+            void Execute([in, optional, defaultvalue(0)] Record* Params);
+            [id(0x00000002)]
+            Record* Fetch();
+            [id(0x00000003)]
+            void Modify(
+                            [in] _MsiViewModify Mode, 
+                            Record* Record);
+            [id(0x00000005), propget]
+            Record* ColumnInfo([in] MsiColumnInfo Info);
+            [id(0x00000004)]
+            void Close();
+            [id(0x00000006)]
+            BSTR GetError();
+    };
 
-    [ uuid(000C109C-0000-0000-C000-000000000046) ]
-    dispinterface View
-    {
+    [
+      uuid(000C109A-0000-0000-C000-000000000046)
+    ]
+    dispinterface UIPreview {
         properties:
         methods:
-    }
+            [id(0x00000001), propget]
+            BSTR Property([in] BSTR Name);
+            [id(0x00000001), propput]
+            void Property(
+                            [in] BSTR Name, 
+                            [in] BSTR rhs);
+            [id(0x00000002)]
+            void ViewDialog([in] BSTR Dialog);
+            [id(0x00000003)]
+            void ViewBillboard(
+                            [in] BSTR Control, 
+                            [in] BSTR Billboard);
+    };
 
-    [ uuid(000C109D-0000-0000-C000-000000000046) ]
-    dispinterface Database
-    {
+    [
+      uuid(000C109F-0000-0000-C000-000000000046)
+    ]
+    dispinterface FeatureInfo {
         properties:
+            [id(0x00000003)]
+            long Attributes;
         methods:
-    }
-
-    [ uuid(000C109E-0000-0000-C000-000000000046) ]
-    dispinterface Session
-    {
-    properties:
-    methods:
-    }
-
-    [ uuid(000C109F-0000-0000-C000-000000000046) ]
-    dispinterface FeatureInfo
-    {
+            [id(0x00000001), propget]
+            BSTR Title();
+            [id(0x00000002), propget]
+            BSTR Description();
+    };
+
+    [
+      uuid(000C1096-0000-0000-C000-000000000046)
+    ]
+    dispinterface RecordList {
         properties:
         methods:
-    }
+            [id(0xfffffffc)]
+            IUnknown* _NewEnum();
+            [id(00000000), propget]
+            Record* Item(long Index);
+            [id(0x00000001), propget]
+            long Count();
+    };
 
-    [ uuid(000C10A0-0000-0000-C000-000000000046) ]
-    dispinterface Product
-    {
+
+    [
+      uuid(000C1095-0000-0000-C000-000000000046)
+    ]
+    dispinterface StringList {
         properties:
         methods:
-    }
+            [id(0xfffffffc)]
+            IUnknown* _NewEnum();
+            [id(00000000), propget]
+            BSTR Item(long Index);
+            [id(0x00000001), propget]
+            long Count();
+    };
 
-    [ uuid(000C10A1-0000-0000-C000-000000000046) ]
-    dispinterface Patch
-    {
+    [
+      uuid(000C10A0-0000-0000-C000-000000000046)
+    ]
+    dispinterface Product {
         properties:
         methods:
-    }
-}
+            [id(0x00000001), propget]
+            HRESULT ProductCode([out, retval] BSTR* retval);
+            [id(0x00000002), propget]
+            HRESULT UserSid([out, retval] BSTR* retval);
+            [id(0x00000003), propget]
+            HRESULT Context([out, retval] MsiInstallContext* retval);
+            [id(0x00000004), propget]
+            HRESULT State([out, retval] MsiInstallState* retval);
+            [id(0x00000005), propget]
+            HRESULT InstallProperty(
+                            [in] BSTR Name, 
+                            [out, retval] BSTR* retval);
+            [id(0x00000006), propget]
+            HRESULT ComponentState(
+                            [in] BSTR Component, 
+                            [out, retval] MsiInstallState* retval);
+            [id(0x00000007), propget]
+            HRESULT FeatureState(
+                            [in] BSTR Feature, 
+                            [out, retval] MsiInstallState* retval);
+            [id(0x0000000e), propget]
+            HRESULT Sources(
+                            [in] long SourceType, 
+                            [out, retval] StringList** retval);
+            [id(0x0000000f), propget]
+            HRESULT MediaDisks([out, retval] RecordList** retval);
+            [id(0x00000008)]
+            HRESULT SourceListAddSource(
+                            [in] MsiInstallSourceType iSourceType, 
+                            [in] BSTR Source, 
+                            [in] long dwIndex);
+            [id(0x00000009)]
+            HRESULT SourceListAddMediaDisk(
+                            [in] long dwDiskId, 
+                            [in] BSTR VolumeLabel, 
+                            [in] BSTR DiskPrompt);
+            [id(0x0000000a)]
+            HRESULT SourceListClearSource(
+                            [in] MsiInstallSourceType iSourceType, 
+                            [in] BSTR Source);
+            [id(0x0000000b)]
+            HRESULT SourceListClearMediaDisk([in] long iDiskId);
+            [id(0x0000000c)]
+            HRESULT SourceListClearAll([in] MsiInstallSourceType iSourceType);
+            [id(0x0000000d)]
+            HRESULT SourceListForceResolution();
+            [id(0x00000010), propget]
+            HRESULT SourceListInfo(
+                            [in] BSTR Property, 
+                            [out, retval] BSTR* retval);
+            [id(0x00000010), propput]
+            HRESULT SourceListInfo(
+                            [in] BSTR Property, 
+                            [in] BSTR retval);
+    };
+
+
+    [
+      uuid(000C10A1-0000-0000-C000-000000000046)
+    ]
+    dispinterface Patch {
+        properties:
+        methods:
+            [id(0x00000001), propget]
+            HRESULT PatchCode([out, retval] BSTR* retval);
+            [id(0x00000002), propget]
+            HRESULT ProductCode([out, retval] BSTR* retval);
+            [id(0x00000003), propget]
+            HRESULT UserSid([out, retval] BSTR* retval);
+            [id(0x00000004), propget]
+            HRESULT Context([out, retval] MsiInstallContext* retval);
+            [id(0x00000005), propget]
+            HRESULT State([out, retval] MsiInstallState* retval);
+            [id(0x0000000c), propget]
+            HRESULT Sources(
+                            [in] long SourceType, 
+                            [out, retval] StringList** retval);
+            [id(0x0000000d), propget]
+            HRESULT MediaDisks([out, retval] RecordList** retval);
+            [id(0x00000006)]
+            HRESULT SourceListAddSource(
+                            [in] MsiInstallSourceType iSourceType, 
+                            [in] BSTR Source, 
+                            [in] long dwIndex);
+            [id(0x00000007)]
+            HRESULT SourceListAddMediaDisk(
+                            [in] long dwDiskId, 
+                            [in] BSTR VolumeLabel, 
+                            [in] BSTR DiskPrompt);
+            [id(0x00000008)]
+            HRESULT SourceListClearSource(
+                            [in] MsiInstallSourceType iSourceType, 
+                            [in] BSTR Source);
+            [id(0x00000009)]
+            HRESULT SourceListClearMediaDisk([in] long iDiskId);
+            [id(0x0000000a)]
+            HRESULT SourceListClearAll([in] MsiInstallSourceType iSourceType);
+            [id(0x0000000b)]
+            HRESULT SourceListForceResolution();
+            [id(0x0000000e), propget]
+            HRESULT SourceListInfo(
+                            [in] BSTR Property, 
+                            [out, retval] BSTR* retval);
+            [id(0x0000000e), propput]
+            HRESULT SourceListInfo(
+                            [in] BSTR Property, 
+                            [in] BSTR retval);
+            [id(0x0000000f), propget]
+            HRESULT PatchProperty(
+                            [in] BSTR Property, 
+                            [out, retval] BSTR* Value);
+    };
+};
+
+
+
-- 
1.4.1

-------------- next part --------------
From ddcb832a5526ae5116d3b1fbdc508907704e859b Mon Sep 17 00:00:00 2001
From: Misha Koshelev <mk144210 at bcm.tmc.edu>
Date: Fri, 23 Feb 2007 20:03:50 -0600
Subject: msi: Add handles for JScript/VBScript actions that call one script function.
---
 dlls/msi/custom.c  |  217 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 dlls/msi/msipriv.h |    1 
 2 files changed, 218 insertions(+), 0 deletions(-)

diff --git a/dlls/msi/custom.c b/dlls/msi/custom.c
index ba5c825..2da7e97 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,199 @@ 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;
+    }
+
+    TRACE("%s %s\n", debugstr_w( info->dllname ), debugstr_w( info->function ) );
+
+    hPackage = alloc_msihandle( &info->package->hdr );
+    if (hPackage)
+    {
+	TRACE("calling %s\n", debugstr_w( info->function ) );
+	r = call_script( hPackage, info->type, info->dllname, info->function, info->action);
+        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 dllname, 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( dllname );
+    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;
+    WCHAR tmp_file[MAX_PATH];
+    WCHAR fmt[MAX_PATH];
+    static const WCHAR f1[] = {'m','s','i',0};
+    HANDLE file;
+    DWORD sz, write;
+
+    TRACE("%s %s\n", debugstr_w(source), debugstr_w(target));
+  
+    if (MSI_GetPropertyW(package, cszTempFolder, fmt, &sz) != ERROR_SUCCESS)
+        GetTempPathW(MAX_PATH, fmt);
+
+    if (GetTempFileNameW(fmt, f1, 0, tmp_file) == 0)
+    {
+        TRACE("Unable to create file\n");
+        return ERROR_FUNCTION_FAILED;
+    }
+    track_tempfile(package, tmp_file);
+
+    /* Write out script from target field to file (a little roundabout but makes script code simpler) */
+    file = CreateFileW(tmp_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
+                       FILE_ATTRIBUTE_NORMAL, NULL);
+    if (file == INVALID_HANDLE_VALUE)
+        return ERROR_FUNCTION_FAILED;
+    else
+    {
+        WriteFile(file, target, sizeof(WCHAR)*(strlenW(target)+1), &write, NULL);
+        CloseHandle(file);
+    }
+    
+    info = do_msidbCustomActionTypeScript( package, type, tmp_file, NULL, action );
+
+    return wait_thread_handle( info );
+}
+
+static UINT HANDLE_CustomType5_6(MSIPACKAGE *package, LPCWSTR source,
+                               LPCWSTR target, const INT type, LPCWSTR action)
+{
+    msi_custom_action_info *info;
+    WCHAR tmp_file[MAX_PATH];
+    UINT r;
+
+    TRACE("%s %s\n", debugstr_w(source), debugstr_w(target));
+
+    r = store_binary_to_temp(package, source, tmp_file);
+    if (r != ERROR_SUCCESS)
+	return r;
+
+    info = do_msidbCustomActionTypeScript( package, type, tmp_file, target, action );
+
+    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;
+
+    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;
+    }
+
+    info = do_msidbCustomActionTypeScript( package, type, file->TargetPath, target, action );
+
+    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;
+    WCHAR tmp_file[MAX_PATH];
+    WCHAR fmt[MAX_PATH];
+    static const WCHAR f1[] = {'m','s','i',0};
+    HANDLE file;
+    DWORD sz, write;
+
+    TRACE("%s %s\n", debugstr_w(source), debugstr_w(target));
+
+    prop = msi_dup_property(package,source);
+    if (!prop)
+	return ERROR_SUCCESS;
+      
+    if (MSI_GetPropertyW(package, cszTempFolder, fmt, &sz) != ERROR_SUCCESS)
+        GetTempPathW(MAX_PATH, fmt);
+
+    if (GetTempFileNameW(fmt, f1, 0, tmp_file) == 0)
+    {
+        TRACE("Unable to create file\n");
+        return ERROR_FUNCTION_FAILED;
+    }
+    track_tempfile(package, tmp_file);
+
+    /* Write out script from target field to file (a little roundabout but makes script code simpler) */
+    file = CreateFileW(tmp_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
+                       FILE_ATTRIBUTE_NORMAL, NULL);
+    if (file == INVALID_HANDLE_VALUE)
+        return ERROR_FUNCTION_FAILED;
+    else
+    {
+        WriteFile(file, prop, sizeof(WCHAR)*(strlenW(prop)+1), &write, NULL);
+        CloseHandle(file);
+    }
+    
+    info = do_msidbCustomActionTypeScript( package, type, tmp_file, NULL, action );
+
+    return wait_thread_handle( info );
+}
+
 void ACTION_FinishCustomActions(MSIPACKAGE* package)
 {
     struct list *item;
diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h
index 971f71e..fb43b05 100644
--- a/dlls/msi/msipriv.h
+++ b/dlls/msi/msipriv.h
@@ -750,6 +750,7 @@ extern UINT ACTION_RegisterMIMEInfo(MSIP
 extern UINT ACTION_RegisterFonts(MSIPACKAGE *package);
 
 /* Helpers */
+extern DWORD call_script(MSIHANDLE hPackage, INT type, LPCWSTR filename, LPCWSTR function, LPCWSTR action);
 extern DWORD deformat_string(MSIPACKAGE *package, LPCWSTR ptr, WCHAR** data );
 extern LPWSTR msi_dup_record_field(MSIRECORD *row, INT index);
 extern LPWSTR msi_dup_property(MSIPACKAGE *package, LPCWSTR prop);
-- 
1.4.1

-------------- next part --------------
From f04d238d950da30f8481d80e642136c1b2fc40fe Mon Sep 17 00:00:00 2001
From: Misha Koshelev <mk144210 at bcm.tmc.edu>
Date: Fri, 23 Feb 2007 20:05:28 -0600
Subject: msi: Add full JScript/VBScript support and partial expandable OLE automation support.
---
 dlls/msi/Makefile.in  |    4 
 dlls/msi/automation.c |  754 +++++++++++++++++++++++++++++++++++++++++++++++++
 dlls/msi/automation.h |  138 +++++++++
 dlls/msi/script.c     |  448 +++++++++++++++++++++++++++++
 4 files changed, 1344 insertions(+), 0 deletions(-)

diff --git a/dlls/msi/Makefile.in b/dlls/msi/Makefile.in
index 5fb0941..4e01dab 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 \
@@ -37,6 +38,7 @@ C_SRCS = \
 	record.c \
 	registry.c \
 	regsvr.c \
+	script.c \
 	select.c \
 	source.c \
 	string.c \
@@ -48,6 +50,8 @@ C_SRCS = \
 	where.c
 
 IDL_TLB_SRCS = msiserver.idl
+IDL_H_SRCS = msiserver.idl
+IDL_I_SRCS = msiserver.idl 
 
 BISON_SRCS = \
 	cond.y \
diff --git a/dlls/msi/automation.c b/dlls/msi/automation.c
new file mode 100644
index 0000000..b1527c2
--- /dev/null
+++ b/dlls/msi/automation.c
@@ -0,0 +1,754 @@
+/*
+ * 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 "automation.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
+
+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, LPVOID funcInvoke)
+{
+    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.
+ */
+
+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 RecordDispId_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 ViewDispId_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 ViewDispId_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 ViewDispId_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 DatabaseDispId_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 SessionDispId_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 SessionDispId_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 SessionDispId_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 SessionDispId_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 SessionDispId_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 SessionDispId_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;
+}
diff --git a/dlls/msi/automation.h b/dlls/msi/automation.h
new file mode 100644
index 0000000..ed67dbf
--- /dev/null
+++ b/dlls/msi/automation.h
@@ -0,0 +1,138 @@
+/*
+ * 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
+ */
+
+#ifndef __WINE_MSI_AUTOMATION__
+#define __WINE_MSI_AUTOMATION__
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "msi.h"
+#include "msiquery.h"
+#include "objbase.h"
+#include "objidl.h"
+#include "winnls.h"
+#include "wine/list.h"
+
+#include "msiserver.h"
+
+/*
+ * 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;
+
+/* 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);
+
+/* 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;
+
+#endif /* __WINE_MSI_AUTOMATION__ */
diff --git a/dlls/msi/script.c b/dlls/msi/script.c
new file mode 100644
index 0000000..6d62c41
--- /dev/null
+++ b/dlls/msi/script.c
@@ -0,0 +1,448 @@
+/*
+ * 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 "automation.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};
+
+/* Would be better not to have to define this here, but need to tell which scripts are Unicode and
+ * which are not so we can convert to unicode */
+#define CUSTOM_ACTION_TYPE_MASK 0x3F
+
+/*
+ * MsiActiveScriptSite - Our IActiveScriptSite implementation.
+ */
+
+typedef struct {
+    IActiveScriptSite lpVtbl;
+    AutomationObject *session;
+    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->session = NULL;
+
+    *ppObj = object;
+
+    return S_OK;
+}
+
+/*
+ * Helper functions to run scripts 
+ *
+ *    - We write all scripts to a file in custom.c so we can use one function to implement both 
+ *      scripts that are files (either installed or written from an msi binary) and from properties
+ *      or from the custom action table.
+ */
+
+LPCWSTR read_script_from_file(LPCWSTR szFile, INT type)
+{
+    HANDLE hFile;
+    DWORD sz, szHighWord = 0, read;
+    WCHAR *script=NULL, *script2=NULL;
+
+    hFile = CreateFileW(szFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+    if (hFile == INVALID_HANDLE_VALUE) 
+	return NULL;
+
+    sz = GetFileSize(hFile, &szHighWord);
+    if (sz == INVALID_FILE_SIZE || szHighWord != 0) 
+	return NULL;
+
+    script = msi_alloc(sizeof(CHAR)*(sz+1));
+    if (!script) 
+	return NULL;
+  
+    if (!ReadFile(hFile, (LPVOID)script, sz, &read, NULL)) 
+    {
+	msi_free(script);
+	return NULL;
+    }
+
+    /* Convert to unicode if necessary (hack to determine which types need to be converted) */
+    switch (type & CUSTOM_ACTION_TYPE_MASK)
+    {
+	case 5:
+	case 6:
+	case 21:
+	case 22:
+	    /* Null terminate string before converting */
+	    ((CHAR *)script)[read] = 0;
+
+	    TRACE("Converting script to UniCode\n");
+	    sz = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, (LPCSTR)script, -1, script2, 0);
+	    script2 = msi_alloc(sizeof(WCHAR)*sz);
+	    if (!script2) 
+	    {
+		msi_free(script);
+		return NULL;
+	    }
+	    if (!MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, (LPCSTR)script, -1, script2, sz))
+	    {
+		msi_free(script2);
+		msi_free(script);
+		return NULL;
+	    }
+	    TRACE("Converted successfully\n");
+	    return script2;
+
+        default:
+	    return script;
+    }
+}
+
+/* JScript or VBScript? */
+LPCWSTR progid_from_type(INT type)
+{
+    if (type & msidbCustomActionTypeJScript) return szJScript;
+    else if (type & msidbCustomActionTypeVBScript) return szVBScript; 
+    ERR("Unknown script type %d\n", type);
+    return NULL;
+}
+
+/*
+ * 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;
+    MsiActiveScriptSite *msiActiveScriptSite = NULL;
+    IDispatch *iDispatch = NULL;
+    DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
+    DISPID dispid;
+    CLSID clsid;
+    VARIANT var;
+
+    /* Reeturn 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 **)&msiActiveScriptSite);
+    if (hr != S_OK) goto done;
+
+    /* Create a session object */
+    hr = create_automation_object(hPackage, NULL, (void **)&msiActiveScriptSite->session, &DIID_Session, SessionImpl_Invoke);
+    if (hr != S_OK) goto done;
+    IUnknown_AddRef((IUnknown *)msiActiveScriptSite->session);
+
+    /* Create the scripting engine */
+    progId = progid_from_type(type);
+    hr = CLSIDFromProgID(progId, &clsid);
+    if (FAILED(hr)) {
+	ERR("Could not find CLSID for program ID %s. Is scripting installed?\n", debugstr_w(progId));
+	goto done;
+    }
+    hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IActiveScript, (void **)&iActiveScript);
+    if (FAILED(hr)) {
+	ERR("Could not instantiate class for program ID %s\n", debugstr_w(progId));
+	goto done;
+    }
+
+    /* If we got this far, Windows Script is installed, so don't return success by default anymore */
+    ret = ERROR_INSTALL_FAILURE; 
+
+    /* Try to load the script file */
+    script = read_script_from_file(filename, type);
+    if (!script) goto done;
+
+    TRACE("Calling function %s, script is %s\n", debugstr_w(function), debugstr_w(script));
+
+    /* Get the IActiveScriptParse engine interface */
+    hr = IActiveScript_QueryInterface(iActiveScript, &IID_IActiveScriptParse, (void **)&iActiveScriptParse);
+    if (FAILED(hr)) goto done;
+
+    /* Give our host to the engine */
+    hr = IActiveScript_SetScriptSite(iActiveScript, (IActiveScriptSite *)msiActiveScriptSite);
+    if (FAILED(hr)) goto done;
+
+    /* Initialize the script engine */
+    hr = IActiveScriptParse_InitNew(iActiveScriptParse);
+    if (FAILED(hr)) goto done;
+
+    /* Add the session object */
+    hr = IActiveScript_AddNamedItem(iActiveScript, szSession, SCRIPTITEM_ISVISIBLE);
+
+    /* Pass the script to the engine */
+    hr = IActiveScriptParse_ParseScriptText(iActiveScriptParse, script, NULL, NULL, NULL, 0, 0, 0L, NULL, NULL);
+    if (FAILED(hr)) goto done;
+
+    /* Start processing the script */
+    hr = IActiveScript_SetScriptState(iActiveScript, 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(iActiveScript, NULL, &iDispatch);
+	if (FAILED(hr)) goto done; 
+
+	hr = IDispatch_GetIDsOfNames(iDispatch, &IID_NULL, (WCHAR **)&function, 1,LOCALE_USER_DEFAULT, &dispid);
+	if (FAILED(hr)) goto done;
+  
+	hr = IDispatch_Invoke(iDispatch, 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 (iDispatch) IDispatch_Release(iDispatch);
+    if (iActiveScript) IActiveScriptSite_Release(iActiveScript);
+    if (msiActiveScriptSite &&
+	msiActiveScriptSite->session) IUnknown_Release((IUnknown *)msiActiveScriptSite->session);
+    if (msiActiveScriptSite) IUnknown_Release((IUnknown *)msiActiveScriptSite);
+    if (script) msi_free((WCHAR *)script);
+
+    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((IDispatch *)This->session, ppti, &DIID_Session, 0); 
+	else if (dwReturnMask & SCRIPTINFO_IUNKNOWN) {
+	    IDispatch_QueryInterface((IDispatch *)This->session, &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



More information about the wine-devel mailing list