新手:为什么我的自制屏幕录音机会崩溃?(c#和windows窗体)
[已解决]奥菲尔的解决方案开箱即用。目前在24华氏度下运行五分钟 我正试图从屏幕上保存图像 基本上,我的问题是,当我减少Thread.sleep(创建一个合适的帧速率)时,程序崩溃。程序崩溃的速度越快,thread.sleep接近0,但我甚至找不到问题所在,因为我从未处理过此类问题(如果是unity3d,我会处理这一切) 我也有一些甜蜜的错误向你走来 System.Drawing.dll中发生类型为“System.ComponentModel.Win32Exception”的未处理异常 错误代码:-2147467259 我建立了一个try-catch(我对它知之甚少),但在几次测试后它也断了,让我看看我是否能得到那个日志新手:为什么我的自制屏幕录音机会崩溃?(c#和windows窗体),c#,video,screenshot,C#,Video,Screenshot,[已解决]奥菲尔的解决方案开箱即用。目前在24华氏度下运行五分钟 我正试图从屏幕上保存图像 基本上,我的问题是,当我减少Thread.sleep(创建一个合适的帧速率)时,程序崩溃。程序崩溃的速度越快,thread.sleep接近0,但我甚至找不到问题所在,因为我从未处理过此类问题(如果是unity3d,我会处理这一切) 我也有一些甜蜜的错误向你走来 System.Drawing.dll中发生类型为“System.ComponentModel.Win32Exception”的未处理异常 错误代码
System.ComponentModel.Win32Exception(0x80004005): The operation completed successfully as System.Drawing.Graphics.CopyFromScreen(Int32 sourceX, Int32 sourceY, Int32 destinationX,Int32 destinationY, Size blockRegionSize)
at Screen_Recorder.Form1.ScreenCapture() in C:Users\Jupiter\Desktop\visual studio experiments\Screen Recorder\ScreenRecorder\Form1.cs:line 35
如果单击“确定”,则会显示:
System.ArgumentException: Parameter is not valid.
at System.Drawing.Bitmap..ctor(Int32 width, Int32 height, PixelFormat format)
at System.Drawing.Bitmap..ctor(int32 width, Int32 height)
at Screen_Recorder.Form1.ScreenCapture() C:Users\Jupiter\Desktop\visual studio experiments\Screen Recorder\ScreenRecorder\Form1.cs:line 32
然后它会无限重复这个错误
不管怎样,我要去睡觉了,明天再去睡觉,但在此之前的任何建议都将不胜感激 内存泄漏
图形
和位图
是一次性对象,使用完后应将其丢弃。您只能使用块将本例中的
图形
放入块中,最后一个位图应在循环的每次迭代中处理。
因此,您的代码应该如下所示:
private void ScreenCapture()
{
while (true)
{
var bm = new Bitmap((int)Math.Round(Screen.PrimaryScreen.Bounds.Width * 1.5),
(int)Math.Round(Screen.PrimaryScreen.Bounds.Height * 1.5));
using (Graphics g = Graphics.FromImage(bm)) g.CopyFromScreen(0, 0, 0, 0, bm.Size);
// As per the comment by HansPassant - the following would cause
// a thread race with the UI thread.
//this.pictureBox1.Image?.Dispose();
//this.pictureBox1.Image = bm;
// Instead we use beginInvoke to run this on the UI thread
Action action = () =>
{
this.pictureBox1.Image?.Dispose();
this.pictureBox1.Image = bm;
};
this.BeginInvoke(action);
Thread.Sleep(250);
}
}
这个循环永远不会结束(因为<代码>(true)”,也许您应该考虑添加<代码>取消标记->代码>,使用<代码>任务<代码>,而不是<代码>线程< /代码>。
还有最后一件事,完成后也应该处理picturebox本身。这是一个原因,一个非常常见的原因,但不是唯一的原因。Image属性不是线程安全的,在UI线程绘制图像的同时调用Dispose()将不会有好的结果。失败的几率要低得多,但不是零,因此调试起来要困难得多。@HansPassant我不确定我是否完全理解您的意思,但是如果我们保存对映像的引用,设置新映像,然后处理旧映像呢?这能解决问题吗?不,这仍然是一场线程竞赛,因为Paint()方法可能正在运行中,并且正在使用旧的引用。冷硬的事实是,您必须使用BeginInvoke()以便代码在UI线程上运行。或者调用该部分?必须在UI线程上运行映像属性分配和Dispose调用。另外一个问题是firehose问题,当工作线程创建位图的速度快于UI线程显示位图的速度时,会发生此问题。但是这很容易识别,OP会看到UI线程没有响应。
private void ScreenCapture()
{
while (true)
{
var bm = new Bitmap((int)Math.Round(Screen.PrimaryScreen.Bounds.Width * 1.5),
(int)Math.Round(Screen.PrimaryScreen.Bounds.Height * 1.5));
using (Graphics g = Graphics.FromImage(bm)) g.CopyFromScreen(0, 0, 0, 0, bm.Size);
// As per the comment by HansPassant - the following would cause
// a thread race with the UI thread.
//this.pictureBox1.Image?.Dispose();
//this.pictureBox1.Image = bm;
// Instead we use beginInvoke to run this on the UI thread
Action action = () =>
{
this.pictureBox1.Image?.Dispose();
this.pictureBox1.Image = bm;
};
this.BeginInvoke(action);
Thread.Sleep(250);
}
}