C# 当同时使用DTF和MSI API的C无法找到INSTALLLOCATION时,为什么vbs能够找到INSTALLLOCATION?

C# 当同时使用DTF和MSI API的C无法找到INSTALLLOCATION时,为什么vbs能够找到INSTALLLOCATION?,c#,installation,vbscript,windows-installer,dtf,C#,Installation,Vbscript,Windows Installer,Dtf,VBS按照我的要求工作,但是使用C的COM API和DTF都没有找到InstallLocation。以下是我到目前为止所做的 由于,我能够使用vbs找到注册表中不可用的InstallLocation。我知道vbs正在调用%WINDIR%\system32\msi.dll上可用的COM API C COM API 所以我想我应该用C来调用这个方法。但它失败了。即使我可以确认存在和安装,它也无法打开我检查的其中一个产品GUID 注意:有些产品没有抛出异常,并且正确地找到了InstallLocatio

VBS按照我的要求工作,但是使用C的COM API和DTF都没有找到InstallLocation。以下是我到目前为止所做的

由于,我能够使用vbs找到注册表中不可用的InstallLocation。我知道vbs正在调用%WINDIR%\system32\msi.dll上可用的COM API

C COM API 所以我想我应该用C来调用这个方法。但它失败了。即使我可以确认存在和安装,它也无法打开我检查的其中一个产品GUID

注意:有些产品没有抛出异常,并且正确地找到了InstallLocation。这还不是全部

以下是我的代码

        static Dictionary<string, string> FindInstallLocationsCOM(Dictionary<string, string> products)
        {
            var locationDictionary = new Dictionary<string, string>();

            // Get the type of the Windows Installer object
            Type installerType = Type.GetTypeFromProgID("WindowsInstaller.Installer");

            // Create the Windows Installer object
            Object installerObj = Activator.CreateInstance(installerType);
            Installer installer = installerObj as Installer;

            foreach (var product in products)
            {
                try
                {
                    var session = installer.OpenProduct(product.Value);
                    if (session != null)
                    {
                        session.DoAction("CostInitialize");
                        session.DoAction("CostFinalize");
                        var installLocation = session.Property["INSTALLLOCATION"];
                        MessageBox.Show(product.Key + "\n" + "Product Code : " + product.Value + "\n" + "Install Location : " + installLocation);
                        locationDictionary.Add(product.Key, installLocation);
                    }
                }
                catch (Exception e)
                {
                    MessageBox.Show("Error : Could not open Product " + e.Message + "\n" + "Product : " + product.Key + "\n" + "Product Code : " + product.Value);
                }
            }

            return locationDictionary;
        }
好吧,那不行,让我们试试DTF

C DTF 但这也没有成功。下面是我的代码。这不会触发异常,即使是通过COM API无法检测到的异常也能够检测自身,但InstallLocation属性为空字符串

注意:有些产品已填充InstallLocation属性。这还不是全部

为什么VBS能够检测到InstallLocation,而C都无法检测到?我错过了什么


我不能使用VBS的原因是,除非我使用vb.net,否则try-catch不可用。

在SteinAsmul建议DTF不会自动调用与成本相关的操作后,我进一步阅读了DTF文档

我发现在DTF中也可以使用DoAction。因此,我使用了以下内容,var installLocation现在具有我想要的预期值

Installer.SetInternalUI(InstallUIOptions.Silent);
var session = Installer.OpenProduct(product.Value);
session.DoAction("CostInitialize");
session.DoAction("CostFinalize");
var installLocation = session["INSTALLLOCATION"];
session.Close();

在SteinAsmul建议DTF不会自动调用与成本相关的操作之后,我进一步阅读了DTF文档

我发现在DTF中也可以使用DoAction。因此,我使用了以下内容,var installLocation现在具有我想要的预期值

