Интерфейс плагина и его vtable
От: AlexGin Беларусь  
Дата: 12.10.17 08:26
Оценка:
Доброе время суток, уважаемые коллеги!

Суть вопроса в том, что у нас в разработке уже около года идёт приложение на C++ (MSVC2015) с плагинами.
Идея, заложенная в систему плагинов, кратко изложена здесь: http://www.andynicholas.com/?p=27
В основу интерфейса плагина (aka абстрактный базовый класс в контексте C++) первоначельно был заложен такой вот код:
class IPluginlInterface
{
public:
    virtual ~IPluginInterface() {};
    virtual void Init() = 0;
    virtual char* GetInterfaceName() const = 0;
    virtual char* GetInterfaceDescription() const = 0;
    virtual char* GetInterfaceVersion() const = 0;
    virtual char* GetInterfaceDateTime() const = 0;
    virtual int  GetInterfaceCategory() const = 0; 
    virtual int  GetInterfaceFlags() const = 0;
    virtual void SetCallbackNotifyer(INotifyer1* pNotyfier) = 0;
    virtual void SetIXMLConfigPointer(IXMLConfig* pXMLConfig) = 0;
    virtual void SetIDALPointer(IDAL* pIDAL) = 0;
    virtual void SetDataItem1(DataItem1* pItem) = 0; 
    virtual void SetDataItem2(DataItem2* pItem) = 0;
    virtual void SetBackupOptions(int iOptions) = 0;
    virtual INotifyer1* GetCallbackNotifyer() const = 0;
    virtual DataItem1* GetDataItem1() const = 0; 
    virtual DataItem2* GetDataItem2() const = 0;
    virtual long PerformCalculations() = 0;
    virtual void DeInit(int& aiDeInitCounter) = 0;
};

Эта версия — самая первая (старая).
Теперь интерфейс развивается — добавляются новые вирт-методы.
Я предлагаю их добавлять в самый конец — после DeInit.
Это позволит использовать те плагины, которые компилировались под старой версией интерфейса.
Коллега по работе добавил новый метод SuspendCalculations. При этом сделал так:
class IPluginlInterface
{
public:
    virtual ~IPluginInterface() {};
    virtual void Init() = 0;
    virtual char* GetInterfaceName() const = 0;
    virtual char* GetInterfaceDescription() const = 0;
    virtual char* GetInterfaceVersion() const = 0;
    virtual char* GetInterfaceDateTime() const = 0;
    virtual int  GetInterfaceCategory() const = 0; 
    virtual int  GetInterfaceFlags() const = 0;
    virtual void SetCallbackNotifyer(INotifyer1* pNotyfier) = 0;
    virtual void SetIXMLConfigPointer(IXMLConfig* pXMLConfig) = 0;
    virtual void SetIDALPointer(IDAL* pIDAL) = 0;
    virtual void SetDataItem1(DataItem1* pItem) = 0; 
    virtual void SetDataItem2(DataItem2* pItem) = 0;
    virtual void SetBackupOptions(int iOptions) = 0;
    virtual INotifyer1* GetCallbackNotifyer() const = 0;
    virtual DataItem1* GetDataItem1() const = 0; 
    virtual DataItem2* GetDataItem2() const = 0;
    virtual long SuspendCalculations() = 0;  // Добавлен этот новый вирт-метод!!!
    virtual long PerformCalculations() = 0;
    virtual void DeInit(int& aiDeInitCounter) = 0;
};

После чего, в моих кодах вместо вызова DeInit происходил вызов PerformCalculations.
Это и понятно, так как на позицию, где ранее в таблице виртуальных функций был DeInit "переехал" PerformCalculations.
В общем — проблему я пофиксил. Тем не менее, пока открыт такой вот вопрос:

Я полагаю, что все новые вирт-методы должны добавляться после DeInit, это обеспечит запуск старых плагинов.
Коллега по работе предлагает размещать так, как оно кажется логичнее (без ориентации на совместимость со старымы плагинами),
мотивируя это тем, что все плагины также придётся пересобирать.

А как бы сделалы Вы, уважаемые?

P.S. Технологию COM не предлагать.
Я раньше много работал с COM и знаю эту технологию, однако использовать в нашем проекте не хочу.
COM добавляет лишние сложности там, где их совсем даже не требуется.
Отредактировано 12.10.2017 8:34 AlexGin . Предыдущая версия . Еще …
Отредактировано 12.10.2017 8:28 AlexGin . Предыдущая версия .
Re: Интерфейс плагина и его vtable
От: uzhas Ниоткуда  
Дата: 12.10.17 08:52
Оценка: 4 (1)
Здравствуйте, AlexGin, Вы писали:

AG>Я полагаю, что все новые вирт-методы должны добавляться после DeInit, это обеспечит запуск старых плагинов.

AG>Коллега по работе предлагает размещать так, как оно кажется логичнее (без ориентации на совместимость со старымы плагинами),
AG>мотивируя это тем, что все плагины также придётся пересобирать.

вы там определитесь нужна ли обратная совместимость со старыми плагинами или нет.
как только определитесь, то и решение сможете принять

насчет обратной совместимости: я работал с подобной системой и там виртуальные методы добавлялись в конец (там обязательно надо было поддерживать обратную совместимость) и вот однажды после добавления очередного метода совместимость сломалась.
оказалось, что если добавляется метод с именем, который уже есть (но с другим аргументами, к примеру), то студийный компилятор ломает порядок методов, группируя методы с одинаковым именем
так что будьте внимательны
Re: Интерфейс плагина и его vtable
От: ffk  
Дата: 12.10.17 08:54
Оценка: 4 (1) +1
Здравствуйте, AlexGin, Вы писали:

Это очень странное решение завязываться на бинарное представление vtbl

Правильнее, на мой взгляд, сделать новый интерфейс:

class IPluginlInterface2 : public IPluginlInterface
{
    virtual long SuspendCalculations() = 0;  // Добавлен этот новый вирт-метод!!!
}


Все новый плагины будут использовать его, а в программе сделать враппер для старых интерфейсов:

class IPluginlInterfaceWrapper : public IPluginlInterface2
{
public:
    IPluginlInterfaceWrapper(IPluginlInterface * old_plugin);

    virtual void Init() { old_plugin->Init(); } 
    virtual char* GetInterfaceDescription() const { return old_plugin->GetInterfaceDescription(); }
    ...
    virtual long SuspendCalculations() { /* Как быть? */}
}
Re[2]: Интерфейс плагина и его vtable
От: AlexGin Беларусь  
Дата: 12.10.17 09:13
Оценка:
Здравствуйте, uzhas, Вы писали:

U>вы там определитесь нужна ли обратная совместимость со старыми плагинами или нет.

Вообще-то НЕ обязательна.
Так как все плагины всё равно завязаны на головное приложение.
Посторонних разработчиков/компаний, которые бы занимались клепанием плагинов к нашей системе пока нет.
Точнее — пока что не предвидится.

U>как только определитесь, то и решение сможете принять

Ну ИМХО для решения важно также и смотреть вперёд — сегодня совместимость не актуальна, а завтра...

