【问题标题】:How to close an MSI file after reading or updating如何在读取或更新后关闭 MSI 文件
【发布时间】:2013-06-26 00:30:18
【问题描述】:

我在关闭 MSI 文件时需要帮助。

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

OpenDatabase,DatabasePath,OpenMode

在这条线上

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

所以,我相信这是因为 msi 文件已经打开。谁能帮我关闭一个已经打开的 msi。

【问题讨论】:

  • 您是否在寻找Close() 方法或尝试将database 变量封装在using 语句中?
  • 数据库没有 close() 方法,“using”语句不起作用。
  • 我的回答将解决您的问题。如果没有,你就做错了。

标签: c# windows-installer


【解决方案1】:

我猜您正在使用从 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(隐式或显式),则在垃圾收集器开始清理之前不会释放未管理的资源,这不是一件好事。

【讨论】:

  • 谢谢克里斯,我明白了你想要解释的内容。但是现在,我已经使用互操作库实现了它。我想我会使用你的方法,一旦我计划更新这个应用程序。再次感谢您的帮助。
  • 我在这方面有很多经验。相信我,重构不会那么难,而且你的状态会更好。你等待的时间越长,你就会有更多的返工。 DTF 使用 P/Invoke,它比 COM Interop 更干净,还支持 WPF 数据绑定和 LINQ to MSI 查询。
  • 这个问题的一部分是我发现从 msi 文件中找到产品版本的唯一答案使用了 COM 库(就像其他人一样)。我最终使用的 Microsoft.Deployment.WindowsInstaller 库在 wixtoolset SDK 中可用。 stackoverflow.com/questions/7145810/…>
  • MSI SDK 附带 COM 自动化接口和 Win32 安装程序功能。 DTF 为 .NET 创建了一组最终 P/Invoke 安装程序功能的类。 docs.microsoft.com/en-us/windows/win32/msi/installer-functions
【解决方案2】:

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

我使用数据库作为全局变量,因为整个应用程序中的许多不同事务都需要它,所以在打开 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();

希望我的回答也能帮助陷入同样情况的人们。

【讨论】:

  • 谢谢! GC.Collect 没有为我做这件事,而这件事做到了。
【解决方案3】:

将数据库变量设置为空或只是强制变量超出范围。这应该释放打开的句柄。

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

【讨论】:

  • 你为什么不直接处理类?
【解决方案4】:

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

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();

尝试一下……最后,你应该会很好。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多