- PR -

.net2005 C# BackgroundImageをオーバーライドするとOutOfMemoryになってしまいます

投稿者投稿内容
katudon
会議室デビュー日: 2007/04/26
投稿数: 13
投稿日時: 2007-05-08 22:55
いつもお世話になっております。
ユーザコントロールにてBackgroundImageをオーバーライドするとgetの際に何度もgetを呼び出しOutOfMemoryで落ちてしまいます。
overrideする目的としては、private属性のImageデータを保持して、setの際にImageデータに保存しようとする目論見でしたが、逆のgetのときに発生してしまいます。
Image mImage;

public override Image BackgroundImage{
get {
return mImage;
}
set {
mImage = value;
}
}
前にFontプロパティがアンビエントだと気づかずに同じことをやらかしましたが、
BackgroundImageはアンビエントプロパティではないのでなぜこのような現象がおきているのは不思議です。

同件だと思いますが、カスタムコントロール内の公開関数からBackgoundImageにImageをセットすると、同様にOutOfMemoryで落ちます。
このような関数です。
void SetIamage(Image inImage)
{


if (BackgroundImage != null) BackgroundImage.Dispose();
BackgroundImage = inImage;
Refresh();
return;
}
単純なことだとは思いますが、数日どうしても解決できずにおります。
どなたかご教唆いただければ幸いです。
囚人
ぬし
会議室デビュー日: 2005/08/13
投稿数: 1019
投稿日時: 2007-05-08 23:33
試しましたが発生しません。
現象が発生する最低限のコードをお願いします。
_________________
囚人のジレンマな日々
katudon
会議室デビュー日: 2007/04/26
投稿数: 13
投稿日時: 2007-05-09 11:48
囚人様>
ありがとうございます。ソースが50ぐらいありますので別プロジェクトにて整理します。少々お待ちください。
katudon
会議室デビュー日: 2007/04/26
投稿数: 13
投稿日時: 2007-05-11 13:06
お世話になっております。
下記のカスタムコントロールを作成した際の現象です。

動的にこのコントロールを生成して表示しようとするとSystem.OutOfMemoryが発生してしまいます。
デザインモードで追加しようとした場合、
System.Runtime.InterServices.ExternalException:GDI+で汎用エラーが発生しました。
でエラーになってしまいます。
過去のログに似た記事を発見し、下記のwImage.Dispose()を入れてみましたが、この場合、ArgumentExceptionが発生するため、現在コメントアウトしています。

HashTableを使用しているのが問題なのかと思いますが、解決策が見当たりません。
GDI+で汎用エラーが発生しましたにつきましては、バグのような記事もありましたが、現段階でそのような結論付けをするわけにもいかず、困っております。
ご教唆よろしくお願いいたします。


using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Diagnostics;
using System.ComponentModel;
using System.Collections;


namespace ControlLibrary
{
public partial class MyControl :System.Windows.Forms.Control
{
protected Hashtable mHashTable = new Hashtable();
public MyControl () {
ImageRead("xxx.jpg");
}
public override Image BackgroundImage
{
get
{
if (mHashTable["Image"] == null) return null;
return (Image)mHashTable["Image"];
}
set
{
if (mHashTable["Image"] == null) return;
mHashTable["Image"] = value ;
}
}
protected override void OnPaint(PaintEventArgs pe)
{
Image wImage = (Image)mHashTable["Image"];
if (wImage != null) {
Graphics g = pe.Graphics;
g.DrawImage(wImage, new Rectangle(0, 0, wImage.Width, Height));
} else {
base.OnPaint(pe);
}
}
public bool ImageRead(string inFileName) {
if (inFileName.Length == 0) return false;
try {
System.IO.FileStream wFileStream =
new System.IO.FileStream(inFileName, System.IO.FileMode.Open);
Image wImage = new Bitmap(wFileStream);
wFileStream.Close ();
wFileStream.Dispose ();
mHashTable.Add("Image", wImage);
wImage.Dispose();
} catch(System.IO.FileNotFoundException e) {
MessageBox.Show ("FileNotFound:" + inFileName + ":" + e.ToString());
return false;
} catch (Exception e) {
MessageBox.Show ("Exception:" + inFileName + ":" + e.ToString());
return false;
}
return true;
}

}
}

katudon
会議室デビュー日: 2007/04/26
投稿数: 13
投稿日時: 2007-05-11 13:11
すみません。ソースの掲載を間違えました。
再度掲載させていただきます。
xxx.jpgは適当な画像を当てていただければと思います。

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Diagnostics;
using System.ComponentModel;
using System.Collections;


