After seeing hundreds of frustrated posts on this topic, I realize how
widespread the problem is. I'm not talking about skin rashes, but something
more insidous: CHtmlView does not play nicely with the MFC print
architecture.
MS seems well aware of this limitation, having documented an exhaustive list
of workarounds:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnie55/html
/wb_print.asp?frame=true
But none of the strategies presented by MS are complete solutions. If
you're like me, you want CHtmlView to behave exactly like any other CView
subclass when it comes to printing, which means supporting these MFC print
methods transparently:
- DoPreparePrinting
- OnBeginPrinting
- OnEndPrinting
- OnEndPrintPreview
- OnPrepareDC
- OnPreparePrinting
- OnPrint
Like many of you, I've wrestled with this for a while, trying various
techniques:
- Calling IWebBrowser2::ExecWB (aka IOleCommandTarget::Exec) to invoke print
functionality. Problem: requires user interaction with dialogs - no way to
integrate into a composite print job or use in a service or batch process.
- StretchBlt-ing the CHtmlView rendering directly to the MFC print/preview
DC. Problems: no support for pagination, hard copy quality is poor due to
scaling of the screen rendering.
- QI-ing from CHtmlView's contained IWebBrowser2 to IViewObject2, and
calling its Draw method on the MFC print/preview DC. Problem: like blt-ing,
no support for pagination.
Recently, I got ambitous and began tinkering with print templates, first
introduced in IE 5.5. This to me appears to be the most promising approach.
By hooking the IWebBrowser2 object's call to MSHTML.DLL::ShowHTMLDialogEx, I
was able to determine the function's arguments so that I could
programmatically invoke the modeless HTML print preview dialog myself,
off-screen. From this, I can enumerate the pages and programmatically
advance the page displayed in the HTML print preview to correspond with the
one requested in the CView::OnPrint method call.
While tantalizingly close, I'm still unable to render the paginated content
to my MFC print/preview DC. I've spent days spelunking the html print
preview's DOM to find the right combination of OLE interfaces to make things
work, but to no avail. I've used the COM spying techniques developed by
Keith Brown and Chris Sells in trying to gain some insight into how the
print template classes (in iepeers.dll) work "under the hood". I even tried
dropping the Mozilla ActiveX Control into my CHtmlView subclass - no luck.
The closest I've come is in QI'ing an IViewObject2 interface from my html
print preview document, but its Draw method fails generically (E_FAIL).
In principle, all other obstacles can be overcome (e.g., hooking and
stuffing the web browser's page setup and printer dialogs with the MFC print
settings). The last hurdle is simply rendering the paginated content to the
desired surface.
I would love to collaborate with anyone on this and come up with a complete
and tidy CHtmlView printing solution. I'd be happy to post sample code
demonstrating my progress thus far.
Let's fix this!