IIS 安装的自定义操作 - ComboxBox 为空问题

发布于 2024-11-03 10:03:54 字数 12274 浏览 3 评论 0原文

我正在遵循许多不同的教程,试图制作一个通用的 IIS WIX 安装程序,然后我可以根据需要将其拆分到不同的库中。

教程

到目前为止,我已经有了一个在使用 /q 标志运行时似乎可以工作的安装。但是在交互模式下,应该填充组合框的自定义操作不起作用。

我尝试过调试,但遇到了以下问题:

  1. Session.Log 命令似乎没有在任何地方输出
  2. 附加到 msiexec 并调用 Debugger.Launch 或 MmsiBreak 似乎会立即退出(即使启用了断点)。

开始变得令人沮丧,因为从自定义操作中获取值并将其传递到组合框中应该不会那么困难。

任何人都知道根本原因是什么,我希望很多人都使用过此代码或类似的代码:

using System;
using System.Diagnostics;
using System.DirectoryServices;
using System.Globalization;
using System.Linq;
using Microsoft.Deployment.WindowsInstaller;
using Microsoft.Web.Administration;
using Microsoft.Win32;

namespace MyNameSpace
{
    /// <summary>
    /// Static class for the IIS Installer Custom Action.
    /// </summary>
    public static class CustomActions
    {

        #region Private Constants

        private const string IISEntry = "IIS://localhost/W3SVC";
        private const string SessionEntry = "WEBSITE";
        private const string ServerComment = "ServerComment";
        private const string CustomActionException = "CustomActionException: ";
        private const string IISRegKey = @"Software\Microsoft\InetStp";
        private const string MajorVersion = "MajorVersion";
        private const string IISWebServer = "iiswebserver";
        private const string GetComboContent = "select * from ComboBox";
        private const string AvailableSites = "select * from AvailableWebSites";
        private const string SpecificSite = "select * from AvailableWebSites where WebSiteID=";
        #endregion

        #region Custom Action Methods

        [CustomAction]
        public static ActionResult GetWebSites(Session session)
        {
            ActionResult result = ActionResult.Failure;
            try
            {
                if (session == null) { throw new ArgumentNullException("session"); }

                View comboBoxView = session.Database.OpenView(GetComboContent);
                View availableWSView = session.Database.OpenView(AvailableSites);

                if (IsIIS7Upwards)
                {
                    GetWebSitesViaWebAdministration(comboBoxView, availableWSView);
                }
                else
                {
                    GetWebSitesViaMetabase(comboBoxView, availableWSView);
                }

                result = ActionResult.Success;
            }
            catch (Exception ex)
            {
                if (session != null)
                {
                    session.Log(CustomActionException + ex);
                }
            }

            return result;
        }

        [CustomAction]
        public static ActionResult UpdatePropsWithSelectedWebSite(Session session)
        {
            Debugger.Break();

            ActionResult result = ActionResult.Failure;

            try
            {
                if (session == null) { throw new ArgumentNullException("session"); }

                string selectedWebSiteId = session[SessionEntry];
                session.Log("CA: Found web site id: " + selectedWebSiteId);

                using (View availableWebSitesView = session.Database.OpenView(
                    SpecificSite + selectedWebSiteId))
                {
                    availableWebSitesView.Execute();

                    using (Record record = availableWebSitesView.Fetch())
                    {
                        if ((record[1].ToString()) == selectedWebSiteId)
                        {
                            session["WEBSITE_ID"] = selectedWebSiteId;
                            session["WEBSITE_DESCRIPTION"] = (string)record[2];
                            session["WEBSITE_PATH"] = (string)record[3];
                        }
                    }
                }

                result = ActionResult.Success;
            }
            catch (Exception ex)
            {
                if (session != null)
                {
                    session.Log(CustomActionException + ex);
                }
            }

            return result;
        }
        #endregion

        #region Private Helper Methods
        private static void GetWebSitesViaWebAdministration(View comboView,
            View availableView)
        {
            using (ServerManager iisManager = new ServerManager())
            {
                int order = 1;

                foreach (Site webSite in iisManager.Sites)
                {
                    string id = webSite.Id.ToString(CultureInfo.InvariantCulture);
                    string name = webSite.Name;
                    string path = webSite.PhysicalPath();

                    StoreSiteDataInComboBoxTable(id, name, path, order++, comboView);
                    StoreSiteDataInAvailableSitesTable(id, name, path, availableView);
                }
            }
        }

