tagCANDY CGI VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板) [ツリー表示へ]   [Home]
一括表示(VB.NET VB2005)
タイトルエクセル行削除を行うと、プロセスが残ってしまいました。
記事No2781
投稿日: 2005/12/16(Fri) 17:08
投稿者徳蔵丸
[OSのVer]:Windows2000  [VBのVer]:VB.NET 2003
お世話になっております。
昨日お助けいただいた内容で結構つぶせたのですが、
どうしても解決できないのでまた質問させていただきます。
今回のメモリ開放できないロジックは、問題Bの個所です。

最初に、セル範囲(1, 2, 4, 5)をコピーし、
次に、セル(6, 2)貼り付ける
そして、コピー先の最下行を削除する。
と言うプログラムです。


当初は、ペーストのときも「xlRange.Copy(destination:=xlCells(6, 2))」
のロジックを使っていたのでプロセスが残ってしまいましたが、これは
過去ログを参照させて頂いて下記ロジックのように解決できました。
しかし、「問題B」のロジックについてはどうしてもプロセスを開放することが
できなくて困っています。
どうしたら開放することができるのでしょうか。
どうぞ、よろしくお願い致します。

            Dim xlCells As Excel.Range
            Dim xlRange As Excel.Range
            Dim xlRangeX As Excel.Range
            Dim xlRangeY As Excel.Range
            Dim xlRangePaset As Excel.Range

'セル範囲(1, 2, 4, 5)をコピーする。
            xlCells = xlSheet.Cells
            xlRangeX = xlCells(1, 2)
            MRComObject(xlCells)
            xlCells = xlSheet.Cells
            xlRangeY = xlCells(4, 5)
            MRComObject(xlCells)
            xlRange = xlSheet.Range(xlRangeX, xlRangeY)
            MRComObject(xlRangeX)
            MRComObject(xlRangeY)
            xlRange.Copy()

'コピーした範囲をセル(6, 2)貼り付ける
            xlCells = xlSheet.Cells
            xlRangePaset = xlCells(6, 2)
            xlRangePaset.Insert()
            MRComObject(xlRangePaset)
            MRComObject(xlCells)
            MRComObject(xlRange)

            'コピーした表の最下行を削除する。
            xlCells = xlSheet.Cells
            xlRange = xlCells(9, 1)
            xlRange.EntireRow.Delete()   '←問題B

[ツリー表示へ]
タイトルRe: エクセル行削除を行うと、プロセスが残ってしまいました。
記事No2783
投稿日: 2005/12/16(Fri) 19:50
投稿者花ちゃん
> どうしても解決できないのでまた質問させていただきます。
> 今回のメモリ開放できないロジックは、問題Bの個所です。
解っているなら自分で処理して下さい。 ここの Excelのプロセスが正常に終了しない理由
.NETからExcelの基本的な操作方法(6) の中の '=========  データの入力処理  ============  
Excelのセルへのデータ入力例色々(Marshal.ReleaseComObject() を実行)
等を今一度よくご覧下さい。

>             xlRange.EntireRow.Delete()   '←問題B
変数 xlRange の中身を変更するのなら違う 変数を使用するか、一度開放しないと
いけません。(使い回しができない)
逆に xlCells(5, 3) こちらはセルアドレスを変更しても使い回しができます。
その辺の事も含めここの解説をよくご覧下さい。でないと都度他人の頼る事になります。
又、原因も問題の箇所も解っているし、対策も解っているのだから自分で色々試さないと
壁を乗り越える事(自分のものにする事)ができませんよ。
ここに掲載しているものや、掲示板のログ等で十分資料はあります。

[ツリー表示へ]
タイトルRe^2: エクセル行削除を行うと、プロセスが残ってしまいました。
記事No2787
投稿日: 2005/12/19(Mon) 09:28
投稿者徳蔵丸
[OSのVer]:Windows    [VBのVer]:VB.NET  
週末に引越作業をしていたので返信が遅れてすいません。

> 解っているなら自分で処理して下さい。 ここの Excelのプロセスが正常に終了しない理由
> .NETからExcelの基本的な操作方法(6) の中の '=========  データの入力処理  ============  
> Excelのセルへのデータ入力例色々(Marshal.ReleaseComObject() を実行)
> 等を今一度よくご覧下さい。
はい、拝見させていただきます。

