tags:

views:

116

answers:

2

I have found that when I add new events to an existing COM/IDL interface, I sometimes run into strange issues unless they are added to the end of the interface.

For example, say I have the following interface:

interface IMyEvents
{
    HRESULT FooCallback(
        [in] long MyParam1,
        [in] long MyParam2,
        [in] long MyParam3);

    HRESULT BarCallback(
        [in] long MyParam1,
        [in] BSTR MyParam2,
        [in] BSTR MyParam3);
};

Now let's say I want to add a new callback event, NewCallback. If I add it like this, I tend not to have any problems when the event is fired across COM:

interface IMyEvents
{
    HRESULT FooCallback(
        [in] long MyParam1,
        [in] long MyParam2,
        [in] long MyParam3);

    HRESULT BarCallback(
        [in] long MyParam1,
        [in] BSTR MyParam2,
        [in] BSTR MyParam3);

    /* New event added to the end */
    HRESULT NewCallback(
        [in] BSTR MyParam1,
        [in] BSTR MyParam2,
        [in] BSTR MyParam3);
};

But if I add it like this, I can run into all sorts of problems (e.g. buffer overruns) when the event is fired.

interface IMyEvents
{
    HRESULT FooCallback(
        [in] long MyParam1,
        [in] long MyParam2,
        [in] long MyParam3);

    /* New event added to the middle */
    HRESULT NewCallback(
        [in] BSTR MyParam1,
        [in] BSTR MyParam2,
        [in] BSTR MyParam3);

    HRESULT BarCallback(
        [in] long MyParam1,
        [in] BSTR MyParam2,
        [in] BSTR MyParam3);
};

I'm guessing it has something to do with DLL entry points, address offsets, or something similar. Or maybe it's because I haven't re-built something properly, and adding it to the end allows it to work by sheer luck.

Can anyone explain this behaviour?

+4  A: 

You are not supposed to modify an existing COM interface. Clients that were not compiled with the change are not aware of it and will continue calling as they had done before the change.

The result is that existing clients call BarCallback with a long integer, but instead get NewCallback that thinks this long integer is a BSTR. The results are often unpleasent.

You'll get similar problems with adding new functions at the end. Older COM object do not have the new function implemented and will likely just crash when you try to call it.

However, if you do not have existing clients in the wild using the old interface, just make sure you unregister everything and replace the object, clients and proxies and stubs you generated.

Sorry, I should have been clear in my original question. All clients to my COM interface are under control of me, so I can re-build them against the change. There are no clients (as far as I am aware) which I cannot re-compile. This is a COM interface which is used internally within various components of the software I work on.
LeopardSkinPillBoxHat
My guess is that you have some binary client or server that was not properly updated or registered. I'd suggest making a clean build and checking on a clean machine.
Even if you control all the code following the rule of adding into the end of file can drastically reduce amount of pain you incur from forgetting to recompile something. It's good practice and very easy to follow.
sharptooth
Btw all this is only true if the clients use early binding. Those who use late binding will be able to see the change at runtime.
sharptooth
A: 

I do not think it has anything to do with adding the code at the end.

I remember adding function in the mid of the interface file.

But whenever you modify it, ensure that you unregister the dll and regenerate all the files again. (as mentioned in previous post) Be precise in all the steps because debugging this stuff at runtime is tough.

lava