tagCANDY CGI VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板) [ツリー表示へ]   [Home]
一括表示(VB.NET VB2005)
タイトル掛線を書いて、EXCELを終了
記事No997
投稿日: 2004/07/20(Tue) 18:08
投稿者kkouzi
[OSのVer]:Windows XP Professional [VBのVer]:VB.NET 2003 Office 2000使用

いつも参考にさせてもらっています。
質問なのですが、下記のようなプログラムを書いて、EXCEL上に掛線を引きたいのですが、
Excelのプロセスが残ります。
Bordersのオブジェクトを解放する必要があるのは分かったのですが、書き方をいろいろ
変えてみたのですが、上手くいきません。何か方法はあるのでしょうか?
すみませんがよろしくお願いします。

'アプリケーションオブジェクト取得用変数
Dim objApp As Excel.Application
'ブックスオブジェクト取得用変数
Dim objbooks As Excel.Workbooks
'ブックオブジェクト取得用変数
Dim objbook As Excel.Workbook
'シートオブジェクト取得用変数
Dim objsheet As Excel.Worksheet
'掛線オブジェクト取得用変数
Dim objBorders As Excel.Borders

'アプリケーションオブジェクト生成
objApp = New Excel.Application
        
'ワークブック開く
objbooks = objApp.Workbooks
'ブックを追加
objbook = objbooks.Add
'現在、アクティブなシートを取得する
objsheet = objApp.ActiveSheet

'掛線を引く
objBorders = _
objsheet.Cells(1, 1).Borders
objBorders.LineStyle = Excel.XlLineStyle.xlContinuous

'オブジェクト解放
System.Runtime.InteropServices.Marshal.ReleaseComObject(objBorders)
objBorders = Nothing
System.Runtime.InteropServices.Marshal.ReleaseComObject(objsheet)
objbook.Close(False)
objsheet = Nothing
System.Runtime.InteropServices.Marshal.ReleaseComObject(objbook)
objbook = Nothing
System.Runtime.InteropServices.Marshal.ReleaseComObject(objbooks)
objbooks = Nothing
objApp.Quit()
System.Runtime.InteropServices.Marshal.ReleaseComObject(objApp)
objApp = Nothing

'ガーベジコレクト起動
GC.Collect()

[ツリー表示へ]
タイトルRe: 掛線を書いて、EXCELを終了
記事No999
投稿日: 2004/07/21(Wed) 14:35
投稿者花ちゃん
上記コードを試した限りでは、問題ないようですが(プロセスは残っていない)

ここの .NETのExcel関係や掲示板のログ等にも色々書き込みがありますので
参考にして下さい。

[ツリー表示へ]
タイトルRe: 掛線を書いて、EXCELを終了
記事No1000
投稿日: 2004/07/22(Thu) 01:49
投稿者魔界の仮面弁士
1000番!

> '現在、アクティブなシートを取得する
> objsheet = objApp.ActiveSheet
今回の「プロセスが残る問題」とは、直接関係ありませんが、
ワークシートは、「Excelアプリ」ではなく、「ワークブック」に所属していますので、
「objsheet = objbook.ActiveSheet」の方が適切かと思います。

# ただし、objApp.ActiveSheet の場合は、objbook 以外のシートが取得される可能性も
# ありえますので、厳密に言えば、objbook.ActiveSheet とは別の意味となりますけれどね。

なお、ActiveSheetが返すシートは、ワークシートとは限りませんので(チャートシートの可能性がある)、
シート名等が分かっている場合は、objbook.Worksheets("Sheet1") などの方が良いかも知れません。


> '掛線を引く
> objBorders = _
> objsheet.Cells(1, 1).Borders
> objBorders.LineStyle = Excel.XlLineStyle.xlContinuous
原因はここです。ReleaseComObjectされていないオブジェクトがありますよ。


