views:

16

answers:

1

Hello.

I want to caputure an image of a control which is an ActiveX imported control and display that image in WPF. The reason I do not use the windows forms host is that it is too slow (i want to create a list with these activex controls) : so far i have:

    public Bitmap CaptureCtrl(Control ctrl)
    {
        // Ein neues Image mit der grösse des jeweiligen Controls anlegen
        Console.WriteLine("new Bitmap({0:d}, {0:d}, g)", ctrl.Size.Width, ctrl.Size.Height);
        Bitmap newImage = new Bitmap(ctrl.Size.Width, ctrl.Size.Height);

        Graphics memoryGraphics = Graphics.FromImage(newImage);
        //Handle holen
        var hwnd = ctrl.Handle;
        IntPtr src = NativeMethods.GetDC(hwnd);
        IntPtr dest = memoryGraphics.GetHdc();

        // das Handle des Ziels
        // die X Position an der das Bild eingefügt werden soll
        // die Y Position an der das Bild eingefügt werden soll
        // die breite des Bildes
        // die höhe des Bildes
        // das Handle der Quelle
        // die X Position an der das Control liegt
        // die Y Position an der das Control liegt
        // Raster Operation Code an dieser Stelle ist es SRCCOPY
        // Natürlich muß der auf der Seite angegebene Hex wert noch in ein int umgerechnet werden
        // mehr informationen auf http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wceui40/html/_celrfternaryrasteroperations.asp
        Console.WriteLine("BitBlt(dest, 0, 0, {0:d}, {1:d}, src, {2:d}, {3:d}, 13369376)", ctrl.ClientRectangle.Width, ctrl.ClientRectangle.Height, ctrl.Location.X, ctrl.Location.Y);
        NativeMethods.BitBlt(dest, 0, 0, ctrl.ClientRectangle.Width, ctrl.ClientRectangle.Height, src, ctrl.Location.X, ctrl.Location.Y, 13369376);

        // Handles wieder Freigeben
        NativeMethods.ReleaseDC(hwnd, src);
        memoryGraphics.ReleaseHdc(dest);

        return newImage;
    }

And:

    /// <summary>
    /// Converts a <see cref="System.Drawing.Bitmap"/> into a WPF <see cref="BitmapSource"/>.
    /// </summary>
    /// <remarks>Uses GDI to do the conversion. Hence the call to the marshalled DeleteObject.
    /// </remarks>
    /// <param name="source">The source bitmap.</param>
    /// <returns>A BitmapSource</returns>
    public static System.Windows.Media.Imaging.BitmapSource ToBitmapSource(this System.Drawing.Bitmap source)
    {
        System.Windows.Media.Imaging.BitmapSource bitSrc = null;

        IntPtr hBitmap = source.GetHbitmap();

        try
        {
            bitSrc = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                hBitmap,
                IntPtr.Zero,
                Int32Rect.Empty,
                System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
        }
        catch (Win32Exception we)
        {
            bitSrc = null;
            Console.WriteLine(we.ToString()+ " data: "+we.Data + " code: " + we.ErrorCode);
        }
        finally
        {
            NativeMethods.DeleteObject(hBitmap);
        }

        return bitSrc;
    }

and the calling code:

    using (var capture = host.CaptureCtrl(this.control))
    {
         this.image.Source = capture.ToBitmapSource();
    }

the NativeMethod calls are imported from the dlls and should be clear. Now the problem is that the pictures are just grey and not filled with the content (it seems that there is indeed something copied)

A: 

I found a solution to the problem (not necessarily the bug which is in the current version), for anyone interested...

if the caputure method is replaced with this, then it works like a charm:

public Bitmap CaptureCtrl(Control ctrl)
{
   // Ein neues Image mit der grösse des jeweiligen Controls anlegen
   Bitmap newImage = new Bitmap(ctrl.Size.Width, ctrl.Size.Height);
   ctrl.DrawToBitmap(newImage, ctrl.ClientRectangle);
   return newImage;
}
Sebastian Godelet
I should mention that I paint the components in a Windows forms frame which must be Visible=true (otherwise i get an OCX state exception).
Sebastian Godelet