installer - studio - sql server developer
WIX, acción personalizada administrada por Dot Net, cuadro combinado de relleno dinámico con instancias de SQL Server, MSI (3)
En WIX, necesito un código personalizado gestionado por dot net para rellenar dinámicamente un cuadro combinado con los valores de instancias de servidor sql en esa red.
Traté de google pero no funcionó
Cualquier ayuda es muy apreciada.
[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;
}
Hay un C ++ CA para hacer exactamente esto en http://msiext.codeplex.com .
OP no preguntó, pero en caso de que alguien se esté preguntando, sí, también puede hacerlo en el guión. Este ejemplo rellena un ListBox, no un ComboBox, pero la idea es la misma.
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;
}
Hay algunos métodos de apoyo:
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();
}
Y sí, estoy en desacuerdo filosóficamente con el punto de vista de Rob Mensching de que Script Custom Actions chupa