2009-09-03 59 views
5

编辑:我已经更新了下面的代码,以便它现在可以工作,这要归功于Rob的回答。如何在安装时在WiX中填充组合框?

我发现一对夫妇的展示了如何做到这一点的网页(http://www.cmcrossroads.com/content/view/13160/120/http://www.mail-archive.com/[email protected]/msg05103.html),并通过对WAI的源代码(http://wai.codeplex.com/)看了,但我似乎无法得到它在我的工作,安装不管我尝试什么。如果有人能够发现我做错了,我会非常感激。我对对话的WiX的片段看起来是这样的:

<UI> 
    <Dialog> 

...snip... 

    <Control Id="WebsiteName" Type="ComboBox" ComboList="yes" Sorted="yes" Property="IIS_WEBSITENAME" X="20" Y="73" Width="150" Height="17"/> 

...snip... 

    <!-- We want our custom action to fill in the WebsiteName ComboBox above 
     however, if no ComboBox entries exist at compile time then the 
     ComboBox table is not created in the MSI and we can't add to it in 
     the custom action. So we have this hidden dummy list box to force 
     the table to appear. --> 
    <Control Id="DummyComboBox" Hidden="yes" Type="ComboBox" Sorted="yes" ComboList="yes" Property="DUMMYPROPERTY" X="65" Y="60" Width="150" Height="18"> 
     <ComboBox Property="DUMMYPROPERTY"> 
     <ListItem Text="Dummy" Value="Dummy"/> 
     </ComboBox> 
    </Control> 
    </Dialog> 
</UI> 

<Property Id="DUMMYPROPERTY">Dummy</Property> 
<Property Id="IIS_WEBSITENAME"/> 
<CustomAction Id="FillWebsiteNameList" BinaryKey="WiXCustomAction.dll" DllEntry="FillWebsiteNameList" Execute="immediate" /> 
<InstallUISequence> 
    <Custom Action="FillWebsiteNameList" After="CostFinalize"/> 
</InstallUISequence> 

我的自定义操作的代码是:

[CustomAction] 
public static ActionResult FillWebsiteNameList(Session xiSession) 
{ 
    xiSession.Log("Begin FillWebsiteNameList"); 

    xiSession.Log("Opening view"); 

    View lView = xiSession.Database.OpenView("SELECT * FROM ComboBox"); 
    lView.Execute(); 

    xiSession.Log("Creating directory entry"); 

    DirectoryEntry lIis = new DirectoryEntry("IIS://localhost/w3svc"); 

    xiSession.Log("Checking each child entry"); 

    int lIndex = 1; 
    foreach (DirectoryEntry lEntry in lIis.Children) 
    { 
    if (lEntry.SchemaClassName == "IIsWebServer") 
    { 
     xiSession.Log("Found web server entry: " + lEntry.Name); 

     string lWebsiteName = (string)lEntry.Properties["ServerComment"].Value; 
     xiSession.Log("Website name: " + lWebsiteName); 

     xiSession.Log("Creating record"); 
     Record lRecord = xiSession.Database.CreateRecord(4); 

     xiSession.Log("Setting record details"); 
     lRecord.SetString(1, "IIS_WEBSITENAME"); 
     lRecord.SetInteger(2, lIndex); 
     lRecord.SetString(3, lEntry.Name); // Use lWebsiteName only if you want to look up the site by name. 
     lRecord.SetString(4, lWebsiteName); 

     xiSession.Log("Adding record"); 
     lView.Modify(ViewModifyMode.InsertTemporary, lRecord); 

     ++lIndex; 
    } 
    } 

    xiSession.Log("Closing view"); 

    lView.Close(); 

    xiSession.Log("Return success"); 

    return ActionResult.Success; 
} 

曾经有两个问题:

1)上方运行过程中失败的码“执行期间函数失败,数据库:表更新失败”。 - 这是因为索引问题导致代码尝试将一个字符串写入一个int列。

2)如果我改变线

lRecord.SetString(2, lWebsiteName); 

lRecord.SetString(2, lEntry.Name); 

然后看着跟踪的动作看似成功,但安装程序运行时,组合框没有条目选择从。

如果我更改组合框的硬编码值,一切正常,即使我硬编码lWebsiteName的等效。

+0

