tags:

views:

60

answers:

3

In a WPF application (C#), one of the elements is Win32 Window, created by overriding the HwndHost class. There are about 10 instance of this Win32 window in the WPF at any given time. One should render completely (works fine), and the other 9 should only show previews, without creating a Win32 window, just a bitmap.

I've been trying to find way to generate said bitmap. Tried a lot of different things but nothing has really worked so far. The main problem I run into is that HwndHost.WndProc is only called when the window is visible.

I can take a screenshot of a visible window, render it to memory and create a bitmap fine.. I just need some way of doing this while the window is not visible.

My understanding is still quite fuzzy, so any insight is appreciated.

A: 

Look into the graphic technique of "double buffering." Once you understand this technique - it's not hard - you will have a solution to your problem. In my opinion. :-)

Links:

Win32 Double Buffering

MSDN Double Buffering Lots 'O Links

WinForms Double Buffering Found through Google - Unknown Quality

JustBoo
A: 

I don't know how this works in C# with WPF, so I'll just give you the Windows API perspective and hope some of it leads you to a solution.

All drawing is done to a Device Context (DC). When Windows asks you to paint a window, it also gives you access to a DC corresponding to the drawable surface of the window.

To draw without a window, you need to create your own DC and, since the bits aren't going to a window, you need to select a bitmap into the DC to hold the results. In the Windows API you would use CreateCompatibleDC and SelectObject. Once you have a DC, you paint into it as normal, then deselect the bitmap.

Mark Ransom
+3  A: 

You can coerce a window to draw into a bitmap by simulating a WM_PAINT message. You will need to set up a memory DC and select your destination bitmap into it, then pass that DC handle as an arg in the paint message. See the MSDN docs for specifics.

Once the args are all ready to roll, do a SendMessage(HwndHost.Handle, WM_PAINT, etc etc). When that call returns, the bitmap should contain the image of the window.

Note that there are many messages involved to fully painting an entire window. The general pattern is:

  1. Invalidate the entire client area of the window. Otherwise, nothing will be drawn because the clip rect will be empty.
  2. Set up your memory bitmap in a memory DC
  3. Send a WM_ERASEBKGND message to the window handle, passing in the memory dc handle
  4. Send the WM_PAINT message to the window handle, passing in the memory dc handle

The image of the window should now be in the memory bitmap.

If you also want to capture the border, window frame, and window caption of the target window, you will need to simulate the non-client paint message: WM_NCPAINT is the main one, off the top of my head.

There is also a WM_PRINT message which supposedly helps with drawing into a memory DC destined for printing, but I've had trouble with it several versions of Windows ago. Child controls not drawing themselves, etc.

dthorpe
Thank you, this is the direction I began going in last night. Reading this now, it is even more clear. Very detailed, thank you very much!
mkocubinski