Grzegorz Fedczyszyn
Grzegorz Fedczyszyn

Reputation: 344

Get primary keys from MSI table using msi.dl in c#

I have a problem with calling get_PrimaryKeys() function from msi.dll in c#. I want to fund out what are the primary keys in a given MSI table. I use the following code:

Type installerType = Type.GetTypeFromProgID("WindowsInstaller.Installer");
installer = (Installer)Activator.CreateInstance(installerType);
database = installer.OpenDatabase(MSIPath, MsiOpenDatabaseMode.msiOpenDatabaseModeTransact);
WindowsInstaller.Record data = null;     
data = database.PrimaryKeys[tableName];
string s = data.get_StringData(1);

If I use database.get_PrimaryKeys(tableName), it gives the same error which is:

COMexception
Member not found. (Exception from HRESULT: 0x80020003 (DISP_E_MEMBERNOTFOUND))

When I use other functions form msi.dll they works fine.

What is the problem?

Upvotes: 2

Views: 689

Answers (2)

Carsten
Carsten

Reputation: 2211

I checked the official MSI-sample code from Microsoft here https://github.com/microsoft/Windows-classic-samples/blob/main/Samples/Win7Samples/sysmgmt/msi/scripts/WiTextIn.vbs

I also did a couple of tests with that VBS-samples and it turns out, that the table-name needs EXACTLY as listed in the MSI. E.g. 'file' will not work, but 'File'. It is case-sensitive!

Here a small PS-snippet that shows the sequence:

$installer = New-Object -ComObject WindowsInstaller.Installer
$msi = 'c:\windows\installer\MySampleFile.MSI'
$db  = $installer.OpenDatabase($msi, 0)
$keys = $db.PrimaryKeys('Media')
$keys.StringData(1)

Returns "DiskId" as the PrimaryKey-columns for that table.

Upvotes: 0

Yan Sklyarenko
Yan Sklyarenko

Reputation: 32270

There's an easier way to query MSI database from C# code. The WiX Toolset includes a well-designed convenient .NET API called DTF (Deployment Tools Foundation), which makes is possible to write the following (C#):

  using (var database = new Database("path\\to\\package.msi", DatabaseOpenMode.ReadOnly))
  {
    var table = database.Tables["someTableName"];
    foreach (var column in table.PrimaryKeys)
    {
      Console.WriteLine("The table {0} defines {1} as primary key", table.Name, column);
    }
  }

All you have to do:

  • install WiX Toolset
  • reference Microsoft.Deployment.WindowsInstaller.dll in your C# project
  • add using Microsoft.Deployment.WindowsInstaller; namespace

You don't have to build your MSI with WiX in order to get advantage out of DTF. Reference DTF.chm (installed together with WiX) to know more about it.

Upvotes: 1

Related Questions