如何在读取或更新后关闭MSI文件

时间:2013-02-11 09:08:00

标签: c# windows-installer

我需要帮助才能关闭MSI文件。

我正在创建一个MSI文件编辑器,我可以在其中打开并更新msi文件。但问题是当我尝试重新打开同一个文件时(只是为了交叉检查更新的msi),它会抛出错误

  

的openDatabase,DatabasePath,用于openmode

在这一行

database = installer.OpenDatabase(msiFile.FullName, MsiOpenDatabaseMode.msiOpenDatabaseModeTransact);

所以,我相信它,因为msi文件已经打开。任何人都可以帮我关闭已经开放的msi。

4 个答案:

答案 0 :(得分:2)

我猜你正在使用从WindowsInstaller.Installer COM对象生成的互操作库。你不想那样做。相信我这个。而是下载Windows Installer XML并查找SDK文件夹中的Microsoft.Deployment.WindodsInstaller程序集。该库是部署工具基础(DTF)的一部分,它是与Windows Installer交互的黄金标准。

在DTF中,Database类实现了IDisposable接口,因此最优雅的方法是将它放在using语句中。

using(Database database = new Database(...))
{
 // Do Stuff Here
}

.NET将在块完成后自动调用Dispose()方法,然后关闭数据库并释放非托管句柄。然后将通知垃圾收集器在稍后的非重要时间清理托管类。如果您无法调用Dispose(隐式或显式),那么在垃圾收集器开始清理之前,不会释放未管理的资源,这对您来说不是一件好事。

答案 1 :(得分:1)

将数据库设置为null或仅强制变量超出范围。这应该释放打开的手柄。

或者,您可能需要强制垃圾收集器运行以放弃句柄。 Best Practice for Forcing Garbage Collection in C#

答案 2 :(得分:1)

嘿斯蒂芬和克里斯托弗,这就是我用你宝贵的建议解决我的问题的方法。

我使用数据库作为全局变量,因为我需要在整个应用程序中进行许多不同的事务,所以在打开msi文件之前添加了这些行。

if (view != null)
   {
      System.Runtime.InteropServices.Marshal.FinalReleaseComObject(view);
      view = null;
   }
if (database != null)
   {
      System.Runtime.InteropServices.Marshal.FinalReleaseComObject(database);
      database = null;
   }
GC.Collect();

希望我的回答也能帮助人们陷入同样的​​境地。

答案 3 :(得分:0)

您必须释放每个句柄,例如:

Database database = _installer.OpenDatabase(...);
View view = database.OpenView(query);
view.Execute();
Record record = view.Fetch();

Marshal.FinalReleaseComObject(record);
view.Close();
Marshal.FinalReleaseComObject(record);
Marshal.FinalReleaseComObject(database);
record = null;
view = null;
database = null;
GC.Collect();

尝试一下......最后,你应该做得很好。