U>насчет обратной совместимости: я работал с подобной системой и там виртуальные методы добавлялись в конец (там обязательно надо было поддерживать обратную совместимость) и вот однажды после добавления очередного метода совместимость сломалась.

U>оказалось, что если добавляется метод с именем, который уже есть (но с другим аргументами, к примеру), то студийный компилятор ломает порядок методов, группируя методы с одинаковым именем
U>так что будьте внимательны
Это интересный факт.
Перегрузка виртуальных методов, в общем-то также может иметь место. Здесь спорить не буду.
Получается, что совместимость основанная на таком предположении, что добавляем вирт-методы в конец — несостоятельная

В общем — спасибо, за совет, примем к сведению.
Отредактировано 12.10.2017 9:41 AlexGin . Предыдущая версия .
Re[2]: Интерфейс плагина и его vtable
От: AlexGin Беларусь  
Дата: 12.10.17 09:32
Оценка:
Здравствуйте, ffk, Вы писали:

ffk>Здравствуйте, AlexGin, Вы писали:


ffk>Это очень странное решение завязываться на бинарное представление vtbl

Да, решение это не самое лучшее, сам чувствую.
Посему и совета спрашиваю

ffk>Правильнее, на мой взгляд, сделать новый интерфейс:


ffk>
ffk>class IPluginlInterface2 : public IPluginlInterface
ffk>{
ffk>    virtual long SuspendCalculations() = 0;  // Добавлен этот новый вирт-метод!!!
ffk>}
ffk>

Возможно, что это хорошая идея

ffk>Все новый плагины будут использовать его, а в программе сделать враппер для старых интерфейсов:

ffk>

ffk>class IPluginlInterfaceWrapper : public IPluginlInterface2
ffk>{
ffk>public:
ffk>    IPluginlInterfaceWrapper(IPluginlInterface * old_plugin);

ffk>    virtual void Init() { old_plugin->Init(); } 
ffk>    virtual char* GetInterfaceDescription() const { return old_plugin->GetInterfaceDescription(); }
ffk>    ...
ffk>    virtual long SuspendCalculations() { /* Как быть? */}
ffk>}

ffk>

Решение вроде как интересное...
В то же время: здесь и наследование (от базового IPluginlInterface) и агрегация (мембер old_plugin).
Не слишком ли много всего?
Может какой популярный паттерн проектирования на эту тему есть?
Re[3]: Интерфейс плагина и его vtable
От: ffk  
Дата: 12.10.17 09:46
Оценка: 4 (1)
Здравствуйте, AlexGin, Вы писали:

ffk>>[/ccode]

AG>Решение вроде как интересное...
AG>В то же время: здесь и наследование (от базового IPluginlInterface) и агрегация (мембер old_plugin).
AG>Не слишком ли много всего?
AG>Может какой популярный паттерн проектирования на эту тему есть?

Да. Wrapper aka Adapter. Наследование и агрегирование тут нормально. Вам надо "старый" плагин заставить работать с новыми требованиями. Для этого вы оборачиваете каждый метод. Если у вас меняется логика вызова методов, то вы это обработаете во врапере. Например, в первой версии интерфеса гараниторовалось, что в метод SetDataItem1 не могут передать nullptr, а во второй вы этого не гарантируете, то можете обработать это во врапере. В таком подходе точка совместимости локализована. Ваша программа может вообще забыть о старых интерфейсах и контрактах для них и работать только с новыми.

P.S. Наследование не обязательно, я бы его не делал.
Re: Интерфейс плагина и его vtable
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 12.10.17 09:47
Оценка: +1
Здравствуйте, AlexGin, Вы писали:

AG>А как бы сделалы Вы, уважаемые?

Если всё под винду, то я бы выбрал скорее всего COM, а всю сложность работы с ним спрятал в билдовую систему и заствил/научил всех использовать АТЛ.
AG>COM добавляет лишние сложности там, где их совсем даже не требуется.
Где, например?
Sic luceat lux!
Re[2]: Интерфейс плагина и его vtable
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 12.10.17 09:53
Оценка:
Здравствуйте, Kernan, Вы писали:

K>Здравствуйте, AlexGin, Вы писали:


AG>>А как бы сделалы Вы, уважаемые?

Есть ещё один вариант, подключать плагины не бинарно, а через некоего брокера(например, dbus) или, например, популярные сегодня message queue. В самом просто приближении, каждый плагин общается с ядром через loopback сокет, в этом случае не надо заморачиваться с ABI, а добавление новых сообщений будет проходить очень быстро + нет проблем с обратной совместимостью. Концептуального отличия от COM правда тут не так много.
Sic luceat lux!
Отредактировано 12.10.2017 9:55 Kernan . Предыдущая версия .
Re[2]: Интерфейс плагина и его vtable
От: AlexGin Беларусь  
Дата: 12.10.17 10:21
Оценка: :)
Здравствуйте, Kernan, Вы писали:

K>Здравствуйте, AlexGin, Вы писали:


AG>>А как бы сделалы Вы, уважаемые?

K>Если всё под винду, то я бы выбрал скорее всего COM, а всю сложность работы с ним спрятал в билдовую систему и заствил/научил всех использовать АТЛ.
Пока под винду, но мы используем Qt 5.9 и в перспективе можем перейти на кроссплатформу (Linux: Ubuntu, Debian).
Насчёт билдовой системы: работаем с QMake, которую можно применять как в родном для неё QtCreator, так и в MSVC (через QtVsAddin).
На данной стадии проекта применять что-то другое, кроме данного простого решения, не планируем.

AG>>COM добавляет лишние сложности там, где их совсем даже не требуется.

K>Где, например?
Как в своих основах:
1) Базовый интрефейс IUnknown (вот: https://msdn.microsoft.com/en-us/library/windows/desktop/ms680509(v=vs.85).aspx )
имеет в своём составе вирт-методы AddRef и Release. Да, в 1990-х это было актуально, однако теперь,
когда уже есть официально признанный std::shared_ptr ИМХО идея IUnknown потеряла всякую актуальность.
2) Лишнее наследование, совсем не продиктованное требованиями прикладной задачи, — также оверхед.
Так и в реализации:
a) Генерация сущностей в виде GUID, призванная исключить "DLL hell", кажется мне всё таки избыточной, за исключением ситуации —
если мы компания уровня M$, предлагающая свои продукты миллиардной аудитории
b) Язык определения интерфейсов MIDL ( https://msdn.microsoft.com/en-us/library/windows/desktop/aa367091(v=vs.85).aspx ) также
лишняя (в конетксте прикладных задач) сущность. Её наличие только усложняет коды проекта.
c) Поддержка и развитие проектов на базе COM куда более трудозатратная, чем без COM.
Здесь я подразумеваю как все пользовательские действия (в той же студии), котрые направлены на поддержку инфраструктуры COM, однако,
не актуальны (от слова совсем) для прикладной задачи; так и процесс сопровождения (документация по проекту и её поддержка).

Кроме всего этого, я (как тимлид) применяя COM должен набрать в мою рабочую группу людей, владеющих данной (ныне не актуальной) технологией,
или обучить существующую команду работой с нею. Это также — лишние телодвижения

