Question

I've recently inherited a project that creates and implements a COM coclass/interface in a DLL. This COM DLL is utilized by an application which applies a GUI to the COM class's interface. This is the only application that uses the COM DLL. I'm new to dealing with COM and good documentation is hard to find.

Part of my task involves adding some methods/properties (as well as removing some that are no longer needed) to the interface. I've learned that I need to modify the IDL to accomplish this. Right now I have simply added my new methods and properties to the end of the interface and things seem to be working good. However when I remove one of the properties (for example) things go bad quickly when I run the application.

interface IMyComInterface : IDispatch
    {
        [id(1), helpstring("method CheckMessage")] HRESULT CheckMessage([in] VARIANT vMsg);
        [id(2), helpstring("method CheckFolder")] HRESULT CheckFolder([in] VARIANT Folder, [out] VARIANT *pCount, [out, retval] VARIANT *pErrorCount);
        //[propget, id(3), helpstring("property Flags")] HRESULT Flags([out, retval] VARIANT *pVal);
        //[propput, id(3), helpstring("property Flags")] HRESULT Flags([in] VARIANT newVal);
        [propget, id(4), helpstring("property MessageStore")] HRESULT MessageStore([out, retval] VARIANT *pVal);
        [propput, id(4), helpstring("property MessageStore")] HRESULT MessageStore([in] VARIANT newVal);
        [propget, id(5), helpstring("property Directory")] HRESULT Directory([out, retval] VARIANT *pVal);
        [propput, id(5), helpstring("property Directory")] HRESULT Directory([in] VARIANT newVal);
    }

I'm guessing it has to do with the broken up ID number sequence. I suppose I could shift everything under it up and things would work. But I'm curious on the proper method for doing all of this.

Much thanks.

Was it helpful?

Solution

If the GUI uses IDispatch::Invoke to invoke your methods, it should be resilient to changes in the interface (as long as you keep the IDs the same), because the method calls are resolved at runtime (late binding). It is common for VB6 programs and scripting languages to operate this way.

However, if the GUI is compiled directly against IMyComInterface (which is most likely if it's a C++ or C# app), what matters is the exact order of methods in the interface. The method calls are resolved at compile time (early binding), and the index of the method in the interface is stored in the COM client. If you delete a method from the IDL, all the function calls from the client will be off by one. This is why adding a new method at the end works, but deleting methods in the middle doesn't.

The simplest way around all these problems (since you control both the COM DLL and the GUI) is to make sure you recompile everything after changing the IDL. In the general case, though, you should treat every interface as "an immutable contract of a functional group of methods" (source), and never modify a COM interface after it has been released into the world.

OTHER TIPS

If the COM client is C++, it will probably use early binding (which means it relies on the layout of the interface staying the same) instead of late binding. In that case it doesn't matter what the DISPIDs are, because DISPIDs are used for late binding, not for early binding. That's why removing methods/properties from the interface will break the client unless you re-compile it. That's also why it isn't recommended to change COM interfaces, and instead to add new interfaces that inherit from the old one and add the new functionality:

interface IMyComInterface : IDispatch
{
    // existing methods/properties
}

interface IMyComInterface2 : IMyComInterface
{
    // new methods/properties
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top