Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

CreateDispTypeInfo and CreateStdDispatch quirks

334 views
Skip to first unread message

Leon

unread,
Nov 13, 2004, 7:37:52 PM11/13/04
to
Note: this is not a question, but my experience with using the OLE
functions CreateDispTypeInfo and CreateStdDispatch. By posting this
message, I hope to prevent people from having the same difficulties as
I had with using these functions.

I had a hard time implementing an IDispatch interface using these
functions, mainly because the MSDN documentation about them is either
incomplete, and in some cases even incorrect. Also, these functions
(or the objects generated by them) tend to return very little error
information, thus making it rather hard to debug your code without
tracing into to assembly code.

* CreateDispTypeInfo() requires that the passed INTERFACEDATA struct
remains in memory as long as you intend to use the generated ITypeInfo
interface. Apparently, it is copied by reference rather than by value.
This might even mean that the functionality exposed by the ITypeInfo
object can be modified by changing values in the original
INTERFACEDATA struct, but I haven't tried this.

* Unlike the documentation says, the calling convention allowed in the
METHODDATA struct (the CALLCONV cc member) does NOT allow CC_PASCAL,
but only the constants 1 and 4 (CC_CDECL and CC_STDCALL). I had to
find this out the hard way, by walking through both functions'
assembly code :(

I also have some tips/things to remember when using these functions:

* When Invoke()ing a dispatch method that is exposed using a generated
ITypeInfo object, don't forget to pass a non-null pointer to a
DISPPARAMS struct (i.e. the pDispParams argument), even when the
exposed method doesn't take any parameters. This might seem obvious,
but the returned error code (E_INVALIDARG) is rather cryptic, since
Invoke() won't tell you _which_ parameter is invalid. (Yes, that's
right, Invoke() can return E_INVALIDARG, even though the documentation
says it can't).

* CreateDispTypeInfo requires you to specify which vtable entry/index
the exposed method has (in the METHODDATA.iMeth field). A quick and
dirty way to figure out the correct vtable index for a method is the
following:

Given a class MyClass and a virtual function func(). To find func()s
vtable index, take a pointer to a MyClass instance, and use it to call
func(), e.g.:

MyClass pObj = new MyClass();
pObj->func();

Compile this code with assembly code generation on (or, alternatively,
trace through this code in debug mode, and switch to the Disassembly
view at this function call). You will see something like this:

pObj->func();
0044F9E5 mov eax,dword ptr [pObj]
0044F9E8 mov ecx,dword ptr [eax]
0044F9EA mov esi,esp
0044F9EC mov edx,dword ptr [pObj]
0044F9EF push edx
0044F9F0 call dword ptr [ecx+28h] // <-- here

The CALL denoted with "here" is the virtual function call through the
vtable, and the +28h denotes the offset in this vtable in bytes. 28h
is 0x28, or 40 in decimal. Because every vtable entry is 4 bytes, we
divide it by four to find that MyClass::func() is located at vtable
index 40 / 4 = 10. Hence, this is the value to pass as iMeth to expose
func().

Hope this might help some people in the future ;)

Cheers,
Leon.

0 new messages