Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Graphics.CopyFromScreen "parameter is not valid"

I had made an app in C# that will perform screen capture continuously and display it in a PictureBox using timer. After running for a few seconds, there was an ArgumentException.

Below is the code and the line that has the 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;

        }
    }

Besides that, I had notices that an alert saying low memory from Windows after running the app for a few seconds.

Any tips on resolving this problem?

like image 711
Boon Avatar asked Jan 27 '26 04:01

Boon


2 Answers

You keep setting a new bitmap to the picturebox, and the previous bitmap is never disposed. After a while, the system runs short of GDI handles and/or memory (running your code, I consumed one gig of memory in under 15 seconds).

You can simply reuse your existing bitmap:

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();
    }

}

You also don't have to reset pictureBox1.SizeMode on each iteration.


Alternatively, you can dispose the previous bitmap manually:

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;
    }
}
like image 131
GSerg Avatar answered Jan 28 '26 18:01

GSerg


   pictureBox1.Image = bitmap;

Yes, your program won't last long when you frequently update the picture box. The Bitmap class is the singular .NET class where IDisposable can't easily be ignored. It is like an iceberg, bitmaps can use massive amounts of unmanaged memory but very little managed memory. You must dispose bitmaps when you no longer use them to prevent them from consuming all available unmanaged memory for their pixel data. The garbage collector tends to hide that problem but it can't do so when it doesn't run frequently enough. And the managed portion of Bitmap is too small to trigger a collection often enough. Fix:

   if (pictureBox1.Image != null) pictureBox1.Image.Dispose();
   pictureBox1.Image = bitmap;
like image 30
Hans Passant Avatar answered Jan 28 '26 20:01

Hans Passant



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!