在我的安裝程序中,我不想創建網站。我想讓用戶選擇一個現有的網站。我在Javascript中使用了自定義操作,並使用了一個自定義UI面板。
自定義操作代碼:
//
// CustomActions.js
//
// Custom Actions usable within WIX For IIS installations.
//
// EnumerateWebSites_CA():
// Adds new UI to the MSI at runtime to allow the user to select a
// website, to which an ISAPI filter will be added.
//
// UpdatePropsWithSelectedWebSite_CA():
// fills session with properties for the selected website.
//
// SetAuthProps_CA():
// sets properties for the needed user and group that needs authorization to the created dir.
//
//
// original idea from:
// http://blog.torresdal.net/2008/10/24/WiXAndDTFUsingACustomActionToListAvailableWebSitesOnIIS.aspx
//
// Mon, 23 Nov 2009 10:54
//
//
// ===================================================================
// http://msdn.microsoft.com/en-us/library/aa372516(VS.85).aspx
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.
};
//*****************************************************************************
// Purpose: Custom action that enumerates the local websites, and stores their
// properties in the ListBox and AvailableWebSites tables.
// Effects: Fills the ListBox table and creates and fills the AvailableWebSites
// tables.
// Returns: MsiActionStatus.Ok if the custom action executes without error.
// MsiActionStatus.Abort if error.
//*****************************************************************************
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 bby 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.
// old quote: ``````
// my quote: '''''
// var createCmd = Session.Database.OpenView("CREATE TABLE 'AvailableWebSites' ('WebSiteNo' INT NOT NULL, 'WebSiteDescription' CHAR(50), 'WebSitePort' CHAR(50) NOT NULL, 'WebSiteIP' CHAR(50), 'WebSiteHeader' CHAR(50) PRIMARY KEY 'WebSiteNo')")
var createCmd = Session.Database.OpenView("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)")
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");
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.
var 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;
}
//*****************************************************************************
// Purpose: Custom action that copies the selected website's properties from the
// AvailableWebSites table to properties.
// Effects: Fills the WEBSITE_DESCRIPTION, WEBSITE_PORT, WEBSITE_IP, WEBSITE_HEADER
// properties.
// Returns: MsiActionStatus.Ok if the custom action executes without error.
// MsiActionStatus.Abort if error.
//*****************************************************************************
function UpdatePropsWithSelectedWebSite_CA()
{
try
{
LogMessage("function UpdatePropsWithSelectedWebSite_CA() ENTER");
var selectedWebSiteId = Session.Property("WEBSITE");
LogMessage("selectedWebSiteId(" + selectedWebSiteId + ") type(" + typeof selectedWebSiteId + ")");
// check if the user selected anything
if (selectedWebSiteId == "")
{
LogMessage("function UpdatePropsWithSelectedWebSite_CA() EXIT (None)");
return MsiActionStatus.None;
}
if (selectedWebSiteId.toUpperCase() == "SERVER")
{
Session.Property("WEBSITE_NAME") = "W3SVC";
Session.Property("WEBSITE_DESCRIPTION") = "Server";
Session.Property("WEBSITE_PORT") = "";
Session.Property("WEBSITE_IP") = "";
Session.Property("WEBSITE_HEADER") = "";
LogMessage("function UpdatePropsWithSelectedWebSite_CA() EXIT (Ok)");
return MsiActionStatus.Ok;
}
var websitesView = Session.Database.OpenView("SELECT * FROM `AvailableWebSites` WHERE `Num`=" + selectedWebSiteId);
websitesView.Execute();
var record = websitesView.Fetch();
LogMessage("website Fetch() complete");
if (record.IntegerData(1) == parseInt(selectedWebSiteId))
{
Session.Property("WEBSITE_NAME") = record.StringData(2);
Session.Property("WEBSITE_DESCRIPTION") = record.StringData(3);
Session.Property("WEBSITE_PORT") = record.StringData(4);
Session.Property("WEBSITE_IP") = record.StringData(5);
Session.Property("WEBSITE_HOSTNAME") = record.StringData(6);
}
websitesView.Close();
LogMessage("function UpdatePropsWithSelectedWebSite_CA() EXIT (Ok)");
}
catch (exc1)
{
Session.Property("CA_EXCEPTION") = exc1.message ;
LogException(exc1);
return MsiActionStatus.Abort;
}
return MsiActionStatus.Ok;
}
// 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) = "IisEnumSites: Exception: 0x" + decimalToHexString(exc.number) + " : " + exc.message;
Session.Message(MsgKind.Error + Icons.Critical + Buttons.btnOkOnly, record);
}
// spool an informational message into the MSI log, if it is enabled.
function LogMessage(msg)
{
var record = Session.Installer.CreateRecord(0);
record.StringData(0) = "IisEnumSites: " + msg;
Session.Message(MsgKind.Log, record);
}
function decimalToHexString(number)
{
if (number < 0)
{
number = 0xFFFFFFFF + number + 1;
}
return number.toString(16).toUpperCase();
}
// Testing only
function Test1_CA()
{
var record = Session.Installer.CreateRecord(0);
record.StringData(0) = "Hello, this is an error message";
Session.Message(msgKindUser + iconInformation + btnOk, record);
return MsiActionStatus.Ok;
}
註冊自定義操作是這樣的:
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<Binary Id="IisScript_CA" SourceFile="CustomActions.js" />
<CustomAction Id="EnumerateWebSites"
BinaryKey="IisScript_CA"
JScriptCall="EnumerateWebSites_CA"
Execute="immediate"
Return="check" />
<CustomAction Id="UpdatePropsWithSelectedWebSite"
BinaryKey="IisScript_CA"
JScriptCall="UpdatePropsWithSelectedWebSite_CA"
Execute="immediate"
Return="check" />
</Fragment>
</Wix>
這是UI面板.wxs:
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<UI>
<Dialog Id="SelectWebSiteDlg" Width="370" Height="270" Title="Select a Web Site">
<Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="Next" />
<Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Text="Back" />
<Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="Cancel">
<Publish Event="SpawnDialog" Value="CancelDlg">1</Publish>
</Control>
<Control Id="Description" Type="Text" X="25" Y="23" Width="280" Height="15" Transparent="yes" NoPrefix="yes" Text="Please select which web site you want to install to." />
<Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes" Text="Select a Web Site" />
<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="60" Width="290" Height="14" NoPrefix="yes" Text="Select the web site for the filter:" />
<Control Id="SelectWebSiteCombo" Type="ListBox" X="20" Y="75" Width="200" Height="150" Property="WEBSITE" Sorted="yes" />
</Dialog>
</UI>
</Fragment>
</Wix>
UI面板呈現列表框,其自動與從列表框表元素與網站的第一個字段中填充。該表在運行時由Javascript中的自定義操作填充。
要在正確的時間調用自定義動作,您需要在main中使用類似這樣的東西。WXS文件:
<InstallUISequence>
<Custom Action="EnumerateWebSites" After="CostFinalize" Overridable="yes">NOT Installed</Custom>
</InstallUISequence>
任何想法爲什麼上面的腳本會拋出「IisEnumSites:異常:0x80004005:修改,模式,記錄」錯誤消息? – Aaron 2011-02-09 14:21:07
啊,不,我不知道。 – Cheeso 2011-02-10 16:05:57