Excelのプロセスが正常に終了しない理由(その2) | |
1.Excel のプロセスが終了しないのでハマってしまった事例その1。 まず、(サンプル投稿用掲示板に投稿してある起動・終了用コード) を追加して下記のコードを試して見て下さい。 下記コードは、サンプル投稿用掲示板に投稿すべく作っていて気がついたものです。 Private Sub Button40_Click(sender As System.Object, e As System.EventArgs) Handles Button40.Click Call ExcelOpen("", "") '新規ファイルをオープンして、Excel を起動 '============================================================================= xlSheet.Range("A1").Value = "123" xlSheet.Cells._Default(2, 2) = "123" xlSheet.Cells(3, 3) = "123" '確認のために、1秒間表示しておく System.Threading.Thread.Sleep(1000) '間違ったコードで、デクリメントもしていないのに下記のチェックを実施すると解放される '============================================================================= 'Excelファイルを上書き保存(True 又省略すれば)して終了処理を実行 Call ExcelClose(IO.Path.GetFullPath(".\Test.xlsx"), False) 'False の場合保存しないで終了 '============================================================================= '上記、Call ExcelClose() で、Excel.EXE を終了後タスクマネージャーに 'Excel.EXE が残っていないか調査した場合解放されてしまう '(以前このようなコードを使ってチェックしていた事も要因の一つになっています。) Dim st As Integer = System.Environment.TickCount Do While System.Environment.TickCount - st < 5000 System.Windows.Forms.Application.DoEvents() System.Threading.Thread.Sleep(500) If Process.GetProcessesByName("Excel").Length = 0 Then MessageBox.Show(Me, "Excel.EXE は解放されました。") Exit Do End If Loop End Sub 上記を実行すると、[Excel.EXE は解放されました。]と言ったメッセージボックスが表示されるはずです。 (ここで言うプロセスが終了しないとか、Excel が残っているとかは、Button40 の処理が終了して、Excel が閉じられた状態で、タスクマネージャーに、Excel.exe が表示したままの事を指します。これは、IDE を終了した時点では、Excel.exe が消える程度のものですが...。) 何回も、Excel.exe のプロセスが起動していないかチェックをループで行っていたのが原因です。 まさか、このような事で解放されるとは思ってもいなかったので、このツールを使ってチェックしていた事が一番の要因でした。 掲載していたサンプルをご利用されていた方々にもご迷惑をお掛けした事をお詫び致します。 |
|
事例その2 '============================================================================= '1.単一セルを参照する場合 xlSheet.Range("A1").Value = 3.14159 'VB6.0 用の表記 Dim xlRange As Excel.Range = xlSheet.Range("A1") '.NET 系の表記 xlRange.Value2 = 3.14159 MRComObject(xlRange) '10.Range.Cells プロパティを使ってセルを参照する Dim xlCells1 As Excel.Range = xlSheet.Cells() Dim xlRange1 As Excel.Range = xlSheet.Range(xlCells1(1, 1), xlCells1(5, 3)) xlRange1.Font.Italic = True MRComObject(xlCells1) MRComObject(xlRange1) '15.AutoFill メソッドを使ってセルに連続してデータを入力する xlRange = xlSheet.Range("A1") xlRange.Value = "1月" xlRange.AutoFill(Destination:=xlSheet.Range("A1:L1"), Type:=Excel.XlAutoFillType.xlFillMonths) MRComObject(xlRange, True) '============================================================================= 上記は、単純な解放処理漏れのミスです。 IDE 上で、長いコードを見ていると気が付きにくいのですが、(試作中のツールで見ると一目瞭然)カラーで太字で表示されている部分が解放漏れになっています。 こういった事は、VB6.0 や VBA のコードを移植しているとよく起きる(私だけですが)事で、これらの部分のコードは、VBAやVB6.0では、問題がないので、Web 上でもよく見かけるし、VBA のコードを移植していてもついうっかり使ってしまっていたりするかと思いますが、面倒がらず、オブジェクト.オブジェクト.プロパティとなるようなコードは、十分注意して、変数に受けるようにして下さい。 |
|
事例その3 さて、間違ったコードのどこに原因があるのでしょうか? Private Sub Button39_Click(sender As System.Object, e As System.EventArgs) Handles Button39.Click Call ExcelOpen("", "") '新規ファイルをオープンして、Excel を起動 '============================================================================= Dim adrs1 As String Dim xlRange As Excel.Range xlRange = xlSheet.Range("A1:E6") 'A1:E6 の範囲に仮データを入力 xlRange.Value = "A1〜E6" MRComObject(xlRange) '------------------------------------------------------------------------------- '間違ったコード Dim xlRangeEnd As Excel.Range xlRange = xlSheet.Range("D3") xlRangeEnd = xlRange.End(Excel.XlDirection.xlToLeft) adrs1 = xlRangeEnd.Address MessageBox.Show(Me, " D3 からの左端のセル位置は、" & adrs1 & " です。") xlRangeEnd = xlRange.End(Excel.XlDirection.xlToRight) adrs1 = xlRangeEnd.Address MessageBox.Show(Me, " D3 からの右端のセル位置は、" & adrs1 & " です。") MRComObject(xlRangeEnd) MRComObject(xlRange) '============================================================================= '一旦終了して、間違ったコード での状態を確認 Call ExcelClose(IO.Path.GetFullPath(".\Test.xlsx"), False) Call ProcessCheck() 'ここで強制終了をして下さい。 '============================================================================= '正しいコードのテストの為、再度、起動 Call ExcelOpen("", "") '新規ファイルをオープンして、Excel を起動 '============================================================================= xlRange = xlSheet.Range("A1:E6") 'A1:E6 の範囲に仮データを入力 xlRange.Value = "A1〜E6" MRComObject(xlRange) '------------------------------------------------------------------------------- '正しくは、下記のように、xlRange の参照先は、変更されていないが、xlRangeEnd は '定数で参照先が変更されているのに、都度のデクリメントをしなかった事で解放漏れに 'なってしまったので、都度、デクリメントをする事で解放されるようになった。 xlRange = xlSheet.Range("D3") xlRangeEnd = xlRange.End(Excel.XlDirection.xlToLeft) adrs1 = xlRangeEnd.Address MessageBox.Show(Me, " D3 からの左端のセル位置は、" & adrs1 & " です。") MRComObject(xlRangeEnd) xlRangeEnd = xlRange.End(Excel.XlDirection.xlToRight) adrs1 = xlRangeEnd.Address MessageBox.Show(Me, " D3 からの右端のセル位置は、" & adrs1 & " です。") MRComObject(xlRangeEnd) MRComObject(xlRange) '============================================================================= Call ExcelClose(IO.Path.GetFullPath(".\Test.xlsx"), False) Call ProcessCheck() End Sub コードをご覧になって、問題点が解った方おられたでしょうか? 私は、何度も見直したのですが、問題個所を見つける事ができませんでした。 このように、Excel の定数で指定した事で、Range オブジェクトの参照先が変わってしまって解放漏れになっているとは思ってもみませんでした。 (参照先が変われば、デクリメントが必要な事は、重々承知のはずが) 原因が解れば何でもない事なのですが、コードを目で追っているだけでは、うっかり見過ごしてしまう事例ではないでしょうか。 |