トップ回答者
PictureBoxの内容をClipboardへコピーするには

質問
回答
-
>それは設計が悪いです。
>「暗黙的な方法」が実装されていない場合にリソース漏れが発生しますが、それはクラスライブラリのバグです。
とは言え、「暗黙的な方法」だけに頼るのはよくありません。
「暗黙的な方法」が実装されていても、それが効果を発揮するのは、アンマネージリソースをカプセルするオブジェクトがGCによって回収される時になります。
なので、アンマネージリソースをカプセルするオブジェクトインスタンスがユーザコード内での意味を失ってからGCによってそのインスタンスが回収されるまでの期間、リソースリークと同等の状態が発生します。
(例えば FileStream のインスタンスを Close() しないでうっちゃらかしておくと、FileStream のインスタンスがGCによって回収するまで、そのファイルの読み書きができない、などの不都合が発生し得ます。)
# 「その状態をリソースリークと呼ぶのは不適切である」という意見はあるかもしれませんが。
なので、特別な理由が無い限り、アンマネージリソースをカプセルするオブジェクトインスタンスに対しては、そのオブジェクトインスタンスの寿命をプログラマやフレームワークが明示的に管理するのが基本パターンであるべきと思います。- 回答としてマーク クサキ 2009年11月13日 0:29
-
「GCに回収されるまでタイムラグがある」というのは表現ならわかりますし、IDisposableによる解放をした方がいいことも賛成です。しかし元コメントは「解放の対象になりません」と言い切っているので、この点は間違ってると思い指摘しました。
ざっと読んでみて、それぞれの投稿が「何に対して言及しているか」に迷いました。
今回の話題の中心となっている、Graphics クラスに対してに限った狭い話であれば、ファイナライザが定義されているためにいずれ回収されるので「解放の対象になりません」は誤りと言えます。
しかし、自作クラスを含めたクラスデザインという広い話であれば、「きちんと設計しないとリソース漏れを引き起こす」(「解放の対象になりません」)ということが正しいでしょう。
質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に困った第三者の方が検索しやすくなります。- 回答としてマーク クサキ 2009年11月13日 0:29
-
コントロールに直接描画した結果のものは、後に残しておくことはできません。その場限りのものです(DrawToBitmap でハードコピーを取るって乱暴な手段はありますが)。
後に残しておきたいのなら、コントロールに直接描画するのではなく、新しく Bitmap オブジェクトを作成し、Bitmap に対して(Graphics.FromImage で取得した Graphics を使って)描画を行い、コントロールにはこの Bitmap を描画するだけにしてください(PictureBox なら Paint イベントなど使う必要もなく Image プロパティに設定するだけです。画像に手を加えた後は Invalidate メソッドを呼び出して再描画させます)。
// 描画手順を残しておいて、PictureBox に描画したのと同じ操作を、新しく作成した Bitmap に対して行うということも可能です。- 回答としてマーク クサキ 2009年11月12日 8:08
-
Hongliang さんの 「PictureBox に描画したのと同じ操作を、新しく作成した Bitmap に対して行う」 方法はこんな感じかな。
private void pictureBox1_Paint(object sender, PaintEventArgs e) { Graphics g = e.Graphics; PaintToImage(g); } private void PaintToImage(Graphics g) { g.DrawEllipse(new Pen(Color.Green, 3), 20, 20, 40, 40); } private void ClipBoardButton_Click(object sender, EventArgs e) { using (Bitmap bmp = new Bitmap(pictureBox1 と同じサイズ)) using (Graphics g = Graphics.FromImage(bmp)) { PaintToImage(g); Clipboard.SetDataObject(bmp, true); } }
なお、Bitmap や Graphics などを自分で作った場合には、使い終わったらきちんと Dispose() してやる必要があります。
(上記のでは using を使って Dispose() しています)
もちろん、PaintEventArgs の中にある Graphics だとか、PictureBox.Image の中にある Bitmap だとかは、自分で作ったものではないので勝手に Dispose() してはいけません。
青柳 臣一 (Shinichi Aoyagi)- 回答としてマーク クサキ 2009年11月12日 8:09
-
これまで、Graphics.FromHwndを使っていましたが、Dispose()を
書いていませんでしたが、特に問題を起こしていませんでした。
C#はガベージコネクションが解放するので必要ないと思っていましたが、必要ないのは配列だけということですか?
.NET でも、きちんと解放処理を書かないとリソース漏れを起こします。マネージリソース(.NET のオブジェクト)は、ガベージコレクタの対象となりますが、
アンマネージリソース(ファイルやデータベース接続やハンドル等etc・・・)は解放の対象になりません。以下、参考URLです。
http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1220462157さらに詳しい資料ですが
ガベージ・コレクタを明示的に動作させるには?
http://www.atmarkit.co.jp/fdotnet/dotnettips/021gc/gc.html
確実な終了処理を行うには?
http://www.atmarkit.co.jp/fdotnet/dotnettips/027dispose/dispose.html
以下もっと深い話です。(^ω^;ガベージコレクション入門: Microsoft .NET Framework の自動メモリ管理
http://msdn.microsoft.com/ja-jp/library/bb985010.aspx
http://msdn.microsoft.com/ja-jp/library/dd297765.aspx- 回答としてマーク クサキ 2009年11月12日 8:09
-
.NET でも、きちんと解放処理を書かないとリソース漏れを起こします。
マネージリソース(.NET のオブジェクト)は、ガベージコレクタの対象となりますが、
アンマネージリソース(ファイルやデータベース接続やハンドル等etc・・・)は解放の対象になりません。
アンマネージ リソースをクリーンアップするための Finalize および Dispose の実装 ではこれらのリソースを解放する明示的な方法と暗黙的な方法の両方をサポートする必要があります。暗黙的な制御を提供するには、オブジェクトにプロテクト Finalize を実装します (C# および C++ のデストラクタ構文)。そのオブジェクトへの有効な参照がなくなった後で、ガベージ コレクタがこのメソッドを呼び出します。
と説明しています。ここで言及されている「暗黙的な方法」が実装されていない場合にリソース漏れが発生しますが、それはクラスライブラリのバグです。- 回答としてマーク クサキ 2009年11月13日 0:29
すべての返信
-
WinXP SP3/VS2008 SP1 で
Clipboard.SetDataObject(pictureBox1.Image, true);
を試してみましたが、正常に実行され、アプリケーション終了後もクリップボードに画像データが存在していることを確認できました。
ローカルファイル・プロジェクトのリソースと、画像を切り替えて試しましたが、こちらの環境では正常に実行します。
情報があまりに足りないので、実行環境や、可能なら周辺のソースも提示してもらえませんか。 -
Vista, VisualStudio2008 C# Windowsフォームアプリケーションです。
以下のコーディングです。
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.DrawEllipse(new Pen(Color.Green, 3), 20, 20, 40, 40);
}
private void ClipBoardButton_Click(object sender, EventArgs e)
{
Clipboard.SetDataObject(pictureBox1.Image, true); // 例外発生
}
エラーは以下のようです。
'System.ArgumentNullException' のハンドルされていない例外が System.Windows.Forms.dll で発生しました。
追加情報: 値を Null にすることはできません。
http://dobon.net/vb/dotnet/graphics/pictureboximageanddrawimage.html
を見ましたが、具体的にどうして良いか分かりませんのでよろしくお願いします。 -
コントロールに直接描画した結果のものは、後に残しておくことはできません。その場限りのものです(DrawToBitmap でハードコピーを取るって乱暴な手段はありますが)。
後に残しておきたいのなら、コントロールに直接描画するのではなく、新しく Bitmap オブジェクトを作成し、Bitmap に対して(Graphics.FromImage で取得した Graphics を使って)描画を行い、コントロールにはこの Bitmap を描画するだけにしてください(PictureBox なら Paint イベントなど使う必要もなく Image プロパティに設定するだけです。画像に手を加えた後は Invalidate メソッドを呼び出して再描画させます)。
// 描画手順を残しておいて、PictureBox に描画したのと同じ操作を、新しく作成した Bitmap に対して行うということも可能です。- 回答としてマーク クサキ 2009年11月12日 8:08
-
Hongliang さんの 「PictureBox に描画したのと同じ操作を、新しく作成した Bitmap に対して行う」 方法はこんな感じかな。
private void pictureBox1_Paint(object sender, PaintEventArgs e) { Graphics g = e.Graphics; PaintToImage(g); } private void PaintToImage(Graphics g) { g.DrawEllipse(new Pen(Color.Green, 3), 20, 20, 40, 40); } private void ClipBoardButton_Click(object sender, EventArgs e) { using (Bitmap bmp = new Bitmap(pictureBox1 と同じサイズ)) using (Graphics g = Graphics.FromImage(bmp)) { PaintToImage(g); Clipboard.SetDataObject(bmp, true); } }
なお、Bitmap や Graphics などを自分で作った場合には、使い終わったらきちんと Dispose() してやる必要があります。
(上記のでは using を使って Dispose() しています)
もちろん、PaintEventArgs の中にある Graphics だとか、PictureBox.Image の中にある Bitmap だとかは、自分で作ったものではないので勝手に Dispose() してはいけません。
青柳 臣一 (Shinichi Aoyagi)- 回答としてマーク クサキ 2009年11月12日 8:09
-
Bitmapとgを関連付けることが出来るようになり解決しました。
また、「PictureBox に描画したのと同じ操作を行う」 方法の方がその場だけのメモリの確保でこちらを使うことにしました。
具体的なコーディングありがとうございました。
Dispose()に関して追加の質問をさせてください。
Graphics g = Graphics.FromHwnd(Pic1.Handle);
Graphics g = Pic1.CreateGraphics();
Graphics g = Graphics.FromImage(_bmp);
これらは、ボタンのClickイベントにあろうが、PictureBoxのPaintイベントにあろうが、
自分で作った g で、g.Dispose()が必要ということですか?
これまで、Graphics.FromHwndを使っていましたが、Dispose()を
書いていませんでしたが、特に問題を起こしていませんでした。
C#はガベージコネクションが解放するので必要ないと思っていましたが、必要ないのは配列だけということですか?
-
これまで、Graphics.FromHwndを使っていましたが、Dispose()を
書いていませんでしたが、特に問題を起こしていませんでした。
C#はガベージコネクションが解放するので必要ないと思っていましたが、必要ないのは配列だけということですか?
.NET でも、きちんと解放処理を書かないとリソース漏れを起こします。マネージリソース(.NET のオブジェクト)は、ガベージコレクタの対象となりますが、
アンマネージリソース(ファイルやデータベース接続やハンドル等etc・・・)は解放の対象になりません。以下、参考URLです。
http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1220462157さらに詳しい資料ですが
ガベージ・コレクタを明示的に動作させるには?
http://www.atmarkit.co.jp/fdotnet/dotnettips/021gc/gc.html
確実な終了処理を行うには?
http://www.atmarkit.co.jp/fdotnet/dotnettips/027dispose/dispose.html
以下もっと深い話です。(^ω^;ガベージコレクション入門: Microsoft .NET Framework の自動メモリ管理
http://msdn.microsoft.com/ja-jp/library/bb985010.aspx
http://msdn.microsoft.com/ja-jp/library/dd297765.aspx- 回答としてマーク クサキ 2009年11月12日 8:09
-
.NET でも、きちんと解放処理を書かないとリソース漏れを起こします。
マネージリソース(.NET のオブジェクト)は、ガベージコレクタの対象となりますが、
アンマネージリソース(ファイルやデータベース接続やハンドル等etc・・・)は解放の対象になりません。
アンマネージ リソースをクリーンアップするための Finalize および Dispose の実装 ではこれらのリソースを解放する明示的な方法と暗黙的な方法の両方をサポートする必要があります。暗黙的な制御を提供するには、オブジェクトにプロテクト Finalize を実装します (C# および C++ のデストラクタ構文)。そのオブジェクトへの有効な参照がなくなった後で、ガベージ コレクタがこのメソッドを呼び出します。
と説明しています。ここで言及されている「暗黙的な方法」が実装されていない場合にリソース漏れが発生しますが、それはクラスライブラリのバグです。- 回答としてマーク クサキ 2009年11月13日 0:29
-
>それは設計が悪いです。
>「暗黙的な方法」が実装されていない場合にリソース漏れが発生しますが、それはクラスライブラリのバグです。
とは言え、「暗黙的な方法」だけに頼るのはよくありません。
「暗黙的な方法」が実装されていても、それが効果を発揮するのは、アンマネージリソースをカプセルするオブジェクトがGCによって回収される時になります。
なので、アンマネージリソースをカプセルするオブジェクトインスタンスがユーザコード内での意味を失ってからGCによってそのインスタンスが回収されるまでの期間、リソースリークと同等の状態が発生します。
(例えば FileStream のインスタンスを Close() しないでうっちゃらかしておくと、FileStream のインスタンスがGCによって回収するまで、そのファイルの読み書きができない、などの不都合が発生し得ます。)
# 「その状態をリソースリークと呼ぶのは不適切である」という意見はあるかもしれませんが。
なので、特別な理由が無い限り、アンマネージリソースをカプセルするオブジェクトインスタンスに対しては、そのオブジェクトインスタンスの寿命をプログラマやフレームワークが明示的に管理するのが基本パターンであるべきと思います。- 回答としてマーク クサキ 2009年11月13日 0:29
-
「GCに回収されるまでタイムラグがある」というのは表現ならわかりますし、IDisposableによる解放をした方がいいことも賛成です。しかし元コメントは「解放の対象になりません」と言い切っているので、この点は間違ってると思い指摘しました。
う~んmmm、言葉尻だけを捕らえて突っ込まれるのも何かと。
あと、WinFormのControlおよびその派生クラスのように、IDisposableでありながら別フレームワークで解放するものもありますし。そのためDispose()不要ですよね。
プログラムの設計ミスを全て GC が綺麗に片付けてくれるわけではありませんよね?
だから
> .NET でも、きちんと解放処理を書かないとリソース漏れを起こします。
と最初に書いているわけなんですが。 -
う~んmmm、言葉尻だけを捕らえて突っ込まれるのも何かと。
別に言葉尻をとらえてのつもりはありません。
プログラムの設計ミスを全て GC が綺麗に片付けてくれるわけではありませんよね?
だから
> .NET でも、きちんと解放処理を書かないとリソース漏れを起こします。
と最初に書いているわけなんですが。
きちんと解放処理を書かないユーザーのためにもクラスライブラリ設計者は暗黙的な解放を実装しなければならない、というのがリンク先の記述です。
ちなみにひらぽんさんの示したリンク先(Yahoo)の記述も間違ってるし…。Environment.Exit()は解放処理をせずプロセスを終了させます。例えば、usingブロックの中でEnvironment.Exit()を呼び出してもブロックを抜けているわけではないのでDispose()を呼びません。
私のリンクしたMSDNの記述を読んでいただけたらと思います。
# それを理解した上で、Dispose()した方がbetterというのが渋木さんのコメントだと思います。 -
「GCに回収されるまでタイムラグがある」というのは表現ならわかりますし、IDisposableによる解放をした方がいいことも賛成です。しかし元コメントは「解放の対象になりません」と言い切っているので、この点は間違ってると思い指摘しました。
ざっと読んでみて、それぞれの投稿が「何に対して言及しているか」に迷いました。
今回の話題の中心となっている、Graphics クラスに対してに限った狭い話であれば、ファイナライザが定義されているためにいずれ回収されるので「解放の対象になりません」は誤りと言えます。
しかし、自作クラスを含めたクラスデザインという広い話であれば、「きちんと設計しないとリソース漏れを引き起こす」(「解放の対象になりません」)ということが正しいでしょう。
質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に困った第三者の方が検索しやすくなります。- 回答としてマーク クサキ 2009年11月13日 0:29
-
皆様には、私が引き起こした回答に付き合っていただき、誠に感謝いたします。m(_ _;)m
私としましては、
Dispose()に関して追加の質問をさせてください。
・・・ 中略 ・・・
これまで、Graphics.FromHwndを使っていましたが、Dispose()を
書いていませんでしたが、特に問題を起こしていませんでした。
C#はガベージコネクションが解放するので必要ないと思っていましたが、必要ないのは配列だけということですか?
に反応し、「Dispose 全般」 に関する質問と捉えて
> .NET でも、きちんと解放処理を書かないとリソース漏れを起こします。
つまり・・・
「使い終わったなら、きちんと Dispose しましょうよ」
という意味で、回答させて頂いた次第なわけです。言葉足らずで誤解を招いたのなら謝ります。 -
>「使い終わったなら、きちんと Dispose しましょうよ」
↑は、多くの場合正しいです。
でも、「IDisposable インターフェースを実装しているオブジェクトインスタンスがプログラマ視点で不要になったら、必ずユーザコード中で IDisposable.Dispose() 呼び出しを行わなくてはならない」というものでもないんです (^^;
既に別の例も出てますが、例えば、Control.Paint イベントで渡されてくる Graphics なんかは Windows Forms のフレームワークが寿命を管理しているので、これは、プログラマ視点で「不要」と判断しても、ユーザコードで勝手に Dispose() してはいけません。
その辺理解はされているんでしょうが、言い切ってしまうと↑のようなパターンをばっさり切り捨てることになるので、物言いがついたものと思います。
あと、「リソースリーク」という言葉は「アプリケーション終了まで決して解放されるチャンスがない状態」というのが古典的な意味なので、「ファイナライザによって回収されるチャンスが用意されている以上、それはリソースリークではない」というのは正論です。
ただ、個人的には、オブジェクトインスタンスがユーザコード上での参照を失ってからGCによって回収されるまでの期間に関して注目すれば、ユーザコードもフレームワークも手出しできない状態でオブジェクトインスタンス(と結びつけられたアンマネージリソース)が居座っている(かつ居座ることが他の不都合につながり得る)ので、この状態を「リソースリーク」と呼んでしまっても別に差し支えないかな、と思います。
この状態を指し示す、簡潔で分かりやすい語があればいいんでしょうけど、「リソースリークのような状態」程度しか思い浮かびません (^^;
# ちゃんとした用語があるのかな? -
>「使い終わったなら、きちんと Dispose しましょうよ」
↑は、多くの場合正しいです。
でも、「IDisposable インターフェースを実装しているオブジェクトインスタンスがプログラマ視点で不要になったら、必ずユーザコード中で IDisposable.Dispose() 呼び出しを行わなくてはならない」というものでもないんです (^^;
既に別の例も出てますが、例えば、Control.Paint イベントで渡されてくる Graphics なんかは Windows Forms のフレームワークが寿命を管理しているので、これは、プログラマ視点で「不要」と判断しても、ユーザコードで勝手に Dispose() してはいけません。
その辺理解はされているんでしょうが、言い切ってしまうと↑のようなパターンをばっさり切り捨てることになるので、物言いがついたものと思います。
ありがとうございます。言い切ったのはまずかったですね。(-ω-;「リソース漏れを起こす可能性があります」
程度に留めておけばよかったです。
また 「暗黙的な方法」 という言葉は知りませんでしたが、私としては「Dispose~Finalise パターン」
という言葉で理解しています。
「クラス ライブラリ開発のデザインガイドライン」 は一通り目を通しておりましたので、
「Dispose が呼び出されることを前提にはしないでください。Dispose が呼び出されなかった場合は、型が所有するアンマネージ リソースも Finalize メソッドで解放する必要があります。」
ということには特に意識しているつもりです。
実際、現在使っている某ベンダー製の ActiveX が明示的に Dispose しないと怪しい挙動を引き起こすため
使用クラス側では、Dispose が呼ばれなかった場合を考慮して、Finalize では必ず Dispose を呼ぶ仕様にしております。いずれにせよ、GC とアンマネージリソースと .NET のクラスライブラリの関連についていろいろ疑問が生じてきたため、
別スレッドを立てて質問をさせて頂きたいと思います。 -
>また 「暗黙的な方法」 という言葉は知りませんでしたが、私としては
>「Dispose~Finalise パターン」「暗黙的な方法」という用語があるわけではありませんが、Dispose() メソッド呼び出しや using 句などによる明示的な IDisposable.Dispose() メソッド呼び出しに対して、ファイナライザによるユーザコードやフレームワークなどとは関わりなくアンマネージリソースの解放が行われることを指す語であるものと思います。
>実際、現在使っている某ベンダー製の ActiveX が明示的に Dispose しないと怪しい挙動を引き起こすため
えーとですね、ActiveX (COM) と Dispose の間には本質的な関係はありません。
COM は .NET 以前の技術なので、COM オブジェクトインスタンスの寿命は .NET のオブジェクトインスタンスとはまったく異なる仕組みで管理されます。
.NET から COM オブジェクトのインスタンスを扱う場合、.NET 用のラッパクラスを生成して利用するはずですが、このラッパクラスは IDisposable を実装していなかったはずです。
なので
>使用クラス側では、Dispose が呼ばれなかった場合を考慮して、Finalize では必ず Dispose を呼ぶ仕様にしております。
は、COM オブジェクトインスタンスの寿命管理を明示的に行う、という目的には真正面からは合致していません。
間接的に COM オブジェクトインスタンスの解放を速める効果がある場合もあるし、そうでない場合も十分考えられます。
-
> COM は .NET 以前の技術なので、COM オブジェクトインスタンスの寿命は
> .NET のオブジェクトインスタンスとはまったく異なる仕組みで管理されます。
それは一応承知しているつもりです。(^ω^;
> NET から COM オブジェクトのインスタンスを扱う場合、.NET 用のラッパクラスを生成して利用するはずですが、
> このラッパクラスは IDisposable を実装していなかったはずです。
いや、それがですね・・・COM のラッパクラスにしっかりあるんです。
オブジェクトブラウザで追跡したら、ActiveX コントロールなので AxHost クラスがラッピングしていますね。(^ω^;
でも普通のコントロールのように貼り付れば、
後はコンテナオブジェクト側で自動的に解放処理が行われるだろうと思っていたら、
アプリケーションの終了時に COMException が頻発しまくるのでベンダーに尋ねたら、
「コンテナオブジェクトの終了時に、明示的に Dispose してください」
と回答されました。で、結局こんな処理を・・・(-ω-;''' <summary> ''' <see>某Control</see> のリソースを解放 ''' </summary> Protected Overrides Sub Dispose(ByVal disposing As Boolean) Try ' 強制的に COM コントロールを解放 If (Me.ほげcom1 IsNot Nothing) Then Me.ほげcom1.Dispose() End If If (Me.ほげcom2 IsNot Nothing) Then Me.ほげcom2.Dispose() End If If (Me.ほげcom3 IsNot Nothing) Then Me.ほげcom3.Dispose() End If If (Me.ほげcom4 IsNot Nothing) Then Me.ほげcom4.Dispose() End If If (disposing) Then If (components IsNot Nothing) Then components.Dispose() End If GC.SuppressFinalize(Me) End If Finally MyBase.Dispose(disposing) End Try End Sub ''' <summary> ''' デストラクタ ''' </summary> Protected Overrides Sub Finalize() Dispose(False) End Sub
問題の ActiveX は VC6 製で、実は我々は .NET でのファーストユーザーとのことですが。(汗
ベンダーさんに対しては 「COM は古いから、早く .NET アセンブリで出してくれ」 と催促してますが、
どうやら 1~2年は確実に無理そうですw -
>> NET から COM オブジェクトのインスタンスを扱う場合、.NET 用のラッパクラスを生成して利用するはずですが、
>> このラッパクラスは IDisposable を実装していなかったはずです。
>
>いや、それがですね・・・COM のラッパクラスにしっかりあるんです。
>オブジェクトブラウザで追跡したら、ActiveX コントロールなので AxHost クラスがラッピングしていますね。(^ω^;
ActiveX コントロールだからですかね?
ずいぶん前に COM オブジェクト(ActiveX DLL)のラッパ見て「ないのかー」とがっかりした記憶があるんですが。
でも
>「コンテナクラスの終了時に、明示的に Dispose してください」
はちょっと解せないなぁ。
ActiveX コントロールってことは Form 上に配置するわけで、親 Form (やその配下のコンテナ)に Controls.Add() されてるわけですよね?
であれば、親 Form が Clsoe() される時に、ActiveX コントロールも Dispose() されると思うんですが。 -
でも
>「コンテナクラスの終了時に、明示的に Dispose してください」
はちょっと解せないなぁ。
ActiveX コントロールってことは Form 上に配置するわけで、親 Form (やその配下のコンテナ)に Controls.Add() されてるわけですよね?
であれば、親 Form が Clsoe() される時に、ActiveX コントロールも Dispose() されると思うんですが。
いまベンダーさんとのやり取りを読み返してみたら、COMException ではなく正確には
System.Runtime.InteropServices.InvalidComObjectException
「基になる RCW から分割された COM オブジェクトを使うことはできません」
でした。
これがアプリ終了時に頻発しまくり、まともに終了できないという問題が発生しておりました。
ベンダーさんからは 「コンテナオブジェクトの解放時に明示的に Dispose して下さい」 という回答とともに、
修正版を送っていただいて一応問題は片付きましたが、私も解せない感がありますです。(-ω-; -
あと追記ですが、
ActiveX コントロールだからですかね?
ずいぶん前に COM オブジェクト(ActiveX DLL)のラッパ見て「ないのかー」とがっかりした記憶があるんですが。
ですね。AxHost クラスは System.Windows.Forms.Control を継承してました。
AxHost クラスの解説には
「ActiveX コントロールをラップし、完全な機能を備えた Windows フォーム コントロールとしてそのコントロールを公開します。 」
とありますです。 -
最後に試したのが夏だったので、今後の参考のため、いま一度 「明示的な Dispose 」 を外してデバッグ実行を繰り返してみました。
''' <summary> ''' <see>某Control</see> のリソースを解放 ''' </summary> Protected Overrides Sub Dispose(ByVal disposing As Boolean) Try ' コメントアウト!
' If (Me.ほげcom1 IsNot Nothing) Then ' Me.ほげcom1.Dispose() ' End If ' If (Me.ほげcom2 IsNot Nothing) Then ' Me.ほげcom2.Dispose() ' End If ' If (Me.ほげcom3 IsNot Nothing) Then ' Me.ほげcom3.Dispose() ' End If ' If (Me.ほげcom4 IsNot Nothing) Then ' Me.ほげcom4.Dispose() ' End If If (disposing) Then If (components IsNot Nothing) Then components.Dispose() End If GC.SuppressFinalize(Me) End If Finally MyBase.Dispose(disposing) End Try End Sub ''' <summary> ''' デストラクタ ''' </summary> Protected Overrides Sub Finalize() Dispose(False) End Sub正常に終わる時もあるかと思えば、
不定期で System.Runtime.InteropServices.InvalidComObjectException が発生したり、
例外は発生しないもののいつまで立ってもデバッグが停止しなかったり!駄目だこりゃ!! ><
逆に明示的に Dispose をしている分には問題ありません。それともそう見えるだけ? (謎
まぁ、そもそも VC6 時代のActiveX を .NET3.5 で動かすのに無理があるのでしょうね。。。(汗
#かなりスレの本題とは外れてしまいましたね。すみません。m(_ _;)m