> >             xlRange.EntireRow.Delete()   '←問題B
> 変数 xlRange の中身を変更するのなら違う 変数を使用するか、一度開放しないと
> いけません。(使い回しができない)
> 逆に xlCells(5, 3) こちらはセルアドレスを変更しても使い回しができます。
> その辺の事も含めここの解説をよくご覧下さい。でないと都度他人の頼る事になります。
上記ご指摘を含めつつ、解決の道を探ってみます。

> 又、原因も問題の箇所も解っているし、対策も解っているのだから自分で色々試さないと
> 壁を乗り越える事(自分のものにする事)ができませんよ。
> ここに掲載しているものや、掲示板のログ等で十分資料はあります。
私の調査不足ですね。
色々試してみたのですが、それでもできなかったので投稿させていただきましたが
自己満足のようでした。
もう一度、こちらのサイトを見直して見ます。

※返信が遅れたので、まずはご一報まで。

[ツリー表示へ]
タイトルRe^3: エクセル行削除を行うと、プロセスが残ってしまいました。
記事No2814
投稿日: 2005/12/22(Thu) 11:27
投稿者徳蔵丸
[OSのVer]:Windows    [VBのVer]:VB.NET  
結果を先にお伝えしますと、対応策を解明することができませんでした。
ということで、以下の変更を行いました。
:変更前:
1.1行〜10行までをコピーする。
2.21行目から、「1.」をペーストする。
3.30行目を削除する。

:変更後:
1.1行〜9行までをコピーする。
2.21行目から、「1.」をペーストする。

といった具合に、行削除を止めました。
原因がわからなかったことは悔やめますが、時間もないので
プログラミングとしては今回はこれで対応しようと思います。

色々、ありがとうございました。

[ツリー表示へ]
タイトルRe^4: エクセル行削除を行うと、プロセスが残ってしまいました。
記事No2817
投稿日: 2005/12/25(Sun) 23:14
投稿者じゃんぬねっと
参照先http://jeanne.wankuma.com/
私のコードでは問題なく動いてます。
というか、先のコードじゃ絶対正しく動きませんよ。

EntireRow の参照を解放しないままなのでは?
参照カウントとか、そういう勉強をした方がいいかもしれませんね。

[ツリー表示へ]
タイトルRe^5: エクセル行削除を行うと、プロセスが残ってしまいました。
記事No2818
投稿日: 2005/12/27(Tue) 13:54
投稿者徳蔵丸
[OSのVer]:Windows    [VBのVer]:VB.NET  

じゃんぬねっとさん、返信ありがとうございます。

> EntireRow の参照を解放しないままなのでは?
ご指摘ありがとうございます。
今回の仕様は前述の通り変更しましたが、個人的に未解決が嫌なので
考えていきます。

> 参照カウントとか、そういう勉強をした方がいいかもしれませんね。
はい、このことは勉強が足らないことを痛感しています。
参照カウントなどの勉強をしようと思って、書籍などを探していますが
これはといったものに当たらない状況です。。。

[ツリー表示へ]
タイトルRe^6: エクセル行削除を行うと、プロセスが残ってしまいました。
記事No2824
投稿日: 2005/12/28(Wed) 11:00
投稿者魔界の仮面弁士
> > EntireRow の参照を解放しないままなのでは?
> ご指摘ありがとうございます。
> 今回の仕様は前述の通り変更しましたが、個人的に未解決が嫌なので
> 考えていきます。

xlRange.EntireRow.Delete() '←問題B

このように、「.」が2回連続する箇所は要注意です。解放漏れの可能性が大です。

そのドットが、名前空間(Microsoft.Office.〜など)の区切りを表している場合は良いのですが、
プロパティやメソッドの区切りだった場合、それが「ActiveXオブジェクト(COM)」を返していると、
参照の解放漏れが発生し、Excelが残ってしまう原因となります。

# ちなみに、最初から.NET専用に開発されれたコンポーネントの場合は、こうした問題はおきません。
# あくまで、.NET から ActiveX コンポーネントを扱う場合だけの話です。


