2009-09-03 3 views
5

Редактировать: Я обновил код ниже, чтобы он теперь работал, благодаря ответу Роба.Как заполнить ComboBox во время установки в 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) Код выше не удалось во время бега пользовательского действия с «Функция не удалась во время выполнения. Database: Table (s) Update failed.» - Это из-за проблемы с индексацией, вызывающей код, чтобы попытаться написать строку в столбец int.

2) Если изменить линию

lRecord.SetString(2, lWebsiteName); 

в

lRecord.SetString(2, lEntry.Name); 

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

Если я изменил выпадающий список, чтобы иметь жестко заданные значения, все работает нормально, даже если я жестко задал эквивалент lWebsiteName.

+0

так что установщик должен запускаться как администратор?или как избежать отказа в доступе при попытке получить список веб-сайтов? –

+0

Он должен быть запущен как администратор. Наслаждайтесь решением этой проблемы. – jcmcbeth

ответ

3

Я не использую DTF (все естественные C++ CustomActions для меня), но записи основаны на 1. Вы пытались переместить все вызовы SetRecord() одним индексом?

Кроме того, код .wxs выше, кажется, предполагает, что вы используете «DUMMYPROPERTY» в качестве свойства управления для ComboBox, а не «IIS_WEBSITENAME», как используется код .cs.

+0

Спасибо, я пробовал 1 на какой-то момент, но я пробовал так много вещей, которые, возможно, не сделал с этим кодом! Я попробую еще раз. Я использую DUMMYPROPERTY во втором скрытом комбоконтроллере, чтобы убедиться, что таблица ComboBox создана, я попробую указать ее на то же свойство, что и реальный элемент управления, и посмотреть, что это делает. – Dan

+0

Это была индексация (которая объясняла обе проблемы). Еще раз спасибо. – Dan

0

Этот довольно старый, однако у меня была аналогичная проблема, и я хотел бы поделиться тем, что нашел, возможно, это экономит время.

, чтобы убедиться, ComboBox таблицы создается использование 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> 

У меня есть функция JavaScript для заполнения ListItems: (да, я знаю, что некоторые из вас не» т как 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. всегда (я имею в виду ВСЕГДА) использовать нуль, нулевую длину и проверку ошибок, пытаться/улавливать и обеспечивать ведение журнала с чем-то вроде этого:

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; 
} 
Смежные вопросы