2009-09-03 6 views
5

編集:以下のコードを更新して、Robの答えを受けて動作するようにしました。インストール時に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)走行時に失敗した上記のコード「実行中に関数が失敗しました。」データベース:テーブルの更新に失敗しました。これは、索引付けの問題により、コードが文字列をint列に書き込んで書き込むためです。

2)私は

lRecord.SetString(2, lEntry.Name); 

にライン

lRecord.SetString(2, lWebsiteName); 

を変更する場合は、トレースでアクションを見ては成功したように見えますが、インストーラの実行時にコンボボックスから選択することはございません。

ハードコードされた値を持つようにコンボボックスを変更した場合、lWebsiteNameに相当するものをハードコードしても、すべて正常に動作します。

+0

ので、インストーラが管理者として実行する必要がありますか?またはどのようにWebサイトのリストを取得しようとすると拒否されたアクセスを避けるのですか? –

+0

これは管理者として実行する必要があります。その問題をお楽しみください。 – jcmcbeth

答えて

3

私はDTFを使用していませんが、私の場合、Natural C++ CustomActionsは使用していませんが、レコードは1ベースです。 SetRecord()呼び出しをすべて1つのインデックスで移動しようとしましたか?

また、上記の.wxsコードは、.csコードが使用しているように、 "IIS_WEBSITENAME"ではなくComboBoxのコントロールプロパティとして "DUMMYPROPERTY"を使用していることを示唆しているようです。

+0

ありがとう、私はある時点で1を試してみましたが、このコードではこれほど多くのことを試みたことがありません!私はもう一度やり直します。 私は2番目の非表示のコンボコントロールでDUMMYPROPERTYを使用して、ComboBoxテーブルが作成されるようにしています。実際のコントロールと同じプロパティを指し示し、何かがあるかどうかを確認します。 – Dan

+0

インデックス作成(両方の問題を説明した)でした。再度、感謝します。 – Dan

0

これはかなり古いですが、似たような問題があり、私が見つけたものを共有したいと思っています。これは誰かの時間を節約するかもしれません。

CAが規定値上書きされないよう、コンボボックスのテーブルを使用EnsureTableを作成していることを確認する:私はのListItemを埋めるためにJavaScript関数を持っている

<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> 

を:(はい、私は「あなたのいくつかはドン知っていますカスタムアクションのための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.P.いつも(私は常に意味)nullを使用し、長さがゼロとエラーチェック、のtry/catchし、このようなものでロギングを確認してください。

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; 
} 
関連する問題