Customizing the implementation process for MSI installation packages

Source: Internet
Author: User

Sometimes we need to perform the installation of another program in the program, which requires us to customize the implementation of the MSI installation package.

For example, I want to do a setup management program, can be installed according to the user's choice of different sub-products. When the user selects three products, it is obviously inappropriate to display the interactive UI for the installation of the three products. We expect a unified custom UI to replace each product's own UI.

Usually use Msiexec.exe, so the most direct idea is to execute in a sub-process :

msiexec.exe/qn


This is to be able to complete the task, but is not too simple? What do we do if we want to cancel this installation after the installation begins? Or we want to get some information about the installation progress.

You can actually get this thing done by calling three WindowsAPI ! The following C # demo uses a custom Form to indicate the installation process for multiple MSI files. F A scrollbar is placed on the Orm and is matched with a labelthat is constantly updated.

The following is the UIin the installation process:



Click the Cancel button to cancel the installed UI:



Let's take a look at these three APIs:

[DllImport ("Msi.dll", CharSet = CharSet.Auto)]

internal static extern int Msisetinternalui (int dwuilevel, IntPtr phwnd);


When calling Msiexec.exe, we let the installation process display a different UI by specifying the/q parameter. If the UI is not displayed, the parameter/qn will be used. The Msisetinternalui method is to do the same thing. Using the following call, you can remove the UI that comes with the MSI:

Nativemethods.msisetinternalui (2, IntPtr.Zero)


[DllImport ("Msi.dll", CharSet = CharSet.Auto)]

Internal static extern Msiinstalluihandler Msisetexternalui ([MarshalAs (UNMANAGEDTYPE.FUNCTIONPTR)] Msiinstalluihandlerpuihandler, Nativemethods.installlogmode dwmessagefilter, IntPtr pvcontext);

The Msisetexternalui function allows you to specify a user-defined external UI handler to handle messages generated during installation. This external UI handler is called before the internal UI handler is called. If a value other than 0 is returned in the external UI handler, the message has already been processed.

This external UI handler is the first parameter of the Msisetexternalui method, and we implement this handler to deal with the messages we are interested in, such as updating the progress bar after the installation progress has changed. or pass our message through it to the MSI, say to MSI, stop the installation, and perform the cancel operation. The use of this method should be noted that when you complete the installation must be set back to the original handler. Otherwise, executing the MSI installation package may cause problems later.


MSDN has a Msiinstalluihandler demo that interested students can look at.

[DllImport ("Msi.dll", CharSet = CharSet.Auto)]

