I have an MSI file built from my C# Visual Studio 2010. The version is set through the Version
property. I wanted to know if there is a way to determine the version without having to install the file. Currently when right click and view the properties it isn't displayed.

- 84,773
- 49
- 224
- 367

- 14,489
- 16
- 75
- 116
-
3Take a look at his post. It may be helpful for your question: http://stackoverflow.com/questions/815744/retrieving-version-of-an-msi-file-built-with-wix – TonySalimi Aug 22 '11 at 10:12
-
So this a bug in Windows? You can view the version number of any EXE but cannot do the same for MSI. I often wonder does anybody at Microsoft ask "Why are we doing this?" There are so many litle annoyances that reach the users. – Paul McCarthy Dec 17 '20 at 10:26
4 Answers
The following code may be helpful. But remember that you should first add a COM reference to the Microsoft Windows Installer Object Library and add the WindowsInstaller namespace to your code. The following function may be what you need.
public static string GetMsiInfo( string msiPath, string Info)
{
string retVal = string.Empty;
Type classType = Type.GetTypeFromProgID( “WindowsInstaller.Installer” );
Object installerObj = Activator.CreateInstance( classType );
Installer installer = installerObj as Installer;
// Open msi file
Database db = installer.OpenDatabase( msiPath, 0 );
// Fetch the property
string sql = String.Format(“SELECT Value FROM Property WHERE Property=’{0}’”, Info);
View view = db.OpenView( sql );
view.Execute( null );
// Read in the record
Record rec = view.Fetch();
if ( rec != null )
retVal = rec.get_StringData( 1 );
return retVal;
}
If you need the version, pass in the name of the MSI file you want, e.g.
string version = GetMsiInfo( "d:\product.msi", “ProductVersion” );

- 1
- 1

- 8,257
- 4
- 33
- 62
Yes - I think you need to inspect the MSI database however, which requires either some API calls or a wrapper utility.
Microsofts ORCA application should let you do this (although I've never tried it myself).

- 84,773
- 49
- 224
- 367
-
1thanks for your answer. For anyone else, it's found under the 'Property' tab in ORCA – probably at the beach Aug 22 '11 at 10:25
-
if you do not have ORCA - the link no longer works but there is another question answered how to install ORCA: https://stackoverflow.com/q/48315763/669692 – Andrzej Martyna Aug 19 '20 at 09:27
Instead of using the COM library, you can use the Microsoft.Deployment.WindowsInstaller
library from the wixtoolset SDK. Once referenced, you can very similarly get the version info.
private string GetMsiInfo(string msiPath)
{
using (var database = new Microsoft.Deployment.WindowsInstaller.Database(msiPath))
{
var sql = "SELECT Value FROM Property WHERE Property ='ProductVersion'";
using (var view = database.OpenView(sql))
{
view.Execute();
using (var record = view.Fetch())
{
var version = record?.GetString(1);
return version;
}
}
}
}
I haven't found a way to get the correct assembly via nuget installer. However, after I installed the wixtoolset https://wixtoolset.org/releases/, I was able to add a reference in my project directly under assemblies -> extensions -> Microsoft.Deployment.WindowsInstaller
.

- 121
- 1
- 5
Based on Gupta's answer, I added COM release calls. If you want to recreate or replace the file you accessed in your further workflow, it might be still in use and you will get an exception if the GC did not yet release the objects, so let's do this manually.
public static string GetMsiInfo(string msiPath, string info)
{
string retVal = string.Empty;
Type classType = Type.GetTypeFromProgID("WindowsInstaller.Installer");
dynamic installer = Activator.CreateInstance(classType);
try
{
// Open msi file
var db = installer.OpenDatabase(msiPath, 0);
try
{
// Fetch the property
string sql = $"SELECT Value FROM Property WHERE Property ='{info}'";
var view = db.OpenView(sql);
try
{
view.Execute(null);
// Read in the record
var rec = view.Fetch();
if (rec != null)
retVal = rec.StringData(1);
return retVal;
}
finally
{
view.Close();
Marshal.ReleaseComObject(view);
}
}
finally
{
//db.Commit();
Marshal.ReleaseComObject(db);
}
}
finally
{
Marshal.ReleaseComObject(installer);
}
}
I think using this code, there is no need to add a COM reference or an extra namespace as mentioned by Gupta, because we use late binding here (see the dynamic).

- 1,045
- 10
- 14