Search
Module:
Directory

   Desktop Functions:

   Smart Device Functions:


Show Recent Changes
Subscribe (RSS)
Misc. Pages
Comments
FAQ
Helpful Tools
Playground
Suggested Reading
Website TODO List
Download Visual Studio Add-In

MsiRecordSetString (msi)
 
.
Summary
Copies a string into the designated field.

C# Signature:

[DllImport("msi.dll", CharSet=CharSet.Unicode)]
static extern int MsiRecordSetString(IntPtr hRecord, int iField, string szValue);

Notes:

None.

Tips & Tricks:

Please add some!

Sample Code:

The sample application below demonstrates how to use MsiRecordSetString, MsiOpenDatabase, MsiCreateRecord, MsiCloseHandle, MsiDatabaseOpenView, MsiViewExecute, MsiDatabaseCommit, and MsiViewClose in C# to modify a property value in an MSI database. To run it, simply create a new Windows Console application and replace the code that Visual Studio gives you with the code below. You may have to modify the namespace name. The sample as-is requires a valid MSI database named SETUP.msi, with a property named PROPERTY1 in the Property table, to be located in C:\. You can of course change the path to your MSI database in the calls to ChangeMSIProperty() in Main() and use any existing property you wish.

The sample application below demonstrates how to use MsiRecordSetString, MsiOpenDatabase, MsiCreateRecord, MsiCloseHandle, MsiDatabaseOpenView, MsiViewExecute, MsiDatabaseCommit, and MsiViewClose in C# to modify a property value in an MSI database. To run it, simply create a new Windows Console application and replace the code that Visual Studio gives you with the code below. You may have to modify the namespace name. The sample as-is requires a valid MSI database named SETUP.msi, with a property named PROPERTY1 in the Property table, to be located in C:\. You can of course change the path to your MSI database in the calls to ChangeMSIProperty() in Main().

using System;

using System.Globalization;

using System.Runtime.InteropServices;

namespace ConsoleApplication1

{

    /////////////////////////////////////////////////////////////////////////////
    // MsiInstallationSupportException  class
    /////////////////////////////////////////////////////////////////////////////
    public class MsiInstallationSupportException : ApplicationException
    {
    // This class encapsulates and overloads exception handling.
    public MsiInstallationSupportException() : base() { }
    public MsiInstallationSupportException(string message, Exception innerException) : base(message, innerException) { }
    public MsiInstallationSupportException(string message) : base(message) { }
    }

    /////////////////////////////////////////////////////////////////////////////
    // Program class
    /////////////////////////////////////////////////////////////////////////////
    class Program
    {
    //*******************************************
    // This enum contains common MSI error codes.
    //*******************************************
    private enum WINDOWS_MESSAGE_CODES
    {
        ERROR_SUCCESS = 0,
        ERROR_INVALID_PARAMETER = 87,
        ERROR_NO_MORE_ITEMS = 259,
        ERROR_INSTALL_USEREXIT = 1602,
        ERROR_INSTALL_FAILURE = 1603,
        ERROR_BAD_CONFIGURATION = 1610,
        ERROR_INSTALL_IN_PROGRESS = 1618,
        ERROR_INSTALL_SOURCE_ABSENT = 1612,
        ERROR_UNKNOWN_PRODUCT = 1605,
        ERROR_FUNCTION_FAILED = 1627,
        ERROR_INVALID_HANDLE_STATE = 1609,
        ERROR_MORE_DATA = 234,
        ERROR_UNKNOWN_PROPERTY = 1608,
        ERROR_CREATE_FAILED = 1631,
        ERROR_OPEN_FAILED = 110,
        ERROR_BAD_QUERY_SYNTAX = 1615
    }

       //***********************************
       // DllImports for the MSI API's used.
       //***********************************
    [DllImport("msi.dll", SetLastError = true)]
    static extern int MsiOpenDatabase(string szDatabasePath, IntPtr phPersist, out IntPtr phDatabase);

    [DllImport("msi.dll", ExactSpelling = true)]
    static extern IntPtr MsiCreateRecord(uint cParams);

    [DllImport("msi.dll", ExactSpelling = true)]
    static extern int MsiCloseHandle(IntPtr hAny);

    [DllImport("msi.dll", CharSet = CharSet.Unicode)]
    static extern int MsiDatabaseOpenViewW(IntPtr hDatabase, [MarshalAs(UnmanagedType.LPWStr)] string szQuery, out IntPtr phView);

    [DllImport("msi.dll", CharSet = CharSet.Unicode)]
    static extern int MsiViewExecute(IntPtr hView, IntPtr hRecord);

    [DllImport("msi.dll", CharSet = CharSet.Unicode)]
    static extern int MsiDatabaseCommit(IntPtr hDatabase);

    [DllImport("msi.dll", CharSet = CharSet.Unicode)]
    static extern int MsiRecordSetString(IntPtr hRecord, int iField, string szValue);

    [DllImport("msi.dll")]
    static extern int MsiViewClose(IntPtr viewhandle);

    //*****************************************
    // Open mode constants for MsiOpenDatabase.
    //*****************************************
    const int MSIDBOPEN_READONLY =     0;  // database open read-only, no persistent changes
    const int MSIDBOPEN_TRANSACT =     1;  // database read/write in transaction mode
    const int MSIDBOPEN_DIRECT =       2;  // database direct read/write without transaction
    const int MSIDBOPEN_CREATE =       3;  // create new database, transact mode read/write
    const int MSIDBOPEN_CREATEDIRECT = 4;  // create new database, direct mode read/write

