DOBON.NET DOBON.NETプログラミング掲示板過去ログ

Excel(セル選択範囲等の影響で)実行プロセスが解放されない

環境/言語:[Win2000SP4, VB.NET2003, Office2000SP3]
分類:[.NET]

Sample--------------------------------------------------------------------
Dim xlApp As Excel.Application
Dim xlBooks As Excel.Workbooks
Dim xlBook As Excel.Workbook
Dim xlSheets As Excel.Sheets
Dim xlSheet As Excel.Worksheet
Dim xlRange1 As Excel.Range, xlRange2 As Excel.Range

xlApp = New Excel.Application
xlApp.Visible = True
xlBooks = xlApp.Workbooks
xlBook = xlBooks.Open(xlFilePath)
xlSheets = xlBook.Worksheets
xlSheet = xlBook.Sheets(1)

'利用者数分の新規シート追加、ただし定型シートが1ページに存在済み
If max_sheet - 1 > 0 Then
xlSheet = xlBook.Sheets(1)
Dim xlNewSheet As Object = _
xlSheets.Add(Count:=max_sheet - 1, after:=xlSheet)
If System.Runtime.InteropServices.Marshal.IsComObject(xlNewSheet) Then
ReleaseCOM(xlNewSheet)
End If
End If

1ページめの定型シートをクリップボードにコピーする
If max_sheet > 1 Then
'複数利用者が存在するとき、1ページめの定型シートをクリップにコピーする
xlSheet = xlSheets(sheet_count)
'利用者毎にシート切り替え
xlSheets(sheet_count).Activate()
xlSheet.Application.Visible = True
xlRange1 = xlSheet.Range("A1", "N33")
xlRange1.Copy()
End If

'2ページめ以降に定型シートをクリップボードからペーストする
For sheet_count = 2 To max_sheet
xlSheet = xlSheets(sheet_count)

xlSheet.Cells(5, 9) = "H 17" '和暦年代入(文字型)
xlSheet.Cells(5, 12) = 7 '月代入(数値型)


'利用者毎にシート切り替え
xlSheets(sheet_count).Activate()
xlSheet.Application.Visible = True
xlRange2 = xlSheet.Range("A1", "N33")
xlRange2.PasteSpecial(Excel.XlPasteType.xlPasteAll)

'ペースト後、列幅を定型シートと同じにする
For sheet_column = CInt(Asc("A")) To CInt(Asc("N"))
sheet_point = Chr(sheet_column) & ":" & Chr(sheet_column)
xlSheet.Columns(sheet_point).ColumnWidth = _
xlSheets(1).Columns(sheet_point).ColumnWidth
Next

'ペースト後、行幅を定型シートと同じにする
For sheet_row = 1 To 33
sheet_point = sheet_row.ToString & ":" & sheet_row.ToString
xlSheet.Rows(sheet_point).RowHeight = _
xlSheets(1).rows(sheet_point).RowHeight
Next
Next

xlApp.DisplayAlerts = False
xlBook.SaveAs(xlFilePath)

ReleaseCOM(xlRange2)
ReleaseCOM(xlRange1)
ReleaseCOM(xlSheet)
ReleaseCOM(xlSheets)
xlBook.Close(False)
ReleaseCOM(xlBook)
xlBooks.Close()
ReleaseCOM(xlBooks)
xlApp.Quit()
ReleaseCOM(xlApp)
System.Threading.Thread.Sleep(5000)

Public Sub ReleaseCOM(ByVal o As Object) 'COMプロセス解放
Try
System.Runtime.InteropServices.Marshal.ReleaseComObject(o)
Catch
Finally
o = Nothing
End Try
End Sub
-------------------------------------------------------------------------
質問
追加するすべてのシートに先頭シート内容を(行・列幅含めて)貼り付け、和暦年月も
代入したい。上記サンプル、セル選択範囲等の影響で、Excel実行プロセスが解放される
方策があれば教えてください。
とにもかくにもFinallyで、ReleaseComObject
ソースコードを提示する前に見直してください。

Comオブジェクトの場合

a.b.cは危険です。
暗黙的にbの参照が行われます。
> xlSheets = xlBook.Worksheets
> xlSheet = xlBook.Sheets(1)
上記はNG。
 xlSheets = xlBook.Worksheets
 xlSheet = xlSheets(1)
にしましょう。

> If max_sheet - 1 > 0 Then
>    xlSheet = xlBook.Sheets(1)
なぜ、xlSheet 変数を取得しなおしているのでしょう?
直前に、1番目のシートを取得しているのですから、それを使えば良いのでは。

>    xlSheet = xlSheets(sheet_count)                
既に、xlSheet には、1番目のシートが取得されているはずです。
それを sheet_count番目のシートに入れ替えるなら、その前に、
先に取得した 1番目のシートの参照を解放しておきましょう。

