C#图形.CopyFromScreen”;参数无效”;

本文关键字:无效 参数 图形 CopyFromScreen | 更新日期: 2023-09-27 18:15:48

我在C#中制作了一个应用程序,它将连续执行屏幕捕获,并使用计时器将其显示在PictureBox中。运行几秒钟后,出现ArgumentException。

下面是代码和具有ArgumentException 的行

private void timer1_Tick(object sender, EventArgs e)
    {
        Rectangle bounds = Screen.GetBounds(Point.Empty);
        Graphics graphics;
        Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height);
        using (graphics = Graphics.FromImage(bitmap))
        {
            graphics.CopyFromScreen(0, 0, 0, 0, new Size(bounds.Width , bounds.Height )); // ArgumentException
            pictureBox1.Image = bitmap;
            pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
        }
    }

除此之外,我还注意到,在运行应用程序几秒钟后,Windows发出了内存不足的警报。

关于解决这个问题有什么建议吗?

C#图形.CopyFromScreen”;参数无效”;

您一直在picturebox中设置一个新位图,而以前的位图永远不会被丢弃。过了一段时间,系统缺少GDI句柄和/或内存(运行您的代码时,我在不到15秒内消耗了一GB内存(。

您可以简单地重用现有位图:

Rectangle bounds = Screen.GetBounds(Point.Empty);
Image bitmap = pictureBox1.Image ?? new Bitmap(bounds.Width, bounds.Height);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
    graphics.CopyFromScreen(0, 0, 0, 0, new Size(bounds.Width, bounds.Height));
    if (pictureBox1.Image == null)
    {
        pictureBox1.Image = bitmap;
    }
    else
    {
        pictureBox1.Refresh();
    }
}

您也不必在每次迭代中重置pictureBox1.SizeMode


或者,您可以手动处理以前的位图:

Rectangle bounds = Screen.GetBounds(Point.Empty);
Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
    graphics.CopyFromScreen(0, 0, 0, 0, new Size(bounds.Width, bounds.Height));
    using (Image prev_bitmap = pictureBox1.Image)
    {
        pictureBox1.Image = bitmap;
    }
}
   pictureBox1.Image = bitmap;

是的,当你经常更新图片框时,你的程序不会持续太久。Bitmap类是一个奇异的.NET类,其中IDisposable不能被轻易忽略。它就像一座冰山,位图可以使用大量的非托管内存,但很少使用托管内存。当不再使用位图时,必须处置位图,以防止位图为其像素数据占用所有可用的非托管内存。垃圾收集器倾向于隐藏这个问题,但如果运行频率不够高,它就无法做到这一点。位图的托管部分太小,无法经常触发集合。修复:

   if (pictureBox1.Image != null) pictureBox1.Image.Dispose();
   pictureBox1.Image = bitmap;

以下知识库有助于理解此问题:位图和图像构造函数依赖

GDI+,因此System.Drawing命名空间,可能会推迟对原始图像比特进行解码,直到图像需要这些比特为止。此外,即使在图像被解码之后,GDI+也可能确定丢弃大位图,稍后重新解码。因此,GDI+必须能够访问位图或图像生命周期内图像的源位对象

为了保留对源位的访问,GDI+锁定任何源文件,并且强制应用程序维持任何源流的使用寿命位图或图像对象的寿命。

人们必须弄清楚什么时候可以处理这个物体。