Silverlight 4 から Out of Browser でCOMオートメーション機能が使えるようになった。これにより Excel などの外部アプリケーションを直接呼び出し操作できるようになりました。
Silverlight 4 の出荷候補版も出たので試しに COM による Excel 連携機能を実装してみることにした。今回は作ったのは、twitter で検索した結果を Excel シートに流し込むアプリです。
f:id:tilfin:20100317222724p:image

開発環境

Windows 7 上の Visual Studio 2010 RC と Microsoft Silverlight 4 Tools for Visual Studio 2010 RC による

ポイント

COMオートメーション機能

まず COMオートメーションの機能は、βからRCになり仕様が変わっています。
AutomationFactory.CreateObject にオブジェクト名を指定してインスタンスを生成します。下記ではさらのExcelを表示して、ワークブックを追加しその最初の(アクティブ)シートを取得しています。

using System.Runtime.InteropServices.Automation;
・・・
dynamic excel = AutomationFactory.CreateObject(“Excel.Application”);
excel.Visible = true;
dynamic workbook = excel.workbooks.Add();
dynamic excelSheet = excel.ActiveSheet;

※ dynamic を使用するには Microsoft.CSharp の参照追加が必要です。

twitter検索

ボタンのクリックイベントでsearchTextBoxに入力されてたTextでtwitter search API をたたきます。
DataContractJsonSerializer を使って、レスポンスストリームから直接 JSON を C# 上の構造体クラスのデータオブジェクトに変換しています。ToExcelに結果オブジェクトを渡して処理をします(これは後述)。

private void button1_Click(object sender, RoutedEventArgs e) {
if (searchTextBox.Text.Length == 0) return;
string word = System.Windows.Browser.HttpUtility.UrlEncode(searchTextBox.Text);
HttpWebRequest webreq = (HttpWebRequest)WebRequest.Create(“http://search.twitter.com/search.json?q=" + word);
webreq.Method = “GET”;
webreq.BeginGetResponse(new AsyncCallback(WebResponseCallback), webreq);
}
private void WebResponseCallback(IAsyncResult ar) {
try {
HttpWebRequest request = (HttpWebRequest)ar.AsyncState;
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(ar);
Stream responseStream = response.GetResponseStream();
TwitterResult result;
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(TwitterResult));
result = ser.ReadObject(responseStream) as TwitterResult;
ToExcel(result);
} catch (Exception) {
}
}

TwitterResult, TwitterResultItem に twitter のレスポンスデータ表現を定義しています。

using System.Runtime.Serialization;
[DataContract]
public class TwitterResult
{
[DataMember(Name = “results”)]
public IList Results { get; set; }
}
[DataContract]
public class TwitterResultItem
{
[DataMember(Name = “profile_image_url”)]
public string ProfileImageUrl { get; set; }
[DataMember(Name = “created_at”)]
public string CreatedAt { get; set; }
[DataMember(Name = “from_user”)]
public string FromUser { get; set; }
[DataMember(Name = “to_user_id”)]
public string ToUserId { get; set; }
[DataMember(Name = “text”)]
public string Text { get; set; }
[DataMember(Name = “id”)]
public long Id { get; set; }
[DataMember(Name = “from_user_id”)]
public string FromUserId { get; set; }
[DataMember(Name = “to_user”)]
public string ToUser { get; set; }
[DataMember(Name = “geo”)]
public string Geo { get; set; }
[DataMember(Name = “iso_language_code”)]
public string IsoLanguageCode { get; set; }
[DataMember(Name = “source”)]
public string Source { get; set; }
public TwitterResultItem() {
}
}

データをExcelに表示

GetExcelSheet() が返すのは前述の excelSheet です。やっていることは 2行目2列目のセルを選択し、さらに行全体を選択します。その位置に対して行を挿入します。
挿入した位置の行にTwitterのユーザーIDと呟き内容を1,2列目にセットします。
以上を取得したつぶやき数だけ繰り返してします。

private void ToExcel(TwitterResult result) {
dynamic sheet = GetExcelSheet();
foreach (TwitterResultItem item in result.Results) {
dynamic range = sheet.Cells[2, 2];
dynamic row = range.EntireRow;
row.Insert(0, false);
range = sheet.Range(sheet.Cells[2, 1], sheet.Cells[2, 2]);
string[] values = { item.FromUser, item.Text };
range.value = values;
}
}

まとめ

COM連携
Out of Browserでのデバッグ

デバッグにはまずWebプロジェクトで実行後にインストール。その後スタートアップを非Webプロジェクトに設定してデバッグを開始します。