Installer.SetInternalUI(InstallUIOptions.Silent);
var session = Installer.OpenProduct(product.Value);
session.DoAction("CostInitialize");
session.DoAction("CostFinalize");
var installLocation = session["INSTALLLOCATION"];
session.Close();

你可以试试这个,虽然它不是非常抛光或测试

使用COM:

using System;
using System.Windows.Forms;
using WindowsInstaller;

namespace DTFTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Type installerType = Type.GetTypeFromProgID("WindowsInstaller.Installer");
            var installer = (WindowsInstaller.Installer)Activator.CreateInstance(installerType);
            if (installer == null) { return; }

            var session = installer.OpenProduct("Product-GUID-here");
            if (session == null) { return; }

            session.DoAction("CostInitialize");
            session.DoAction("CostFinalize");

            MessageBox.Show(session.Property["Directory-Property-Here"]);
        }
    }
}
使用DTF:

using System;
using Microsoft.Deployment.WindowsInstaller;
using System.Windows.Forms;

namespace DTFTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Installer.SetInternalUI(InstallUIOptions.Silent);
            var session = Installer.OpenProduct("Product-GUID-here");
            session.DoAction("CostInitialize");
            session.DoAction("CostFinalize");
            MessageBox.Show(session["Directory-Property-Here"]);
            session.Close();
        }
    }
}

你可以试试这个,虽然它不是非常抛光或测试

使用COM:

using System;
using System.Windows.Forms;
using WindowsInstaller;

namespace DTFTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Type installerType = Type.GetTypeFromProgID("WindowsInstaller.Installer");
            var installer = (WindowsInstaller.Installer)Activator.CreateInstance(installerType);
            if (installer == null) { return; }

            var session = installer.OpenProduct("Product-GUID-here");
            if (session == null) { return; }

            session.DoAction("CostInitialize");
            session.DoAction("CostFinalize");

            MessageBox.Show(session.Property["Directory-Property-Here"]);
        }
    }
}
使用DTF:

using System;
using Microsoft.Deployment.WindowsInstaller;
using System.Windows.Forms;

namespace DTFTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Installer.SetInternalUI(InstallUIOptions.Silent);
            var session = Installer.OpenProduct("Product-GUID-here");
            session.DoAction("CostInitialize");
            session.DoAction("CostFinalize");
            MessageBox.Show(session["Directory-Property-Here"]);
            session.Close();
        }
    }
}

