トップ回答者
System.Drawing.Graphics.ClipBounds で ArgumentException

質問
-
お世話になります。
DataGridViewを使ったプログラムのメモリリークを調査していた所、Graphics.ClipBoundsでArgumentExceptionが発生しているのを見つけました。
> System.Drawing.dll!System.Drawing.Graphics.ClipBounds.get() 行 4134 C#Graphics.csを確認した所、次のようになっていました。
--------
/// <include file='doc\Graphics.uex' path='docs/doc[@for="Graphics.ClipBounds"]/*' />
/// <devdoc>
/// </devdoc>
public RectangleF ClipBounds {
get {
GPRECTF rect = new GPRECTF(); ←ここで例外int status = SafeNativeMethods.Gdip.GdipGetClipBounds(new HandleRef(this, this.NativeGraphics), ref rect);
if (status != SafeNativeMethods.Gdip.Ok) {
throw SafeNativeMethods.Gdip.StatusException(status);
}return rect.ToRectangleF();
}
}
--------この GPRECTFのソースも見たのですが、引数なしのコンストラクタがありません。
http://referencesource.microsoft.com/#System.Drawing/commonui/System/Drawing/Advanced/GPRECTF.cs実害はないようですが、メモリリークの要因かもしれないので気になっています。
何か関連情報をお持ちの方が見えましたら、お教えください。
回答
-
勘違いをされているようなので…
基本的に例外は何もないところから発生することはありません。ArgumentExceptionのインスタンスがnewされそのコンストラクタ引数に従ってMessageプロパティが設定されます。その後、throw文で例外が投げられるわけですが、その際にStackTraceプロパティが設定されます。
ですので、まずStackTraceプロパティに書かれているメソッドにthrow文があります。メソッド内にthrow文が複数あった場合はMessageなど他のプロパティから推測できます。
# 基本的に、でありExecutionEngineExceptionやStackOverflowExceptionなどなどランタイムが投げる特殊な例外もありますが…。
今回の場合、私の推測が正しければ throw SafeNativeMethods.Gdip.StatusException(status); で投げられており、それはソースコードからも分かるように SafeNativeMethods.Gdip.GdipGetClipBounds(new HandleRef(this, this.NativeGraphics), ref rect); がOk以外のステータスを返したから、と思います。
-
つまり実際は SafeNativeMethods.Gdip.StatusException の throw 処理中に ArgumentException が発生したため、結果として ArgumentException に見えているという理解で良いのでしょうか。
理解力に乏しくですみません。
GdipGetClipBounds が失敗するわけですし、Graphics の状態がおかしいか、呼び出しスレッドがおかしいかなど、周りのコードの問題だと思われます。- 回答としてマーク まさゆき 2015年6月17日 0:27
すべての返信
-
勘違いをされているようなので…
基本的に例外は何もないところから発生することはありません。ArgumentExceptionのインスタンスがnewされそのコンストラクタ引数に従ってMessageプロパティが設定されます。その後、throw文で例外が投げられるわけですが、その際にStackTraceプロパティが設定されます。
ですので、まずStackTraceプロパティに書かれているメソッドにthrow文があります。メソッド内にthrow文が複数あった場合はMessageなど他のプロパティから推測できます。
# 基本的に、でありExecutionEngineExceptionやStackOverflowExceptionなどなどランタイムが投げる特殊な例外もありますが…。
今回の場合、私の推測が正しければ throw SafeNativeMethods.Gdip.StatusException(status); で投げられており、それはソースコードからも分かるように SafeNativeMethods.Gdip.GdipGetClipBounds(new HandleRef(this, this.NativeGraphics), ref rect); がOk以外のステータスを返したから、と思います。
-
つまり実際は SafeNativeMethods.Gdip.StatusException の throw 処理中に ArgumentException が発生したため、結果として ArgumentException に見えているという理解で良いのでしょうか。
理解力に乏しくですみません。
GdipGetClipBounds が失敗するわけですし、Graphics の状態がおかしいか、呼び出しスレッドがおかしいかなど、周りのコードの問題だと思われます。- 回答としてマーク まさゆき 2015年6月17日 0:27
-
だから何もないところからArgumentExceptionが発生することはありません。再度説明しますがnew ArgumentExceptionされたからこそArgumentExceptionが投げられるわけです。
SafeNativeMethods.Gdip.StatusException()はいわゆるexception helper関数であり、statusに応じたExceptionを返す関数であり、statusがInvalidParameterかUnknownImageFormatかPropertyNotFoundかPropertyNotSupportedかFontFamilyNotFoundかFontStyleNotFoundかNotTrueTypeFontの可能性があります。
- 回答の候補に設定 佐祐理 2015年6月17日 0:50
-
>だから何もないところからArgumentExceptionが発生することはありません。
それはわかっています。
わからないのは、誰が new ArgumentException したかでした。
SafeNativeMethods.Gdip.StatusException(status) のソースを確認したら、ArgumentExceptionも投げてました。
-----
internal static Exception StatusException(int status) {Debug.Assert(status != Ok, "Throwing an exception for an 'Ok' return code");
switch (status) {
case GenericError: return new ExternalException(SR.GetString(SR.GdiplusGenericError), E_FAIL);
case InvalidParameter: return new ArgumentException(SR.GetString(SR.GdiplusInvalidParameter));
case OutOfMemory: return new OutOfMemoryException(SR.GetString(SR.GdiplusOutOfMemory));
case ObjectBusy: return new InvalidOperationException(SR.GetString(SR.GdiplusObjectBusy));
case InsufficientBuffer: return new OutOfMemoryException(SR.GetString(SR.GdiplusInsufficientBuffer));
case NotImplemented: return new NotImplementedException(SR.GetString(SR.GdiplusNotImplemented));
case Win32Error: return new ExternalException(SR.GetString(SR.GdiplusGenericError), E_FAIL);
case WrongState: return new InvalidOperationException(SR.GetString(SR.GdiplusWrongState));
case Aborted: return new ExternalException(SR.GetString(SR.GdiplusAborted), E_ABORT);
case FileNotFound: return new FileNotFoundException(SR.GetString(SR.GdiplusFileNotFound));
case ValueOverflow: return new OverflowException(SR.GetString(SR.GdiplusOverflow));
case AccessDenied: return new ExternalException(SR.GetString(SR.GdiplusAccessDenied), E_ACCESSDENIED);
case UnknownImageFormat: return new ArgumentException(SR.GetString(SR.GdiplusUnknownImageFormat));
case PropertyNotFound: return new ArgumentException(SR.GetString(SR.GdiplusPropertyNotFoundError));
case PropertyNotSupported:return new ArgumentException(SR.GetString(SR.GdiplusPropertyNotSupportedError));
-----
ということで、佐祐理様の言われたとおりでした。
ありがとうございました。