        private static void GetWebSitesViaMetabase(View comboView, View availableView)
        {
            using (DirectoryEntry iisRoot = new DirectoryEntry(IISEntry))
            {
                int order = 1;

                foreach (DirectoryEntry webSite in iisRoot.Children)
                {
                    if (webSite.SchemaClassName.ToLower(CultureInfo.InvariantCulture)
                        == IISWebServer)
                    {
                        string id = webSite.Name;
                        string name = webSite.Properties[ServerComment].Value.ToString();
                        string path = webSite.PhysicalPath();

                        StoreSiteDataInComboBoxTable(id, name, path, order++, comboView);
                        StoreSiteDataInAvailableSitesTable(id, name, path, availableView);
                    }
                }
            }
        }

        private static void StoreSiteDataInComboBoxTable(string id, string name,
            string physicalPath, int order, View comboView)
        {
            Record newComboRecord = new Record(5);
            newComboRecord[1] = SessionEntry;
            newComboRecord[2] = order;
            newComboRecord[3] = id;
            newComboRecord[4] = name;
            newComboRecord[5] = physicalPath;
            comboView.Modify(ViewModifyMode.InsertTemporary, newComboRecord);
        }

        private static void StoreSiteDataInAvailableSitesTable(string id, string name,
            string physicalPath, View availableView)
        {
            Record newWebSiteRecord = new Record(3);
            newWebSiteRecord[1] = id;
            newWebSiteRecord[2] = name;
            newWebSiteRecord[3] = physicalPath;
            availableView.Modify(ViewModifyMode.InsertTemporary, newWebSiteRecord);
        }

        // determines if IIS7 upwards is installed so we know whether to use metabase
        private static bool IsIIS7Upwards
        {
            get
            {
                bool isV7Plus;

                using (RegistryKey iisKey = Registry.LocalMachine.OpenSubKey(IISRegKey))
                {
                    isV7Plus = (int)iisKey.GetValue(MajorVersion) >= 7;
                }

                return isV7Plus;
            }
        }

        #endregion
    }

    public static class ExtensionMethods
    {
        private const string IISEntry = "IIS://localhost/W3SVC/";
        private const string Root = "/root";
        private const string Path = "Path";

        public static string PhysicalPath(this Site site)
        {
            if (site == null) { throw new ArgumentNullException("site"); }

            var root = site.Applications.Where(a => a.Path == "/").Single();
            var vRoot = root.VirtualDirectories.Where(v => v.Path == "/")
                .Single();

            // Can get environment variables, so need to expand them
            return Environment.ExpandEnvironmentVariables(vRoot.PhysicalPath);
        }

        public static string PhysicalPath(this DirectoryEntry site)
        {
            if (site == null) { throw new ArgumentNullException("site"); }

            string path;

            using (DirectoryEntry de = new DirectoryEntry(IISEntry
                + site.Name + Root))
            {
                path = de.Properties[Path].Value.ToString();
            }

            return path;
        }
    }
}