今回の場合、xlRange は COM オブジェクト(Excel.Range)です。これは既に変数に受けてあるので良いとして。
Range クラスの EntireRow プロパティもまた、COM を返します。Excel.Range ですね。
ですから、これも変数に受けねばなりません(が、提示されてコードでは変数受けていませんね)。

ちなみに、その Delete メソッドは Boolean 型を返します。もし、これが COM を返す場合は、
やはり変数に受けて、最後に解放する必要がある事に注意してください。


> > 参照カウントとか、そういう勉強をした方がいいかもしれませんね。
> はい、このことは勉強が足らないことを痛感しています。
.NET のオブジェクトが、すべて System.Object を実装しているのと同様に、
COM のオブジェクトは、すべて IUnknown というインターフェイスを実装しています。

そして IUnknown は、「参照カウント」と「型変換機能」の2つの機能を持っています。

参照カウンタとは、『ActiveXコンポーネントが参照されている回数』を管理する仕組みです。

・COMオブジェクトが生成されると、参照カウンタが 1 にセットされます。
・COMオブジェクトが変数等に参照されると、参照カウンタが自動的に増加します。
・型変換を行った場合も参照カウンタが増加します。
・参照していた変数等が解放されると、参照カウンタも減少します。
・最終的に参照カウンタが 0 になると、メモリ上から解放されます。

これが、COM の「参照カウント」という仕組みです。
(上記では、意図的に "カウンタ" と "カウント" を使い分けています)


ところが、.NET のメモリ管理は COM のそれとは異なる仕組みになっています。

.NET側の説明は省きますが、この両者の違いが原因で、.NET側で変数が解放されても、
それが COM 側に即座に伝わる事はありません。そのため、COM の 解放処理を行うために、
明示的に『ReleaseComObject メソッド』を呼ぶ必要があるというわけです。

# VB6 や VBScript は、元々が COMベースの言語なので、明示的な解放は不要なのですけれども。


> これはといったものに当たらない状況です。。。
少し専門的になってもよければ、虚無僧あたりは如何でしょう。
hhttp://www5.plala.or.jp/atata/

参照カウンタについては、上記サイト内の COM研究室 - SEQ 5〜6 あたりで取り扱われています。

[ツリー表示へ]
タイトルRe^7: エクセル行削除を行うと、プロセスが残ってしまいました。
記事No2825
投稿日: 2005/12/28(Wed) 18:55
投稿者徳蔵丸
[OSのVer]:Windows    [VBのVer]:VB.NET  

魔界の仮面弁士さん、返信ありがとうございます。
たくさんの説明、大変わかりやすく大変うれしく感じております。
(いつでも見れるように自マシンへテキスト保存しました。)

現在、年末年始休暇前対応のため多忙でして、自分の時間を作ることができない状況です。
この年末年始休暇中に色々試してきます。
下記のご紹介いただいたページも熟読してきます。

> 少し専門的になってもよければ、虚無僧あたりは如何でしょう。
> hhttp://www5.plala.or.jp/atata/
> 参照カウンタについては、上記サイト内の COM研究室 - SEQ 5〜6 あたりで取り扱われています。

本当にありがとうございました。

[ツリー表示へ]
タイトルRe^8: エクセル行削除を行うと、プロセスが残ってしまいました。
記事No2830
投稿日: 2006/01/05(Thu) 09:14
投稿者徳蔵丸
[OSのVer]:Windows2000  [VBのVer]:VB.NET2003
※自己レスで失礼します。
あけましておめでとうございます。

> 'xlsRange.EntireRow.Delete() '←問題B
この問題を以下のように修正しました。
これで、解決ができました。
これも、その他の自力解決と同様の方法で解決できたのに
なぜ、この対応だけできないと思ったのかが不思議です…。
いろいろ、ありがとうございました。

'コピーした表の最下行を削除する。
Dim xlsEntireRow As Excel.Range
xlsCells = xlsSheet.Cells
xlsRange = xlsCells(9, 1)
MRComObject(xlsCells)
xlsEntireRow = xlsRange.EntireRow
xlsEntireRow.Delete()
MRComObject(xlsEntireRow)
MRComObject(xlsRange)

[ツリー表示へ]