Creating COM objects and passing out pointers to them via a COM interface

Sarah Thompson sarah@telergy.com
Sat, 25 Jan 2003 04:49:45 -0000


Hi again,

A slightly harder problem this time. I want to implement something that
looks something like the Microsoft XML parser. This is a very COM heavy
contraption that provides an interface that looks to client applications
like a tree of COM objects that reflects the internal structure of an XML
document.

The idea is, you start with the document object, make a method call
requesting the root node, and have a COM object that wraps that node
returned to you. You can then request the children of that node, and their
children and siblings, all which involves being passed back interface
pointers to COM objects. Effectively, there is one COM object per syntactic
item in the XML document.

I already have my document object working nicely. This is where the actual
database resides. I want to be able to spawn views of this database as COM
objects. When I've done this in the past (using ATL mostly, euuuugh), I've
used an IDL definition something like

   HRESULT CreateView([in,string] BSTR query, [out,retval] IDbView **);

What's the correct way to implement the necessary Haskell code to create the
coclass and return a pointer to it? I fiddled around for ages, but either
couldn't get GHC to like the types I was using, or when I finally got it to
compile, I found that my test harness was being passed an invalid COM
object. This should be simple stuff, so I'm sure someone will have done it!

Secondly, it is a nasty, though fairly common trick, if you know your
objects are going to be created in the same process space, to allow them
some 'behind the scenes' communication. In my case, I'd like to avoid
needing to serialise and deserialse the data in a view during creation of
these child objects (of which there may be a great many, and which may be
created on the fy rather often). Ideally, I'd like to be able to do
something like:

newView :: String -> State -> IO State
newView db (State st) = do
    db <- readIORef st
    r <- newIORef db
    -- Insert some kind of COM magic here
    return (State r)

so the database content gets copied within the Haskell environment (lazily,
I'd hope), without needing to be serialised and deserialised. Is this
feasible? One (messy) approach might be to create a bunch of extra
interfaces on the main database object, then create 'thin wrapper' child
objects that simply make calls back into the parent object. I'm not so keen
on that for various reasons, however.

Sarah