我使用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 = "";
}它工作得很好,只是当代码运行完毕时,它保存了一个内部MSI文件句柄,所以当我试图移动或重命名MSI文件时,我会得到该文件仍在使用的错误。这种情况一直持续到我实际从调用上述方法的ASPX页面导航。
我的问题是,我显然没有关闭上面代码中的某些句柄或对象。但那会是什么呢?
PS。我正在VS2010的开发环境中测试它。
编辑:按照阿德里亚诺的建议编辑代码。谢谢!
发布于 2012-03-26 07:28:29
COM对象还没有被释放(当它超出作用域时应该是自动释放的,但是在.NET中这并不是很好的工作)。因为它没有实现IDisposable接口,所以不能调用它的Dispose()方法,也不能在using语句中使用它。您必须显式地调用Marshal.FinalReleaseComObject。例如:
try
{
// Your stuffs
}
finally
{
dv.Close();
Marshal.FinalReleaseComObject(dv);
Marshal.FinalReleaseComObject(db);
}此外,请注意,您实际上不需要调用Commit()方法,因为您没有做任何更改,只是进行了一个查询。
发布于 2012-03-26 11:01:04
FWIW,您应该使用(WiX)部署工具基础(DTF)。这是一个来自微软的自由和开放源码软件项目,可以在CodePlex上找到。它具有与COM类非常相似但实现IDisosable的类的MSI互操作库,并在幕后使用P/Invoke而不是COM。如果您愿意,甚至支持Linq到MSI。完整的源代码是可用的。
DTF是.NET世界中MSI互操作的黄金标准。以下是两个例子:
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());
}
}
}
}发布于 2012-03-26 07:26:53
尝试Dispose对象。
dv.Dispose();
db.Dispose();https://stackoverflow.com/questions/9868091
复制相似问题