P.S. Да, первоначельная идея — сделать COM компонент и применять в разных языковых средах (C, C++, VB) —
зародившаяся примерно четверть века назад, была революционна, но теперь идея актуальность потеряла, а излишняя сложность — осталась
Отредактировано 12.10.2017 10:59 AlexGin . Предыдущая версия . Еще …
Отредактировано 12.10.2017 10:40 AlexGin . Предыдущая версия .
Отредактировано 12.10.2017 10:30 AlexGin . Предыдущая версия .
Отредактировано 12.10.2017 10:28 AlexGin . Предыдущая версия .
Re[3]: Интерфейс плагина и его vtable
От: uzhas Ниоткуда  
Дата: 12.10.17 10:38
Оценка:
Здравствуйте, AlexGin, Вы писали:

AG>Получается, что совместимость основанная на таком предположении, что добавляем вирт-методы в конец — несостоятельная


есть определенные хитрости, которые надо держать в голове.
на самом деле ABI на C++ интерфейсах — вполне работоспособная тема. она хороша своей простотой и отсутствием накладных расходов на вызовы. но нужна определенная аккуратность и бдительность.
сложные типы (например, std::vector) не пробрасываются через такое API
на данный момент я также работаю с подобной системой, так что они вполне распространены
как говорится, не так страшен чёрт, как его малюют
Re[4]: Интерфейс плагина и его vtable
От: AlexGin Беларусь  
Дата: 12.10.17 10:55
Оценка:
Здравствуйте, uzhas, Вы писали:

U>Здравствуйте, AlexGin, Вы писали:


AG>>Получается, что совместимость основанная на таком предположении, что добавляем вирт-методы в конец — несостоятельная


U>есть определенные хитрости, которые надо держать в голове.

U>на самом деле ABI на C++ интерфейсах — вполне работоспособная тема. она хороша своей простотой и отсутствием накладных расходов на вызовы. но нужна определенная аккуратность и бдительность.
+100500
Вы, уважаемый uzhas, под выделенным, подразумевали примерно это:
https://stackoverflow.com/questions/2171177/what-is-an-application-binary-interface-abi
http://alenacpp.blogspot.com.by/2007/03/c-abi.html

U>сложные типы (например, std::vector) не пробрасываются через такое API

+100500
Да, сам объект в интерфейсе метода некошерен!
Но указатель на объект типа std::vector передавать (на уровне интерфейсного метода приведённый к типу void*),
IMHO вполне возможно...

U>на данный момент я также работаю с подобной системой, так что они вполне распространены

U>как говорится, не так страшен чёрт, как его малюют

Вот и мне не хочется "тащить в проект" сложность COM, чтобы весь код проекта рос как "снежный ком"
Re: Интерфейс плагина и его vtable
От: kov_serg Россия  
Дата: 12.10.17 11:09
Оценка:
Здравствуйте, AlexGin, Вы писали:

AG>А как бы сделалы Вы, уважаемые?

Я бы скриптовый язык lua для плагинов использовал.
Re[3]: Интерфейс плагина и его vtable
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 12.10.17 11:17
Оценка: +2
Здравствуйте, AlexGin, Вы писали:

AG>Пока под винду, но мы используем Qt 5.9 и в перспективе можем перейти на кроссплатформу (Linux: Ubuntu, Debian).

В QT же есть библиотека для создания плагинов. Почему её не использовать? Оно работает и как раз решает все описанные выше проблемы.
P.S. Я не согласен с твоими выводами по поводу COM, но спорить тут нет смысла.
Sic luceat lux!
Отредактировано 12.10.2017 11:38 Kernan . Предыдущая версия .
Re[5]: Интерфейс плагина и его vtable
От: uzhas Ниоткуда  
Дата: 12.10.17 11:30
Оценка: +1
Здравствуйте, AlexGin, Вы писали:

AG>под выделенным, подразумевали примерно это:

AG>https://stackoverflow.com/questions/2171177/what-is-an-application-binary-interface-abi

да, это оно

U>>сложные типы (например, std::vector) не пробрасываются через такое API

AG>+100500
AG>Да, сам объект в интерфейсе метода некошерен!
AG>Но указатель на объект типа std::vector передавать (на уровне интерфейсного метода приведённый к типу void*),
AG>IMHO вполне возможно...

проброска std контейнеров между разными модулями (exe/dll) — еще более хрупкое ABI. я и с такими работал. тут обычно делают так, что все бинари собираются одновременно одним компилятором с одними и теми же настройками для C++ runtime, в частности, отключают статический рантайм ну и с debug/release надо не путаться.
я бы не рекомендовал идти таким путем. т.к. в голове еще больше деталей надо держать)
лучше не передавать контейнеры, т.к. в разных модулях они могут иметь немного разную реализацию.

