Whidbey CopyFromScreen compatible method for V1.1 operation.

A newsgroup user was using GDI to do some image copying from the screen. Now, just about everyone working with GDI always asks the question of whether or not there is a better alternative in .NET and GDI+. Normally there is, and they just don't know about it, so you enlighten these users with the power of the platform. There aren't equivalent screen scraping API's so you have to use the all powerful BitBlt. Since the user wanted a .NET style version, I've tried to stay true to just using available API calls. Note that I'm using a Graphics.FromHwnd hack to get the desktop DC. Even though you can create a Graphics over top of the desktop DC, you still can't use this Graphics object to perform operations on the desktop (at least my latest tests have failed miserably).

[DllImport( "gdi32.dll", CharSet = CharSet.Auto,

SetLastError = true, ExactSpelling = true )]

public static extern int BitBlt(

    HandleRef hDC, int x, int y, int nWidth, int nHeight,

    HandleRef hSrcDC, int xSrc, int ySrc, int dwRop );

 

public static void CopyFromScreen(

    Graphics gfx, int xSource, int ySource,

    int xDest, int yDest, Size blockRegionSize ) {

 

    HandleRef src, dest;

    Graphics hDCDesktop = Graphics.FromHwnd( IntPtr.Zero );

 

    try {

        dest = new HandleRef( null, gfx.GetHdc() );

        src = new HandleRef( null, hDCDesktop.GetHdc() );

 

        int result = BitBlt(

            dest, xDest, yDest,

            blockRegionSize.Width, blockRegionSize.Height,

            src, xSource, ySource, 0xcc0020 );

 

        if ( result == 0 ) { throw new Exception(); }

    } finally {

        if ( dest.Handle != IntPtr.Zero )

            gfx.ReleaseHdc();

        if ( src.Handle != IntPtr.Zero )

            hDCDesktop.ReleaseHdc();

    }

}

Couple of notes. HandleRef? Not sure why they use a HandleRef if they aren't worried about finalizable handles... Probably so that the shared API has a common signature for other cases. I'll leave it in there. I've moved the creation of the refs into the try block in case one of the GetHdc calls fails. In Whidbey I think there may be a resource leak in this method where they aren't accounting for a failure between allocating the first DC and then getting the second DC (they have their refs outside of the try...finally block). Device context handles shouldn't be zero'ed if they are valid, so I check those in order to release the handles in the finally block. Something about the above method just doesn't sit well with me. Doesn't feel clean and safe... I'll get some sleep and think on it more later.
Published Thursday, October 07, 2004 6:26 AM by Justin Rogers
Filed under:

Comments

No Comments

Leave a Comment

(required) 
(required) 
(optional)
(required)