DOBON.NET DOBON.NETプログラミング掲示板過去ログ

連続して画面をキャプチャする方法

環境/言語:[OS : Windows XP / 言語 : C# / .NET Framework : 3.5]
分類:[.NET]

2010/12/23(Thu) 02:42:12 編集(管理者)

【解決したい問題】

連続して画面をキャプチャするアプリケーションを作成したく
奮闘中です。

【解決するために何をしたか】

DOBON.NET様の「画面をキャプチャする」(以下URL)
http://dobon.net/vb/dotnet/graphics/screencapture.html
のソースを使用し、以下の関数を作成しました。
--------------------------------------------------------

public static Bitmap Capture()
{
//Bitmapの作成
Bitmap bmp = new Bitmap(Screen.PrimaryScreen.Bounds.Width,
Screen.PrimaryScreen.Bounds.Height); //←ArgumentException発生

//Graphicsの作成
Graphics g = Graphics.FromImage(bmp);
//画面全体をコピーする
g.CopyFromScreen(new Point(0, 0), new Point(0, 0), bmp.Size);
//解放
g.Dispose();

return bmp;
}
--------------------------------------------------------

--------------------------------------------------------
public static Bitmap Capture2()
{
//プライマリモニタのデバイスコンテキストを取得
IntPtr disDC = GetDC(IntPtr.Zero);
//Bitmapの作成
Bitmap bmp = new Bitmap(Screen.PrimaryScreen.Bounds.Width,
Screen.PrimaryScreen.Bounds.Height);
//Graphicsの作成
Graphics g = Graphics.FromImage(bmp);
//Graphicsのデバイスコンテキストを取得
IntPtr hDC = g.GetHdc(); //←ArgumentException発生
//Bitmapに画像をコピーする
BitBlt(hDC, 0, 0, bmp.Width, bmp.Height,
disDC, 0, 0, SRCCOPY);
//解放
g.ReleaseHdc(hDC);
g.Dispose();
ReleaseDC(IntPtr.Zero, disDC);

return bmp;
}
--------------------------------------------------------
上記関数を以下のようなforループで呼び出したところ、
for( int i = 0 ; i < 1000 ; i++ )
{
Capture();
}
87〜9回目で、上記関数のコメントをつけた部分でArgumentExceptionが発生してしまいました。

【追加事項】

ArgumentExceptionの詳細は以下のとおりです。
複数回呼び出す場合には何か特別な処理をしないといけないものでしょうか?

System.ArgumentException はハンドルされませんでした。
Message="使用されたパラメータが有効ではありません。"
Source="System.Drawing"
StackTrace:
場所 System.Drawing.Bitmap..ctor(Int32 width, Int32 height, PixelFormat format)
場所 System.Drawing.Bitmap..ctor(Int32 width, Int32 height)
場所 Mng.RF.Drawing.ScreenShot.Capture2() 場所 Z:\xxxxxxx.xxxxxxxxx\VisualStudio projects\Mng.RF.Drawing\Mng.RF.Drawing\ScreenShot.cs:行 78
場所 Mng.RF.Drawing.Debug.MainForm.button3_Click(Object sender, EventArgs e) 場所 Z:\xxxxxxx.xxxxxxxxx\VisualStudio projects\Mng.RF.Drawing\Mng.RF.Drawing.Debug\MainForm.cs:行 64
場所 System.Windows.Forms.Control.OnClick(EventArgs e)
場所 System.Windows.Forms.Button.OnClick(EventArgs e)
場所 System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
場所 System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
場所 System.Windows.Forms.Control.WndProc(Message& m)
場所 System.Windows.Forms.ButtonBase.WndProc(Message& m)
場所 System.Windows.Forms.Button.WndProc(Message& m)
場所 System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
場所 System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
場所 System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
場所 System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
場所 System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
場所 System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
場所 System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
場所 System.Windows.Forms.Application.Run(Form mainForm)
場所 Mng.RF.Drawing.Debug.Program.Main() 場所 Z:\xxxxxxx.xxxxxxxxx\VisualStudio projects\Mng.RF.Drawing\Mng.RF.Drawing.Debug\Program.cs:行 18
場所 System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
場所 System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
場所 Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
場所 System.Threading.ThreadHelper.ThreadStart_Context(Object state)
場所 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
場所 System.Threading.ThreadHelper.ThreadStart()
InnerException:
2010/12/23(Thu) 02:42:38 編集(管理者)

■No27880に返信(katoraさんの記事)
> public static Bitmap Capture()
> public static Bitmap Capture2()
これらのメソッドが返す Bitmap は、その後、
使い終わった後で Dispose していますか?

> 場所 Z:\xxxxxxx.xxxxxxxxx\
# 個人名?
Bitmap クラスや Graphics クラスが内部的に利用している GDI+ はメモリ不足の時に引数が不正というエラー(.NET では ArgumentException)といったよくわからないエラー(例外)を出すことがあります。

解決策としては、魔界の仮面弁士さんが書かれていますように、不要な Bitmap を Dispose することが最初にすべきことでしょうか。
>魔界の仮面弁士 様
>Azulean 様
アドバイスありがとうございます。
お二人のおっしゃるとおりBitmapオブジェクトをDisposeする
以下のコードに修正することで例外が発生しなくなりました。

for( int i = 0 ; i < 1000 ; i++ )
{
//Capture();
Bitmap bmp = Capture();
bmp.Dispose();
}

>魔界の仮面弁士様
ディレクトリ名は私が好きな漫画家さんのお名前からお借りしたものです
今にして思えばそれをそのまま使用するのは不適切であったかと思います。
できれば修正、または削除をしたいところですが
投稿する際に削除キーを設定するのを失念してしまい、
修正することができませんでした。。。
やはり最初に設定をしなかったら手の打ちようがないものでしょうか?
2010/12/23(Thu) 01:30:32 編集(投稿者)

■No27885に返信(katoraさんの記事)
> 投稿する際に削除キーを設定するのを失念してしまい、
> 修正することができませんでした。。。
> やはり最初に設定をしなかったら手の打ちようがないものでしょうか?

その旨をここで書いておけば良いと思います。
どの部分をどのように削りたいか、理由も添えて。

数日反応がないようであれば、メールフォームを利用するのも手でしょうか。
http://dobon.net/cgi-bin/mail/index.html
No27880 と No27881 について、人の名前と思われる箇所を「xxxxxxx.xxxxxxxxx」で置換しました。それ以外も修正が必要でしたら、修正が必要な箇所とその理由をお知らせください。

よろしくお願いいたします。
>Azulean 様
アドバイスありがとうございます。
今回の件大変勉強になりました。

>管理人様
師走のお忙しいところにも関わらず
迅速なご対応を下さり感謝いたします。
お手を煩わせることとなり申し訳ありませんでした。

以下に本件のまとめをし、解決済みとさせていただきます。
【現象】
Bitmapオブジェクトを連続して作成した際、
GDI+が関係してくるコードでArgumentExceptionが発生する。

【原因】
作成されたBitmapオブジェクトがメモリを圧迫し、
メモリ不足が発生したため、GDI+が例外を出した。

【対応】
不要となったBitmapオブジェクトを明示的にDisposeする。


魔界の仮面弁士様、Azulean様、管理人様
そして本件に係る原因を調査してくださいました皆様
本当にありがとうございました。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板