>    xlSheets(sheet_count).Activate()
これもNG。xlSheets(sheet_count) を一度変数にうけておき、
Activate()実行後に、その変数を解放させましょう。

>    xlSheet.Application.Visible = True
これもNG。Applicationが解放されませんからね。
というよりも、そもそも普通はこのような面倒な書き方はせず、
  xlApp.Visible = True
だけで済ませるべきです。

>    xlSheet.Cells(5, 9) = "H 17"    '和暦年代入(文字型)
>    xlSheet.Cells(5, 12) = 7        '月代入(数値型)
こういった書き方もNG。Cellsプロパティを使うなら、
   A = xlSheet.Cells
   B = A._Default(5, 9)   'または単純に A(5, 9)
   C = A._Default(5, 12)  'または単純に A(5, 12)
   B.Value = "H 17"
   C.Value = 7
のように置き換えて、この後、変数 A, B, C の解放が必要です。

>       xlSheet.Columns(sheet_point).ColumnWidth = _
>                  xlSheets(1).Columns(sheet_point).ColumnWidth
これも、上記 Cellsプロパティと同様の理由でNG。このままのコードですと、
上記1行だけで、解放されていないオブジェクトが 4つもできてしまいます。


…他にも、いろいろと突っ込みどころはありますが、キリが無いのでこの辺で。(^^;
こんにちは、じゃんぬ です。

■No11807に返信(小島いさおさんの記事)
> 方策があれば教えてください。

中さん・弁さん両名が仰っていることは、すでにこちらで、ひどりさんが助言しています。
同じことを何度も繰り返していては、意味がありません。
http://dobon.net/cgi-bin/vbbbs/cbbs.cgi?mode=al2&namber=11791
ちょっと長いけど、如何に気合を入れてプログラムしなくちゃいけないか例を見せます。
これを見れば、きっちり、余すところ無く、オブジェクト参照を捕らえて、ReleaseComObjectを、finallyで行うか。それが分かると思います。


#region private static void テキストシェイプ値を設定する(Excel.Application app, String テキストシェイプ名, double 値, string Format, bool カラー設定フラグ, int ColorNo)
private static void テキストシェイプ値を設定する(Excel.Application app, String テキストシェイプ名, double 値, string Format, bool カラー設定フラグ, int ColorNo)
{
 Excel.Worksheet ワークシート = null;
 try
 {
  ワークシート = (Excel.Worksheet)app.ActiveSheet;
  Excel.Shapes シェイプs = null;
  try
  {
   シェイプs = ワークシート.Shapes;
   Excel.Shape シェイプ = null;
   try
   {
    シェイプ = シェイプs._Default(テキストシェイプ名);
    Excel.TextFrame tf = null;
    try
    {
     tf = シェイプ.TextFrame;
     Excel.Characters キャラクタ = null;
     try
     {
      キャラクタ = tf.Characters(Missing.Value, Missing.Value);
      キャラクタ.Text = 値.ToString(Format);
     }
     finally
     {
      if ( キャラクタ != null )
      {
       Marshal.ReleaseComObject(キャラクタ);
       キャラクタ = null;
      }
     }

    }
    finally
    {
     if ( tf != null )
     {
      Marshal.ReleaseComObject(tf);
      tf = null;
     }
    }
    Excel.FillFormat ff = null;
    try
    {
     ff = シェイプ.Fill;
     //カラー設定フラグ がtrueの場合には色を設定する
     if ( カラー設定フラグ == true )
     {
      Excel.ColorFormat cf = null;
      try
      {
       cf = ff.ForeColor;
       cf.SchemeColor = ColorNo;
       ff.Visible = Office.MsoTriState.msoTrue;
      }
      finally
      {
       if ( cf != null )
       {
        Marshal.ReleaseComObject(cf);
        cf = null;
       }
      }
     }
    }
    finally
    {
     if ( ff != null )
     {
      Marshal.ReleaseComObject(ff);
      ff = null;
     }
    }

   }
   finally
   {
    if ( シェイプ != null )
    {
     Marshal.ReleaseComObject(シェイプ);
     シェイプ = null;
    }
   }

  }
  finally
  {
   if ( シェイプs != null )
   {
    Marshal.ReleaseComObject(シェイプs);
    シェイプs = null;
   }
  }
 }
 finally
 {
  if ( ワークシート != null )
  {
   Marshal.ReleaseComObject(ワークシート);
   ワークシート = null;
  }
 }
}
#endregion
Excel各種オブジェクトに参照や代入する場合、そのオブジェクトを変数化して
不要になったら、すぐ解放…

魔界の仮面弁士さんのコーディング例をヒントに、試行錯誤しましたが、
何とか解決できました。

ファイルからシートの扱いまでは、いくつかサンプルあるけど、
セル操作のサンプルに乏しく、苦労しました。
みなさん、ご協力ありがとうございました。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板