UI

 <?xml version="1.0" encoding="UTF-8"?>
    <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
        <Fragment>
            <CustomAction Id="UpdatePropsWithSelectedWebSite" BinaryKey="IISWebSiteCA"
                  DllEntry="UpdatePropsWithSelectedWebSite" Execute="immediate"
                  Return="check" />
            <Binary Id="IISWebSiteCA" SourceFile="$(var.MyCA.TargetDir)MyCA.CA.dll" />
        </Fragment>
        <Fragment>
            <UI>
                <Dialog Id="InstallationAddress" Width="370" Height="270" Title="Experian">
                    <Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17"
                             Default="yes" Text="!(loc.WixUINext)">
                        <Condition Action="disable">WEBSITE = "" OR VD = ""</Condition>
                        <Condition Action="enable"><![CDATA[WEBSITE <> "" AND VD <> ""]]></Condition>
                    </Control>
                    <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17"
                             Text="!(loc.WixUIBack)" />
                    <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17"
                             Cancel="yes" Text="!(loc.WixUICancel)">
                        <Publish Event="SpawnDialog" Value="CancelDlg">1</Publish>
                    </Control>
                    <Control Id="Title" Type="Text" X="15" Y="6" Width="219" Height="15" Transparent="yes"
                             NoPrefix="yes" Text="!(loc.SelectInstallAddress)" />
                    <Control Id="Description" Type="Text" X="25" Y="23" Width="340" Height="15" Transparent="yes" NoPrefix="yes" Text="!(loc.SelectInstallationDescription)" />
                    <Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="44"
                             TabSkip="no" Text="!(loc.InstallDirDlgBannerBitmap)" />
                    <Control Id="BannerLine" Type="Line" X="0" Y="44" Width="370" Height="0" />
                    <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="370" Height="0" />
                    <Control Id="SelectWebSiteLabel" Type="Text" X="20" Y="105" Width="290" Height="10"
                             NoPrefix="yes" Text="!(loc.Site)" />
                    <Control Id="SelectWebSiteCombo" Type="ComboBox" X="20" Y="117" Width="250" Height="16"
                             Property="WEBSITE" Sorted="yes" ComboList="yes" />
                    <Control Type="Text" Id="VirtualDirectoryLabel" Width="290" Height="10" X="20" Y="140"
                             Text="!(loc.VirtualDirectory)" />
                    <Control Type="Edit" Id="VirtualDirectoryTextbox" Width="250" Height="18" X="20" Y="152"
                             Property="VD" />
                    <Control Type="Text" Id="InfoText1" Width="350" Height="17" X="10" Y="55"
                             Text="!(loc.Info1)" />
                    <Control Type="Text" Id="InfoText2" Width="350" Height="17" X="10" Y="75"
                             Text="!(loc.Info2)" />
                </Dialog>
            </UI>
        </Fragment>
    </Wix>

I'm following a number of different tutorials in an attempt to make a generic IIS WIX installer which I can then split up as appropriate into different libraries.

Tutorials

So far, I've got an installation that seems to work when run with the /q flag. However in interactive mode, the custom action which is supposed to populate the combo box isn't working.

I've tried to debug but I've come into the following problems:

  1. Session.Log commands don't seem to output anywhere
  2. Attaching to msiexec and calling Debugger.Launch or MmsiBreak seem to just exit straight away (even with breakpoints enabled).

Starting to get frustrating as it shouldn't be this difficult to take values from a custom action and pass them into a combo box.

Anybody have any ideas what could be the root cause, I'm expecting a lot of people have either used this code or something similar to it:

using System;
using System.Diagnostics;
using System.DirectoryServices;
using System.Globalization;
using System.Linq;
using Microsoft.Deployment.WindowsInstaller;
using Microsoft.Web.Administration;
using Microsoft.Win32;

namespace MyNameSpace
{
    /// <summary>
    /// Static class for the IIS Installer Custom Action.
    /// </summary>
    public static class CustomActions
    {

        #region Private Constants

        private const string IISEntry = "IIS://localhost/W3SVC";
        private const string SessionEntry = "WEBSITE";
        private const string ServerComment = "ServerComment";
        private const string CustomActionException = "CustomActionException: ";
        private const string IISRegKey = @"Software\Microsoft\InetStp";
        private const string MajorVersion = "MajorVersion";
        private const string IISWebServer = "iiswebserver";
        private const string GetComboContent = "select * from ComboBox";
        private const string AvailableSites = "select * from AvailableWebSites";
        private const string SpecificSite = "select * from AvailableWebSites where WebSiteID=";
        #endregion

        #region Custom Action Methods

        [CustomAction]
        public static ActionResult GetWebSites(Session session)
        {
            ActionResult result = ActionResult.Failure;
            try
            {
                if (session == null) { throw new ArgumentNullException("session"); }

                View comboBoxView = session.Database.OpenView(GetComboContent);
                View availableWSView = session.Database.OpenView(AvailableSites);

                if (IsIIS7Upwards)
                {
                    GetWebSitesViaWebAdministration(comboBoxView, availableWSView);
                }
                else
                {
                    GetWebSitesViaMetabase(comboBoxView, availableWSView);
                }

                result = ActionResult.Success;
            }
            catch (Exception ex)
            {
                if (session != null)
                {
                    session.Log(CustomActionException + ex);
                }
            }

            return result;
        }

