Question: I am using the following code under ASP.NET 4.0 framework to obtain the version of MSI file from a web app:

```
string strVersion = "";

try
{
    Type InstallerType;
    WindowsInstaller.Installer installer;

    InstallerType = Type.GetTypeFromProgID("WindowsInstaller.Installer");
    installer = (WindowsInstaller.Installer)Activator.CreateInstance(InstallerType);

    WindowsInstaller.Database db = installer.OpenDatabase(strMSIFilePath, 0);

    WindowsInstaller.View dv = db.OpenView("SELECT `Value` FROM `Property` WHERE `Property`='ProductVersion'");

    WindowsInstaller.Record record = null;

    dv.Execute(record);

    record = dv.Fetch();

    strVersion = record.get_StringData(1).ToString();

    dv.Close();
    //db.Commit();
    System.Runtime.InteropServices.Marshal.FinalReleaseComObject(dv);
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(db);
}
catch
{
    //Failed
    strVersion = "";
}

```

It works fine except that when the code finishes running it holds an internal MSI file handle so when I try to move or rename the MSI file I get the error that the file is still in use. This continues until I actually navigate away from the ASPX page that calls the method above.

My question is, I obviously didn't close some handle or object in the code above. But what could that be?

PS. I'm testing it in a development IDE from VS2010.

**EDIT:** Edited the code like it should be after Adriano's suggestion. Thanks!

Answer: 
FWIW, you should be using Windows Installer XML (WiX) Deployment Tools Foundation (DTF). It's an FOSS project from Microsoft that can be found on CodePlex. It has MSI interop libraries with classes that are very similar to the COM classes but implement IDisosable and use P/Invoke instead of COM behind the scenes. There is even support for Linq to MSI if you want. And the full source code is available.

DTF is the gold standard for MSI interop in a .NET world. Here are two examples:

```
using System;
using System.Linq;
using Microsoft.Deployment.WindowsInstaller;
using Microsoft.Deployment.WindowsInstaller.Linq;

namespace ConsoleApplication3
{
    class Program
    {
        const string DATABASE_PATH = @"C:\FOO..MSI";
        const string SQL_SELECT_PRODUCTVERSION = "SELECT `Value` FROM `Property` WHERE `Property`='ProductVersion'";

        static void Main(string[] args)
        {
            using (Database database = new Database(DATABASE_PATH, DatabaseOpenMode.ReadOnly))
            {
                Console.WriteLine(database.ExecuteScalar(SQL_SELECT_PRODUCTVERSION).ToString());
            }
            using (QDatabase database = new QDatabase(DATABASE_PATH, DatabaseOpenMode.ReadOnly))
            {
                var results = from property in database.Properties where property.Property == "ProductVersion" select property.Value;
                Console.WriteLine(results.AsEnumerable<string>().First());                    
            }
        }
    }
}

```
try to `Dispose` the Objects.

```
dv.Dispose();
db.Dispose();

```