WIX, Dot Net managed custom Action, dynamically fill combo box with SQL Server instances, MSI

后端 未结 3 1984
感情败类
感情败类 2021-02-04 14:19

In WIX am in-need of a dot net managed custom code to dynamically populate a combo box with the values of sql server instances in that network.

I tried to google but go

相关标签:
3条回答
  • 2021-02-04 14:33

    OP didn't ask, but in case someone is wondering, yes, You can do this in script, as well. This example populates a ListBox, not a ComboBox, but the idea is the same.

    function EnumerateWebSites_CA()
    {
        try 
        {
            LogMessage("function EnumerateWebSites_CA() ENTER");
    
            var c = 1;
            var serverBindings, aBindings;
    
            var listboxesView = Session.Database.OpenView("SELECT * FROM ListBox");
            listboxesView.Execute();
    
            var record = Session.Installer.CreateRecord(4);
            record.StringData(1) = "WEBSITE";     // Property
            record.IntegerData(2) = c++;          // display order
            record.StringData(3) = "Server";      // returned by the selection
            record.StringData(4) = "Server-wide"; // displayed in the UI
            listboxesView.Modify(MsiViewModify.InsertTemporary, record);
    
            // Create this table dynamically.  We could also create this
            // custom table in the WiX .wxs file , but that's not necessary.
            var query = "CREATE TABLE AvailableWebSites " + 
                "(Num INT NOT NULL, Name CHAR(64), Desc CHAR(64), Port CHAR(16) NOT NULL, IP CHAR(32), Hostname CHAR(80) PRIMARY KEY Num)";
            var createCmd = Session.Database.OpenView(query);
            createCmd.Execute();
            createCmd.Close();
    
            LogMessage("Table 'AvailableWebSites' has been created");
    
            var websitesView = Session.Database.OpenView("SELECT * FROM AvailableWebSites");
            websitesView.Execute();
    
            LogMessage("Query from Table 'AvailableWebSites' has returned");
    
            // do a WMI query to get the list of Websites on the server
            var iis = GetObject("winmgmts://localhost/root/MicrosoftIISv2"); 
    
            // See the metabase hierarchy diagram here:
            //   http://msdn.microsoft.com/en-us/library/ms524661.aspx
    
            // http://msdn.microsoft.com/en-us/library/ms525545.aspx
            // list "virtual servers", which is the same as websites. 
            query  = "SELECT * FROM IIsWebServerSetting" 
    
            // get the list of virtual servers
            var results = iis.ExecQuery(query);
    
            LogMessage("WMI Query completed.");
    
            LogMessage("WMI Query results : " + typeof results);
    
            for(var e = new Enumerator(results); !e.atEnd(); e.moveNext()) 
            { 
                var site = e.item();
                // site.Name                   // W3SVC/1, W3SVC/12378398, etc
                // site.Name.substr(6)         // 1, 12378398, etc
                // site.ServerComment)         // "Default Web Site", "Site2", etc
                // site.ServerBindings(0).Port // 80, 8080, etc
    
                LogMessage("Web site " + site.Name);
    
                LogMessage("listbox record");
                record = Session.Installer.CreateRecord(4);
                record.StringData(1) = "WEBSITE";
                record.IntegerData(2) = c++;
                record.StringData(3) = site.Name.substr(6); // site.Name;
                record.StringData(4) = site.ServerComment + " (" + site.Name + ")";
                listboxesView.Modify(MsiViewModify.InsertTemporary, record);
    
                LogMessage("websites record");
                LogMessage("website(" + site.Name + ") name(" + site.ServerComment + ") port(" + site.ServerBindings(0).Port + ")"); 
                record = Session.Installer.CreateRecord(6);
                record.IntegerData(1) = parseInt(site.Name.substr(6));  // WebSiteNo
                record.StringData(2) = site.Name;                       // name, like W3SVC/1
                record.StringData(3) = site.ServerComment;              // WebSiteDescription
                record.StringData(4) = site.ServerBindings(0).Port;     // WebSitePort
                record.StringData(5) = site.ServerBindings(0).Ip;       // WebSiteIP; maybe empty
                record.StringData(6) = site.ServerBindings(0).Hostname; // WebSiteHeader; maybe empty
                websitesView.Modify(MsiViewModify.InsertTemporary, record);
            }
            listboxesView.Close();
            websitesView.Close();
    
            LogMessage("function EnumerateWebSites_CA() EXIT");
        }
    
        catch (exc1)
        {
            Session.Property("CA_EXCEPTION") = exc1.message ;
            LogException(exc1);
            return MsiActionStatus.Abort;
        }
        return MsiActionStatus.Ok;
    }
    

    There are a few supporting methods:

    var MsiViewModify = 
    {
        Refresh          : 0,
        Insert           : 1,
        Update           : 2,
        Assign           : 3,
        Replace          : 4,
        Merge            : 5,
        Delete           : 6,
        InsertTemporary  : 7,   // cannot permanently modify the MSI during install
        Validate         : 8,
        ValidateNew      : 9,
        ValidateField    : 10,
        ValidateDelete   : 11
    };
    
    
    // http://msdn.microsoft.com/en-us/library/sfw6660x(VS.85).aspx
    var Buttons = 
    {
        OkOnly           : 0,
        OkCancel         : 1,
        AbortRetryIgnore : 2,
        YesNoCancel      : 3
    };
    
    var Icons= 
    {
        Critical         : 16,
        Question         : 32,
        Exclamation      : 48,
        Information      : 64
    }
    
    var MsgKind =
    {
        Error            : 0x01000000,
        Warning          : 0x02000000,
        User             : 0x03000000,
        Log              : 0x04000000
    };
    
    // http://msdn.microsoft.com/en-us/library/aa371254(VS.85).aspx
    var MsiActionStatus = 
    {
        None             : 0,
        Ok               : 1, // success
        Cancel           : 2,
        Abort            : 3,
        Retry            : 4, // aka suspend?
        Ignore           : 5  // skip remaining actions; this is not an error.
    };
    
    // spool an informational message into the MSI log, if it is enabled. 
    function LogMessage(msg)
    {
        var record = Session.Installer.CreateRecord(0);
        record.StringData(0) = "CustomActions: " + msg;
        Session.Message(MsgKind.Log, record);
    }
    
    // Pop a message box.  also spool a message into the MSI log, if it is enabled. 
    function LogException(exc)
    {
        var record = Session.Installer.CreateRecord(0);
        record.StringData(0) = "CustomActions: Exception: 0x" + decimalToHexString(exc.number) + " : " + exc.message;
        Session.Message(MsgKind.Error + Icons.Critical + Buttons.btnOkOnly, record);
    }
    
    function decimalToHexString(number)
    {
        if (number < 0)
            number = 0xFFFFFFFF + number + 1;
        return number.toString(16).toUpperCase();
    }
    

    And yes, I disagree philosophically with Rob Mensching's viewpoint that Script Custom Actions suck

    0 讨论(0)
  • 2021-02-04 14:46
        [CustomAction]   
        public static ActionResult FillServerInstances(Session xiSession)
        {         
            xiSession.Log("Begin CustomAction");
    
            xiSession.Log("Opening view");
            View lView = xiSession.Database.OpenView("DELETE FROM ComboBox WHERE ComboBox.Property='DBSRVR'");
            lView.Execute();
    
            lView = xiSession.Database.OpenView("SELECT * FROM ComboBox");
            lView.Execute();
    
            int Index = 1;
            bool flag = false;
            try
            {
                foreach (DataRow dr in Microsoft.SqlServer.Management.Smo.SmoApplication.EnumAvailableSqlServers(false).Rows)
                {
                    String InstanceName = dr["Name"].ToString();
    
                    if (InstanceName.Equals(xiSession["ComputerName"] + @"\" + xiSession["SQLINSTANCENAME"], StringComparison.InvariantCultureIgnoreCase))
                    { flag = true; }
    
                    Record lRecord = xiSession.Database.CreateRecord(4);
                    xiSession.Log("Setting record details");
                    lRecord.SetString(1, "DBSRVR");
                    lRecord.SetInteger(2, Index);
                    lRecord.SetString(3, InstanceName);
                    lRecord.SetString(4, InstanceName);
    
                    xiSession.Log("Adding record");
                    lView.Modify(ViewModifyMode.InsertTemporary, lRecord);
    
                    ++Index;
                }
            }
            catch (Exception ex)
            {
                logException(xiSession, ex);              
            }
            if (flag)
            {
                xiSession["DBSRVR"] = xiSession["ComputerName"].ToString() + @"\" + xiSession["SQLINSTANCENAME"].ToString();
            }
    
            lView.Close();
    
            xiSession.Log("Closing view");
            lView.Close();
            return ActionResult.Success;       
        }
    
    0 讨论(0)
  • 2021-02-04 14:51

    There's a C++ CA to do exactly this in http://msiext.codeplex.com.

    0 讨论(0)
提交回复
热议问题