Why is it necessary to add new events to the *end*

2019-07-17 02:52发布

问题:

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?

回答1:

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.



回答2:

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.