Как правильно расширить существующий компонент ActiveX / COM?


Я обновляю приложение MFC, содержащее пользовательский элемент управления ActiveX. В рамках обновления у меня была причина добавить новые методы к элементу управления ActiveX, и поэтому теперь он имеет другой интерфейс к старой версии. Изменения не повлияли на первоначальные методы, поэтому старые клиенты все еще могут использовать новый компонент.

У меня все работает, но я знаю, что то, что я сделал, воняет! Как правильно обновить данный продукт.

Это компонент был построен с использованием MFC, и Гугл не предоставляет большой помощи, кроме базового "создание элемента управления ActiveX с помощью учебников типа MFC". Я могу найти кучу материала об ATL, но я не хочу переносить компонент.

У меня были различные предложения от коллег, такие как изменение GUID и наследование интерфейса, но ничего определенного.

Итак, в целом, что считается лучшей практикой для обновления COM-интерфейсов?

И если вы случайно знаете, как это конкретно сделано в среде MFC, что тоже было бы очень полезно.

Я попытался создать второй интерфейс (см. ниже), как это было предложено MSalters, но я не уверен, что я сделал это правильно. Я создал новый интерфейс и новый кокласс в файле odl. Это приводит к тому, что в клиентском приложении MFC генерируются два отдельных класса-оболочки, один из которых является производным от CWnd Для теста coclass, а другой-производным от COleDispatchDriver для теста coclass2. класс-оболочка....

library TestLib
{
    importlib(STDOLE_TLB);

    // This is the original interface.......

    [ uuid(D2F8E5A8-8A95-463C-814F-B3CF84286223)]
    dispinterface _DTest
    {
        properties:
        methods:
            [id(1)] short TestMethod();
    };

    //  Class information for CTestCtrl
    [ uuid(1DBD2333-2073-4FB6-89AC-E4B200ADED48), control ]
    coclass Test
    {
        [default] dispinterface _DTest;
    };


    //  This is the new interface.

    [ uuid(D2F8E5A8-8A95-463C-814F-B3CF84286224)]
    dispinterface _DTest2
    {
        properties:
        methods:
            [id(1)] short TestMethod();
            [id(2)] short TestMethod2();
    };

    //  Class information for CTestCtrl2

    [ uuid(1DBD2333-2073-4FB6-89AC-E4B200ADED49), control ]
    coclass Test2
    {
        [default] dispinterface _DTest2;
    };
};
2 2

2 ответа:

Зависит.

Если у вас есть клиенты, которые компилируют свой собственный код (C++ , C# или VB) в библиотеке типов ваших элементов управления, .H файл, или .idl файл, вам, вероятно, нужно изменить идентификаторы COM GUID.

Вот случаи, когда вам не нужно менять идентификаторы COM GUID:

  1. Никакие сторонние разработчики не потребляют ваш код. Никто не будет сломан, если вы измените интерфейс.

  2. Это элемент управления ActiveX, размещенный в webbrowser и доступный через Яваскрипт.

  3. Все программное обеспечение, зависящее от вашей библиотеки DLL COM, поставляется вместе с обновленной версией вашего элемента управления.

  4. Это "внутреннее". Любой зависимый может быстро перекомпилировать при необходимости.

Если любое из вышеперечисленного верно, то вам не нужно менять идентификаторы COM GUID. Просто добавьте новые методы в существующее объявление интерфейса. Перекомпилируйте все зависимое программное обеспечение с изменением.

Вот случаи, когда вы должны быть осторожный.

  1. Кто - то другой уже скомпилировал (C++, C# или VB) и отправил программное обеспечение против вашего существующего интерфейса-и они не могут сразу обновить, когда вы отправляете. Новые методы должны быть объявлены на новом интерфейсе COM. Существующая декларация кокласса получает внесены изменения, а также поддерживают этот интерфейс.

  2. Вы удаляете методы, изменяете поведение или иным образом вносите критические изменения в программное обеспечение для доставки. Измените свой guid на Коклассе так, чтобы он возможно, может сосуществовать бок о бок с теми, кто зависит от старой версии. Переименуйте библиотеку DLL так, чтобы она не обязательно перезаписывала старую при обновлении.

В приведенном выше примере я не думаю, что вам нужно объявлять новый кокласс - просто новый интерфейс. И ваш новый интерфейс не нуждается в реализации методов первого. Просто отметьте оба интерфейса на коклассе.

dispinterface _DTest
{
    properties:
    methods:
        [id(1)] short TestMethod();
};

//  This is the new interface.
[ uuid(D2F8E5A8-8A95-463C-814F-B3CF84286224)]
dispinterface _DTest2
{
    properties:
    methods:
        [id(2)] short TestMethod2();
};


//  Class information for CTestCtrl
[ uuid(1DBD2333-2073-4FB6-89AC-E4B200ADED48), control ]
coclass Test
{
    [default] dispinterface _DTest;
    dispinterface _DTest2;
}

};

Вы всегда можете добавить интерфейсы. Новый элемент управления может просто реализовать старый и новый интерфейсы одновременно. Наследование-это простой метод C++ для переработки больших частей старого интерфейса и реализации.