Пользовательские действия для установки IIS — проблема с пустым ComboxBox

#iis #combobox #wix #custom-action

#iis #поле со списком #wix #пользовательское действие

Вопрос:

Я следую ряду различных руководств в попытке создать универсальный установщик IIS WIX, который затем я могу соответствующим образом разделить на разные библиотеки.

Руководства

Пока что у меня есть установка, которая, похоже, работает при запуске с флагом / q. Однако в интерактивном режиме пользовательское действие, которое должно заполнять поле со списком, не работает.

Я пытался выполнить отладку, но столкнулся со следующими проблемами:

  1. Сеанс.Команды журнала, похоже, нигде не выводятся
  2. Подключение к msiexec и вызов отладчика.Запуск или 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 = @"SoftwareMicrosoftInetStp";
        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 resu<
        }

        [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 resu<
        }
        #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;
        }
    }
}
  

ПОЛЬЗОВАТЕЛЬСКИЙ интерфейс

  <?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>
  

Ответ №1:

Две быстрые вещи:

  • Я не вижу, где вы планируете свое действие здесь (только его определение и двоичную запись), поэтому я не уверен, что оно выполняется; записи в подробном журнале могут подтвердить или опровергнуть это. Даже если он запущен…
  • Сеанс.Журнал не работает для действия, запущенного из диалогового окна (ограничения установщика Windows), поэтому, даже если оно запущено, оно не сообщит больше, чем о том, что действие было запущено. Один из распространенных обходных путей — убедиться, что вы регистрируете изменения свойств, и изменить свойство: Session["LOGHACK"] = message;

Комментарии:

1. Прошу прощения, я не добавил основную информацию о продукте (бит, который управляет пользовательскими действиями). Я обновлю свой пост.