C#でExcelファイルを読み書きするプログラムと、そのプログラム(exe)を配布するためのインストーラを作ってみた。
それは、作成したExcelを使ったプログラムは、exeの配布だけでは他のPCでは動かないため。
Excel関連のDLLも一緒に配布する必要がある。
例えば、前に作成したサンプルアプリの場合、配布時は以下のDLLが必要。
- Microsoft.Office.Interop.Excel.dll
- Microsoft.Vbe.Interop.dll
- office.dll
- stdole.dll
⇒これ、後から気づいたけど実は認識誤り(.NET Framework 3.5までの話)。
.NET Framework 4以降ではDLL配布を不要にする方法がある。
説明も後記するので最後までちゃんと読んでね。
昔のVisual Studioではセットアッププロジェクト(Windows ベースのアプリケーションのmsiインストーラ)を作成する際、必要なDLLを自動で抽出してくれていた。
インストーラ付きで配布するのが嫌という場合、exeと抽出されたDLLだけを他PCにコピーしても動作する。
ただ、インストーラ無しで、抽出されたDLLを勝手に再配布するのはNGかも知れない。
あと、勿論、配布先PCにもMicrosoft Excelをインストールしておく必要はある。
じゃぁ、昔みたいにインストーラを作ればいい。
と、思ったら、、
Visual Studio 2012以降では、セットアップ プロジェクトが無くなり、ウィザードでインストーラ作成(ディプロイメント)することが出来なくなってしまったらしい。
・・・それは困った。
必要なDLLはMSDNとかに載っているかもしれないけど、前と同じような方法ができないか調べてみた。
すると、従来のセットアッププロジェクトに代わり、InstallShield Limited Editionを使ってインストーラを作れることが分かった。
でも、InstallShieldって有料じゃなの?
と思ったけど、このLimited Editionってのは簡易版で無料らしい。
ただ、無料版のVisual Studio Expressでは使えず、Visual Studio Professional以降じゃないと、InstallShield Limited Editionは使えないようだ。
という事で、おさらいも兼ねてVisual Studio 2013を使ってExcelを使ったプログラムと、インストーラをInstallShieldで作ってみることにした。
Excel用のプログラム作成
まずは、C#でExcelを使ったプログラムを作成。
exeの作成方法は、ほぼ前回と同じ。
- Visual Studio 2013を起動。
- [ファイル]→[新規作成]→[プロジェクト]メニュー選択。
- [新しいプロジェクト]ダイアログが開くので、左側ツリーで[テンプレート]→[Visual C#]を選択し、右側リストから[Windows フォーム アプリケーション]を選択し[OK]ボタン押下。
- 画面右上の[ソリューション エクスプローラー]ペインにある「参照設定」を右クリックし、ポップアップメニュー「参照の追加」を選択。
- [参照マネージャー]ダイアログの左側ツリーから[COM]→[タイプ ライブラリ]を選択し、右側リストから[Microsoft Excel *.* Object Library]のチェックボックスをONにし[OK]ボタン押下。
- ソリューション エクスプローラーの[参照設定]配下に、以下のオブジェクトが追加されたことを確認する。
- Microsoft.Office.Core
- Microsoft.Office.Interop.Excel
- VBIDE
- Form1のGUI編集で、TextBoxとButtonコントロールを以下のような感じで配置する。
- フォーム(Form1)と、実行ボタン(button1)をそれぞれダブルクリックし、空のForm1_Loadと、button1_Clickイベントを作成しておく。
private void Form1_Load(object sender, EventArgs e) { } private void button1_Click(object sender, EventArgs e) { }
- Form1.csを編集し、以下のようなコードを書く。
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.IO; using Excel = Microsoft.Office.Interop.Excel; namespace WindowsFormsApplication1 { public partial class Form1 : Form { private static string fileName = Directory.GetCurrentDirectory() + "\\sample.xlsx"; public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { textBox1.ReadOnly = true; textBox1.Text = fileName; } private void button1_Click(object sender, EventArgs e) { this.Cursor = Cursors.WaitCursor; // マウスカーソルを砂時計 Excel.Application oExcelApp = null; // Excelオブジェクト Excel.Workbook oExcelWBook = null; // Excel Workbookオブジェクト try { oExcelApp = new Excel.Application(); oExcelApp.DisplayAlerts = false; // Excelの確認ダイアログ表示有無 oExcelApp.Visible = false; // Excel表示有無 // Excelファイルをオープンする(第一パラメタ以外は省略可) oExcelWBook = (Excel.Workbook)(oExcelApp.Workbooks.Open( fileName, // Filename Type.Missing, // UpdateLinks Type.Missing, // ReadOnly Type.Missing, // Format Type.Missing, // Password Type.Missing, // WriteResPassword Type.Missing, // IgnoreReadOnlyRecommended Type.Missing, // Origin Type.Missing, // Delimiter Type.Missing, // Editable Type.Missing, // Notify Type.Missing, // Converter Type.Missing, // AddToMru Type.Missing, // Local Type.Missing // CorruptLoad )); Excel._Worksheet oWSheet = (Excel._Worksheet)oExcelWBook.ActiveSheet; // セルA1の値を取得 MessageBox.Show("セルA1の値:" + oWSheet.Cells[1, 1].Value); // セルA2に更新時刻を書き込み oWSheet.Cells[2, 1] = DateTime.Now.ToString("HH時mm分ss秒"); Excel.Range oRange = oWSheet.Cells[2, 1]; // セル選択 oRange.Font.Size = 8; oRange.Font.Name = "MS 明朝"; oRange.Font.Color = 0xFF0000; oRange.Interior.Color = 0x44FFFF; // [Microsoft Excel - 互換性チェック]ダイアログの表示有無 oExcelWBook.CheckCompatibility = false; oExcelWBook.SaveAs(fileName); // Excel保存 MessageBox.Show( "保存しました。", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information); } catch (FileNotFoundException ex) { MessageBox.Show( "Excelファイルの操作に失敗しました。\n\n" + ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Warning); } catch (System.Runtime.InteropServices.COMException ex) { MessageBox.Show( "Excelファイルの操作に失敗しました。\n\n" + ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Warning); } finally { if (oExcelWBook != null) { oExcelWBook.Close(Type.Missing, Type.Missing, Type.Missing); oExcelApp.Quit(); } } this.Cursor = Cursors.Default; // マウスカーソルを戻す } } }
- 読み込み&書き込みするためのExcelファイルを用意。
Excelで”sample.xlsx”を新規作成し、セルA1に適当な文字を書いて保存しておく。
- プログラムをビルドして実行。(exeと同じフォルダにsample.xlsxを用意)
- 実行すると、バックグラウンドでExcelが起動され、セルA1に書いた値が表示される。
- 再び”sample.xlsx”を開いてみると、セルA2が黄色(青文字)になり、日時が書きこまれている。
これで、サンプルプログラムは完成。
で、今回は更にアプリ配布用のインストーラも作ってみる。
InstallShield Limited Editionのインストール
インストーラ作成のために、まずはInstallShieldのインストールを行う。
- 上記サンプルプログラムを開いておく。
(サンプルじゃなくてもいいので、インストーラ作成したい何かしらのソリューションを開いておく) - [ファイル]→[追加]→[新しいプロジェクト]メニュー選択。
- [新しいプロジェクトの追加]ダイアログで、左側ツリーから[その他のプロジェクトの種類]→[セットアップと配置]を選択。
更に、”InstallShield Limited Edition の有効化”を選択し[OK]ボタン押下。
- Webページが開かれるので、そのページ内の「手順 2: ダウンロード Web サイトにアクセスします。」リンクをクリック。
- 下記入力フォームに必要な情報を入力し[Download Now]をクリック。
- シリアルナンバーが表示されるのでメモっておく。メールでも届くけど。
- [Download]ボタンをクリック。
ファイルサイズは約60MB。
- ダウンロードした”InstallShield2013LimitedEdition.exe”を実行。
ウィザードの指示通りインストール。
- インストール完了。
- Visual Studioを起動中の場合は一旦終了してから、再びサンプルプログラムのソリューションを開く。
- 再び[ファイル]→[追加]→[新しいプロジェクト]メニュー選択。
- [新しいプロジェクトの追加]ダイアログが開かれる。
今度はリストに”InstallShield Limited Edition Project”が追加されているので、これを選択し[OK]ボタン押下。
- 評価を続けるか、トライアルライセンスをアクティベートするか聞かれるので、
“Activate or Register for free copy of InstallShiled”を選択し[Next]ボタン押下。
- さっきダウンロード時にメモったシリアルナンバーを入力し[Activate]ボタン押下。
- 完了すると、Visual Studioの方にセットアップのプロジェクトが追加される。
インストーラの作成
で、いよいよアプリ配布用のインストーラを作成してみる。
上記の続きから。
- 基本的に、インストーラーの作成は、この画面下にあるアイコンを左から順に設定していくことになる。
- まずは、”Application Infomation”をクリック。
- ついでに、インストーラを日本語化するため、左側メニューの[General Infomation]をクリック。
- 一覧の[Setup Language]で”Japanese: 日本語”を選択。
そして[General Infomation]タブを閉じる。
- アプリケーションの情報(会社名、アプリケーション名、アプリケーションのバージョン、Webアドレス)を入力する。
- 次、”Installation Requirements”をクリック。
インストール要件を指定する。
- 次、”Installation Architecture”をクリック。
アーキテクチャを設定するらしいが、InstallShield Limited Editionでは変更不可っぽい(鍵アイコン)のでそのまま。
- 次、”Application Files”をクリック。
追加するファイルを指定する。
まずは、アプリ本体を追加するため、[Add Project Outputs]ボタンを押下し、”プライマリ出力”をチェックし[OK]押下。
- あと、今回のサンプルではExcelファイルを使うので、これを追加するため、[Add Files]ボタンを押下。
ファイルを開くダイアログで、”sample.xlsx”を選択。
- [INSTALLDIR]配下に、2つのファイルが追加されたことを確認する。
- 次、”Application Shortcuts”。
- [New]ボタンを押下し[Browser for a Destination File]ダイアログを開く。
- 以下のファイルを選択し[Open]ボタン押下。
ProgramFilesFolder
OsadaSoft
Excelサンプルプログラム
WindowsFormsApplication1.プライマリ出力
- 今回はスタートメニューとデスクトップにショートカットを作成することにする。
一覧に追加された”Built”を選択し、[Create shortcut in Start Menu]と、[Create shortcut on Desktop]をチェックする。
- 次、”Application Registry”。
今回はレジストリ操作しないため変更なし。
- 最後、”Installation Interview”。
- そしてプロジェクトをビルドする。
ISEXP : error : -3204: Cannot extract icon with index 0 from file ~\WindowsFormsApplication1\WindowsFormsApplication1\bin\Release\WindowsFormsApplication1.exe.
どうも作成したサンプルプログラム側に、アイコンを設定していないことが原因らしい。
プロジェクトエクスプローラーから、、サンプルプログラム(WindowsFormsApplication1)を右クリックし[プロパティ]ポップアップメニューを選択。
そして、以下の[アイコンとマニフェスト]を選択し、[アイコン]欄に適当なアイコンを指定する。
上記設定後、ソリューションをリビルド。
するとビルドエラーが消える。ビルドが完成し、以下のフォルダ配下に”setup.exe”が作成されている。
¥WindowsFormsApplication1¥Setup2¥Setup2¥Express¥SingleImage¥DiskImages¥DISK1
インストールしてみる
出来上がったインストーラがちゃんと動くかテストしてみる。
- setup.exeを実行。
- 起動中。
ちゃんとInstallShield形式だ。 - InstallShield ウィザードへようこそ
- 使用許諾契約
- ユーザー情報
ユーザー名、所属の入力欄表示されてる。
- [インストール]ボタンを押下。
- 完了。
ちゃんとデスクトップのショートカットも作成されていて、実行もちゃんとできている。
# サンプルアプリは固定フォルダしかアクセスできない作りだったため、ホントは修正する必要があるけど、とりあえず、インストーラ作成の話と直接関係ないので修正は割愛。
これで、一応、他のPCでも動作する。
これでOKじゃん。
…って、
あれ?
?
なんで?
そういやぁ、Office関連のDLLって配布しないとダメじゃん。
- Microsoft.Office.Interop.Excel.dll
- Microsoft.Vbe.Interop.dll
- office.dll
- stdole.dll
↑これらDLLはインストーラの中に含まれていないみたいだけど、何で動いてんの?
というか、そもそもDLLは4つだけでいいのか?
調べてみると、
http://msdn.microsoft.com/ja-jp/library/15s06t57.aspx
Office プロジェクトから Microsoft Office アプリケーションの機能を使用するには、アプリケーションのプライマリ相互運用機能アセンブリ (PIA: Primary Interop Assembly) を使用することが必要です。
で、そのPIAはどこにあるかというと、どうやら以下のフォルダに存在するらしい。
例) C:\Program Files (x86)\Microsoft Visual Studio 12.0\Visual Studio Tools for Office\PIA \Common adodb.dll Extensibility.dll Microsoft.mshtml.dll microsoft.stdformat.dll msdatasrc.dll stdole.dll \Office14 ja\ Microsoft.Office.Interop.Excel.xml Microsoft.Office.Interop.Outlook.xml Microsoft.Office.Interop.Word.xml office.xml IPDMCTRL.dll Microsoft.Office.InfoPath.Permission.dll Microsoft.Office.interop.access.dao.dll Microsoft.Office.Interop.Access.dll Microsoft.Office.Interop.Excel.dll Microsoft.Office.Interop.Graph.dll Microsoft.Office.Interop.InfoPath.dll Microsoft.Office.Interop.InfoPath.SemiTrust.dll Microsoft.Office.Interop.InfoPath.Xml.dll Microsoft.Office.Interop.MSProject.dll Microsoft.Office.Interop.OneNote.dll Microsoft.Office.Interop.Outlook.dll Microsoft.Office.Interop.OutlookViewCtl.dll Microsoft.Office.Interop.PowerPoint.dll Microsoft.Office.Interop.Publisher.dll Microsoft.Office.Interop.SharePointDesigner.dll Microsoft.Office.Interop.SharePointDesignerPage.dll Microsoft.Office.Interop.SmartTag.dll Microsoft.Office.Interop.Visio.dll Microsoft.Office.Interop.Visio.SaveAsWeb.dll Microsoft.Office.Interop.VisOcx.dll Microsoft.Office.Interop.Word.dll Microsoft.Vbe.Interop.dll Microsoft.Vbe.Interop.Forms.dll Office.dll \Office15 ja\ Microsoft.Office.Interop.Excel.xml Microsoft.Office.Interop.Outlook.xml Microsoft.Office.Interop.Word.xml office.xml Microsoft.Office.InfoPath.Permission.dll Microsoft.Office.interop.access.dao.dll Microsoft.Office.Interop.Access.dll Microsoft.Office.Interop.Excel.dll Microsoft.Office.Interop.Graph.dll Microsoft.Office.Interop.InfoPath.dll Microsoft.Office.Interop.InfoPath.SemiTrust.dll Microsoft.Office.Interop.InfoPath.Xml.dll Microsoft.Office.Interop.MSProject.dll Microsoft.Office.Interop.OneNote.dll Microsoft.Office.Interop.Outlook.dll Microsoft.Office.Interop.OutlookViewCtl.dll Microsoft.Office.Interop.PowerPoint.dll Microsoft.Office.Interop.Publisher.dll Microsoft.Office.Interop.SharePointDesigner.dll Microsoft.Office.Interop.SharePointDesignerPage.dll Microsoft.Office.Interop.SmartTag.dll Microsoft.Office.Interop.Visio.dll Microsoft.Office.Interop.Visio.SaveAsWeb.dll Microsoft.Office.Interop.VisOcx.dll Microsoft.Office.Interop.Word.dll Microsoft.Vbe.Interop.dll Microsoft.Vbe.Interop.Forms.dll Office.dll
それで、これらDLLのうち、どれを配布すればいいのか?
http://msdn.microsoft.com/ja-jp/library/15s06t57.aspx
にExcelの場合はコレとかいろいろ書いてある。
調べてみると、やっぱ4つのDLLだけで良さそうだ。
でも、なんでインストーラでDLL入れてないのに他のPCで動くんだ?
再び調べてみた。
すると、こんな記事も。
http://msdn.microsoft.com/ja-jp/library/ee317478.aspx
COM オブジェクトを参照するアプリケーションに型情報を埋め込むと、プライマリ相互運用機能アセンブリ (PIA: Primary Interop Assembly) を使用する必要がなくなります。
ん?
なんか、この方法だとDLL配布しなくても動くということ?
「アプリケーションに型情報を埋め込む」ってのがよく分からないんで、今回作ったC#プロジェクトを確認してみる。
参照追加のときに追加された以下の以下の3つのオブジェクトについて、それぞれプロパティを見てみると「相互運用機能型の埋め込み」なんてのがある。
・Microsoft.Office.Core
・Microsoft.Office.Interop.Excel
・VBIDE
しかも、3つとも「True」だ。
ってことは、DLL配布要らないってことなのか。
素晴らしい!
でも何で?
昔、こんな感じでExcelにアクセスするプログラムを作ったとき、DLLが無いと動かなかった筈。
で、そのために、態々面倒なmsiのインストーラを作って配布していたのに。
どうやら、.NET Framework 4以降から使える「相互運用機能型の埋め込み」プロパティが
使えるようで、これをTrueに設定しておけば、DLLなしで配布できるようだ。
念のため、対象の.NET Frameworkを調べてみる。
プロジェクトを右クリックし「プロパティ」を選択し、「アプリケーション」タブで「対象フレームワーク」を確認。
「.NET Framework 4.5」となっている。
ちなみに、Visual Studio 2013ではフレームワークを「.NET Framework 2.0」~「.NET Framework 4.51」の範囲で選べる。
フレームワークとOS、IDEの関係は以下のような感じ。
http://msdn.microsoft.com/ja-jp/library/bb822049(v=vs.110).aspx
.NET Framework | OS標準 | IDE |
---|---|---|
4.5.1 | Windows 8.1 Windows Server 2012 R2 |
Visual Studio 2013 |
4.5 | Windows 8 Windows Server 2012 |
Visual Studio 2012 |
4 | Visual Studio 2010 | |
3.5 | Windows 7 SP1 Windows Server 2008 R2 SP1 |
Visual Studio 2008 |
3.0 | Windows Vista SP2 Windows Server 2008 R2 SP1 Windows Server 2008 SP2 |
Visual Studio 2005 |
2.0 | Windows Server 2008 R2 SP1 Windows Server 2008 SP2 Windows Server 2003 |
Visual Studio 2005 |
1.1 | Visual Studio .NET 2003 | |
1.0 | Visual Studio .NET |
今回のExcel用プログラムの場合、.NET Framework 4以降からDLL配布なしで使えるということと、
今回のプログラムでは、.NET Framework 4.5の新機能を使用していないため、.NET Framework 4で作って配布した方が良さそう。
もうサポート外なので使っている人はいないと思うけど、Windows XPでも.NET Framework 4までならインストール可能。
あと、もう1つおまけ。
IDEとFrameworkとOfficeのバージョン関係について、以下のサイトが参考になるかも。
http://blogs.msdn.com/b/office_client_development_support_blog/archive/2012/05/23/offica.aspx
基本的に古いバージョンのExcelで開発した方が互換が保てそうだけど、最新のExcelでも新機能を使わないように注意すれば問題なく使えそう。
いずれにしても、ここら辺はより多くの環境で動作確認した方が良さそうだ。
まとめ
一生懸命InstallShieldの記事を書いたけれども、結局、C#でExcelを使ったプログラムを作って配布する場合、
- .NET Framework 4を対象
- 参照設定で、Microsoft.Office.Core、Microsoft.Office.Interop.Excel、VBIDEを追加
- 「相互運用機能型の埋め込み」をTrueに設定
- できれば古いExcel環境で開発 or 新Excel環境の場合は新機能を使用しない
これで、DLL無しで簡単にexe作成&配布がでそう。