Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I extract contents of MSI package from within C++ or C# program?

Say, if I have an MSI installation file, can I extract its contents from a C# or C++ program without installing it?

like image 532
c00000fd Avatar asked Sep 19 '12 06:09

c00000fd


Video Answer


2 Answers

Typically you can perforrm an Administrative installation to extract the contents of an MSI.

msiexec /a foo.msi TARGETDIR=C:\EXTRACTHERE /qn

If you don't want to go out of process you can interop directly with MSI via the MsiInstallProduct function.

szPackagePath [in] A null-terminated string that specifies the path to the location of the Windows Installer package. The string value can contain a URL a network path, a file path (e.g. file://packageLocation/package.msi), or a local path (e.g. D:\packageLocation\package.msi).

szCommandLine [in] A null-terminated string that specifies the command line property settings. This should be a list of the format Property=Setting Property=Setting. For more information, see About Properties.

To perform an administrative installation, include ACTION=ADMIN in szCommandLine. For more information, see the ACTION property.

Note that while you can declare the P/Invoke yourself, there is a really good .NET interop library available with Windows Instaler XML called Deployment Tools Foundation (DTF). The Microsoft.Deployment.WindowsInstaller namespace has a class method called Installer that exposes a static method called InstallProduct. This is a direct encapsulation of MsiInstallProduct.

Using the DTF libraries hides you from the ugliness on the Win32 API and correctly implements IDisposable where needed to ensure that underlying unmanaged handles are released where needed.

Additionally DTF has the Microsoft.DeploymentWindowwsInstaller.Package namespace with the InstallPackage class. This class exposes a method called ExtractFiles() that extracts the files to the working directory. An example of code looks like:

using Microsoft.Deployment.WindowsInstaller;
using Microsoft.Deployment.WindowsInstaller.Package;
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            using( var package = new InstallPackage(@"C:\test.msi", DatabaseOpenMode.ReadOnly))
            {
                package.ExtractFiles();
            }
        }
    }
}
like image 64
Christopher Painter Avatar answered Nov 06 '22 03:11

Christopher Painter


An MSI file is a COM structured storage. It is basically a database. You can find some detailed documentation on msdn:

  • Here is the database API
  • Here you can find some info about a compound binary file format
  • Here is the doc about Windows Installer
like image 23
SingerOfTheFall Avatar answered Nov 06 '22 04:11

SingerOfTheFall