Windows Mobile Screen Capture

I often find myself needing to query the phone's screen dimensions or needing to take a screen shot for demo purposes. This usually resulted in me recycling some of the screen scraping code I wrote for Omnipresence (a prototype cross platform remote desktop type client). I figured I may as well post this code since it's been pretty handy to me, and that others may find it handy as well.

The code below lets you do just that:

  • PixelDimensions - Returns the device's resolution.
  • GetScreenCapture - Capture the current contents of a screen to a bitmap that can then be saved/manipulated however you please.
using System;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Drawing.Imaging;

namespace WindowsMobile.Utilities
{
    public class DeviceScreen
    {
        enum RasterOperation : uint
        {
            SRC_COPY = 0x00CC0020
        }

        [DllImport("coredll.dll")]
        static extern int BitBlt(IntPtr hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, RasterOperation rasterOperation);

        [DllImport("coredll.dll")]
        private static extern IntPtr GetDC(IntPtr hwnd);

        [DllImport("coredll.dll")]
        private static extern int GetDeviceCaps(IntPtr hdc, DeviceCapsIndex nIndex);

        enum DeviceCapsIndex : int
        {
            HORZRES = 8,
            VERTRES = 10,
        }

        public static Size PixelDimensions
        {
            get
            {
                IntPtr hdc = GetDC(IntPtr.Zero);
                return new Size(GetDeviceCaps(hdc, DeviceCapsIndex.HORZRES), GetDeviceCaps(hdc, DeviceCapsIndex.VERTRES));
            }
        }

        public static Bitmap GetScreenCapture()
        {
            IntPtr hdc = GetDC(IntPtr.Zero);
            Size size = PixelDimensions;
            Bitmap bitmap = new Bitmap(size.Width, size.Height, PixelFormat.Format16bppRgb565);
            using (Graphics graphics = Graphics.FromImage(bitmap))
            {
                IntPtr dstHdc = graphics.GetHdc();
                BitBlt(dstHdc, 0, 0, size.Width, size.Height, hdc, 0, 0, RasterOperation.SRC_COPY);
                graphics.ReleaseHdc(dstHdc);
            }
            return bitmap;
        }
    }
}

3 comments:

Anonymous said...

Thanks for sharing your code Koush. I was just wondering - does the IntPtr reference 'hdc' in the GetScreenCapture() method need to be released after using it?

Koush said...

Yes, the pointer needs to be released, otherwise accessing that Bitmap later will throw an exception. To improve performance, you can create overloads of the GetScreenCapture method to accept a precreated Bitmap, or Graphics object. Allocating a Bitmap and creating a Graphics object is pretty expensive.

Unknown said...
This comment has been removed by the author.