вот мы из одного бинаря во второй передали пусть даже указатель на std::vector. может ли второй бинарь хотя бы проитерироваться по этому вектору? только при определенных обстоятельствах, как то настройки компиляции STL (например, https://stackoverflow.com/questions/4738987/iterator-debug-level-error-in-visual-studio )
лучше передать T* + int size
Re[4]: Интерфейс плагина и его vtable
От: AlexGin Беларусь  
Дата: 12.10.17 12:28
Оценка:
Здравствуйте, Kernan, Вы писали:

K>Здравствуйте, AlexGin, Вы писали:


AG>>Пока под винду, но мы используем Qt 5.9 и в перспективе можем перейти на кроссплатформу (Linux: Ubuntu, Debian).

K>В QT же есть библиотека для создания плагинов.
+100500
Так мы именно её и используем в нашем проекте!
Данный вопрос, по развитию интерфейса, применение QtPlugin не отменяет.
В моём первоначальном посте я не указывал, что применяется QtPlugin, просто потому, что не хотел загружать коллег по форуму лишними деталями.

K>Почему её не использовать? Оно работает и как раз решает все описанные выше проблемы.

Там добавляется (на уровне интерфейса плагина), дополнительное наследование от QObject.
Как это может решить вопрос, указанный в первоначальном моём посте данного топика?
Если имеете какое-либо виденье по данному аспекту, уважаемый Kernan, пожалуйста изложите его.

K>P.S. Я не согласен с твоими выводами по поводу COM, но спорить тут нет смысла.

Я высказал мою точку зрения, сформированную во время работы с COM в 2000-х.
Эта технология применялась в стенах нескольких компаний, в котрых я тогда работал.

P.S. В нашем проекте важно решить именно ту проблему, что актуальна для данной задачи
Склоняюсь к применению "адаптера":
https://habrahabr.ru/post/85095
https://gist.github.com/pazdera/1145857
https://www.codeproject.com/Tips/595716/Adapter-Design-Pattern-in-Cplusplus
Отредактировано 12.10.2017 12:33 AlexGin . Предыдущая версия .
Re[2]: Интерфейс плагина и его vtable
От: AlexGin Беларусь  
Дата: 12.10.17 12:51
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Здравствуйте, AlexGin, Вы писали:


AG>>А как бы сделалы Вы, уважаемые?

_>Я бы скриптовый язык lua для плагинов использовал.
Стоит ли вводить новые сущности в проект?
Тем более, что всё (в плане интерфейса плагинов) уже сделано, возможны некоторые небольшие корректировки.
В общем, подсистема плагинов нас вполне устраивает, небольшой вопрос, описанный мною в начале топика — должен иметь адекватное решение.
Re[5]: Интерфейс плагина и его vtable
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 12.10.17 13:39
Оценка: 4 (1) +1
Здравствуйте, AlexGin, Вы писали:

AG>Так мы именно её и используем в нашем проекте!

Видимо, не совсем правильно.
AG>В моём первоначальном посте я не указывал, что применяется QtPlugin, просто потому, что не хотел загружать коллег по форуму лишними деталями.
Самое важное и не указываешь.
K>>Почему её не использовать? Оно работает и как раз решает все описанные выше проблемы.
AG>Там добавляется (на уровне интерфейса плагина), дополнительное наследование от QObject.
Это не так. Там добавляется макрос в класс и после объявляения класса после чего прогоняется через метакомпилятор QT, изучи документацию получше, там всё это есть. Я бы на твоём месте сдел минимальный проект и поисследовал работу с qt-плагинами или скачал минимальный пример где они используются и поковырял его.
AG>Как это может решить вопрос, указанный в первоначальном моём посте данного топика?
Изучив доки и поняв как это всё нужно правильно использовать ты, скорее всего, решишь свои проблемы.
Sic luceat lux!
Отредактировано 12.10.2017 13:40 Kernan . Предыдущая версия .
Re: Интерфейс плагина и его vtable
От: Alexander G Украина  
Дата: 12.10.17 13:41
Оценка:
Здравствуйте, AlexGin, Вы писали:
вопрос:

AG>Я полагаю, что все новые вирт-методы должны добавляться после DeInit, это обеспечит запуск старых плагинов.

AG>Коллега по работе предлагает размещать так, как оно кажется логичнее (без ориентации на совместимость со старымы плагинами),
AG>мотивируя это тем, что все плагины также придётся пересобирать.

AG>А как бы сделалы Вы, уважаемые?


Как вариант, сделать первый метод интерфейса, чтобы версию интерфейса возвращал. И менять его при всех несовместимых изменениях.
Тогда старые плагины можно выкидывать на этапе загрузки, а не смотреть на непредвиденное поведение после.
Русский военный корабль идёт ко дну!
Re[3]: Интерфейс плагина и его vtable
От: kov_serg Россия  
Дата: 12.10.17 13:42
Оценка:
Здравствуйте, AlexGin, Вы писали:

AG>Здравствуйте, kov_serg, Вы писали:


_>>Здравствуйте, AlexGin, Вы писали:


AG>>>А как бы сделалы Вы, уважаемые?

_>>Я бы скриптовый язык lua для плагинов использовал.
AG>Стоит ли вводить новые сущности в проект?
Зависит от задач проекта. Скриптовый язык более гибкий и позволяет обычным текстовым редактором дополнить недостающий функционал.
В отличие от бинарника, можно исправлять ошибки в уже имеющихся дополнять или на их основе делать похожие. Низкий порог входа.
Легковесность. Более выразителен. При необходимости спокойно может вызывать бинарные либы для выполнения тяжелых вычислений.

AG>Тем более, что всё (в плане интерфейса плагинов) уже сделано, возможны некоторые небольшие корректировки.

AG>В общем, подсистема плагинов нас вполне устраивает, небольшой вопрос, описанный мною в начале топика — должен иметь адекватное решение.

AG>Коллега по работе предлагает размещать так, как оно кажется логичнее (без ориентации на совместимость со старымы плагинами),

Должна быть бинарная совместимость и механизм проверки версий.
Я бы добавил еще цифровые подписи чтоб каждый раз на вирусы не проверять

AG>мотивируя это тем, что все плагины также придётся пересобирать.

А если плагины будут сторонние и плагин работавший в старой версии вдруг будет отсутствовать на новой.
Например плагин работающий с банковскими картами. Обновили по и карточки большее не принимаются. Красота.
Re[2]: Интерфейс плагина и его vtable
От: kov_serg Россия  
Дата: 12.10.17 13:55
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>Здравствуйте, AlexGin, Вы писали:

AG>вопрос:

AG>>Я полагаю, что все новые вирт-методы должны добавляться после DeInit, это обеспечит запуск старых плагинов.

AG>>Коллега по работе предлагает размещать так, как оно кажется логичнее (без ориентации на совместимость со старымы плагинами),
AG>>мотивируя это тем, что все плагины также придётся пересобирать.

AG>>А как бы сделалы Вы, уважаемые?


AG>Как вариант, сделать первый метод интерфейса, чтобы версию интерфейса возвращал. И менять его при всех несовместимых изменениях.

AG>Тогда старые плагины можно выкидывать на этапе загрузки, а не смотреть на непредвиденное поведение после.
Надо что бы не плагин проверял, а приложение.
А плагин просто просил известный ему интерфейс (на момент написания плагина) к приложению.
А вот приложение может несколько десятко таких интерфейсов поддерживать.

Например у плагина есть init, done
В init плагин запрацивает интерфейс ПО наример дайте мне версию интерфейса 2.1 после либо получает её либо идёт лесом.
app_runtime rt[1];

int init(queryfn fn) {
  if (fn.query(rt,APP_RUNTIME_VERSION_2_1) return -1;
  rt->set_plugin_info(info);
  rt->create_thread...
  rt->add_menu_item...
  rt->set_event_listner...
  rt->add_resouce...
  ...
  return 0;
}
void done() {
  // release resources used
}
Re: Интерфейс плагина и его vtable
От: c-smile Канада http://terrainformatica.com
Дата: 12.10.17 19:45
Оценка: 6 (1)
Здравствуйте, AlexGin, Вы писали:

AG>Доброе время суток, уважаемые коллеги!


А какие проблемы?

class IPluginlInterface
{
public:
     static int iid() { return 1; }

     virtual IPluginlInterface* GetInterface(int id) const = 0;
 
     template<class IF>  
       IF* Interface() const { return static_cast<IF*>(GetInterface(IF::iid())); }
      

};

class IPluginlInterface2 : IPluginlInterface
{
public:
     static int iid() { return 2; }

     virtual IPluginlInterface* GetInterface(int id) const 
     {
        if( id == iid() ) return this;
        return IPluginlInterface::GetInterface(id);
     }
};



Ну и использование

IPluginlInterface* pp = ...;
IPluginlInterface2* pp2 = pp->Interface<IPluginlInterface2>();
Re[2]: Интерфейс плагина и его vtable
От: AlexGin Беларусь  
Дата: 14.10.17 09:33
Оценка:
Здравствуйте, c-smile, Вы писали:

CS>Здравствуйте, AlexGin, Вы писали:


AG>>Доброе время суток, уважаемые коллеги!


CS>А какие проблемы?


CS>
CS>class IPluginlInterface
CS>{
CS>public:
CS>     static int iid() { return 1; }

CS>     virtual IPluginlInterface* GetInterface(int id) const = 0;
 
CS>     template<class IF>  
CS>       IF* Interface() const { return static_cast<IF*>(GetInterface(IF::iid())); }
      

CS>};

CS>class IPluginlInterface2 : IPluginlInterface
CS>{
CS>public:
CS>     static int iid() { return 2; }

CS>     virtual IPluginlInterface* GetInterface(int id) const 
CS>     {
CS>        if( id == iid() ) return this;
CS>        return IPluginlInterface::GetInterface(id);
CS>     }
CS>};
CS>



CS>Ну и использование


CS>
CS>IPluginlInterface* pp = ...;
CS>IPluginlInterface2* pp2 = pp->Interface<IPluginlInterface2>();
CS>



А нужен ли тут этот метод:
   template<class IF>  
      IF* Interface() const { return static_cast<IF*>(GetInterface(IF::iid())); }


Может проще вместо метода Interface<IF> — применять dynamic_cast
IPluginlInterface* pp = ...;
IPluginlInterface2* pp2 = dynamic_cast<IPluginlInterface2*>(pp);


Какие тут могут быть аргументированные соображения за или против?
Отредактировано 14.10.2017 9:34 AlexGin . Предыдущая версия .
Re[3]: Интерфейс плагина и его vtable
От: AlexGin Беларусь  
Дата: 14.10.17 09:42
Оценка:
Здравствуйте, Kernan, Вы писали:

K>Здравствуйте, Kernan, Вы писали:


K>>Здравствуйте, AlexGin, Вы писали:


AG>>>А как бы сделалы Вы, уважаемые?

K>Есть ещё один вариант, подключать плагины не бинарно, а через некоего брокера(например, dbus) или, например, популярные сегодня message queue. В самом просто приближении, каждый плагин общается с ядром через loopback сокет, в этом случае не надо заморачиваться с ABI, а добавление новых сообщений будет проходить очень быстро + нет проблем с обратной совместимостью. Концептуального отличия от COM правда тут не так много.

Думал на эту тему, но пока копаю в более привычном мне направлении: QtPlugin и его метаданные — вот пример:
http://pavelk.ru/ispolzovanie-q_plugin_metadata-file-jsonfile-json

А также и другие способы решения данного вопроса в рамках C++ как уже рекомендовали в этой ветке:
http://rsdn.org/forum/cpp.applied/6932518.1
Автор: c-smile
Дата: 12.10.17
Re[6]: Интерфейс плагина и его vtable
От: AlexGin Беларусь  
Дата: 14.10.17 09:51
Оценка:
Здравствуйте, Kernan, Вы писали:

AG>>Там добавляется (на уровне интерфейса плагина), дополнительное наследование от QObject.

K>Это не так. Там добавляется макрос в класс и после объявляения класса после чего прогоняется через метакомпилятор QT, изучи документацию получше, там всё это есть. Я бы на твоём месте сдел минимальный проект и поисследовал работу с qt-плагинами или скачал минимальный пример где они используются и поковырял его.

Примеры брал, с ними разбирался.
По крайней мере то, что заявлено авторами в примере, работает успешно.

Вот такие вот макросы (кроме обычного Q_OBJECT):
   Q_PLUGIN_METADATA(IID ...)
   Q_INTERFACES(...)


Возможно, следует копать именно в сторону этих макросов

AG>>Как это может решить вопрос, указанный в первоначальном моём посте данного топика?

K>Изучив доки и поняв как это всё нужно правильно использовать ты, скорее всего, решишь свои проблемы.
Вполне может быть!

Вот — например здесь:
http://pavelk.ru/ispolzovanie-q_plugin_metadata-file-jsonfile-json
про применение метаданных из файла *.json — интересная инфа!
Отредактировано 14.10.2017 9:52 AlexGin . Предыдущая версия .
Re[3]: Интерфейс плагина и его vtable
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 14.10.17 19:47
Оценка:
Здравствуйте, AlexGin, Вы писали:

Подкину на вентилятор

AG>1) Базовый интрефейс IUnknown (вот: https://msdn.microsoft.com/en-us/library/windows/desktop/ms680509(v=vs.85).aspx )

AG>имеет в своём составе вирт-методы AddRef и Release. Да, в 1990-х это было актуально, однако теперь,
AG>когда уже есть официально признанный std::shared_ptr ИМХО идея IUnknown потеряла всякую актуальность.

После изучения std::shared_ptr, я пришел к выводу что это костыли для тех, кто ниасилил счетчики ссылок в начале 2000-ых

IUnknown — это не только ценный мех AddRef и Release, но и еще и QueryInterface. А если конкретнее — динамическая диспетчеризация интерфейсов (я правильно эту штуку "обозвал"?).

Плюс технология прозрачной агрегации компонент.

---
Не обязательно юзать IUnknown как есть и делать интерфейсы совместимыми с COM. Достаточно просто позаимствовать идею.

Я тут как-то исследовал эволюцию базового/внутреннего интерфейса для всех своих программ. Когда-то решил, что достаточно add_ref/release, а вместо QueryInterface вполне сгодится dynamic_cast.

Но к концу второго десятка лет непрерывного развития своей "игрушки" пришел к выводу, что query_interface таки придется прикручивать к внутренним интерфейсам (которые наружу никогда не будут выставлены).

---
UPD. Самое смешное, что когда программировал одну хреновину под .NET (куча классов с IDispose), тоже пришлось к ним прикручивать старый добрый COM счетчики. Только там это были не счетчики ссылок, а счетчики активных вызовов методов.
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Отредактировано 14.10.2017 19:53 DDDX . Предыдущая версия . Еще …
Отредактировано 14.10.2017 19:48 DDDX . Предыдущая версия .
Re: Интерфейс плагина и его vtable
От: Pzz Россия https://github.com/alexpevzner
Дата: 14.10.17 20:16
Оценка:
Здравствуйте, AlexGin, Вы писали:

AG>А как бы сделалы Вы, уважаемые?


Ну во-первых, надо решить, нужна ли вам совместимость. Но если не нужна, то по крайней мере следовало бы проверять, что плагины совместимы с текущей версией программы.

Во-вторых, я не полагался бы на совместимость vtable, даже при добавлении функций в конец. Собственно, переход на другую версию компилятора может поломать совместимость vtable.

Гораздо безопаснее экспортировать из плагина сишный (а не плюсовый) интерфейс. Например, структурку, заполненную указателями на функции. Да, я понимаю, это неудобно, устарело и все такое. Зато это гораздо надежнее, чем то, что делаете вы.
Re[3]: Интерфейс плагина и его vtable
От: c-smile Канада http://terrainformatica.com
Дата: 14.10.17 20:30
Оценка:
Здравствуйте, AlexGin, Вы писали:

AG>А нужен ли тут этот метод:

AG>
AG>   template<class IF>  
AG>      IF* Interface() const { return static_cast<IF*>(GetInterface(IF::iid())); }
AG>


AG>Может проще вместо метода Interface<IF> — применять dynamic_cast

AG>
AG>IPluginlInterface* pp = ...;
AG>IPluginlInterface2* pp2 = dynamic_cast<IPluginlInterface2*>(pp);
AG>


AG>Какие тут могут быть аргументированные соображения за или против?


dynamic_cast будет работать a) если оба модуля скомпилированы с поддержкой rtti и б) если и plugin и твое приложение используют одну и ту же runtime библиотеку.

