代码之家  ›  专栏  ›  技术社区  ›  LeopardSkinPillBoxHat

为什么需要向IDL接口的*结束*添加新事件?

  •  2
  • LeopardSkinPillBoxHat  · 技术社区  · 16 年前

    我发现,当我向现有的COM/IDL接口添加新事件时,有时会遇到一些奇怪的问题,除非将它们添加到接口的末尾。

    例如,假设我有以下接口:

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

    现在假设我想添加一个新的回调事件, NewCallback . 如果我这样添加,当事件在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);
    };
    

    但是如果我像这样添加它,当事件被触发时,我会遇到各种各样的问题(例如缓冲区溢出)。

    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);
    };
    

    我猜这与DLL入口点、地址偏移或类似的事情有关。或者可能是因为我没有正确地重建一些东西,把它添加到最后可以让它完全靠运气工作。

    有人能解释这种行为吗?

    2 回复  |  直到 16 年前
        1
  •  4
  •   sterin    16 年前

    您不应该修改现有的COM接口。未与更改一起编译的客户机不知道该更改,将像更改前一样继续调用。

    结果是,现有的客户机使用长整型调用barcallback,但得到的newcallback认为这个长整型是一个bstr。结果往往是不可靠的。

    在最后添加新函数也会遇到类似的问题。旧的COM对象没有实现新的函数,当您试图调用它时,它可能会崩溃。

    但是,如果您没有使用旧接口的现有客户端,只需确保注销所有内容并替换生成的对象、客户端、代理和存根即可。

        2
  •  0
  •   lava    16 年前

    我认为这与在末尾添加代码没有任何关系。

    我记得在接口文件的中间添加了函数。

    但是,每当您修改它时,请确保您注销该dll并重新生成所有文件。(如前文所述) 所有步骤都要精确,因为在运行时调试这些东西很困难。