    //*********************
    // Program entry point.
    //*********************
    static void Main(string[] args)
    {
        ChangeMSIProperty(@"C:\SETUP.msi", "PROPERTY1", "1"); // Set property "PROPERTY1" to a value of 1.

        ChangeMSIProperty(@"C:\SETUP.msi", "PROPERTY1", "0"); // Now set property "PROPERTY1" to a value of 1.
    }

    //***************************************************
    // The method to call to set/change a property value.
    //***************************************************
    static void ChangeMSIProperty(string path, string property, string value)
    {
        // The sql command. Note the "?" placeholder for the value.
        string sql = @"UPDATE Property SET Value = ? WHERE Property = '" + property + "'";
        IntPtr msiHandle = IntPtr.Zero;
        IntPtr msiRecord = IntPtr.Zero;
        IntPtr msiView = IntPtr.Zero;
        int iOpenMode = MSIDBOPEN_DIRECT;
        IntPtr persist = new IntPtr(iOpenMode);

        try
        {
        // Open the database for read/write access.
        WINDOWS_MESSAGE_CODES returnValue = (WINDOWS_MESSAGE_CODES)MsiOpenDatabase(path, persist, out msiHandle);
        if (returnValue != WINDOWS_MESSAGE_CODES.ERROR_SUCCESS)
            throw new MsiInstallationSupportException(string.Format(CultureInfo.InvariantCulture, "MsiOpenDatabase returned error code {0}.", returnValue.ToString()));
            // If the returnValue error code is defined in the enum WINDOWS_MESSAGE_CODES, the exception message will show the enum code name; otherwise it will show the error number.

        // Create a record to be used in tandem with the view below.
        msiRecord = MsiCreateRecord(1);
        if (msiHandle == IntPtr.Zero)
            throw new MsiInstallationSupportException(string.Format(CultureInfo.InvariantCulture, "MsiCreateRecord failed to return a valid record handle."));

        // Set field 1 of your record to the value to set in the database.
        returnValue = (WINDOWS_MESSAGE_CODES)MsiRecordSetString(msiRecord, (int)1, value);
        if (returnValue != WINDOWS_MESSAGE_CODES.ERROR_SUCCESS)
            throw new MsiInstallationSupportException(string.Format(CultureInfo.InvariantCulture, "MsiRecordSetString returned error code {0}.", returnValue.ToString()));

        // Open a view to use to apply the change. Here's where you specify your sql command.
        returnValue = (WINDOWS_MESSAGE_CODES)MsiDatabaseOpenViewW(msiHandle, sql, out msiView);
        if (returnValue != WINDOWS_MESSAGE_CODES.ERROR_SUCCESS)
            throw new MsiInstallationSupportException(string.Format(CultureInfo.InvariantCulture, "MsiDatabaseOpenViewW returned error code {0}.", returnValue.ToString()));

        // Execute the view, passing it the record set. If the property does not exist, it will NOT be created and there will be NO error thrown.
        returnValue = (WINDOWS_MESSAGE_CODES)MsiViewExecute(msiView, msiRecord);
        if (returnValue != WINDOWS_MESSAGE_CODES.ERROR_SUCCESS)
            throw new MsiInstallationSupportException(string.Format(CultureInfo.InvariantCulture, "MsiViewExecute returned error code {0}.", returnValue.ToString()));

        // Close the view.
        returnValue = (WINDOWS_MESSAGE_CODES)MsiViewClose(msiView);
        if (returnValue == WINDOWS_MESSAGE_CODES.ERROR_SUCCESS) // note prior to 7/11/2010, this was != instead of ==, causing MSI to be inconsistent. Commit seems required. Edited by txcraig
        if (returnValue != WINDOWS_MESSAGE_CODES.ERROR_SUCCESS)
        {
            // Commit the changes.
            returnValue = (WINDOWS_MESSAGE_CODES)MsiDatabaseCommit(msiHandle);
            if (returnValue != WINDOWS_MESSAGE_CODES.ERROR_SUCCESS)
            throw new MsiInstallationSupportException(string.Format(CultureInfo.InvariantCulture, "MsiDatabaseCommit returned error code {0}.", returnValue.ToString()));

        }
        else
        {
            // Failed to close the view.
            if (returnValue != WINDOWS_MESSAGE_CODES.ERROR_SUCCESS)
            throw new MsiInstallationSupportException(string.Format(CultureInfo.InvariantCulture, "MsiViewClose returned error code {0}.", returnValue.ToString()));
        }

        }
        finally
        {
        // Close handles or you could get a corrupted database and un-closed handles.
        if (msiRecord != IntPtr.Zero)
            MsiCloseHandle(msiRecord);

        if (msiView != IntPtr.Zero)
            MsiCloseHandle(msiView);

        if (msiHandle != IntPtr.Zero)
            MsiCloseHandle(msiHandle);
        }
    }
    }

}

Alternative Managed API:

MSI interop library

http://sourceforge.net/project/showfiles.php?group_id=40188&package_id=110212

Documentation

Please edit this page!

Do you have...

  • helpful tips or sample code to share for using this API in managed code?
  • corrections to the existing content?
  • variations of the signature you want to share?
  • additional languages you want to include?

Select "Edit This Page" on the right hand toolbar and edit it! Or add new pages containing supporting types needed for this API (structures, delegates, and more).

 
Access PInvoke.net directly from VS:
Terms of Use
Edit This Page
Find References
Show Printable Version
Revisions