
Once more into the interface compiler
News ·Thursday April 19, 2007 @ 20:19 EDT (link)
This got so long that I've given it its own entry, separate from the original.
As I've mentioned, I recently did a major rewrite of Word's object model dispatch, which included some gnarly templated (declspec) naked assembly functions. Unfortunately, those are going away now, because x86 assembly doesn't compile in x64 builds (apparently the x64 compiler doesn't do inline assembly at all). The price was an extra level of indirection for C function dispatch (as opposed to C++ or generic handler dispatch). I'm also thinking of changing our (Word-specific) interface compiler to allow inserting small chunks of code directly, so that people don't need to build hundreds of stub functions that just vary one or two parameters to a real handler (this might also obviate the existing handlers, which are pretty limited). So, currently we have something like:interface IDBorders
{
...
properties
{
VT_I4 DistanceFromRight
dispid 22
undo_auto
get proc HrOamBordersGetFromTextRight
put proc HrOamBordersPutFromTextRight
}
}
and the C++ implementation:/* H R O A M B O R D E R S G E T F R O M T E X T R I G H T */
/*----------------------------------------------------------------------------
%%Function: HrOamBordersGetFromTextRight
%%Owner: NoBody
%%Id: 00000000-0000-0000-0000-000000000000
----------------------------------------------------------------------------*/
STDMETHODIMPC HrOamBordersGetFromTextRight(IDBorders* pidBorders, long* plFromText) throw0
{
return HrOaFormatBorder(pidBorders, wpropFromTextRight, plFromText, fTrue/*fGet*/);
}
/* H R O A M B O R D E R S P U T F R O M T E X T R I G H T */
/*----------------------------------------------------------------------------
%%Function: HrOamBordersPutFromTextRight
%%Owner: NoBody
%%Id: 00000000-0000-0000-0000-000000000000
----------------------------------------------------------------------------*/
STDMETHODIMPC HrOamBordersPutFromTextRight(IDBorders* pidBorders, long lFromText) throw0
{
return HrOaFormatBorder(pidBorders, wpropFromTextRight, &lFromText, fFalse/*fGet*/);
}
(names and GUIDs removed) repeated over and over with few minor variations; it's be nicer if it was possible to write:interface IDBorders
{
...
properties
{
VT_I4 DistanceFromRight
dispid 22
undo_auto
get { return HrOaFormatBorder(pid, wpropFromTextRight, plProp, fTrue/*fGet*/); }
put { return HrOaFormatBorder(pid, wpropFromTextRight, &lProp, fFalse/*fGet*/); }
}
}
(where pid and lProp/plProp are filled in by our compiler tool, to be the IDispatch interface pointer and the property value respectively). To help prevent abuse, code blocks with more than three statements will result in an error. This win (11 lines + 2 blank per function x 2 = 26 lines saved, which is code developers don't ever need to read) is made possible by the aforementioned removal of assembly: now that we need to generate thunks for C functions, we might as well be flexible with what we put in them, only defaulting to calling the expected implementing function (in this example HrOamBorders(Get|Put)FromRight). The braces make the block unambiguous to our compiler and are a standard sign of a code block in C and C tools.
There are probably downsides to this idea; I hope AT reads this and helps me think this through (hi Ali!). One is that changes to the interface file require (with the new build rules) 111 files to be build in current debug builds, but we can try to cut down those dependencies: really only a handful of source files should depend on object model generated files.
The advantages are clear: remove formulaic code (it could also be moved to a new file, obthunk.cpp, but why write it at all?), making it easier to read source files, and easier to understand how object model calls are implemented (you can go from the property to the actual implementing method, skipping the middleman, and if you really do want to put a breakpoint on a particular method, put a conditional one on the gatekeeper, HrOaDispatch, or put one on the generated thunk function, which has a predictable name).
Muhahaha... I love to delete code. Although I may hold off on this until Office 15 (if I'm still around) - I'll write in the capability, but not do sweeping refactoring yet.