Что в случае exe/dll связки как правило не факт.
Re[4]: Интерфейс плагина и его vtable
От: AlexGin Беларусь  
Дата: 14.10.17 23:11
Оценка:
Здравствуйте, c-smile, Вы писали:

CS>dynamic_cast будет работать a) если оба модуля скомпилированы с поддержкой rtti и б) если и plugin и твое приложение используют одну и ту же runtime библиотеку.

Насчёт поддержки RTTI я так понимаю, что опция /GR присутствует в спиcке опций компилятора MSVC по умолчанию (by default)?
Вот материалы по данной теме:
https://msdn.microsoft.com/en-us/library/we6hfdy0.aspx
https://technet.microsoft.com/en-us/library/b2ay8610(v=vs.100).aspx
https://support.smartbear.com/testcomplete/docs/app-testing/desktop/visual-c/preparing/visual-c-8.html
https://stackoverflow.com/questions/2635123/activate-rtti-in-c
Насчёт GCC и MinGW — вроде также подобная опция включена по умолчанию

CS>Что в случае exe/dll связки как правило не факт.

Насчёт Run-Time библиотеки — очевидно, что используем одну и ту же — как для головного приложения, так и для Plugin-а:
понятно, что и я и мои коллеги применяем одну и туже версию Qt; также как одну и ту же версию MSVC.

