Double-Buffering, BitBlt und Windows Forms


Thomas Wölfer
Thomas Wölfer

23. Mai 2005


Windows.Forms sind ja von Haus aus in der Lage Double-Buffering zu verwenden. Es gibt aber Fälle, bei denen man drauf Einfluss nehmen möchte - und zum Beispiel nur Teile der Client-Area per BitBlit (BitBlt) anzuzeigen. Dazu muss man im wesentlichen die folgenden Dinge tun:

1. Man muss zu einem günstigen Zeitpunkt ein Bitmap der richtigen Größe erzeugen. Der 'richtige' Zeitpunkt ist dabei der OnResize() Event der Form.

2. Man muss zu einem anderen Zeitpunkt das 'fertige' Bild aus dem DeviceContext des Controls in das gemalt wird in das Bitmap kopieren. Das tut man am besten per BitBlt.

3. Will man nun von Hand Teile des Bitmaps zurück kopieren, so geht das einfach mit Graphics.DrawImageUnscaled().

Das einzige Problem ist dabei der Aufruf von BitBlt, denn dafür gibts in Windows.Forms von Haus aus keine Möglichkeit. Eine passende Interop-Klasse, die ein Bitmap aus einem Source-DC in ein Bitmap kopiert könnte zum Beispiel so aussehen:

    public sealed class GdiApi
    {
        private GdiApi() {}

        public static void BitBlt( Graphics source, Bitmap target, int width, int height)
        {
            System.IntPtr hdc = source.GetHdc();

            Graphics gDest = Graphics.FromImage( target);
            IntPtr destDC = gDest.GetHdc();
            NativeMethods.BitBlt( destDC, 0, 0, width, height, hdc, 0, 0, NativeMethods.ROP_SOURCE);

            gDest.ReleaseHdc(destDC);
            gDest.Dispose();
            source.ReleaseHdc( hdc);
        }

        private sealed class NativeMethods
        {
            private NativeMethods() {}

            public const int ROP_SOURCE = 0xcc0020;

            [DllImport("gdi32.dll",ExactSpelling=true,CharSet=System.Runtime.InteropServices.CharSet.Auto)]
            public static extern bool BitBlt(IntPtr hDC,int x,int y,int nWidth,int nHeight,IntPtr hSrcDC,int xSrc,int ySrc,int dwRop);
        }
    }