C#Dispose函数给出错误

时间:2017-07-16 12:49:19

标签: c# winforms bitmap screenshot

我尝试每隔10毫秒拍摄一次屏幕截图并将其设置为带有Timer的Picturebox.image。几秒钟程序运行完美,但几秒后程序崩溃。我尝试在代码末尾使用Dispose()函数来清除内存,但Dispose Function也会出错。 (增加计时器的间隔时间不起作用)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace gameBot
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        public Bitmap screenshot;
        Graphics GFX;
        private void button1_Click(object sender, EventArgs e)
        {
            timer1.enabled = true;
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            takescreenshot();
        }
        private void takescreenshot()
        {

            screenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width, 
            Screen.PrimaryScreen.Bounds.Height);
            GFX = Graphics.FromImage(screenshot);
            GFX.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size);
            pictureBox1.Image = screenshot;
            screenshot.Dispose();              
        }           
    }
}

错误是

  

"未处理的类型' System.ArgumentException'发生在System.Drawing.dll

附加信息:参数无效。"

同样程序在崩溃之前使用了太多的RAM(可能是因为内存不足异常导致崩溃?) As you can see in here

3 个答案:

答案 0 :(得分:1)

我建议改变:

pictureBox1.Image = screenshot;
screenshot.Dispose();

为:

var oldScreenshot = pictureBox1.Image;
pictureBox1.Image = screenshot;
GFX.Dispose();
if (oldScreenshot != null)
    oldScreenshot.Dispose;

确保在分配新屏幕截图时处理旧屏幕截图。

答案 1 :(得分:0)

请参阅Graphics.FromImage()

  

您应该始终调用Dispose方法来释放Graphics和   FromImage方法创建的相关资源。

此外,没有必要将该图形保持在类级别。

考虑到这一点,您只需要:

public Bitmap screenshot;

private void takescreenshot()
{
    if (screenshot != null)
    {
        screenshot.Dispose();
    }

    screenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
    using (Graphics GFX = Graphics.FromImage(screenshot))
    {
        GFX.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size);
    }
    pictureBox1.Image = screenshot;
}

答案 2 :(得分:0)

1)实际上你的第一个问题是“参数无效”。因为你正在处理截图对象。 如果您只尝试运行一次takecreenshot()方法 - 您将收到此错误。我认为这是因为您将对象“屏幕截图”设置为PictureBox1.Image而不是立即处理它。多数民众赞成! PictureBox无法呈现处置对象。

2)尝试在按钮处理程序上修改代码:

    private Object thisLock = new Object();
    private void button1_Click(object sender, EventArgs e)
    {
        Thread thr = new Thread(() =>
        {
            while (true)
            {pictureBox1.Invoke((Action)(() =>
                    {
                        screenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width,
                            Screen.PrimaryScreen.Bounds.Height);
                        GFX = Graphics.FromImage(screenshot);
                        GFX.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0,
                            Screen.PrimaryScreen.Bounds.Size);
                        pictureBox1.Image = screenshot;
                    }));
                }
                Thread.Sleep(10);
        });
        thr.Start();
    }

工作正常!最好的方法是在picturebox完成渲染时获取事件,但我没有找到任何关于此的内容。