问题
VBS works as I desired, but both COM API and DTF using C# is not locating the InstallLocation. Followings are what I have done so far.
Thanks to this post, I was able to find a InstallLocation that is not available on registry using vbs. I understand that vbs is calling for COM API available on %WINDIR%\system32\msi.dll
.
C# COM API
So I thought I would use C# to call this method up. But it failed. Even though I can confirm the existence and installation, it cannot open one of the product GUID (I tripple checked).
Note: there were products that did not throw exception and InstallLocation were properly found. Its just not all.
Followings are my code.
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;
}
OK that did not work, let's try DTF.
C# DTF
But that also was not successful. Following is my code. This does not trigger exception, and even the one that was not detectable via COM API was able to detect itself, but InstallLocation property was empty string.
Note: there were products that did have InstallLocation property filled. Its just not all.
static Dictionary<string,string> FindInstallLocation(Dictionary<string,string> products)
{
var locationDictionary = new Dictionary<string, string>();
foreach (var product in products)
{
try
{
var installed = new ProductInstallation(product.Value);
if (installed != null)
{
var installLocation = installed.InstallLocation;
MessageBox.Show(product.Key + "\n" + "Product Code : " + product.Value + "\n" + "Install Location : " + installLocation);
locationDictionary.Add(product.Key, installLocation);
}
else
{
MessageBox.Show(product.Key + "\n" + "Product Code : " + product.Value + "\n" + "Is not installed");
}
}
catch (Exception e)
{
MessageBox.Show("Error : " + e.Message + "\n" + "Product : " + product.Key + "\n" + "Product Code : " + product.Value);
}
}
return locationDictionary;
}
Why is VBS able to detect the InstallLocation when neither of C# is not able to? What am I missing?
The reason I cannot use VBS is because the try catch is not available unless I use vb.net.
回答1:
After SteinAsmul's suggesion that DTF does not automatically call cost related action, I did further reading in the DTF document.
I found an DoAction
is also available in DTF. So I used the following, and the var installLocation now has the expected value I was looking for.
Installer.SetInternalUI(InstallUIOptions.Silent);
var session = Installer.OpenProduct(product.Value);
session.DoAction("CostInitialize");
session.DoAction("CostFinalize");
var installLocation = session["INSTALLLOCATION"];
session.Close();
回答2:
You can try this though it is not very "polished" or tested.
Using 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"]);
}
}
}
Using 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();
}
}
}
来源:https://stackoverflow.com/questions/63159991/why-is-vbs-able-to-find-the-installlocation-when-c-sharp-using-both-dtf-and-msi