Blog ⋅ Peter Nelson

Summer of WebKit, Part 2: Printing

by peterdn 29. August 2010 15:57

My main aim for WebKit .NET over the past month or two has been to implement printing.  WebKit Cairo has had printing support since January, and I figured it would be a fairly simple task to hook onto that functionality in the .NET world.  As it turned out, there were one or two issues that had to be worked out first.

Handling _RemotableHandle

Several of the printing methods in the IWebFramePrivate interface (in the WebKit COM API), take a parameter of type HDC, which represents a handle to a graphics device context — in this case, a printer device.  Like all Windows handle types, HDC is defined as (void *), however the handle itself is only 32-bits long and so is sign extended to fit into 64-bits on Win64 (according to this white paper).  Unfortunately, due either to some bug or by design, the MIDL compiler marshals this type as a pointer to some barely documented _RemotableHandle structure which looks like the following:

public struct _RemotableHandle {
    public int fContext;
    public struct __MIDL_IWinTypes_0009 u;
}

public struct __MIDL_IWinTypes_0009 {
    public int hInProc;
    public int hRemote;
}

When run through tlbimp.exe and imported into C#, the type signature for one of these printing functions turns out to be:

public uint getPrintedPageCount(ref _RemotableHandle printDC);

Immediately skeptical, I tried various combinations of setting hInProc and hRemote to the value of the printer device handle, and setting fContext to one of the arcane-looking constants WDT_INPROC_CALL and WDT_REMOTE_CALL, but nothing seemed to work.  My first solution was to modify the relevant IDL files in WebKit itself and change the HDC types to OLE_HANDLE.  This worked well, as OLE_HANDLE is defined as a 32-bit value and MIDL marshals it as an Int32.  After inserting a few casts here and there, my printing code suddenly started to work!

This solution was not ideal, however, for a couple of reasons.  Firstly, it required me to make changes to WebKit each time, including inserting casts to OLE_HANDLE in the all functions I needed.  Secondly, as OLE_HANDLE is always 32-bits long, it was likely to cause headaches when the time came to port WebKit to Win64.  I tried getting around this by using (void *) or a different type of handle, but MIDL either didn’t like this or just marshalled the type as a _RemotableHandle again.  Damn.

The solution I eventually settled on is a bit inelegant, but seems to work as intended.  Leaving WebKit well alone, I ran the generated interop assembly through ildasm.exe, replaced all occurrences of the string “valuetype WebKit.Interop._RemotableHandle&” with “int32”, ilasm.exe’d it back together, and voila, it worked perfectly!  So I wrote a small tool that does this find and replace automatically (UNIX afficiendos should scoff at this point), and lumped it all into the solution’s pre-build event.

Functional Printing

With that sorted, and once I discovered that WebKit measures margins in 1000ths of an inch (a key bit of knowledge), printing functionality began to fall into place.  There are still some minor issues with regards to margin sizing, elements which span multiple pages, and print preview, but for the most part it works.  This functionality is included in the 0.5 release of WebKit .NET.

For the next few weeks I’m planning on focussing on JavaScript-C# interop.  I’ve already started playing around with JavaScriptCore to get a feel for how it works (see my JavaScriptCore Shell on GitHub).  Looks like I’m going to have to dust off my C++/CLI skills for the next installment…

In other random news, I’ve been distracted recently by a invite to the MonoDroid preview.  As would be expected of a pre-beta software release, it’s not perfect yet, but I’ve been very impressed by it so far.  The substantial interest generated in it, the huge amount of activity on the mailing list, and the speed at which the developers respond to and fix issues certainly bodes well for the finished product.  For me, the ability to code for Android from within Visual Studio alone may make it worthwhile.  We’ll see.  I may or may not get around to blogging about it.

Tags: , , ,

WebKit | WebKit .NET

Add comment