2

我有一个 .NET 项目,它有 2 个通过 MSMQ 进行通信的组件。我正在使用 Wix 构建我的安装程序,因为 Microsoft 莫名其妙地停止了对 Visual Studio 2012 中的安装程序的支持。我对在 Wix 安装程序中创建 MSMQ 实例的过程非常满意,我对这个过程非常满意检测计算机上是否安装了 MSMQ(通过尝试加载 Mqrt.dll)。

有谁知道如何使用 Wix 安装 MSMQ Windows 系统组件本身?有没有办法让 Wix 指示 Windows 安装系统组件?

4

2 回答 2

4

花了很长时间,但最后我找到了优雅的方法来做到这一点。

1) 在 Visual Studio 中创建一个新的 WiX C# 自定义操作项目

2) 将以下内容粘贴到您的 CustomAction.cs 文件中:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Deployment.WindowsInstaller;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.IO;

namespace InstallMsmq
{
    public class CustomActions
    {
        [CustomAction]
        public static ActionResult CustomAction1(Session session)
        {
            session.Log("Begin CustomAction1");

            return ActionResult.Success;
        }

        [DllImport("kernel32")]
        static extern IntPtr LoadLibrary(string lpFileName);

        [DllImport("kernel32.dll", SetLastError = true)]
        static extern bool FreeLibrary(IntPtr hModule);

        [CustomAction]
        public static ActionResult InstallMsmq(Session session)
        {

            ActionResult result = ActionResult.Failure;
            session.Log("Detecting MSMQ");
            bool loaded;
            CreateConfigFile();
            CreateWindows8InstallerScript();

            try
            {
                IntPtr handle = LoadLibrary("Mqrt.dll");
                if (handle == IntPtr.Zero || handle.ToInt32() == 0)
                {
                    loaded = false;
                }
                else
                {
                    loaded = true;
                    session.Log("MSMQ is already installed");
                    result = ActionResult.Success;
                    FreeLibrary(handle);
                }
            }
            catch
            {
                loaded = false;
            }

            if (!loaded)
            {
                session.Log("Installing MSMQ");
                try
                {

                    Version win8version = new Version(6, 2, 9200, 0);

                    if (Environment.OSVersion.Platform == PlatformID.Win32NT && Environment.OSVersion.Version >= win8version)//Windows 8 or higher
                    {
                        // its win8 or higher.

                        session.Log("Windows 8 or Server 2012 detected");

                        using (Process p = new Process())
                        {
                            session.Log("Installing MSMQ Server");
                            ProcessStartInfo containerStart = new ProcessStartInfo("MSMQWindows8.bat");
                            containerStart.Verb = "runas";
                            p.StartInfo = containerStart;                            
                            bool success = p.Start();
                            p.WaitForExit();
                        }
                    }
                    else if (Environment.OSVersion.Version.Major < 6) // Windows XP or earlier
                    {
                        session.Log("Windows XP or earlier detected");
                        string fileName = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "MSMQAnswer.ans");
                        using (System.IO.StreamWriter writer = new System.IO.StreamWriter(fileName))
                        {
                            writer.WriteLine("[Version]");
                            writer.WriteLine("Signature = \"$Windows NT$\"");
                            writer.WriteLine();
                            writer.WriteLine("[Global]");
                            writer.WriteLine("FreshMode = Custom");
                            writer.WriteLine("MaintenanceMode = RemoveAll");
                            writer.WriteLine("UpgradeMode = UpgradeOnly");
                            writer.WriteLine();
                            writer.WriteLine("[Components]");
                            writer.WriteLine("msmq_Core = ON");
                            writer.WriteLine("msmq_LocalStorage = ON");
                        }

                        using (Process p = new Process())
                        {
                            session.Log("Installing MSMQ Container");
                            ProcessStartInfo start = new ProcessStartInfo("sysocmgr.exe", "/i:sysoc.inf /u:\"" + fileName + "\"");
                            p.StartInfo = start;
                            p.Start();
                            p.WaitForExit();
                        }
                    }
                    else if (Environment.OSVersion.Version.Major < 8) // Vista or later
                    {
                        session.Log("Windows Vista or Windows 7 detected");
                        using (Process p = new Process())
                        {
                            session.Log("Installing MSMQ Container");
                            ProcessStartInfo containerStart = new ProcessStartInfo("ocsetup.exe", "MSMQ-Container /unattendFile:MSMQ.xml");
                            containerStart.Verb = "runas";
                            p.StartInfo = containerStart;
                            p.Start();
                            p.WaitForExit();
                        }
                        using (Process p = new Process())
                        {
                            session.Log("Installing MSMQ Server");
                            ProcessStartInfo serverStart = new ProcessStartInfo("ocsetup.exe", "MSMQ-Server /unattendFile:MSMQ.xml");
                            serverStart.Verb = "runas";
                            p.StartInfo = serverStart;
                            p.Start();
                            p.WaitForExit();
                        }
                    }
                    session.Log("Installation of MSMQ Completed succesfully");
                    result = ActionResult.Success;
                }
                catch (Exception ex)
                {
                    session.Log("Installation of MSMQ failed due to " + ex.Message);
                }
            }
            return result;
        }

