.NETからExcelの基本的な操作方法 (6個) (SNo.062) |
|
サンプル投稿用掲示板の方に、VB.NET(VB2005/VB2008/VB2010)から Excel VBA を使って操作するサンプルをいろいろ投稿したのに伴い、こちらのサンプルとの共通性を図る為にも今回書き直してみました。 ご使用にあたっては、Excelのプロセスが正常に終了しない理由 をよく読んでから実行願います。 このサンプルは、VB2010 から Excel を操作する時に必要な起動・終了処理を紹介しており、VB2010 から Excel を操作している間に、ユーザーが勝手に Excel を閉じるとエラーが発生するので、操作中は、ユーザーが勝手にExcel を閉じれないように設定を追加しております。 尚、VB から Excel を操作する為のサンプル(Tips)は、ここをはじめ、サンプル投稿用掲示板やVB2005用掲示板他いろいろなところに投稿してありますので、サイト内検索等で探して下さい。 サンプル投稿用掲示板のカテゴリ別サンプル一覧からでも見る事ができます。 又、Excel の起動・終了に関する設定は、実行環境用とテスト環境用の両方を掲載しておりますので。できれば、開発時は、テスト環境用の起動・終了に関する設定を使って頂いた方がプロセスの解放状況がよく解りますので便利かと思います。 これらのサンプルをご使用になられる場合は、必ず、下記の Excelのプロセスが正常に終了しない理由をご覧になってから試すようにして下さい。 Excelのプロセスが正常に終了しない理由(その1) Excelのプロセスが正常に終了しない理由(その2) ※ 掲載サンプルは、Excel 2002 の当時に書いたものやExcel 2007 以降のバージョンで書いたもの等入り混じっておりますので、ご使用のバージョンによっては、エラー等が表示される場合があるかもしれませんので、動作環境等をご確認下さい。(ご使用のバージョンに合せて変更して下さい) |
|
※ 下記コードの表示は、自作の【Excel Com オブジェクトの解放漏れチェックツール】の結果を自作のツールでリッチテキストをHTMLファイルに変換した結果を掲載しております。 標準のIDE上のコードのカラー化に加え、Excel Com オブジェクト等もカラー化しております。 '=================================================================================================== 'SampleNo:062 2010.05.17 A 2012.02.28 'タイトル:Excelの起動及び終了方法(062) - VB2010 '動作確認:WindowsVista VB2010(VS2010 Pro) Framework 4 / ターゲットCPU:X86 Excel 2007/Excel 2010 '[Option Compare Text] [Option Explicit On] [Option Infer On] [Option Strict On]で設定 '--------------------------------------------------------------------------------------------------- 'プロジェクト→参照の追加→COM→Microsoft Excel *.* ObjectLibrary を参照設定しておいてください。 'ソースコードは、保存オプションの詳細設定で、日本語(シフトJIS)-コードページ932 で保存しております。 '========1=========2=========3=========4=========5=========6=========7=========8=========9=========0 Imports Microsoft.Office.Interop Public Class Form1 Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click Call ExcelOpen("", "") '新規ファイルをオープンして、Excel を起動 '既存のファイルをオープンして、Excel を起動する場合 (ファイルのフルパス , シート名) 'Call ExcelOpen(System.IO.Path.GetFullPath("..\..\..\data\DBTest.xls"), "Sheet1") '--------------------------------------------------------------------------------------------------- Dim xlRange As Excel.Range Dim strDat(2, 0) As Object xlRange = xlSheet.Range("A5:A7") 'データの入力セル範囲 strDat(0, 0) = "10" 'データの作成 strDat(1, 0) = "20" strDat(2, 0) = "=Sum(A5:A6)" '計算式 xlRange.Value = strDat 'セルへデータの入力 '使い終わった時点で、xlRange オブジェクトを解放 MRComObject(xlRange) '確認のために、5秒間表示して終了処理へ System.Threading.Thread.Sleep(5000) '--------------------------------------------------------------------------------------------------- 'Excelファイルを上書き保存(True 又省略すれば)して終了処理を実行(名前をつけて保存も同じ) Call ExcelClose(IO.Path.GetFullPath(".\Test.xlsx"), False) 'False の場合保存しないで終了 'Excel.EXE がタスクマネージャーに残っていないか調査(テスト環境用の場合のみ追加して下さい) Call ProcessCheck() '正常に動作する事が確認できたらこの行は、コメントにして下さい。 End Sub 下記、Excel の起動・終了に関する設定は、実装用とテスト環境用の両方を掲載しておきますので、条件付きのコンパイルで切り替えるなり、コードを入れ替えるなり、組み替えるなり、お好きな方法でご使用下さい。 (不慣れな内は、テスト環境用のコードを使って開発される事をお薦め致します。) #Region "Excel の起動・終了に関する設定(実装用)" '---------- Private な変数の宣言 ----------------------------------- Private xlApp As Excel.Application Private xlBooks As Excel.Workbooks Private xlBook As Excel.Workbook Private xlSheets As Excel.Sheets Private xlSheet As Excel.Worksheet Private frgClose As Boolean 'ユーザーが Excel を閉じようとしたかのフラグ Private Sub ExcelOpen(ByVal FilePath As String, ByVal SheetName As String) 'Excel のオープン処理用プロシージャ frgClose = False '起動中は、ユーザーが Excel を閉じれないように xlApp = New Excel.Application 'Excel の WorkbookBeforeClose イベントを取得 AddHandler xlApp.WorkbookBeforeClose, AddressOf xlApp_WorkbookBeforeClose xlBooks = xlApp.Workbooks If FilePath.Length = 0 Then '新規のファイルを開く場合 xlBook = xlBooks.Add xlSheets = xlBook.Worksheets xlSheet = CType(xlSheets.Item(1), Excel.Worksheet) Else '既存のファイルを開く場合 xlBook = xlBooks.Open(FilePath) xlSheets = xlBook.Worksheets xlSheet = CType(xlSheets(SheetName), Excel.Worksheet) End If xlApp.Visible = True End Sub Private Sub xlApp_WorkbookBeforeClose(ByVal Wb As Excel.Workbook, ByRef Cancel As Boolean) 'VB2010 から Excel の WorkbookBeforeClose イベントを監視してユーザーが Excel を閉じれないようにする '(VB2010 から Excel を操作している途中でユーザーが勝手に Excel を閉じるとエラーが発生するので) If frgClose = False Then Cancel = True 'ユーザーが Excel を閉じようとしたので、処理をキャンセルする Else Cancel = False 'キャンセルしない(閉じる) End If End Sub Private Sub ExcelClose(ByVal FilePath As String, Optional ByVal CancelSave As Boolean = True) 'Excelファイルを上書き保存して終了処理用プロシージャ frgClose = True 'True : 閉じる事ができる(プログラムからの終了なので) xlApp.DisplayAlerts = False '保存時の問合せのダイアログを非表示に設定 If CancelSave Then Dim kts As String = System.IO.Path.GetExtension(FilePath).ToLower() Dim fm As Excel.XlFileFormat '拡張子に合せて保存形式を変更 Select Case kts Case ".csv" 'CSV (カンマ区切り) 形式 fm = Excel.XlFileFormat.xlCSV Case ".xls" 'Excel 97〜2003 ブック形式 fm = Excel.XlFileFormat.xlExcel8 Case ".xlsx" 'Excel 2007〜ブック形式 fm = Excel.XlFileFormat.xlOpenXMLWorkbook Case ".xlsm" 'Excel 2007〜マクロ有効ブック形式 fm = Excel.XlFileFormat.xlOpenXMLWorkbookMacroEnabled Case Else '必要なものは、追加して下さい。 fm = Excel.XlFileFormat.xlWorkbookDefault MessageBox.Show("ファイルの保存形式を確認して下さい。") End Select Try xlBook.SaveAs(Filename:=FilePath, FileFormat:=fm) 'ファイルに保存 Catch ex As Exception MessageBox.Show(ex.Message) End Try End If MRComObject(xlSheet) 'xlSheet の解放 MRComObject(xlSheets) 'xlSheets の解放 xlBook.Close() 'xlBook を閉じる MRComObject(xlBook) 'xlBook の解放 MRComObject(xlBooks) 'xlBooks の解放 xlApp.Quit() 'Excelを閉じる MRComObject(xlApp) 'xlApp を解放 End Sub '今まで使っていた方法では、Option Strict On の時にエラーとなったので、下記の '魔界の仮面弁士さんの投稿を使用させて頂きました。詳しくは、下記を参照してください。 ' http://hanatyan.sakura.ne.jp/vbnetbbs/wforum.cgi?mode=allread&no=6370#6374 'VB2005/VB2008/VB2010 用 ''' <summary> ''' COMオブジェクトの参照カウントをデクリメントします。 ''' </summary> ''' <typeparam name="T">(省略可能)</typeparam> ''' <param name="objCom"> ''' COM オブジェクト持った変数を指定します。 ''' このメソッドの呼出し後、この引数の内容は Nothing となります。 ''' </param> ''' <param name="force"> ''' すべての参照を強制解放する場合はTrue、現在の参照のみを減ずる場合はFalse。 ''' </param> Public Shared Sub MRComObject(Of T As Class)(ByRef objCom As T, Optional ByVal force As Boolean = False) If objCom Is Nothing Then Return End If Try If System.Runtime.InteropServices.Marshal.IsComObject(objCom) Then If force Then System.Runtime.InteropServices.Marshal.FinalReleaseComObject(objCom) Else System.Runtime.InteropServices.Marshal.ReleaseComObject(objCom) End If End If Finally objCom = Nothing End Try End Sub #End Region End Class #Region "Excel の起動・終了に関する設定(テスト環境用)" '---------- Private な変数の宣言 ----------------------------------- Private xlApp As Excel.Application Private xlBooks As Excel.Workbooks Private xlBook As Excel.Workbook Private xlSheets As Excel.Sheets Private xlSheet As Excel.Worksheet Private Sub ExcelOpen(ByVal FilePath As String, ByVal SheetName As String) 'Excel のオープン処理用プロシージャ 'メッセージボックス等がExcelの裏に隠れないようにする為に Me.TopMost = True frgClose = False '起動中は、ユーザーが Excel を閉じれないように xlApp = New Excel.Application 'Excel の WorkbookBeforeClose イベントを取得 AddHandler xlApp.WorkbookBeforeClose, AddressOf xlApp_WorkbookBeforeClose xlBooks = xlApp.Workbooks If FilePath.Length = 0 Then '新規のファイルを開く場合 xlBook = xlBooks.Add xlSheets = xlBook.Worksheets xlSheet = DirectCast(xlSheets.Item(1), Excel.Worksheet) Else '既存のファイルを開く場合 xlBook = xlBooks.Open(FilePath) xlSheets = xlBook.Worksheets xlSheet = DirectCast(xlSheets(SheetName), Excel.Worksheet) End If xlApp.Visible = True End Sub Private frgClose As Boolean 'ユーザーが Excel を閉じようとしたかのフラグ Private Sub xlApp_WorkbookBeforeClose(ByVal Wb As Excel.Workbook, ByRef Cancel As Boolean) 'VB2010 から Excel の WorkbookBeforeClose イベントを監視してユーザーが Excel を閉じれないようにする If frgClose = False Then Cancel = True 'ユーザーが Excel を閉じれないように Else Cancel = False End If End Sub Private Sub ExcelClose(ByVal FilePath As String, Optional ByVal CancelSave As Boolean = True) 'Excelファイルを上書き保存して終了処理用プロシージャ frgClose = True 'プログラムからExcel を閉じた時のフラグ xlApp.DisplayAlerts = False '保存時の問合せのダイアログを非表示に設定 If CancelSave Then Dim kts As String = System.IO.Path.GetExtension(FilePath).ToLower() Dim fm As Excel.XlFileFormat '拡張子に合せて保存形式を変更(使用する Excel のバージョンに注意) Select Case kts Case ".csv" 'CSV (カンマ区切り) 形式 fm = Excel.XlFileFormat.xlCSV Case ".xls" 'Excel 97〜2003 ブック形式 fm = Excel.XlFileFormat.xlExcel8 Case ".xlsx" 'Excel 2007〜ブック形式 fm = Excel.XlFileFormat.xlOpenXMLWorkbook Case ".xlsm" 'Excel 2007〜マクロ有効ブック形式 fm = Excel.XlFileFormat.xlOpenXMLWorkbookMacroEnabled Case Else '必要なものは、追加して下さい。 fm = Excel.XlFileFormat.xlWorkbookDefault MessageBox.Show("ファイルの保存形式を確認して下さい。") End Select Try xlBook.SaveAs(Filename:=FilePath, FileFormat:=fm) 'ファイルに保存 Catch ex As Exception MessageBox.Show(ex.Message) End Try End If MRComObject(xlSheet) 'xlSheet の解放 MRComObject(xlSheets) 'xlSheets の解放 xlBook.Close() 'xlBook を閉じる MRComObject(xlBook) 'xlBook の解放 MRComObject(xlBooks) 'xlBooks の解放 xlApp.Quit() 'Excelを閉じる MRComObject(xlApp) 'xlApp を解放 End Sub Private Sub ProcessCheck() 'タスクマネージャーに、Excel.exe が残っていないか確認(テスト環境でのみ使用の事) '以前は、Loop しながら5秒間程繰り返し確認していたのだが、その間に解放される場合が 'ある事が判明したので、下記のように1回きりの確認でもデクリメント処理がきちんと '行われていたら解放される事が解ったので下記のように厳密に判定する事にしました。 System.Threading.Thread.Sleep(500) Application.DoEvents() If Process.GetProcessesByName("Excel").Length = 0 Then '先にフォームを閉じるとエラーが発生するので '必要により表示するようにして下さい。 MessageBox.Show(Me, "Excel.EXE は解放されました。") Exit Sub End If If Process.GetProcessesByName("Excel").Length >= 1 Then Dim ret As DialogResult ret = MessageBox.Show(Me, "まだ Excel.EXE が起動しています。強制終了しますか?", _ "確認", MessageBoxButtons.YesNo) If ret = Windows.Forms.DialogResult.Yes Then Dim localByName As Process() = Process.GetProcessesByName("Excel") Dim p As Process '起動中のExcelを取得 For Each p In localByName 'Windou の無い(表示していない)Excel があれば強制終了させる '画面に表示している Excel は、終了させないので必要なら手動で終了して下さい。 If System.String.Compare(p.MainWindowTitle, "", True) = 0 Then 'Excel.EXE のプロセスを削除 p.Kill() End If Next End If End If End Sub Public Sub MRComObject(Of T As Class)(ByRef objCom As T, Optional ByVal force As Boolean = False) Dim IDEEnvironment As Boolean = False 'メッセージボックスを表示させたい場合は、True に設定 If objCom Is Nothing Then If IDEEnvironment = True Then 'テスト環境の場合は下記を実施し、後は、コメントにしておいて下さい。 MessageBox.Show(Me, "Nothing です。") End If Return End If Try If System.Runtime.InteropServices.Marshal.IsComObject(objCom) Then Dim count As Integer If force Then count = System.Runtime.InteropServices.Marshal.FinalReleaseComObject(objCom) Else count = System.Runtime.InteropServices.Marshal.ReleaseComObject(objCom) End If If IDEEnvironment = True AndAlso count <> 0 Then Try 'テスト環境の場合は下記を実施し、後は、コメントにしておいて下さい。 MessageBox.Show(Me, TypeName(objCom) & " 要調査! デクリメントされていません。") Catch ex As Exception MessageBox.Show(Me, " 要調査! デクリメントされていません。") End Try End If Else If IDEEnvironment = True Then 'テスト環境の場合は下記を実施し、後は、コメントにしておいて下さい。 MessageBox.Show(Me, "ComObject ではありませんので、解放処理の必要はありません。") End If End If Finally objCom = Nothing End Try End Sub #End Region |
|
注意! MRComObject は、元々 http://support.microsoft.com/kb/317109/ja の NAR の実装を元に私が少し変更して使っていたのですが、今まで使っていた方法では、Option Strict On の時にエラーとなったので、当サイトの掲示板の 魔界の仮面弁士さん の投稿を使用させて頂いたものなので、そう言った経緯を無視して、転載・引用されると、魔界の仮面弁士さん 等にもご迷惑をおかけする事にもなりますので、絶対に転載されないようにお願い致します。 又、MRComObject の名前は、変更しておりませんが中身が何度となく変更しておりますので、転載先まで変更する事ができず、問題があっても困りますので、必要ならリンクを貼るようにして下さい。 又、Excelのプロセスが正常に終了しない理由 等をよく理解しないまま、MRComObject を使用すれば、全て解放されるかのように誤解されて使用されている場合もあるので、よく読んでからご使用下さい。 |