Capturing the screen

Last post 01-05-2007 7:45 by Anonymous. 2 replies.
Page 1 of 1 (3 items)
Sort Posts: Previous Next
  • 04-21-2003 11:36

    Capturing the screen

    Author: Martin Stave

    The snippets below show how you can capture the screen from your CF application using P/Invoked PocketPC functions. The captured image can be saved as a bmp file or loaded into a picturebox.

    The code also shows how StretchBlt can be used to diplay bitmaps. (StretchBlt is used as BitBlt is not supported)

    Credit goes to Alex Feinman for the code that converts the raw data to a bmp file.

    The code will produce a bmp file for 24 bit high quality .

    const int imgHeight = 320;
    const int imgWidth = 240;
    const int SRCCOPY = 0xCC0020;

    // only used for demo of StretchBlt function
    IntPtr h1 = FindWindow(null, "Form1" );

    IntPtr dc1 = GetDC( IntPtr.Zero );
    IntPtr InMemoryDC = CreateCompatibleDC( dc1 );

    IntPtr hBitmap;
    IntPtr ppvBits;

    BITMAPINFO bmi = new BITMAPINFO();
    bmi.biSize = Marshal.SizeOf(bmi);
    bmi.biBitCount = 24;
    bmi.biPlanes = 1;
    bmi.biWidth = imgWidth;
    bmi.biHeight = imgHeight;
    bmi.biXPelsPerMeter = 0xb12;
    bmi.biYPelsPerMeter = 0xb12;
    bmi.biSizeImage = bmi.biWidth * bmi.biHeight * bmi.biBitCount / 8;
    bmi.biClrUsed = 0;
    bmi.biClrImportant = 0;
    bmi.biCompression = 0; // RLE8 compression does not seem to work for PocketPC
    // Insert palette array here for 8bit palettised image

    hBitmap = CreateDIBSection( new IntPtr(0), bmi, 0, out ppvBits, new IntPtr(0), 0 );
    IntPtr OldBitmap = SelectObject( InMemoryDC, hBitmap );

    IntPtr dc2 = GetWindowDC( h1 );
    StretchBlt( InMemoryDC, 0, 0, imgWidth, imgHeight, dc2, 0, -26, imgWidth, imgHeight, SRCCOPY );

    byte[] rawData = new byte[bmi.biSizeImage];

    Marshal.Copy( ppvBits, rawData, 0, bmi.biSizeImage );

    // debug repaint only to verify bitmap content
    StretchBlt( dc2, 0, 100, imgWidth, imgHeight, InMemoryDC, 0, 0, imgWidth, imgHeight, SRCCOPY );

    SelectObject( InMemoryDC, OldBitmap );
    DeleteDC( InMemoryDC );

    ReleaseDC( IntPtr.Zero, dc1 );
    ReleaseDC( h1, dc2 );

    byte[] bitmap = CreateBitmap(imgWidth, imgHeight, rawData, bmi );

    //Demonstrates how to save image to a file
    FileStream fs = new FileStream(@"\out.bmp", FileMode.Create, FileAccess.Write);
    fs.Write(bitmap, 0, bitmap.Length);
    fs.Close();

    //Demonstrates loading the bitmap to a picturebox
    MemoryStream ms = new MemoryStream(bitmap);
    pictureBox1.Image = new Bitmap( ms );

    //Support functions
    const int sizeBFH = 14; //sizeof(BITMAPFILEHEADER)

    public byte[] CreateBitmap(int width, int height, byte[] bitmapData, BITMAPINFO bi)
    {
    // Calculate bitmap size - 3 bytes per pixel
    // Bitmap scanlines must be aligned at 16 bit boundary.
    // We cut some corners by requiring that width is an even number
    if ( (width & 1) == 1 )
    throw new ArgumentException("Width must be an even number");

    int nSize = sizeBFH + Marshal.SizeOf(typeof(BITMAPINFO)) + (width << 3) * height;
    byte[] data = new byte[nSize];
    byte[] bfh = new byte[sizeBFH];
    BitConverter.GetBytes(( short )0x4d42).CopyTo( data, 0 );
    BitConverter.GetBytes( nSize ).CopyTo( data, 2 );
    int bfhOffBits = (int)(sizeBFH + Marshal.SizeOf(typeof(BITMAPINFO)));
    BitConverter.GetBytes(bfhOffBits).CopyTo(data, 10);

    byte[] hdr = GetBytes(bi);

    Buffer.BlockCopy( hdr, 0, data, sizeBFH, hdr.Length);
    Buffer.BlockCopy( bitmapData, 0, data, (int)bfhOffBits, Math.Min(bitmapData.Length, bi.biSizeImage ));

    return data;
    }

    // This works only for default-aligned structure.
    // It does not work for BITMAPFILEHEADER because bfSize is not aligned to DWORD boundary
    // Unfortunately CF does not allow specifying structure member alignment
    private byte[] GetBytes(object o)
    {
    int size = Marshal.SizeOf(o.GetType());
    IntPtr p = LocalAlloc(GPTR, size);
    Marshal.StructureToPtr(o, p, false);
    byte[] ret = new byte[size];
    Marshal.Copy(p, ret, 0, size);
    LocalFree(p);
    return ret;
    }

    struct BITMAPFILEHEADER
    {
    public Int16 bfType;
    public Int32 bfSize;
    public Int16 bfReserved1;
    public Int16 bfReserved2;
    public Int32 bfOffBits;
    }

    public class BITMAPINFO
    {
    public Int32 biSize;
    public Int32 biWidth;
    public Int32 biHeight;
    public Int16 biPlanes;
    public Int16 biBitCount;
    public Int32 biCompression;
    public Int32 biSizeImage;
    public Int32 biXPelsPerMeter;
    public Int32 biYPelsPerMeter;
    public Int32 biClrUsed;
    public Int32 biClrImportant;
    };

    [System.Runtime.InteropServices.DllImport ("coredll.dll")]
    static extern uint GetLastError();

    [System.Runtime.InteropServices.DllImport ("coredll.dll")]
    static extern IntPtr CreateDIBSection(IntPtr hdc, BITMAPINFO pbmi, uint iUsage, out IntPtr
    ppvBits, IntPtr hSection, uint dwOffset);

    [System.Runtime.InteropServices.DllImport ("coredll.dll")]
    public static extern uint GetSystemPaletteEntries( IntPtr hdc, uint iStartIndexx,
    uint nEntries, IntPtr lppe );

    [System.Runtime.InteropServices.DllImport ("coredll.dll")]
    public static extern int GetObject( IntPtr hgdiobj, int cBuffer, IntPtr lp );

    [System.Runtime.InteropServices.DllImport ("coredll.dll")]
    public static extern IntPtr DeleteDC( IntPtr hdc );

    [System.Runtime.InteropServices.DllImport ("coredll.dll")]
    public static extern IntPtr CreateCompatibleDC( IntPtr hdc );

    [System.Runtime.InteropServices.DllImport ("coredll.dll")]
    public static extern IntPtr SelectObject( IntPtr hdc, IntPtr hgdiobj );

    [System.Runtime.InteropServices.DllImport ("coredll.dll")]
    public static extern IntPtr CreateCompatibleBitmap( IntPtr hdc, int nWidth, int nHeight );

    [System.Runtime.InteropServices.DllImport ("coredll.dll")]
    public static extern IntPtr FindWindow( string s1, string s2);

    [System.Runtime.InteropServices.DllImport ("coredll.dll")]
    public static extern int GetWindowText( IntPtr handle, char [] c, int len );

    [System.Runtime.InteropServices.DllImport ("coredll.dll")]
    public static extern IntPtr GetWindow( IntPtr handle, int cmd );

    [System.Runtime.InteropServices.DllImportAttribute("coredll.dll")]
    private static extern IntPtr GetDC( IntPtr hWnd);

    [System.Runtime.InteropServices.DllImportAttribute("coredll.dll")]
    private static extern IntPtr GetWindowDC( IntPtr hWnd);

    [System.Runtime.InteropServices.DllImportAttribute("coredll.dll")]
    private static extern int GetDeviceCaps( IntPtr hWnd, int nIndex);

    [System.Runtime.InteropServices.DllImportAttribute("coredll.dll")]
    private static extern int DrawText( IntPtr hDC, string lpString, int nCount, ref int [] lpRect, uint uFormat );

    [System.Runtime.InteropServices.DllImportAttribute("coredll.dll")]
    private static extern IntPtr ReleaseDC( IntPtr hWnd, IntPtr hDC );

    [System.Runtime.InteropServices.DllImportAttribute("coredll.dll")]
    private static extern bool SetWindowPos( IntPtr hWnd, IntPtr hWndInsertAfter, int x, int Y, int cx, int cy, uint uFlags );

    [System.Runtime.InteropServices.DllImportAttribute("coredll.dll")]
    private static extern bool StretchBlt(
    IntPtr hdcDest, // handle to destination DC
    int nXDest, // x-coord of destination upper-left corner
    int nYDest, // y-coord of destination upper-left corner
    int nWidth, // width of destination rectangle
    int nHeight, // height of destination rectangle, negative to switch upside down
    IntPtr hdcSrc, // handle to source DC
    int nXSrc, // x-coordinate of source upper-left corner
    int nYSrc, // y-coordinate of source upper-left corner
    int nWidthSrc,
    int nHeightSrc,
    uint dwRop // raster operation code
    );


    const int GPTR = 0x40;
    [DllImport("coredll.dll")]
    private static extern IntPtr LocalAlloc(uint flags, int cb);
    [DllImport("coredll.dll")]
    private static extern IntPtr LocalFree(IntPtr hMem);


    // Although the code only works for 24 bit images, it will also produce raw data for an 8bit paletteized image if a palette is supplied right below where bmi is instantiated. (see comment)

    Change bmi.biBitCount to 8.

    Example of palette:

    // Standard colors
    byte [] pal = {
    0x00, 0x00, 0x00, 0 , // System palette - first 10 colors
    0x80, 0x00, 0x00, 0 ,
    0x00, 0x80, 0x00, 0 ,
    0x80, 0x80, 0x00, 0 ,
    0x00, 0x00, 0x80, 0 ,
    0x80, 0x00, 0x80, 0 ,
    0x00, 0x80, 0x80, 0 ,
    0xC0, 0xC0, 0xC0, 0 ,
    0xC0, 0xDC, 0xC0, 0 ,
    0xA6, 0xCA, 0xF0, 0 ,

    0x2C, 0x00, 0x00, 0 ,
    0x56, 0x00, 0x00, 0 ,
    0x87, 0x00, 0x00, 0 ,
    0xC0, 0x00, 0x00, 0 ,
    0xFF, 0x00, 0x00, 0 ,
    0x00, 0x2C, 0x00, 0 ,
    0x2C, 0x2C, 0x00, 0 ,
    0x56, 0x2C, 0x00, 0 ,
    0x87, 0x2C, 0x00, 0 ,
    0xC0, 0x2C, 0x00, 0 ,
    0xFF, 0x2C, 0x00, 0 ,
    0x00, 0x56, 0x00, 0 ,
    0x2C, 0x56, 0x00, 0 ,
    0x56, 0x56, 0x00, 0 ,
    0x87, 0x56, 0x00, 0 ,
    0xC0, 0x56, 0x00, 0 ,
    0xFF, 0x56, 0x00, 0 ,
    0x00, 0x87, 0x00, 0 ,
    0x2C, 0x87, 0x00, 0 ,
    0x56, 0x87, 0x00, 0 ,
    0x87, 0x87, 0x00, 0 ,
    0xC0, 0x87, 0x00, 0 ,
    0xFF, 0x87, 0x00, 0 ,
    0x00, 0xC0, 0x00, 0 ,
    0x2C, 0xC0, 0x00, 0 ,
    0x56, 0xC0, 0x00, 0 ,
    0x87, 0xC0, 0x00, 0 ,
    0xC0, 0xC0, 0x00, 0 ,
    0xFF, 0xC0, 0x00, 0 ,
    0x00, 0xFF, 0x00, 0 ,
    0x2C, 0xFF, 0x00, 0 ,
    0x56, 0xFF, 0x00, 0 ,
    0x87, 0xFF, 0x00, 0 ,
    0xC0, 0xFF, 0x00, 0 ,
    0xFF, 0xFF, 0x00, 0 ,
    0x00, 0x00, 0x2C, 0 ,
    0x2C, 0x00, 0x2C, 0 ,
    0x56, 0x00, 0x2C, 0 ,
    0x87, 0x00, 0x2C, 0 ,
    0xC0, 0x00, 0x2C, 0 ,
    0xFF, 0x00, 0x2C, 0 ,
    0x00, 0x2C, 0x2C, 0 ,
    0x2C, 0x2C, 0x2C, 0 ,
    0x56, 0x2C, 0x2C, 0 ,
    0x87, 0x2C, 0x2C, 0 ,
    0xC0, 0x2C, 0x2C, 0 ,
    0xFF, 0x2C, 0x2C, 0 ,
    0x00, 0x56, 0x2C, 0 ,
    0x2C, 0x56, 0x2C, 0 ,
    0x56, 0x56, 0x2C, 0 ,
    0x87, 0x56, 0x2C, 0 ,
    0xC0, 0x56, 0x2C, 0 ,
    0xFF, 0x56, 0x2C, 0 ,
    0x00, 0x87, 0x2C, 0 ,
    0x2C, 0x87, 0x2C, 0 ,
    0x56, 0x87, 0x2C, 0 ,
    0x87, 0x87, 0x2C, 0 ,
    0xC0, 0x87, 0x2C, 0 ,
    0xFF, 0x87, 0x2C, 0 ,
    0x00, 0xC0, 0x2C, 0 ,
    0x2C, 0xC0, 0x2C, 0 ,
    0x56, 0xC0, 0x2C, 0 ,
    0x87, 0xC0, 0x2C, 0 ,
    0xC0, 0xC0, 0x2C, 0 ,
    0xFF, 0xC0, 0x2C, 0 ,
    0x00, 0xFF, 0x2C, 0 ,
    0x2C, 0xFF, 0x2C, 0 ,
    0x56, 0xFF, 0x2C, 0 ,
    0x87, 0xFF, 0x2C, 0 ,
    0xC0, 0xFF, 0x2C, 0 ,
    0xFF, 0xFF, 0x2C, 0 ,
    0x00, 0x00, 0x56, 0 ,
    0x2C, 0x00, 0x56, 0 ,
    0x56, 0x00, 0x56, 0 ,
    0x87, 0x00, 0x56, 0 ,
    0xC0, 0x00, 0x56, 0 ,
    0xFF, 0x00, 0x56, 0 ,
    0x00, 0x2C, 0x56, 0 ,
    0x2C, 0x2C, 0x56, 0 ,
    0x56, 0x2C, 0x56, 0 ,
    0x87, 0x2C, 0x56, 0 ,
    0xC0, 0x2C, 0x56, 0 ,
    0xFF, 0x2C, 0x56, 0 ,
    0x00, 0x56, 0x56, 0 ,
    0x2C, 0x56, 0x56, 0 ,
    0x56, 0x56, 0x56, 0 ,
    0x87, 0x56, 0x56, 0 ,
    0xC0, 0x56, 0x56, 0 ,
    0xFF, 0x56, 0x56, 0 ,
    0x00, 0x87, 0x56, 0 ,
    0x2C, 0x87, 0x56, 0 ,
    0x56, 0x87, 0x56, 0 ,
    0x87, 0x87, 0x56, 0 ,
    0xC0, 0x87, 0x56, 0 ,
    0xFF, 0x87, 0x56, 0 ,
    0x00, 0xC0, 0x56, 0 ,
    0x2C, 0xC0, 0x56, 0 ,
    0x56, 0xC0, 0x56, 0 ,
    0x87, 0xC0, 0x56, 0 ,
    0xC0, 0xC0, 0x56, 0 ,
    0xFF, 0xC0, 0x56, 0 ,
    0x00, 0xFF, 0x56, 0 ,
    0x2C, 0xFF, 0x56, 0 ,
    0x56, 0xFF, 0x56, 0 ,
    0x87, 0xFF, 0x56, 0 ,
    0xC0, 0xFF, 0x56, 0 ,
    0xFF, 0xFF, 0x56, 0 ,
    0x00, 0x00, 0x87, 0 ,
    0x2C, 0x00, 0x87, 0 ,
    0x56, 0x00, 0x87, 0 ,
    0x87, 0x00, 0x87, 0 ,
    0xC0, 0x00, 0x87, 0 ,
    0xFF, 0x00, 0x87, 0 ,
    0x00, 0x2C, 0x87, 0 ,
    0x2C, 0x2C, 0x87, 0 ,
    0x56, 0x2C, 0x87, 0 ,
    0x87, 0x2C, 0x87, 0 ,
    0xC0, 0x2C, 0x87, 0 ,
    0xFF, 0x2C, 0x87, 0 ,
    0x00, 0x56, 0x87, 0 ,
    0x2C, 0x56, 0x87, 0 ,
    0x56, 0x56, 0x87, 0 ,
    0x87, 0x56, 0x87, 0 ,
    0xC0, 0x56, 0x87, 0 ,
    0xFF, 0x56, 0x87, 0 ,
    0x00, 0x87, 0x87, 0 ,
    0x2C, 0x87, 0x87, 0 ,
    0x56, 0x87, 0x87, 0 ,
    0x87, 0x87, 0x87, 0 ,
    0xC0, 0x87, 0x87, 0 ,
    0xFF, 0x87, 0x87, 0 ,
    0x00, 0xC0, 0x87, 0 ,
    0x2C, 0xC0, 0x87, 0 ,
    0x56, 0xC0, 0x87, 0 ,
    0x87, 0xC0, 0x87, 0 ,
    0xC0, 0xC0, 0x87, 0 ,
    0xFF, 0xC0, 0x87, 0 ,
    0x00, 0xFF, 0x87, 0 ,
    0x2C, 0xFF, 0x87, 0 ,
    0x56, 0xFF, 0x87, 0 ,
    0x87, 0xFF, 0x87, 0 ,
    0xC0, 0xFF, 0x87, 0 ,
    0xFF, 0xFF, 0x87, 0 ,
    0x00, 0x00, 0xC0, 0 ,
    0x2C, 0x00, 0xC0, 0 ,
    0x56, 0x00, 0xC0, 0 ,
    0x87, 0x00, 0xC0, 0 ,
    0xC0, 0x00, 0xC0, 0 ,
    0xFF, 0x00, 0xC0, 0 ,
    0x00, 0x2C, 0xC0, 0 ,
    0x2C, 0x2C, 0xC0, 0 ,
    0x56, 0x2C, 0xC0, 0 ,
    0x87, 0x2C, 0xC0, 0 ,
    0xC0, 0x2C, 0xC0, 0 ,
    0xFF, 0x2C, 0xC0, 0 ,
    0x00, 0x56, 0xC0, 0 ,
    0x2C, 0x56, 0xC0, 0 ,
    0x56, 0x56, 0xC0, 0 ,
    0x87, 0x56, 0xC0, 0 ,
    0xC0, 0x56, 0xC0, 0 ,
    0xFF, 0x56, 0xC0, 0 ,
    0x00, 0x87, 0xC0, 0 ,
    0x2C, 0x87, 0xC0, 0 ,
    0x56, 0x87, 0xC0, 0 ,
    0x87, 0x87, 0xC0, 0 ,
    0xC0, 0x87, 0xC0, 0 ,
    0xFF, 0x87, 0xC0, 0 ,
    0x00, 0xC0, 0xC0, 0 ,
    0x2C, 0xC0, 0xC0, 0 ,
    0x56, 0xC0, 0xC0, 0 ,
    0x87, 0xC0, 0xC0, 0 ,
    0xFF, 0xC0, 0xC0, 0 ,
    0x00, 0xFF, 0xC0, 0 ,
    0x2C, 0xFF, 0xC0, 0 ,
    0x56, 0xFF, 0xC0, 0 ,
    0x87, 0xFF, 0xC0, 0 ,
    0xC0, 0xFF, 0xC0, 0 ,
    0xFF, 0xFF, 0xC0, 0 ,
    0x00, 0x00, 0xFF, 0 ,
    0x2C, 0x00, 0xFF, 0 ,
    0x56, 0x00, 0xFF, 0 ,
    0x87, 0x00, 0xFF, 0 ,
    0xC0, 0x00, 0xFF, 0 ,
    0xFF, 0x00, 0xFF, 0 ,
    0x00, 0x2C, 0xFF, 0 ,
    0x2C, 0x2C, 0xFF, 0 ,
    0x56, 0x2C, 0xFF, 0 ,
    0x87, 0x2C, 0xFF, 0 ,
    0xC0, 0x2C, 0xFF, 0 ,
    0xFF, 0x2C, 0xFF, 0 ,
    0x00, 0x56, 0xFF, 0 ,
    0x2C, 0x56, 0xFF, 0 ,
    0x56, 0x56, 0xFF, 0 ,
    0x87, 0x56, 0xFF, 0 ,
    0xC0, 0x56, 0xFF, 0 ,
    0xFF, 0x56, 0xFF, 0 ,
    0x00, 0x87, 0xFF, 0 ,
    0x2C, 0x87, 0xFF, 0 ,
    0x56, 0x87, 0xFF, 0 ,
    0x87, 0x87, 0xFF, 0 ,
    0xC0, 0x87, 0xFF, 0 ,
    0xFF, 0x87, 0xFF, 0 ,
    0x00, 0xC0, 0xFF, 0 ,
    0x2C, 0xC0, 0xFF, 0 ,
    0x56, 0xC0, 0xFF, 0 ,
    0x87, 0xC0, 0xFF, 0 ,
    0xC0, 0xC0, 0xFF, 0 ,
    0xFF, 0xC0, 0xFF, 0 ,
    0x2C, 0xFF, 0xFF, 0 ,
    0x56, 0xFF, 0xFF, 0 ,
    0x87, 0xFF, 0xFF, 0 ,
    0xC0, 0xFF, 0xFF, 0 ,
    0xFF, 0xFF, 0xFF, 0 ,
    0x11, 0x11, 0x11, 0 ,
    0x18, 0x18, 0x18, 0 ,
    0x1E, 0x1E, 0x1E, 0 ,
    0x25, 0x25, 0x25, 0 ,
    0x2C, 0x2C, 0x2C, 0 ,
    0x34, 0x34, 0x34, 0 ,
    0x3C, 0x3C, 0x3C, 0 ,
    0x44, 0x44, 0x44, 0 ,
    0x4D, 0x4D, 0x4D, 0 ,
    0x56, 0x56, 0x56, 0 ,
    0x5F, 0x5F, 0x5F, 0 ,
    0x69, 0x69, 0x69, 0 ,
    0x72, 0x72, 0x72, 0 ,
    0x7D, 0x7D, 0x7D, 0 ,
    0x92, 0x92, 0x92, 0 ,
    0x9D, 0x9D, 0x9D, 0 ,
    0xA8, 0xA8, 0xA8, 0 ,
    0xB4, 0xB4, 0xB4, 0 ,
    0xCC, 0xCC, 0xCC, 0 ,
    0xD8, 0xD8, 0xD8, 0 ,
    0xE5, 0xE5, 0xE5, 0 ,
    0xF2, 0xF2, 0xF2, 0 ,
    0xFF, 0xFF, 0xFF, 0 ,

    0xFF, 0xFB, 0xF0, 0 , // System palette - last 10 colors
    0xA0, 0xA0, 0xA4, 0 ,
    0x80, 0x80, 0x80, 0 ,
    0xFF, 0x00, 0x00, 0 ,
    0x00, 0xFF, 0x00, 0 ,
    0xFF, 0xFF, 0x00, 0 ,
    0x00, 0x00, 0xFF, 0 ,
    0xFF, 0x00, 0xFF, 0 ,
    0x00, 0xFF, 0xFF, 0 ,
    0xFF, 0xFF, 0xFF, 0 ,
    };

    Warnings:
    The uncompressed size of the full screen is large for 24 bits resolution, 320 X 240 X 4 = 307200 bytes of raw data.
    If you are stepping through this raw data looking for you image, remember that the image is by default upside down.

    Although inserting the palette this way worked for my demo, I believe the correct way to use it is to copy the structures and palette to unmanaged code using Marshal.Copy.

    \Martin Stave
  • 05-22-2006 5:44 In reply to

    Re: Capturing the screen

    Hi,
    It was not displyed image when adjest to 8bpp.I simply add your pal to BITMAPINFO.
    It gives not support exception.
    Pls give me any comment.

    Thanks
  • 01-05-2007 7:45 In reply to

    Re: Capturing the screen

    Wow, that seems very interesting.
    Thanks very much.
Page 1 of 1 (3 items)