P.S. Здесь следует отметить, что как головное приложение, так и плагин создаётся в одном и том же филиале нашей компании,
даже если передаём на другой филиал, то с оговорками типа: какие библиотеки и компоненты (строго!) применяем.
Посему, если о общем случае совпадение здесь вроде как бы и НЕ очевидно, то в нашем проекте — оно просто ОБЯЗАНО БЫТЬ!
Отредактировано 14.10.2017 23:38 AlexGin . Предыдущая версия . Еще …
Отредактировано 14.10.2017 23:14 AlexGin . Предыдущая версия .
Re[4]: Интерфейс плагина и его vtable
От: AlexGin Беларусь  
Дата: 16.10.17 12:52
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>Я тут как-то исследовал эволюцию базового/внутреннего интерфейса для всех своих программ. Когда-то решил, что достаточно add_ref/release, а вместо QueryInterface вполне сгодится dynamic_cast.

Блог интересный, мне понравилось! Пиши ещё!

Есть места, на которые любуешься
Абстрактный базовый класс (aka interface) — великолепно! Применение шаблонов (templates) — гениально!
И самое важное — когда доходишь до этого всего своим умом, а не просто вычитываешь в толковой кижице


КД>Но к концу второго десятка лет непрерывного развития своей "игрушки" пришел к выводу, что query_interface таки придется прикручивать к внутренним интерфейсам (которые наружу никогда не будут выставлены).

Есть принцип KISS — зачем же нам здесь его нарушать?
Внутренний интерфейс — что за зверь?
Если можно — может есть подходящий паттерн проектирования?

КД>---

КД>UPD. Самое смешное, что когда программировал одну хреновину под .NET (куча классов с IDispose), тоже пришлось к ним прикручивать старый добрый COM счетчики. Только там это были не счетчики ссылок, а счетчики активных вызовов методов.

P.S. Самое главное, ИМХО — осознавать ситуации, когда стреляем пушками по воробьям
Каждая проблема всегда имеет адекватное решение...
Можно придумывать решение "универсальной" проблемы, при этом плодить массу разных сложностей.
Тот же QueryInterface:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms682521(v=vs.85).aspx
Он хороший, когда тиражируем различные компоненты (читай: COM компоненты) сотнями тысяч, а разновидностей их интерфейсов — около тысячи.
Если у меня количество компонентов можно пересчитать по пальцам (одной руки), а количество интерфейсов — хорошо, если пару штук, то
применение dynamic_cast<...>(...) вместо QueryInterface — заметно упрощает жизнь!

P.P.S. Просто задачи, решаемые как нашим приложением, так и его плагинной подсистемой, достаточно специфичны...
Отредактировано 16.10.2017 13:01 AlexGin . Предыдущая версия .
Re[5]: Интерфейс плагина и его vtable
От: c-smile Канада http://terrainformatica.com
Дата: 16.10.17 17:33
Оценка:
Здравствуйте, AlexGin, Вы писали:

CS>>Что в случае exe/dll связки как правило не факт.

AG>Насчёт Run-Time библиотеки — очевидно, что используем одну и ту же — как для головного приложения, так и для Plugin-а:

Не очевидно. Смотря какую. Если runtime со static linkage то по определению exe и dll будут иметь разные runtime.
В случае же MinGW всё вообще может быть интереснее.

А если надо plugin отладить ? Т.е. dll debug runtime а exe release...

Короче: dynamic_cast надежно работает только внутри одного модуля (exe/dll). Всё остальное — гадание на кофейной гуще.
Re[5]: Интерфейс плагина и его vtable
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 16.10.17 19:04
Оценка:
Здравствуйте, AlexGin, Вы писали:

AG>Блог интересный, мне понравилось! Пиши ещё!


... Я там иногда гадости всякие пишу

А так, спасибо за отзыв

КД>>Но к концу второго десятка лет непрерывного развития своей "игрушки" пришел к выводу, что query_interface таки придется прикручивать к внутренним интерфейсам (которые наружу никогда не будут выставлены).


AG>Есть принцип KISS — зачем же нам здесь его нарушать?


Я двумя руками за простоту.

AG>Внутренний интерфейс — что за зверь?


Программа разделена два слоя, которые взаимодействуют через абстрактные C++ интерфейсы (производные от t_smart_interface). Вот как раз их я и назвал "внутренним интерфейсом". Не очень удачно выразился — у меня проблемы с терминологией.

AG>Если можно — может есть подходящий паттерн проектирования?


  Что-то типа такого?
//! \ingroup db_obj
/// <summary>
///  Интерфейс для получения сервисных объектов компоненты
/// </summary>
///  Используется для расширения объектов connection, transaction.
class COMP_CONF_DECLSPEC_NOVTABLE t_db_service_provider:public t_db_smart_interface
{
 public:

  //interface ------------------------------------------------------------

  /// <summary>
  /// Запрос сервисного объекта
  /// </summary>
  //! \param[in] rguidService
  //!   Идентификатор сервиса
  //! \return
  //!   Возвращает указатель на сервисный объект. Если запрашиваемый
  //!   сервис не поддерживается, то возвращается NULL
  virtual t_db_object_ptr query_service(REFGUID rguidService)=0; //throw
};//class t_db_service_provider

КД>>---
КД>>UPD. Самое смешное, что когда программировал одну хреновину под .NET (куча классов с IDispose), тоже пришлось к ним прикручивать старый добрый COM счетчики. Только там это были не счетчики ссылок, а счетчики активных вызовов методов.

AG>P.S. Самое главное, ИМХО — осознавать ситуации, когда стреляем пушками по воробьям


