I'm assuming you want to be able to make use of the advanced features of WPF within a MSHTML context. In that case, Graphics.FromHdc(hdc);
will not do the trick for you. The resulting Graphics
object will have no way to receive WPF content because WPF uses a retained-mode system and its MILCore rendering engine uses Direct3D not GDI+.
I'll give you one sure way to use WPF features inside a IHTMLPainter, plus pointers to another way that would likely be faster if you can get it to work.
Bitmap copying solution
An easy solution is to simply copy the background provided by MSHTML into an ImageBrush, use RenderTargetBitmap to let WPF render to a bitmap, then copy it back to the device.
To do this, construct your WPF content in any Visual subclass with a Background property (eg Grid or Border), then in your IHTMLPainter.Draw() method, just do the following:
- Create a
System.Drawing.Bitmap
corresponding to rcUpdate
BitBlt
from the given DC into the System.Drawing.Bitmap
- Construct an
ImageSoure
from the System.Drawing.Bitmap
(see recent SO answers for details)
- Construct an
ImageBrush
from the BitmapSource
using a viewport/viewbox that will lay it behind the portion of the visual corresponding to rcUpdate
- Set your root visual's background to the ImageBrush
- Set the
RenderTransform
on the root visual so that the rcUpdate portion starts at (0,0)
- Render the root visual to a
RenderTargetBitmap
of rcUpdate size
BitBlt
the RenderTargetBitmap
to the rcUpdate area of the DC
This should work well, be simple to implement, and work for any WPF content including advanced features such as 3D, BitmapEffects, etc. The only disadvantage is that those two bitmap copies might slow things down somewhat.
Note that if you know your WPF Visual is totally opaque you can completely skip steps 1-5 and simply render your Visual to a RenderTargetBitmap and BitBlt it to the device.
Direct3D possibility (partial solution)
Obviously it would be faster to avoid all this bitmap copying during render. This is most likely possible, but I can only give you some ideas to point the way -- it will take a lot of trial and error and probably some undocumented calls to make it work.
Since WPF renders using Direct3D, obviously you would prefer to get a Direct3D surface from MSHTML and paint on it. Doing this requires two things: Getting the surface from MSHTML, and getting MILCore to draw on it.
IHTMLPainter
has a flag HTMLPAINTER_3DSURFACE
to request a Direct3D surface in its GetPainterInfo call, but I couldn't find any examples of how to use HTMLPAINTER_3DSURFACE
. I suspect it could be figured out with a little trial and error.
I did not find any way to get WPF's native component "MILCore" to accept a Direct3D surface to paint on instead of a hWnd. There is no documentation on MILCore, and the only public API for setting up rendering tree, HwndSource, doesn't seem to be able to do the job.