5

編集:Robの回答のおかげで、以下のコードが機能するように更新しました。

これを行う方法を示すページをいくつか見つけました(http://www.cmcrossroads.com/content/view/13160/120/、http://www.mail-archive.com/wix-users@ lists.sourceforge.net/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;
}

以前は2つの問題がありました。

1)カスタムアクションの実行中に上記のコードが失敗し、「実行中に関数が失敗しました。データベース:テーブルの更新に失敗しました。」-これは、インデックスの問題により、コードがint列に文字列を書き込もうとしたことが原因でした。

2)行を変更した場合

lRecord.SetString(2, lWebsiteName);

lRecord.SetString(2, lEntry.Name);

次にトレースを見ると、アクションは成功したように見えますが、インストーラーを実行すると、コンボボックスには選択できるエントリがありません。

コンボボックスをハードコードされた値を持つように変更すると、lWebsiteNameと同等のものをハードコードした場合でも、すべてが正常に機能します。

4

2 に答える 2

3

私はDTF(私にとってはすべて自然なC ++ CustomActions)を使用していませんが、レコードは1ベースです。すべてのSetRecord()呼び出しを1つのインデックスにシフトしてみましたか?

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

于 2009-09-04T18:30:54.213 に答える
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>

ListItemsに入力するためのJavaScript関数があります:(はい、カスタムアクションの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;
    }
}

注:読みやすくするために、最後の関数から関連性のないコードを削除しました。PSは常に(つまり常に)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;
}
于 2015-09-02T06:48:12.533 に答える