Paint Win32 window to file
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 t开发者_运维知识库hings 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.
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:
- Invalidate the entire client area of the window. Otherwise, nothing will be drawn because the clip rect will be empty.
- Set up your memory bitmap in a memory DC
- Send a WM_ERASEBKGND message to the window handle, passing in the memory dc handle
- 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.
You should not directly send a WM_PAINT message, as per MSDN spec. You may use PrintWindow() since Windows XP, perhaps forcing updates with RedrawWindow() called with the RDW_INTERNALPAINT flag set.
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.
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
精彩评论