И тогда хочется начать грязно ругаться. Вот как раз для этого мне и завели этот блог
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re: Интерфейс плагина и его vtable
От: Vi2 Удмуртия http://www.adem.ru
Дата: 17.10.17 07:05
Оценка:
Здравствуйте, AlexGin, Вы писали:

AG>Я полагаю, что все новые вирт-методы должны добавляться после DeInit, это обеспечит запуск старых плагинов.

AG>Коллега по работе предлагает размещать так, как оно кажется логичнее (без ориентации на совместимость со старымы плагинами),
AG>мотивируя это тем, что все плагины также придётся пересобирать.

Есть ещё проблема: запуск новых плагинов на старом сервере. Я тоже думал, что это несбыточно. Ещё как сбыточно.

AG>А как бы сделалы Вы, уважаемые?


Как тебе уже предлагали — запрос службы по SID и получением её рабочего интерфейса. Идея та же, что и у СОМ::QueryInterface.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[2]: Интерфейс плагина и его vtable
От: ομικρον  
Дата: 17.10.17 13:32
Оценка:
Здравствуйте, Pzz, Вы писали:

Pzz>Во-вторых, я не полагался бы на совместимость vtable, даже при добавлении функций в конец. Собственно, переход на другую версию компилятора может поломать совместимость vtable.

С совместимостью все должно быть хорошо, по крайней мере для "правильных" интерфейсов:

In Visual C++ ... COM interfaces are guaranteed not to break from version to version.

https://msdn.microsoft.com/en-us/library/bb531344(v=vs.120).aspx

It is no coincidence that the Win32 COM object layout matches closely the C++ object layout.

https://blogs.msdn.microsoft.com/oldnewthing/20040205-00/?p=40733
Re[3]: Интерфейс плагина и его vtable
От: Pzz Россия https://github.com/alexpevzner
Дата: 17.10.17 13:35
Оценка:
Здравствуйте, ομικρον, Вы писали:

Pzz>>Во-вторых, я не полагался бы на совместимость vtable, даже при добавлении функций в конец. Собственно, переход на другую версию компилятора может поломать совместимость vtable.

ομι>С совместимостью все должно быть хорошо, по крайней мере для "правильных" интерфейсов:
ομι>

ομι>In Visual C++ ... COM interfaces are guaranteed not to break from version to version.


Насколько я понимаю, COM'овский интерфейс — это сишный интерфейс.
Re[3]: Интерфейс плагина и его vtable
От: AlexGin Беларусь  
Дата: 17.10.17 16:43
Оценка:
Здравствуйте, ομικρον, Вы писали:

ομι>Здравствуйте, Pzz, Вы писали:


Pzz>>Во-вторых, я не полагался бы на совместимость vtable, даже при добавлении функций в конец. Собственно, переход на другую версию компилятора может поломать совместимость vtable.

ομι>С совместимостью все должно быть хорошо, по крайней мере для "правильных" интерфейсов:
ομι>

ομι>In Visual C++ ... COM interfaces are guaranteed not to break from version to version.

ομι>https://msdn.microsoft.com/en-us/library/bb531344(v=vs.120).aspx

ομι>

ομι>It is no coincidence that the Win32 COM object layout matches closely the C++ object layout.

ομι>https://blogs.msdn.microsoft.com/oldnewthing/20040205-00/?p=40733

Для данного проекта — COM мы НЕ применяем.
Ввиду его большой избыточности.
Я уже упоминал об этом выше: http://rsdn.org/forum/cpp.applied/6931943.1
Автор: AlexGin
Дата: 12.10.17

COM — хорошо, KISS — ещё лучше
Re[2]: Интерфейс плагина и его vtable
От: AlexGin Беларусь  
Дата: 17.10.17 18:46
Оценка:
Здравствуйте, Vi2, Вы писали:

Vi2>Есть ещё проблема: запуск новых плагинов на старом сервере. Я тоже думал, что это несбыточно. Ещё как сбыточно.


Дело в том, что в этом случае, проблема оказывается намного глубже, нежели просто интерфейс плагинов —
новые плагины на старом сервере не загрузятся (не говоря уж об исполнении).
Плохо это или хорошо — другой вопрос...
По крайней мере, проблема будет отчётливо видна сразу.
Искусственно добиваться совместимости со "старым сервером" — не вижу смысла.
Там всё равно, функционал ядра НЕ поддерживает задач, реализованных в составе новых плагинов.

AG>>А как бы сделалы Вы, уважаемые?


Vi2>Как тебе уже предлагали — запрос службы по SID и получением её рабочего интерфейса. Идея та же, что и у СОМ::QueryInterface.

+100500
Идея хорошая, реализую её в ближайшее время.
Всё равно, это значительно проще, чем тащить в проект весь COM "живьём"
Отредактировано 17.10.2017 18:54 AlexGin . Предыдущая версия .
Re[3]: Интерфейс плагина и его vtable
От: Vi2 Удмуртия http://www.adem.ru
Дата: 17.10.17 20:23
Оценка:
Здравствуйте, AlexGin, Вы писали:

AG>Дело в том, что в этом случае, проблема оказывается намного глубже, нежели просто интерфейс плагинов —

AG>новые плагины на старом сервере не загрузятся (не говоря уж об исполнении).
AG>Плохо это или хорошо — другой вопрос...

А с чего бы им и не загружаться, ведь свойство загрузки одинаково для старых и новых плагинов? Вот и попросит новый плагин у старого сервера IPluginlInterface без новых, добавленных в конец, методов и вуаля. Причём обмен плагинами у пользователей находится вне поля зрения компании производителя.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[4]: Интерфейс плагина и его vtable
От: AlexGin Беларусь  
Дата: 18.10.17 08:37
Оценка:
Здравствуйте, Vi2, Вы писали:

Vi2>Здравствуйте, AlexGin, Вы писали:


AG>>Дело в том, что в этом случае, проблема оказывается намного глубже, нежели просто интерфейс плагинов —

AG>>новые плагины на старом сервере не загрузятся (не говоря уж об исполнении).
AG>>Плохо это или хорошо — другой вопрос...

Vi2>А с чего бы им и не загружаться, ведь свойство загрузки одинаково для старых и новых плагинов? Вот и попросит новый плагин у старого сервера IPluginlInterface без новых, добавленных в конец, методов и вуаля. Причём обмен плагинами у пользователей находится вне поля зрения компании производителя.


Зачем весь этот цирк
Если бы всё было именно так, — я бы взял готовый COM и не парился

Предположим такой вариант — загрузил я новый плагин на старом сервере (на старом пирложении). Что дальше?
Новый плагин, как я уже упоминал — в нашем проекте — решает несколько иные задачи, нежели старый.
Ядро приложения (точнее — старая версия ядра) НЕ ПОДДЕРЖИВАЕТ ДАННЫЙ КЛАСС ЗАДАЧ.
Просто потому, что в момент написания старой версии, ТЗ на данные задачи ещё не было сформировано.

