HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Reading a certain pixels color from a window

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
fromreadingcolorpixelswindowcertain

Problem

I'm currently reading a certain pixels color from a process window like this:

[DllImport("gdi32.dll")]
private static extern int BitBlt(IntPtr srchDc, int srcX, int srcY, int srcW, int srcH, 
                                 IntPtr desthDc, int destX, int destY, int op);

public static Color GetPixel(IntPtr hwnd, int x, int y)
{
    var screenPixel = new Bitmap(1, 1);

    using (Graphics gdest = Graphics.FromImage(screenPixel))
    {
        using (Graphics gsrc = Graphics.FromHwnd(MemoryHandler.GetMainWindowHandle()))
        {
            IntPtr hsrcdc = gsrc.GetHdc();
            IntPtr hdc = gdest.GetHdc();
            BitBlt(hdc, 0, 0, 1, 1, hsrcdc, x, y, (int)CopyPixelOperation.SourceCopy);
            gdest.ReleaseHdc();
            gsrc.ReleaseHdc();
        }
    }

    return screenPixel.GetPixel(0, 0);
}


It seems to be working.

I would like to know if I'm disposing everything that I use correctly to avoid memory leaks. If I inspect my app in the task manager I notice that the memory use is increasing a bit for each time i fetch a pixel, but I suppose the garbage collector will kick in when it's supposed to?

Also, is there any obvious "better" way of doing this?

Solution

You'll actually need to wrap the Bitmap in a using as well because its base class, Image, implements IDisposable:

public static Color GetPixel(IntPtr hwnd, int x, int y)
{
    using (Bitmap screenPixel = new Bitmap(1, 1);
    {
        using (Graphics gdest = Graphics.FromImage(screenPixel))
        {
            using (Graphics gsrc = Graphics.FromHwnd(MemoryHandler.GetMainWindowHandle()))
            {
                IntPtr hsrcdc = gsrc.GetHdc();
                IntPtr hdc = gdest.GetHdc();
                BitBlt(hdc, 0, 0, 1, 1, hsrcdc, x, y, (int)CopyPixelOperation.SourceCopy);
                gdest.ReleaseHdc();
                gsrc.ReleaseHdc();
            }
        }

        return screenPixel.GetPixel(0, 0);
    }
}


Further, the garbage collector works almost immediately. Or more simply put, if you use a memory allocation tool like MemProfiler, the memory will get cleaned up by GC faster than you can collect it with a snapshot. The Bitmap is likely where you are seeing the little tick.

It may also be worth wrapping the API call in a try ... finally:

IntPtr hsrcdc = gsrc.GetHdc();
IntPtr hdc = gdest.GetHdc();

try
{
    using (Graphics gsrc = Graphics.FromHwnd(MemoryHandler.GetMainWindowHandle()))
    {
        BitBlt(hdc, 0, 0, 1, 1, hsrcdc, x, y, (int)CopyPixelOperation.SourceCopy);
    }
}
finally
{
    gdest.ReleaseHdc();
    gsrc.ReleaseHdc();
}


to ensure the ReleaseHdc gets called.

Code Snippets

public static Color GetPixel(IntPtr hwnd, int x, int y)
{
    using (Bitmap screenPixel = new Bitmap(1, 1);
    {
        using (Graphics gdest = Graphics.FromImage(screenPixel))
        {
            using (Graphics gsrc = Graphics.FromHwnd(MemoryHandler.GetMainWindowHandle()))
            {
                IntPtr hsrcdc = gsrc.GetHdc();
                IntPtr hdc = gdest.GetHdc();
                BitBlt(hdc, 0, 0, 1, 1, hsrcdc, x, y, (int)CopyPixelOperation.SourceCopy);
                gdest.ReleaseHdc();
                gsrc.ReleaseHdc();
            }
        }

        return screenPixel.GetPixel(0, 0);
    }
}
IntPtr hsrcdc = gsrc.GetHdc();
IntPtr hdc = gdest.GetHdc();

try
{
    using (Graphics gsrc = Graphics.FromHwnd(MemoryHandler.GetMainWindowHandle()))
    {
        BitBlt(hdc, 0, 0, 1, 1, hsrcdc, x, y, (int)CopyPixelOperation.SourceCopy);
    }
}
finally
{
    gdest.ReleaseHdc();
    gsrc.ReleaseHdc();
}

Context

StackExchange Code Review Q#36899, answer score: 5

Revisions (0)

No revisions yet.