        [CustomAction]
        public static ActionResult UpdatePropsWithSelectedWebSite(Session session)
        {
            Debugger.Break();

            ActionResult result = ActionResult.Failure;

            try
            {
                if (session == null) { throw new ArgumentNullException("session"); }

                string selectedWebSiteId = session[SessionEntry];
                session.Log("CA: Found web site id: " + selectedWebSiteId);

                using (View availableWebSitesView = session.Database.OpenView(
                    SpecificSite + selectedWebSiteId))
                {
                    availableWebSitesView.Execute();

                    using (Record record = availableWebSitesView.Fetch())
                    {
                        if ((record[1].ToString()) == selectedWebSiteId)
                        {
                            session["WEBSITE_ID"] = selectedWebSiteId;
                            session["WEBSITE_DESCRIPTION"] = (string)record[2];
                            session["WEBSITE_PATH"] = (string)record[3];
                        }
                    }
                }

                result = ActionResult.Success;
            }
            catch (Exception ex)
            {
                if (session != null)
                {
                    session.Log(CustomActionException + ex);
                }
            }

            return result;
        }
        #endregion

        #region Private Helper Methods
        private static void GetWebSitesViaWebAdministration(View comboView,
            View availableView)
        {
            using (ServerManager iisManager = new ServerManager())
            {
                int order = 1;

                foreach (Site webSite in iisManager.Sites)
                {
                    string id = webSite.Id.ToString(CultureInfo.InvariantCulture);
                    string name = webSite.Name;
                    string path = webSite.PhysicalPath();

                    StoreSiteDataInComboBoxTable(id, name, path, order++, comboView);
                    StoreSiteDataInAvailableSitesTable(id, name, path, availableView);
                }
            }
        }

        private static void GetWebSitesViaMetabase(View comboView, View availableView)
        {
            using (DirectoryEntry iisRoot = new DirectoryEntry(IISEntry))
            {
                int order = 1;

                foreach (DirectoryEntry webSite in iisRoot.Children)
                {
                    if (webSite.SchemaClassName.ToLower(CultureInfo.InvariantCulture)
                        == IISWebServer)
                    {
                        string id = webSite.Name;
                        string name = webSite.Properties[ServerComment].Value.ToString();
                        string path = webSite.PhysicalPath();

                        StoreSiteDataInComboBoxTable(id, name, path, order++, comboView);
                        StoreSiteDataInAvailableSitesTable(id, name, path, availableView);
                    }
                }
            }
        }

        private static void StoreSiteDataInComboBoxTable(string id, string name,
            string physicalPath, int order, View comboView)
        {
            Record newComboRecord = new Record(5);
            newComboRecord[1] = SessionEntry;
            newComboRecord[2] = order;
            newComboRecord[3] = id;
            newComboRecord[4] = name;
            newComboRecord[5] = physicalPath;
            comboView.Modify(ViewModifyMode.InsertTemporary, newComboRecord);
        }

        private static void StoreSiteDataInAvailableSitesTable(string id, string name,
            string physicalPath, View availableView)
        {
            Record newWebSiteRecord = new Record(3);
            newWebSiteRecord[1] = id;
            newWebSiteRecord[2] = name;
            newWebSiteRecord[3] = physicalPath;
            availableView.Modify(ViewModifyMode.InsertTemporary, newWebSiteRecord);
        }

        // determines if IIS7 upwards is installed so we know whether to use metabase
        private static bool IsIIS7Upwards
        {
            get
            {
                bool isV7Plus;

                using (RegistryKey iisKey = Registry.LocalMachine.OpenSubKey(IISRegKey))
                {
                    isV7Plus = (int)iisKey.GetValue(MajorVersion) >= 7;
                }

                return isV7Plus;
            }
        }

        #endregion
    }

    public static class ExtensionMethods
    {
        private const string IISEntry = "IIS://localhost/W3SVC/";
        private const string Root = "/root";
        private const string Path = "Path";

        public static string PhysicalPath(this Site site)
        {
            if (site == null) { throw new ArgumentNullException("site"); }

            var root = site.Applications.Where(a => a.Path == "/").Single();
            var vRoot = root.VirtualDirectories.Where(v => v.Path == "/")
                .Single();

            // Can get environment variables, so need to expand them
            return Environment.ExpandEnvironmentVariables(vRoot.PhysicalPath);
        }