因此安装程序必须以管理员身份运行?或者当我试图获取网站列表时,如何避免访问被拒绝? – 2010-07-30 15:29:59

+0

它必须以管理员身份运行。享受解决这个问题。 – jcmcbeth 2012-12-19 18:29:58

回答

3

我不使用DTF(所有自然C++ CustomActions对我来说),但记录的是基于1。你有没有试过把所有的SetRecord()调用都由一个索引转移过来?

此外,上面的.wxs代码似乎表明您正在使用“DUMMYPROPERTY”作为ComboBox的控件属性而不是“IIS_WEBSITENAME”,就像.cs代码正在使用的那样。

+0

谢谢,我在某个时候尝试过1,但是我已经尝试了很多我可能没有这样做过的代码!我会再尝试。 我在第二个隐藏的组合控件中使用DUMMYPROPERTY来确保组合框表被创建,我会尝试将它指向与真实控件相同的属性,并查看它是否执行任何操作。 – Dan 2009-09-07 08:43:20

+0

这是索引(它解释了这两个问题)。再次感谢。 – Dan 2009-09-07 10:31:55

0

这是一个很老的,但我有类似的问题,并希望分享我发现,也许这节省了一些人的时间。

,以确保组合框表创建使用EnsureTable,确保CA不会覆盖定义的值:

<EnsureTable Id="ComboBox"/> 
<Property Id="RS_INSTANCES" Secure="yes"/> 
<CustomAction Id="GetRSintances" BinaryKey="JSCommon" Return="ignore" 
       JScriptCall="GetRSintances" Execute="immediate" /> 

<InstallUISequence> 
    <Custom Action="GetRSintances" After="AppSearch"> 
    <![CDATA[NOT Installed AND NOT RS_INSTANCES]]> 
    </Custom> 
</InstallUISequence> 

<InstallExecuteSequence> 
    <Custom Action="GetRSintances" After="AppSearch"> 
    <![CDATA[NOT Installed AND NOT RS_INSTANCES]]> 
    </Custom> 
</InstallExecuteSequence> 

<!-- UI part --> 
<Control Id="ComboBox1" Type="ComboBox" X="20" Y="160" Width="100" Height="20" Property="RS_INSTANCES" Sorted="yes" > 
    <ComboBox Property="RS_INSTANCES"> 
     <!-- dynamicly filled during installation --> 
    </ComboBox> 
    </Control> 

我有填充listItems中的JavaScript函数:(是的,我知道一些你不t等JS的自定义操作,但它仍然是不够方便)

// Add ListItem to ComboBox or ListView at install time 
function AddListItemToMSI(Property, Order, Value, Text, Table) { 
    try { 
    var controlView = Session.Database.OpenView("SELECT * FROM " + Table); 
    controlView.Execute(); 

    var record = Session.Installer.CreateRecord(4); 
    record.StringData(1) = Property; 
    record.IntegerData(2) = Order; 
    record.StringData(3) = Value; 
    record.StringData(4) = Text; 

    controlView.Modify(7, record); 
    controlView.Close(); 
    } 
    catch (err) { 
    ShowMessage('Couldn\'t add ListItem entry, error occured: ' + err.message, msiMessageTypeInfo); 
    } 

    return 1; 
} 

我把它从我的其他功能(也被称为自定义操作)是这样的:

var ComboBoxProperty = 'RS_INSTANCES'; 
var InstanceFullName; 
for (i = 0; i < Names.length; i++) { 
    InstanceFullName = GetInstanceName(Names[i]); //this function looks up full name in the registry 
    AddListItemToMSI(ComboBoxProperty, i, InstanceFullName, '', 'ComboBox'); 
    if (i == 0) { 
     Session.Property(ComboBoxProperty) = InstanceFullName; 
    } 
} 

注意:我从最后一个函数中删除了不相关的代码片段以使其可读。 P.S.总是(我的意思是总是)使用null,零长度和错误检查,尝试/捕获并确保使用类似这样的日志记录:

function ShowMessage(text, options) { 
    if (options == null) { 
     var options = msiMessageTypeUser; 
    } 
    var oRecord = Session.Installer.CreateRecord(1); 
    oRecord.StringData(1) = text; 
    var response = Session.Message(options, oRecord); 
    oRecord.ClearData(); 
    oRecord = null; 
    response = null; 
}