I am writing an Excel RTD server implementation and I'm stuck on the boilerplate for a coclass which implements IDispatch
. I have no access to ATL, but I am using ActiveQt, although I'm interested in how to do this in raw C or C++ too. How to properly implement the IDispatch
methods in a COM server?
The documentation is just panickingly awful, as always. What I have so far read:
- It is better practice to delegate the
IDispatch
method calls to someITypeInfo
. Is this correct? - If so, how to get an
ITypeInfo
to myself? LoadTypeLib() and family (followed by looking atITypeLib::GetTypeInfo()
)? - If not, how is it implemented properly? Links to good-quality documentation and self-contained examples are of much use.
The LoadTypeLib()
approach seems appropriate for a COM client to reach type information for some library, not for a COM server trying to introspect itself. Am I correct?
What you can do is use a Type Library.
If you have one, that's one thing you won't have to do. If you don't have one, then you can create one using the MIDL compiler. That's a free tool that comes with the Platform SDK. Of course in this case, it will mean you will have to write an IDL file (which can be a lot of work but you only need to define what you want). Depending on the kind of COM object you're targeting, an IDL file may already be available in the SDK. Once you have that IDL ready, you can compile it and get back a TLB file.
Once you have that TLB file, you can load it using the LoadTypeLib function. Once you have an ITypeLib reference, you can load the ITypeInfo that you need (there may be more than once), and basically route IDispatch calls (GetIDsOfNames, etc.) into ITypeInfo implementation calls, as they are very similar.
If the interface is properly defined in the IDL and compiled into a type library, implementing
IDispatch
via the type library'sITypeInfo
is quite feasible as it's mostly delegating. The interesting part isITypeInfo::Invoke
which relies upon correct C++ v-table layout:I've used a similar approach to create a script-callable wrapper for MSHTML DOM objects to bypass scripting security restrictions.
So where do you get the ITypeInfo from? Essentially you get it by:
ITypeInfo
implementation knows which function to invoke - it cannot just invoke the C++ functions directly on your class because C++ has no reflection and because it is language neutral. Therefore it can only delegate theInvoke
call to another method declared in the type library.E_NOTIMPL
then implement them one by one)RegisterTypeLib
. If it is embedded as a resource, you should call this from yourDllRegisterServer
implementation.LoadTypeLib
. This gives you anITypeLib
GetTypeInfoOfGuid
.Implementing IDispatch can be easy or hard. (Assuming you cannot use ATL).
The easy way is to not support TypeInfo (return 0 from
GetTypeInfoCount
andE_NOTIMPL
fromGetTypeInfo
. Nobody should call it.).Then all you have to support is
GetIDsOfNames
andInvoke
. It's just a big lookup table essentially.For
GetIDsOfNames
, returnDISP_E_UNKNOWNNAME
ifcNames != 1
. You aren't going to support argument names. Then you just have to lookuprgszNames[0]
in your mapping of names-to-ids.Finally, implement Invoke. Ignore everything except pDispParams and pVarResult. Use VariantChangeType to coerce the parameters to the types you expect, and pass to your implementation. Set the return value and return. Done.
The hard way is to use ITypeInfo and all that. I've never done it and wouldn't. ATL makes it easy so just use ATL.
If picking the hard way, Good luck.