P.S. У нас плагины реализуют некоторые вычислительные задачи, поэтому применение интерфейсов а-ля COM —
просто напросто усложнит проект, но не решит никаких (имеющихся в контексте наших задач), проблем.
Отредактировано 18.10.2017 8:41 AlexGin . Предыдущая версия .
Re[5]: Интерфейс плагина и его vtable
От: Vi2 Удмуртия http://www.adem.ru
Дата: 18.10.17 09:06
Оценка:
Здравствуйте, AlexGin, Вы писали:

AG>

AG>Зачем весь этот цирк

Я тоже не знаю, но он бывает.

AG>Предположим такой вариант — загрузил я новый плагин на старом сервере (на старом приложении). Что дальше?

AG>Новый плагин, как я уже упоминал — в нашем проекте — решает несколько иные задачи, нежели старый.
AG>Ядро приложения (точнее — старая версия ядра) НЕ ПОДДЕРЖИВАЕТ ДАННЫЙ КЛАСС ЗАДАЧ.
AG>Просто потому, что в момент написания старой версии, ТЗ на данные задачи ещё не было сформировано.

Если интерфейсы просто отличаются наличием новых методов в конце вирт.таблицы, то получим не неподдержку данного класса задач, а падение системы. Понятно, что после такого падения эти плагины будут выброшены. Однако отношение к системы будет превратным.

А бывает, что новый плагин решают ту же задачу, но другими средствами, более быстрыми, но и не соответствующими старому серверу.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[5]: Интерфейс плагина и его vtable
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 18.10.17 09:15
Оценка:
Здравствуйте, AlexGin, Вы писали:

AG>Предположим такой вариант — загрузил я новый плагин на старом сервере (на старом пирложении). Что дальше?


Плагин запрашивает версию ядра и сравнивает её с минимально поддерживаемой.

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

AG>P.S. У нас плагины реализуют некоторые вычислительные задачи, поэтому применение интерфейсов а-ля COM -

AG>просто напросто усложнит проект, но не решит никаких (имеющихся в контексте наших задач), проблем.

Вообщем тут тебе говорят, что если взялся за гушь делать систему на независимо разрабатываемых модулях — не упрощай и не пытайся изобретать велосипед

Использование dynamic_cast-ов, исключений, C++ классов через границы модулей до добра не доведет.

И если хочется простоты, не проще ли тогда скомпилировать все вместе в одном бинарнике?
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[2]: Интерфейс плагина и его vtable
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 18.10.17 09:27
Оценка:
Здравствуйте, Pzz, Вы писали:

Pzz>Гораздо безопаснее экспортировать из плагина сишный (а не плюсовый) интерфейс. Например, структурку, заполненную указателями на функции. Да, я понимаю, это неудобно, устарело и все такое. Зато это гораздо надежнее, чем то, что делаете вы.


Надежно, это когда такую структуру заполняет компилятор.

А то я, #$%, знаю тут одних таких "заполнятелей".

Дозаполнялись, что получился <вырезано цензурой> Франкенштейн.

Зато типа свой.
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[4]: Интерфейс плагина и его vtable
От: ομικρον  
Дата: 18.10.17 12:18
Оценка: 4 (1)
Здравствуйте, AlexGin, Вы писали:

AG>Для данного проекта — COM мы НЕ применяем.

AG>Ввиду его большой избыточности.

И правильно. В этой подветке речь идет всего лишь о том, что есть возможность "надежного" (совместимость разных версий приложения, компиляторов, ...) использования интерефейсов с++. Чтобы увидеть это, нужно просто посмотреть на определение COM-интерфейса, вся технология COM здесь несколько сбоку.

A COM interface is nothing more than a named table of function pointers (methods), each of which has documented behavior.

By design, ... a COM interface is binary-compatible with a C++ abstract class.

https://msdn.microsoft.com/en-us/library/ms809982.aspx
Re[6]: Интерфейс плагина и его vtable
От: AlexGin Беларусь  
Дата: 18.10.17 12:33
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>Здравствуйте, AlexGin, Вы писали:


AG>>Предположим такой вариант — загрузил я новый плагин на старом сервере (на старом пирложении). Что дальше?


КД>Плагин запрашивает версию ядра и сравнивает её с минимально поддерживаемой.


КД>Потом начинает запрашивать по IID интерфейсы ядра, через которые он будет взаимодействовать с ним. И если вдруг обнаружит что интерфейс не поддерживается, то значит старым уже является сам плагин


Плагин в данном контексте — это пассивный элемент, загружаемый и запускаемый со стороны головного модуля (приложения).
Он ничего ни у кого не запрашивает. Наоборот — головное приложение запрашивает интерфейс плагина.

AG>>P.S. У нас плагины реализуют некоторые вычислительные задачи, поэтому применение интерфейсов а-ля COM -

AG>>просто напросто усложнит проект, но не решит никаких (имеющихся в контексте наших задач), проблем.

КД>Вообщем тут тебе говорят, что если взялся за гушь делать систему на независимо разрабатываемых модулях — не упрощай и не пытайся изобретать велосипед

Да, велосипеды, мопеды, мотоциклы и даже джипы не нужны, когда мы умеем делать танки!
Это ведь универсальный транспорт — и едет, и стреляет, и пасссажиров защищает.
Зачем делать другой транспорт?

КД>Использование dynamic_cast-ов, исключений, C++ классов через границы модулей до добра не доведет.

Я уже принял решение — делать так, как здесь выше советовал уважаемый товарищ c-smile:
http://rsdn.org/forum/cpp.applied/6932518.1
Автор: c-smile
Дата: 12.10.17


КД>И если хочется простоты, не проще ли тогда скомпилировать все вместе в одном бинарнике?

Бросание в крайности — это наше всё

P.S. Тему считаю закрытой, так как лично я уже определился с решением (см выделенное выше).
Re: Интерфейс плагина и его vtable
От: AlexGin Беларусь  
Дата: 18.10.17 12:48
Оценка:
Огромное спасибо всем ответившим, и особенно — уважаемому товарищу c-smile!

Ответ которого: http://rsdn.org/forum/cpp.applied/6932518.1
Автор: c-smile
Дата: 12.10.17

Я вижу как наиболее оптимальный, и подходящий для нашего проекта.

Ещё раз напомню, что имеется хороший принцип KISS: https://en.wikipedia.org/wiki/KISS_principle
KISS – keep it simple stupid (делайте вещи проще), который даже важнее, чем применеиние COM любой ценой
https://habrahabr.ru/post/249639

Дальнейшие прения по данной теме возможны, но IMHO не рациональны
Отредактировано 18.10.2017 13:11 AlexGin . Предыдущая версия . Еще …
Отредактировано 18.10.2017 12:56 AlexGin . Предыдущая версия .
Re[6]: Интерфейс плагина и его vtable
От: AlexGin Беларусь  
Дата: 18.10.17 12:52
Оценка:
Здравствуйте, уважаемый товарищ c-smile!

Я совершенно согласен с твоими доводами, в т.ч. и по dynamic_cast<...>(...)
Считаю идею, которую ты предложил выше: http://rsdn.org/forum/cpp.applied/6932518.1
Автор: c-smile
Дата: 12.10.17

наиболее подходящей для применения в нашем проекте!

Огромное спасибо, за толковый совет!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.