Internal static extern uint MsiInstallProduct ([MarshalAs (UNMANAGEDTYPE.LPWSTR)] string Szpackagepath,[marshalas ( UNMANAGEDTYPE.LPWSTR)] [string szcommandline];


As its name is, this is the real way to do it.

I can't help but introduce the fourth method, although it is optional for implementing the current function, but for a product, it is used to help.

[DllImport ("Msi.dll", CharSet = CharSet.Auto)]

Internal static extern uint Msienablelog (GcMsiUtil.NativeMethods.InstallLogMode dwlogmode,[marshalas ( UNMANAGEDTYPE.LPWSTR)] [string szlogfile, uint dwlogattributes);

This method will save the installation log to the file path you passed to it. With it life will be happy many, many ... Otherwise, you will be mad when the user tells you that the installation has failed.

Okay, here's the main code for MyInstaller demo:

Installprocessform.cspublic Partial class Installprocessform:form {private MyInstaller _installer = null;        Private BackgroundWorker _installerbgworker = new BackgroundWorker ();            Internal Installprocessform () {InitializeComponent ();            _installer = new MyInstaller ();            _installerbgworker.workerreportsprogress = true;            _installerbgworker.workersupportscancellation = true;            _installerbgworker.dowork + = _installerbgworker_dowork;            _installerbgworker.runworkercompleted + = _installerbgworker_runworkercompleted;            _installerbgworker.progresschanged + = _installerbgworker_progresschanged; This.        shown + = Installprocessform_shown;            private void Installprocessform_shown (object sender, EventArgs e) {//When the window is open, start the background installation        _installerbgworker.runworkerasync (); } private void _installerbgworker_progresschanged (object sender, ProgressChangedEventArgs e) {//message is passed back through E.userstate and is displayed through the label on the window string message = E.userstate.tostring ();            This.label1.Text = message; if (message = "Canceling installation ...") {this.            cancelbutton.enabled = false;        }} private void _installerbgworker_runworkercompleted (object sender, Runworkercompletedeventargs e)            {//end of installation process} private void _installerbgworker_dowork (object sender, DoWorkEventArgs e) {            BackgroundWorker Bgworker = sender as BackgroundWorker;            Start Execution Installation Method _installer = new MyInstaller (); String Msifilepath = "Xxx.msi"; MSI file path _installer.        Install (Bgworker, Msifilepath); The private void Cancelbutton_click (object sender, EventArgs e) {_installer.     Canceled = true;        _installerbgworker.cancelasync (); }}myinstaller.csinternal class MyInstaller {private BaCkgroundworker _bgworker = null;        public bool Canceled {get; set;}            public void Install (BackgroundWorker bgworker, String msifilename) {_bgworker = Bgworker;            Nativemethods.mymsiinstalluihandler oldhandler = null;                try {string logPath = "Test.log";                Nativemethods.msienablelog (NativeMethods.LogMode.Verbose, LogPath, 0u);                Nativemethods.msisetinternalui (2, IntPtr.Zero);                                                Oldhandler = Nativemethods.msisetexternalui (new Nativemethods.mymsiinstalluihandler (MsiProgressHandler), NativeMethods.LogMode.ExternalUI, IntPtr.Zero                );                string param = "Action=install";                _bgworker.reportprogress (0, "Installing xxx ...");            Nativemethods.msiinstallproduct (Msifilename, param);     } catch (Exception e) {//TODO       } finally {//Be sure to set the default handler back. if (Oldhandler! = null) {Nativemethods.msisetexternalui (Oldhandler, Nativemethods.logmod                E.none, IntPtr.Zero);  }}//The most important is this method, which shows only how to cancel an installation, for more details please refer to the MSDN documentation private int Msiprogresshandler (INTPTR context, int messageType, string message) {if (this. Canceled) {if (_bgworker! = null) {_bgworker.reportprogress (                0, "Canceling installation ...");            }//This return value tells the MSI, cancel the current installation of return 2;        } return 1; }} internal static class NativeMethods {[DllImport ("Msi.dll", CharSet = CharSet.Auto)] Internal s        tatic extern int Msisetinternalui (int dwuilevel, IntPtr phwnd); [DllImport ("Msi.dll", CharSet = CharSet.Auto)] internal static extern MymsiinstalluihandLer Msisetexternalui ([MarshalAs (unmanagedtype.functionptr)] Mymsiinstalluihandler Puihandler,        Nativemethods.logmode Dwmessagefilter, IntPtr pvcontext); [DllImport ("Msi.dll", CharSet = CharSet.Auto)] internal static extern uint MsiInstallProduct ([MarshalAs (Unmanagedty Pe.        LPWSTR)] string szpackagepath, [MarshalAs (UNMANAGEDTYPE.LPWSTR)] string szcommandline); [DllImport ("Msi.dll", CharSet = CharSet.Auto)] internal static extern uint Msienablelog (Nativemethods.logmode dwlog        Mode, [MarshalAs (UNMANAGEDTYPE.LPWSTR)] string szlogfile, uint dwlogattributes); Internal delegate int Mymsiinstalluihandler (INTPTR context, int messageType, [MarshalAs (UNMANAGEDTYPE.LPWSTR)] string        message); [Flags] Internal enum Logmode:uint {None = 0u, Verbose = 4096u, External UI = 20239u}}

Briefly, the user-defined UI runs in the main thread and uses BackgroundWorker to perform the installation task. During installation, the cancel message can be passed to Msiprogresshandler, and when the cancel information is detected by Msiprogresshandler, the execution engine of the MSI is told by the return value, and the cancel operation is performed ( MSI installation process is quite rigorous, can not simply kill the installation process! )。

In this way, an installation control program for the custom UI that supports Cancel is ok (demo ha). If you want to install more than one MSI, you just need to loop through the install method.

To summarize, we can implement control of the MSI installation process by invoking several Windows APIs. This is more flexible than calling Msiexec.exe and lays the groundwork for adding new functionality later in the program.


Thanks to the grape brother Nick contributions





Customizing the implementation process for MSI installation packages

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.