先の分も含めて修正すると、このようになります。
なお、Option Strict Onに備え、"As Object"な物は、DirectCastでキャストしてあります。

  Dim objCells As Excel.Range
  Dim objRange As Excel.Range
  objsheet = DirectCast(objbook.ActiveSheet, Excel.Worksheet)
  objCells = objsheet.Cells
  objRange = DirectCast(objCells._Default(1, 1), Excel.Range)
  objBorders = objRange.Borders
  objBorders.LineStyle = Excel.XlLineStyle.xlContinuous
  System.Runtime.InteropServices.Marshal.ReleaseComObject(objCells)
  objCells = Nothing
  System.Runtime.InteropServices.Marshal.ReleaseComObject(objRange)
  objRange = Nothing

このコードであれば、プロセスが残る事はありませんでした。(Excel 2002 + VB.NET 2002)


この時、『Cellsプロパティ』の動作に注意してください。もしも上記を、
  Dim objRange As Excel.Range
  objsheet = DirectCast(objbook.ActiveSheet, Excel.Worksheet)
  objRange = DirectCast(objsheet.Cells(1, 1), Excel.Range)
  objBorders = objRange.Borders
  objBorders.LineStyle = Excel.XlLineStyle.xlContinuous
  System.Runtime.InteropServices.Marshal.ReleaseComObject(objRange)
  objRange = Nothing
にした場合は、プロセスが残る結果となりました。

# ただし、
#    objRange = DirectCast(objsheet.Cells(1, 1), Excel.Range)
# ではなく、
#    objRange = objsheet.Range("A1")
# ならば、プロセスは残りません。


さて、Cellsプロパティについてもう少し書いておきます。

実は、
  objsheet.Cells(1, 1)
というのは、
  objsheet.Cells._Default(1, 1)
の省略表記となります。

つまり、Cells(1, 1) という操作の場合、
  objRange = objsheet.Cells(1, 1)
と書くのではなく、
  objCells = objsheet.Cells
  objRange = DirectCast(objCells(1, 1), Excel.Range)
のように、.Cells が返すRangeオブジェクトと、
._Default が返すRangeオブジェクトとは、別々にわけて変数に取り、
それぞれを ReleaseComObject しないといけないわけです。

これは、
   objBook = objApp.Workbooks(1)
ではなく、
   objBooks = objApp.Workbooks
   objBook = objBooks._Default(1)  'または、「objBook = objBooks(1)」
などと管理しなければならないのと、同じ理由による物です。


> 'ガーベジコレクト起動
> GC.Collect()
これを呼んだとしても、Excelのプロセスが残ってしまう件の解決とはなりません。

COMコンポーネントのメモリ管理と、.NETのメモリ管理は別物ですから、
"garbage collect"したからといって、Excelが解放されるという保障は無いのです。

根本的な解決は、「全てのCOMオブジェクトを ReleaseComObject する事」となります。
hhttp://blogs.users.gr.jp/hidori/archive/2004/01/26/916.aspx

[ツリー表示へ]
タイトルRe^2: 掛線を書いて、EXCELを終了
記事No1001
投稿日: 2004/07/22(Thu) 10:18
投稿者kkouzi
花ちゃん様、魔界の仮面弁士様、
どうもありがとうございました。

魔界の仮面弁士様のロジックで解決することが出来ました。
いろいろと参考になることがあり、すごく勉強になりました。
ありがとうございました。

[ツリー表示へ]
タイトルRe^2: 掛線を書いて、EXCELを終了
記事No2465
投稿日: 2005/10/26(Wed) 16:48
投稿者まどか
#初めて書き込みさせていただきます。

> つまり、Cells(1, 1) という操作の場合、
>   objRange = objsheet.Cells(1, 1)
> と書くのではなく、
>   objCells = objsheet.Cells
>   objRange = DirectCast(objCells(1, 1), Excel.Range)
> のように、.Cells が返すRangeオブジェクトと、
> ._Default が返すRangeオブジェクトとは、別々にわけて変数に取り、
> それぞれを ReleaseComObject しないといけないわけです。

自アプリのプロセスが残る問題の原因がここにありそうです。
ありがとうございました。

[ツリー表示へ]