C代码是错误的,您foreach是针对产品的,但是您将产品作为参数传递给方法。只是说OK不起作用,让我们试试DTF。没有帮助,是不是出错了,如果它做了什么,如果没有,问问自己为什么?啊,我的错。我有可用的字典产品,但由于发布范围的限制,我将产品作为变量传入。在此过程中发生了不匹配。这不是真正的原因。不过谢谢你指出这一点。现在已编辑。链接答案使用的是INSTALLFOLDER而不是INSTALLLOCATION。VBScript检查了哪个属性?InstallLocation我猜您没有进行自定义操作?该VBScript实际上解析目录表,并以这种方式获取安装位置。另一种检索安装目录的方法是,在原始安装期间自己将其写入注册表,然后将其读回。那对你有用吗?取决于你需要什么和你正在做什么。当我稍后回来的时候,我会看看这一点-基本上你可能需要运行成本计算来确保目录得到解决-我不确定DTF在这里自动神奇地做了什么。您可能需要启动MSI API会话对象。C代码错误,foreach用于产品,但您将产品作为参数传递给该方法。只是说OK不起作用,让我们试试DTF。没有帮助,是不是出错了,如果它做了什么,如果没有,问问自己为什么?啊,我的错。我有可用的字典产品,但由于发布范围的限制,我将产品作为变量传入。在此过程中发生了不匹配。这不是真正的原因。不过谢谢你指出这一点。现在已编辑。链接答案使用的是INSTALLFOLDER而不是INSTALLLOCATION。VBScript检查了哪个属性?InstallLocation我猜您没有进行自定义操作?该VBScript实际上解析目录表,并以这种方式获取安装位置。另一种检索安装目录的方法是,在原始安装期间自己将其写入注册表,然后将其读回。那对你有用吗?取决于你需要什么和你正在做什么。当我稍后回来的时候,我会看看这一点-基本上你可能需要运行成本计算来确保目录得到解决-我不确定DTF在这里自动神奇地做了什么。您可能需要启动一个MSI API会话对象。Yes DoAction应该可以用于此目的。很好,它能工作。您应该能够解析任何类似这样的目录属性。仍然让我想知道为什么COM msi路由不能按预期工作。我试着简单地使用COM,它似乎很管用。然而,我所做的是,目录解析有一个小陷阱——ROOTDRIVE的重定向可能会导致路径指向错误的驱动器号——或者看起来是这样。我得再看一看我不确定答案是正确的建议
不再现在无法查看,但请务必阅读答案。您可能需要的信息。是的,DoAction应该可以用于此目的。很好,它能工作。您应该能够解析任何类似这样的目录属性。仍然让我想知道为什么COM msi路由不能按预期工作。我试着简单地使用COM,它似乎很管用。然而,我所做的是,目录解析有一个小陷阱——ROOTDRIVE的重定向可能会导致路径指向错误的驱动器号——或者看起来是这样。我得再看一看我不确定答案是否是正确的建议。现在无法查看,但请务必阅读答案。您可能需要的信息。因此,基本上,在COM实现中,他们可能使用错误的类型强制转换安装程序,因为WindowsInstaller和Microsoft.Deployment.WindowsInstaller中都存在安装程序。是的,可能就是这样-或者其他一些小细节,但命名空间问题可能是一个很好的猜测。现在这个ROOTDRIVE问题让我有点困惑,我担心这个方法的合理性——我必须看一看。根驱动器可能重定向到磁盘空间最多的磁盘。-我不确定答案是否是正确的建议。稍后我会看一看。有关此问题的其他答案,请参阅我的其他评论。我知道WindowsInstaller和Microsoft.Deployment.WindowsInstaller需要单独使用,因为它们对安装程序的实现方式不同,实际上它不会编译。正如在原始文章中提到的,一些目录是使用COM显示的。只是不是全部。这就是为什么这是非常令人困惑的。若它并没有为所有人工作,我可以告诉错误是我的代码。但为什么它会部分工作?您引用的目录属性必须存在于您通过产品代码指向的MSI中。如果未定义目录,则会得到一个空字符串。如果您使用相同的MSI进行测试,并且知道该属性在其中,COM应该可以工作。也许您使用的集合中存在某些东西并获得了值?因此,基本上,在COM实现中,他们可能会使用错误的类型强制转换安装程序,因为WindowsInstaller和Microsoft.Deployment.WindowsInstaller中都存在安装程序。是的,可能就是这样-或者其他一些小细节,但名称空间问题是一个很好的猜测。现在这个ROOTDRIVE问题让我有点困惑,我担心这个方法的合理性——我必须看一看。根驱动器可能重定向到磁盘空间最多的磁盘。-我不确定答案是否是正确的建议。稍后我会看一看。有关此问题的其他答案,请参阅我的其他评论。我知道WindowsInstaller和Microsoft.Deployment.WindowsInstaller需要单独使用,因为它们对安装程序的实现方式不同,实际上它不会编译。正如在原始文章中提到的,一些目录是使用COM显示的。只是不是全部。这就是为什么这是非常令人困惑的。若它并没有为所有人工作,我可以告诉错误是我的代码。但为什么它会部分工作?您引用的目录属性必须存在于您通过产品代码指向的MSI中。如果未定义目录,则会得到一个空字符串。如果您使用相同的MSI进行测试,并且知道该属性在其中,COM应该可以工作。也许你使用的收藏中有一些东西能让你得到价值?