Now that you understand what dispinterfaces and dual interfaces are in relation to a custom interface, we can look at when you would choose one or the other. In most cases, you will want to implement a dual interface simply because it allows both COM clients (usually written in C, C++, or other compiled languages) and automation controllers (usually interpreted languages that run in a tool such as Visual Basic) to access your functions and data equally. When you have an in-process dual interface, you benefit from both high speed through the custom interface and high flexibility through the late-binding IDispatch. When you have an out-of-process object, you benefit from automatic marshaling and can improve performance with a custom proxy/stub implementation. (Although a custom proxy/stub has the risk of RegisterTypeLib—and LoadTypeLib—overwriting its registry entries, thereby eliminating the performance gain.)
A dual interface, however, has the restrictions imposed by automation compatibility: no data structures (other than implementing another property object), no unsigned arguments, having to use BSTRs, and so on. One alternative is to implement both an IDispatch interface and a custom interface without combining them and have the custom interface take advantage of the full range of possible argument types. This allows COM clients to communicate in the best way possible while still allowing automation controllers to access the same stuff but in a less efficient manner.
Picking one interface or the other depends mostly on your target client and the bandwidth you want—as well as on how much time you want to spend in implementation. If you are making a high-speed, in-process object, a custom interface is easiest, but IDispatch is somewhat easier when you have to go out-of-process because then you don't have to make a proxy and stub. If each function in the interface executes rapidly, you want to cut down the per-call overhead as much as possible (especially for the in-process case), so you should use a custom interface. If you're implementing a large object hierarchy, however, with perhaps dozens of objects, the additional implementation cost of a custom interface is considerable.
When you take potential clients into consideration, you also have to think about the ease of calling your interfaces, which is again where dual interfaces are nice. Nevertheless, a vtable interface is more easily called from a C/C++ client; a dispinterface is easier from an interpreted automation controller, but it takes a lot longer to process the call.
From a design perspective, the flexibility of an interface is also an important consideration. When you define a custom vtable interface, you carve it in stone. A revision to that interface (which makes a new interface) requires recompilation of clients that want to take advantage of the changes. On the other hand, a dispinterface can almost revise itself at run time by adding new methods and properties as necessary. The cost of modifying the interface is much less. From a client's point of view, you can always count on IDispatch being there over time, but old custom interfaces can disappear in a newly updated object. In addition, an object that has methods and properties is more easily expressed through a dispinterface. But a related group of functions, such as those in IDataObject, are best expressed through a vtable interface, especially when that group is not expected to change in the future. This is best when you want an interface contract to enforce a rigid standard of some kind, the sort where flexibility is a dirty word. Then there is the design point about late binding vs. early binding, which is, of course, blurred by dual interfaces but is an important consideration nevertheless.
So a plethora of questions must be considered for how you choose which interfaces you want. I can't attempt to answer all the questions that might arise and hope that this short section has given you a good number of strengths and weaknesses of each type of interface. If you're planning on an implementation of a large object hierarchy, you can expect to spend some time with these issues before you come to your final design.
7 Based on a part of the winter vegetable stew that I made for dinner last night. Yes, I actually find time to cook, even when writing a book. |