views:

64

answers:

2

Hi all,

I'm trying to AND two bitmaps like this:

        [DllImport("gdi32.dll")]
        public static extern int SetROP2(IntPtr hDC, int nDrawMode);

        const int SRCAND = 0x008800C6;    // AND raster op.

        lock (g.Clip)
        {
            IntPtr pDC = g.GetHdc ();
            SetROP2 (pDC, SRCAND);
            g.DrawImageUnscaled (currentBitmap, bound.Location);
            g.ReleaseHdc (pDC);
        }

But I get an "Object is currently in use elsewhere" exception from the Draw statement. Moving the ReleaseHdc statement before the Draw statement runs, but doesn't use the specified raster op.

The LockBits approach is too slow, since it copies the whole bitmap twice, one of the bitmaps is huge, and this has to happen many times per second.

Any ideas how I can trick .NET into ANDing bitmaps?

+2  A: 
    lock (g.Clip)

This cannot work. You are getting this exception because you use the bitmap in more than one thread. I'd guess at another thread that's drawing the bitmap. To make that work, you have to make sure that the two threads cannot use the bitmap at the same time. And that indeed requires the lock keyword. But on the same lock object. The Graphics instance you use won't be the same. The lock doesn't work.

Create a dedicated locking object that both threads use.

Hans Passant
I've used the same locking object for both places that can draw, but I'm still getting the same error. It works if I take out the SetROP2 call. If the problem was more than one thread using the same bitmap or graphics object, wouldn't the problem remain?
Found a solution: Using a transparent color for the bitmap background gives the same effect in this case. Thanks for the suggestion Hans.
A: 

Though you found a workaround, it is worth noting the actual source of the exception. GDI and GDI+ operations cannot be interleaved - either one or the other can operate at once, but not both.

In your code, calling g.GetHdc() switches the Graphics object into a state where the newly created HDC can be used for GDI rendering. The Graphics object will then be "in use" until calling g.ReleaseHdc(). At this point, the HDC is destroyed, and the Graphics object can then be used again for rendering.

Noting that the HDC returned by the call to GetHdc() was ney created, and only exists until the call to ReleaseHdc(), where it is destroyed, it is apparent why the ROP is not applied to later operations performed by the Graphics object.

If you needed to use GDI ROPs, you would have to do all associated rendering in a pure GDI context - using Bitmap.GetHbitmap() to get the necessary handles. Be aware that similar to Graphics.GetHdc(), the HBITMAP is newly created from the Bitmap, but shares no state with it.

More details about GDI/GDI+ interop are given in KB 311221

Chris Ostler