        public static string PhysicalPath(this DirectoryEntry site)
        {
            if (site == null) { throw new ArgumentNullException("site"); }

            string path;

            using (DirectoryEntry de = new DirectoryEntry(IISEntry
                + site.Name + Root))
            {
                path = de.Properties[Path].Value.ToString();
            }

            return path;
        }
    }
}

UI

 <?xml version="1.0" encoding="UTF-8"?>
    <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
        <Fragment>
            <CustomAction Id="UpdatePropsWithSelectedWebSite" BinaryKey="IISWebSiteCA"
                  DllEntry="UpdatePropsWithSelectedWebSite" Execute="immediate"
                  Return="check" />
            <Binary Id="IISWebSiteCA" SourceFile="$(var.MyCA.TargetDir)MyCA.CA.dll" />
        </Fragment>
        <Fragment>
            <UI>
                <Dialog Id="InstallationAddress" Width="370" Height="270" Title="Experian">
                    <Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17"
                             Default="yes" Text="!(loc.WixUINext)">
                        <Condition Action="disable">WEBSITE = "" OR VD = ""</Condition>
                        <Condition Action="enable"><![CDATA[WEBSITE <> "" AND VD <> ""]]></Condition>
                    </Control>
                    <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17"
                             Text="!(loc.WixUIBack)" />
                    <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17"
                             Cancel="yes" Text="!(loc.WixUICancel)">
                        <Publish Event="SpawnDialog" Value="CancelDlg">1</Publish>
                    </Control>
                    <Control Id="Title" Type="Text" X="15" Y="6" Width="219" Height="15" Transparent="yes"
                             NoPrefix="yes" Text="!(loc.SelectInstallAddress)" />
                    <Control Id="Description" Type="Text" X="25" Y="23" Width="340" Height="15" Transparent="yes" NoPrefix="yes" Text="!(loc.SelectInstallationDescription)" />
                    <Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="44"
                             TabSkip="no" Text="!(loc.InstallDirDlgBannerBitmap)" />
                    <Control Id="BannerLine" Type="Line" X="0" Y="44" Width="370" Height="0" />
                    <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="370" Height="0" />
                    <Control Id="SelectWebSiteLabel" Type="Text" X="20" Y="105" Width="290" Height="10"
                             NoPrefix="yes" Text="!(loc.Site)" />
                    <Control Id="SelectWebSiteCombo" Type="ComboBox" X="20" Y="117" Width="250" Height="16"
                             Property="WEBSITE" Sorted="yes" ComboList="yes" />
                    <Control Type="Text" Id="VirtualDirectoryLabel" Width="290" Height="10" X="20" Y="140"
                             Text="!(loc.VirtualDirectory)" />
                    <Control Type="Edit" Id="VirtualDirectoryTextbox" Width="250" Height="18" X="20" Y="152"
                             Property="VD" />
                    <Control Type="Text" Id="InfoText1" Width="350" Height="17" X="10" Y="55"
                             Text="!(loc.Info1)" />
                    <Control Type="Text" Id="InfoText2" Width="350" Height="17" X="10" Y="75"
                             Text="!(loc.Info2)" />
                </Dialog>
            </UI>
        </Fragment>
    </Wix>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

故事灯 2024-11-10 10:03:54

两件事:

  • 我不知道你在哪里安排你的行动(只是它的定义和二进制条目),所以我不相信它正在运行;详细日志中的条目可以证实或反驳这一点。即使它正在运行...
  • Session.Log 不适用于从对话框启动的操作(Windows Installer 限制),因此即使它正在运行,它也只会说明该操作已启动。一种常见的解决方法是确保您记录属性更改,并更改属性:Session["LOGHACK"] = message;

Two quick things:

  • I don't see where you're scheduling your action here (just its definition and Binary entry), so I'm not convinced it's being run; the entries in a verbose log could confirm or refute that. Even if it is running...
  • Session.Log does not work on an action launched from a dialog (Windows Installer limitations), so even if this is running it won't say more than that the action was launched. One common workaround is to ensure you're logging property changes, and change a property: Session["LOGHACK"] = message;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文