namespace ControlLibrary
{
public partial class MyControl :System.Windows.Forms.Control
{
protected Hashtable mHashTable = new Hashtable();
public MyControl () {
ImageRead("jsa.jpg");
}
public override Image BackgroundImage
{
get
{
if (!mHashTable.Contains("Image")) return null;
return (Image)mHashTable["Image"];
}
set
{
if (!mHashTable.Contains("Image")) return;
mHashTable["Image"] = value ;
}
}
protected override void OnPaint(PaintEventArgs pe)
{
// TODO: カスタム描画コードをここに追加してください。
if (mHashTable.Contains("Image")) {
Image wImage = (Image)mHashTable["Image"];
Graphics g = pe.Graphics;
g.DrawImage(wImage, new Rectangle(0, 0, wImage.Width, Height));
} else {
base.OnPaint(pe);
}
}
public bool ImageRead(string inFileName) {
if (inFileName.Length == 0) return false;
try {
System.IO.FileStream wFileStream =
new System.IO.FileStream(inFileName, System.IO.FileMode.Open);
Image wImage = new Bitmap(wFileStream);
wFileStream.Close ();
wFileStream.Dispose ();
mHashTable.Add("Image", wImage);
//wImage.Dispose();
} catch(System.IO.FileNotFoundException e) {
MessageBox.Show ("画像ファイルが消失しました。" + inFileName + ":" + e.ToString());
return false;
} catch (Exception e) {
MessageBox.Show ("画像ファイル読み込みでエラーが発生しました" + inFileName + ":" + e.ToString());
return false;
}
return true;
}

}
}
囚人
ぬし
会議室デビュー日: 2005/08/13
投稿数: 1019
投稿日時: 2007-05-11 20:21
引用:

HashTableを使用しているのが問題なのかと思いますが、解決策が見当たりません。


そう思うなら、そういうところを除いて試してみるとかして、問題点を絞っていくとよいです。
適当にコードを追加してみたり削除してみたりして行き当たりばったりでやっても複雑になるだけです。まずはドキュメントを読んでみましょう。

以下、Bitmap クラスの Stream を引数に持つコンストラクタのドキュメントです。

「Bitmap の有効期間の間は、このストリームを開いておく必要があります。」

これで、エラーになってしまう理由は分かりますね

本題とは逸れますが、わざわざオーバーライドしている意図が分かりません。意味がある処理なのでしょうか?
_________________
囚人のジレンマな日々
katudon
会議室デビュー日: 2007/04/26
投稿数: 13
投稿日時: 2007-05-11 21:21
囚人さん
ありがとうございます。
Bitmapの有効期限の間は、このストリームを開いておくという点については、Disposeが余計だということで、理解しております。

目的としては、マウスオーバー、マウスダウンの際に表示する画像が変わるカスタムコントロールを作成しようとしておりました。
このため、画像をHashTableにて複数個保有し、マウスの状態に応じて画像を変更しようという意図だったのですが、BackgroundImageについてもこのHashTableでまとめて管理できないかと考えた次第です。
BackgroundImageは使用しないようにして、OnPaint側で対処することにします。
BackgroundImageが何度もコールされる件については、原因がわかりましたら、改めて報告させていただきます。

ご教唆いただきありがとうございました。
囚人
ぬし
会議室デビュー日: 2005/08/13
投稿数: 1019
投稿日時: 2007-05-11 21:32
引用:

BackgroundImageが何度もコールされる件については、原因がわかりましたら、改めて報告させていただきます。


あ、すみません。本題を忘れていました。

BackgroundImage が何度もコールされたとしても、別にメモリ不足(OutOfMemryException)にならないと思います。新しい画像を生成してるわけでも新しいインスタンスを作成しているわけでもないので。

まぁ提示されているコードには原因なさそうです。

また本題と逸れますが
コード:
protected override void OnPaint(PaintEventArgs pe) 
{ 
	// TODO: カスタム描画コードをここに追加してください。 
	if (mHashTable.Contains("Image")) { 
		Image wImage = (Image)mHashTable["Image"]; 
		Graphics g = pe.Graphics; 
		g.DrawImage(wImage, new Rectangle(0, 0, wImage.Width, Height)); 
	} else { 
		base.OnPaint(pe); 
	} 
} 


よっぽどの理由がない限り、base.OnePaint() は呼んでおいたほうが良いです。そうでないと MyControl のクライアントが Paint イベントを受け取れません。
_________________
囚人のジレンマな日々

スキルアップ/キャリアアップ(JOB@IT)