        private static void CreateWindows8InstallerScript()
        {
            StreamWriter configFile = new StreamWriter("MSMQWindows8.bat");
            configFile.WriteLine("%WINDIR%\\SysNative\\dism.exe /online /enable-feature /all /featurename:MSMQ-Server");
            configFile.Close();
        }
        private static void CreateConfigFile()
        {
            StreamWriter configFile = new StreamWriter("MSMQ.xml");
            configFile.WriteLine("<?xml version=\"1.0\"?>");
            configFile.WriteLine("");
            configFile.WriteLine("<unattend>");
            configFile.WriteLine("");
            configFile.WriteLine("  <servicing>");
            configFile.WriteLine("");
            configFile.WriteLine("    <package action=\"configure\">");
            configFile.WriteLine("");
            configFile.WriteLine("<assemblyIdentity name=\"Microsoft-Windows-Foundation-Package\" version=\"6.0.6000.16386\" language=\"neutral\" processorArchitecture=\"AMD64\" publicKeyToken=\"31bf3856ad364e35\" versionScope=\"nonSxS\"/>");
            configFile.WriteLine("");
            configFile.WriteLine("      <selection name=\"MSMQ-Container\" state=\"true\"/>");
            configFile.WriteLine("");
            configFile.WriteLine("<selection name=\"MSMQ-Server\" state=\"true\"/>");
            configFile.WriteLine("");
            configFile.WriteLine("<selection name=\"MSMQ-Triggers\" state=\"true\"/>");
            configFile.WriteLine("");
            configFile.WriteLine("<selection name=\"MSMQ-DCOMProxy\" state=\"true\"/>");
            configFile.WriteLine("");
            configFile.WriteLine("<selection name=\"MSMQ-Multicast\" state=\"true\"/>");
            configFile.WriteLine("");
            configFile.WriteLine("<selection name=\"MSMQ-ADIntegration\" state=\"true\"/>");
            configFile.WriteLine("");
            configFile.WriteLine("<selection name=\"MSMQ-HTTP\" state=\"true\"/>");
            configFile.WriteLine("");
            configFile.WriteLine("    </package>");
            configFile.WriteLine("");
            configFile.WriteLine("  </servicing>");
            configFile.WriteLine("");
            configFile.WriteLine("</unattend>");
            configFile.Close();
        }
    }
}

3) 编译自定义动作

4) 将以下内容添加到您的 WiX setup.wxs 文件中:

<Binary SourceFile="[path to custom action project]\bin\[Debug or Release]\[custom action project name].CA.dll" Id="[custom action project name]step" />
<CustomAction Id="[custom action project name]CustomAction" BinaryKey="[custom action project name]step" DllEntry="[custom action project name]" Execute="deferred" Impersonate="no"/>
<InstallExecuteSequence>
  <Custom Action="[custom action project name]CustomAction" Before="InstallFiles"/>
</InstallExecuteSequence> 

5) 可以将自定义操作配置为在安装过程中的多个点中的任何一个点运行(详见此处:http ://wixtoolset.org/documentation/manual/v3/xsd/wix/installexecutesequence.html )。上面的示例在安装 .wxs 文件中详述的文件之前运行自定义操作。

6) 测试 - 如果一切顺利,您应该有一个安装文件,它将 msmq 安装为安装序列的一部分!

于 2014-01-27T11:04:02.630 回答
-1

当您的产品依赖于其他第三方先决条件(例如 MSMQ、.NET Framework、SQL Server 等)时,您需要使用引导程序来运行一系列安装:首先是所需的先决条件,然后是主要的产品安装。

在 WiX 中,这些链称为bundles,并使用burn引导程序创建/运行。

于 2013-03-06T07:56:00.250 回答