ISWIX, LLC View Christopher Painter's profile on LinkedIn profile for Christopher Painter at Stack Overflow, Q&A for professional and enthusiast programmers

January 17, 2007

Windows Installer Factory Provider for ADO.NET 2.0

I have to admit that for the last couple of months I really havn't spent much time working on installs. Instead I've been getting waist deep into C# programming, specifically ADO.NET 2.0 Factory Patterns. I guess that's what happens when you go to a new job to work with the founder of the Austin .NET User Group.

Although I've programmed on just about every platform and language over the years, Setup has always been deep in my blood. As I dug deeper and deeper into ADO.NET 2.0, I just couldn't help wonder what would be involved in making a Factory Provider for MSI databases. The goal would be to abstract .NET developer from the ugliness of the MSI API as much as possible. Every interop implementation that I've seen to date either was a direct wrap of the MSI API or Automation interface. Even the prettier ones like Rich's Pahvant.MSI still feels very MSI. What I wanted was the ability for anyone who's ever done ADO.NET to quickly be able to query and update MSI databases.

I've only barely begun on this project, but here is what I can report so far. It's really not that difficult to derive the classes needed from various abstract classes and interfaces. For example you can say:

using System;
using System.Data;
using System.Data.Common;
using
System.Data.MSI;
namespace System.Data.MSI
{
public sealed class
MSIFactory : DbProviderFactory
{
public static readonly MSIFactory
Instance = new MSIFactory();
public override DbCommand
CreateCommand()
{
return new MSICommand();
}
public override
DbCommandBuilder CreateCommandBuilder()
{
return new
MSICommandBuilder();
}
public override DbConnection
CreateConnection()
{
return new MSIConnection();
}
public override
DbConnectionStringBuilder CreateConnectionStringBuilder()
{
return new
MSIConnectionStringBuilder();
}
public override DbDataAdapter
CreateDataAdapter()
{
return new MSIDataAdapter();
}
public override
DbParameter CreateParameter()
{
return new object() as
DbParameter;
}
}
}

Then you create an App.Config file to teach the framework about your new Factory Class:



<?xml version="1.0" encoding="utf-8">
<configuration>
<system.data>
<dbproviderfactories>
<remove invariant="System.Data.MSI"/>
<add name="MSI Data Provider" invariant="System.Data.MSI" description=".Net Framework Data Provider for MSI"
type="System.Data.MSI.MSIFactory, System.Data.MSI"/>
</dbproviderfactories>
</system.data>
</configuration>

From there you go about defining each of your classes and wiring them up to communicate with the MSI API. Once this is all done it's time for the big payoff. Retrieving the contents of the Property table into a DataTable becomes as simple as:

using System;
using System.Data;
using System.Data.Common;
using System.Data.MSI;

DbProviderFactory factory =
DbProviderFactories.GetFactory("System.Data.MSI");
DbConnection connection =
factory.CreateConnection();
DbDataAdapter adapter =
factory.CreateDataAdapter();
DbCommand selectCommand =
factory.CreateCommand();
DataTable propertyTable = new
DataTable();
connection.ConnectionString =
"DatabasePath=D:\\somepackage.msi;Persist=MSIDBOPEN_READONLY";
connection.Open();

selectCommand.Connection
= connection;
selectCommand.CommandText = "SELECT * FROM
PROPERTY";
adapter.SelectCommand =
selectCommand;
adapter.Fill(propertyTable);


I have alot of work ahead of me, but I think this would be a really cool project to work on. I'm considering throwing this up on CodePlex if anyone would like to work on it with me. Just drop me a note. Until then, as Rob Mensching would say..... Keep on coding. You know I will.

No comments: