5

I have been making an application to take snapshots of websites. Everything works well, until now: I have the application take MANY photos, and the process of the image taking is done as following:

using (Graphics graphics = Graphics.FromImage(mBitmap))
{
   IntPtr hdc = graphics.GetHdc();
   SendMessage(new HandleRef(mWebBrowser, mWebBrowser.Handle), 791, hdc, (IntPtr)30);
   BitBlt(new HandleRef(graphics, hdc), 0, 0, mBitmap.Width, mBitmap.Height, new HandleRef(graphics, hdc), 0, 0, 13369376);
   graphics.ReleaseHdc();
}

(this is a varying of the code of DrawToBitmap from the WebBrowser control. taken with ILSpy).

The error occurs on the IntPtr hdc = graphics.GetHdc(); line.

I sought for people asking about this "Parameter is Invalid" when using the GetHdc method, and people said that it might be because of not releasing prior GDI objects. this is not the case, since the Graphics object is withing a using statement, and so is the bitmap...

I need to note that I have many webbrowsers at the same time (I never destroy them, I re-use them, this is for another error which I had and this was the only way I could solve it...)

When I'm looking on the TaskManager on the amount of GDI Object, I see it is a huge amount. But - the error did not occur when I happened to have the most GDI Objects... I guess that this amount of objects comes from the WebBrowsers...?

The original DrawToBitmap code from ILSpy is:

int nWidth = Math.Min(this.Width, targetBounds.Width);
int nHeight = Math.Min(this.Height, targetBounds.Height);
Bitmap image = new Bitmap(nWidth, nHeight, bitmap.PixelFormat);
using (Graphics graphics = Graphics.FromImage(image))
{
    IntPtr hdc = graphics.GetHdc();
    UnsafeNativeMethods.SendMessage(new HandleRef(this, this.Handle), 791, hdc, (IntPtr)30);
    using (Graphics graphics2 = Graphics.FromImage(bitmap))
    {
        IntPtr hdc2 = graphics2.GetHdc();
        SafeNativeMethods.BitBlt(new HandleRef(graphics2, hdc2), targetBounds.X, targetBounds.Y, nWidth, nHeight, new HandleRef(graphics, hdc), 0, 0, 13369376);
        graphics2.ReleaseHdcInternal(hdc2);
    }
    graphics.ReleaseHdcInternal(hdc);
}

The documentation claims that Webbrowser does not support DrawToBitmap, but it works nicely until some stage when it just throws this exception.

svick
  • 236,525
  • 50
  • 385
  • 514
Nati Cohen
  • 230
  • 4
  • 11
  • 1
    There is a system limit to the _total_ amount of available handles. But I thought it was rather high these days. – H H Dec 10 '11 at 22:00
  • I'm a little confused why you're creating multiple `HandleRef`s for the same call. You're probably better off writing `var href = new HandleRef(graphics, hdc)`, and then passing that ref in both places to `BitBlt`. That said, it's apparently not the problem? I also wonder why you're calling `BitBlt` rather than using `Graphics.DrawImage` or somesuch. – Jim Mischel Dec 10 '11 at 22:03
  • The webbrowser is hidden. as I said in the parenthesis, this code was varied from a code taken from ILSPy on System.windows.forms. I did it because I wanted to have a higher degree of control over what happends, instead of just using WebBrowser.DrawToBitmap. Thanks for the comment about the HandleRefs. – Nati Cohen Dec 10 '11 at 22:13
  • 1
    Are you sure that the error is on the call to `graphics.GetHdc`? I'd suspect instead that the problem is in the call to `BitBlt`. If you look at the code from ILSpy, you'll see that it's using two different device contexts. Your call to `BitBlt` is using the same DC for the source and destination. Your code is trying to copy an image onto itself. The `WebBrowser` code is copying from one bitmap to another. – Jim Mischel Dec 11 '11 at 00:06
  • I have checked and the error definitely happends on the GetHdc. I.did chanhe the code,but the fact is that it qaworks until I get the error. – Nati Cohen Dec 12 '11 at 17:44

1 Answers1

1

Even this post is very old I want to help to solve this problem, because I had the same and I solved it this way:

private static Graphics graphics = null;
private static IntPtr hdc = IntPtr.Zero;
private static IntPtr dstHdc = IntPtr.Zero;

private static Capture()
{
    if (graphics == null)
    {
       hdc = GetDC(IntPtr.Zero);
       graphics = Graphics.FromImage(bitmap);
       dstHdc = graphics.GetHdc();
    }
    BitBlt(dstHdc, 0, 0, screen_resolution.Width, screen_resolution.Height, hdc, 0, 0, RasterOperation.SRC_COPY);
}

The solution for me was, that I call graphics.GetHdc() only one time when the object is Zero. After that I never use call graphics.GetHdc().

nxexo007
  • 37
  • 2