Excelの起動
Excelのアプリケーションを起動するサンプルを確認していきましょう。今回のサンプルは、Silverlight連載の月間ページビューをExcelに表示してグラフを表示するためのものです。図3に実行イメージを示します。
![図3 実行イメージ](http://cz-cdn.shoeisha.jp/static/images/article/5859/5859_fig3.gif)
Excelのオートメーションオブジェクトを利用すれば、グラフを作成したり、セルに色をつけることも可能ですが、表示したいイメージがある程度決まっているのなら、あらかじめExcelのテンプレートを作成し、Silverlight側では単に動的に変動する値を埋める、といった単純なものにした方がいいでしょう。
今回は、グラフの範囲設定と、ヘッダー行に色をつけた図4のExcelブックを図4のようにWebサーバーの「~/ExcelTemplate/テンプレート.xlsx」に作成しておきます。Silverlight側は、Excel起動ボタンが押されたタイミングでテンプレートをダウンロードし、ページビューのセルに値を設定してExcelを起動して、グラフを表示します。
![図4 Webサイトの構成](http://cz-cdn.shoeisha.jp/static/images/article/5859/5859_fig4.gif)
まずはコードの全体をリスト2に示します。
// Excelの起動ボタンのクリック時のイベントハンドラ private void btnExecExcel_Click(object sender, RoutedEventArgs e) { // 1.Excelテンプレートのダウンロード var client = new WebClient(); client.OpenReadCompleted += client_OpenReadCompleted; client.OpenReadAsync(new Uri(@"http://localhost:1348/ExcelTemplate/テンプレート.xlsx")); } // ダウンロード終了時のイベントハンドラ void client_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e) { if (e.Error != null) return; // 2.Excelテンプレートファイルの保存 var filePath = System.IO.Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "テンプレート.xlsx"); var s = new BinaryReader(e.Result); var b = s.ReadBytes((int)e.Result.Length); File.WriteAllBytes(filePath, b); // オートメーションが利用出来るかの確認 if (!AutomationFactory.IsAvailable) return; // 3.Excel オートメーションを作成して値を書き込む using (dynamic excel = AutomationFactory.CreateObject("Excel.Application")) using (var books = excel.Workbooks) using (var book = books.Open(@"C:\temp\テンプレート.xlsx")) using (var sheets = book.Worksheets) using (var sheet = sheets[1]) using (var cells = sheet.Cells) { // 2010/08 - 2011/01 のページビュー var pageViews = new List<int>() { 1034, 6809, 2093, 1776, 1248, 1326 }; var baseRowIndex = 3; var baseColIndex = 3; for (var index = 0; index < pageViews.Count; index++) { var cell = cells[baseRowIndex, baseColIndex + index]; cell.Value = pageViews[index]; } excel.Visible = true; } }
簡単にプログラムを確認していきましょう。このサンプルには、大きく分けて下記の3つの手順があります。
- Excelテンプレートのダウンロード
- Excelテンプレートファイルの保存
- Excel オートメーションを作成して値を書き込む
1. Excelテンプレートのダウンロード
WebClientクラスのOpenReadAsyncメソッドを利用して、Webサーバーに配置されたExcelファイルをダウンロードします。同時に、ダウンロード終了時のイベントハンドラを登録しておきます。
2. Excelテンプレートファイルの保存
ダウンロードしたデータをオートメーションから読み込むために、ユーザーのドキュメントフォルダにテンプレート.xlsxという名前で保存します。Silverlightでは、ファイルをユーザーのストレージに保存する場合はSaveFileDialogクラスを通じてユーザーがアクションを起こす必要がありますが、信頼されたアプリケーションでは特定ディレクトリであればユーザーの同意は必要ありません。詳しくは、前回の連載を確認してください。
3. Excelオートメーションを作成して値を書き込む
前述の通り、Excelのオートメーションオブジェクトを作成し、ExcelのC3のセル(2010/08の実績)からH3(2011/01の実績)に対しそれぞれのページビューを設定して、最後にVisibleプロパティをtrueにすることで、Excelを起動してグラフを表示しています。
単なるオートメーションの呼び出しであれば、CreateObjectメソッドで取得したオブジェクトのみをDisposeすればよいのですが、暗黙オブジェクトを生成するオートメーションには注意が必要です。
例えば、リスト3の例では、bookオブジェクトからWorkSheets、WorkSheet、Cells、Cellの4つのオブジェクトが暗黙的に参照され、生成されています。
book.Worksheets[1].Cells[3, 3] = "1";
このような例では、Silverlightアプリケーションが終了するまで、Excelのプロセスが残ってしまうことがあります。多くのクライアントを相手にしたり、再起動の間隔が長いWebサイトのアプリケーション程に気を尖らすことも無いのかもしれませんが、メモリリークの原因にもなるので、暗黙のオブジェクトにも注意して廃棄を行うようにしましょう。
WMIを使ったプリンタ一覧の取得
よく使いそうな例として、WMI(Windows Management Instrumentation)を使ったサンプルも見ておきましょう。WMIはコンピューターの情報を簡単に管理するためのライブラリで、現在のプロセスの情報やプリンタの情報などをSQLに似た言語で簡単に取得、管理できます。WMIに関する情報は、TechNetのスクリプトセンターを参照してください。
リスト4は、現在コンピュータにインストールされているプリンタの一覧を取得する例です。
var printerList = new StringBuilder(); using (dynamic wmi = AutomationFactory.CreateObject("WbemScripting.SWbemLocator")) { wmi.Security_.ImpersonationLevel = 3; wmi.Security_.AuthenticationLevel = 4; using (var service = wmi.ConnectServer(".", @"root\cimv2")) { foreach (var printer in service.ExecQuery("Select * from Win32_Printer")) { printerList.AppendFormat("プリンタ名: {0} ポート名:{1}\n", printer.Name, printer.PortName); } } } MessageBox.Show(printerList.ToString());
WMIのプログラムIDは、WbemScripting.SWbemLocatorです。Excelの例と同様に、CreateObjectメソッドでオートメーションオブジェクトを取得し、プリンタ情報を管理するWin32_Printerに対してクエリーを行っています。
このサンプルを実行すると、図5のような画面が表示されます。
![図5 実行結果](http://cz-cdn.shoeisha.jp/static/images/article/5859/5859_fig5.gif)
現在のところ、Silverlight単体ではローカルコンピューターにインストールされたプリンタの情報を取得できません。プリンタに限らず、デバイスに関係する情報を取得するためには、多くの場合オートメーションオブジェクトに頼る必要があります。