如何在.NET中释放COM句柄

ahm*_*md0 3 .net c# asp.net windows-installer com-interop

我在ASP.NET 4.0框架下使用以下代码从Web应用程序获取MSI文件的版本:

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 = "";
}
Run Code Online (Sandbox Code Playgroud)

它工作正常,但是当代码完成运行时它保存一个内部MSI文件句柄,所以当我尝试移动或重命名MSI文件时,我得到文件仍在使用的错误.这一直持续到我实际离开调用上述方法的ASPX页面.

我的问题是,我显然没有在上面的代码中关闭一些句柄或对象.但这可能是什么?

PS.我正在VS2010的开发IDE中测试它.

编辑:编辑代码应该是在阿德里亚诺的建议之后.谢谢!

Adr*_*tti 9

COM对象尚未发布(它应该在超出范围时自动释放,但在.NET中这不能很好地工作).因为它没有实现IDisposable接口,所以无法调用其Dispose()方法,也无法在using语句中使用它.您必须显式调用Marshal.FinalReleaseComObject.例如:

try
{
    // Your stuffs
}
finally
{
    dv.Close();
    Marshal.FinalReleaseComObject(dv);
    Marshal.FinalReleaseComObject(db);
}
Run Code Online (Sandbox Code Playgroud)

此外请注意,您并不需要调用该Commit()方法,因为您没有进行任何更改,只是查询.

  • 我补充一点,这应该是在'finally`块中.因此,即使抛出异常,它也将始终释放COM对象. (2认同)