Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Проанализируйте интерфейс системы плагинов, Укажите на ошибки проектирования 
V
    Опции темы
ZVano
Дата 16.9.2011, 11:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 259
Регистрация: 11.12.2006
Где: Украина, Кривой Р ог

Репутация: нет
Всего: 4



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

Идеология такова:
Код

Идеология плагина.
0. Плагин работает только в паре с менеджером плагинов.
1. Плагин имеет идентификатор, который ему назначил менеджер плагинов.
Идентификатор временный. Выдается в момент загрузки и действителен до выгрузки.
2. Плагин имеет ссылку на менеджер плагинов.
3. Плагин имеет структуру с реальной информацией о плагине.

Алгоритм работы системы:
1. Некая программа:
1.1 Загружает DLL с менеджером плагинов.
1.2. Запрашивает у DLL ссылку на объект менеджера плагинов
1.2.1 Получает адрес функции C_DLLFUNNAME_GET_PLUGINS_MANAGER_INTERFACE
1.2.2 Вызовом функции получает базовую структуру IPluginsManager.
1.3 Выполняет предустановку менеджера плагинов.
>> При этом программа может привести базовый интерфейс к целевому руководствуясь
>> либо флагом "TPluginsManagerInfo.managerVersion", либо своей внутренней логикой.
1.4 Запрашивает у менеджера плагинов один или несколько базовых плагинов.
>> Получает их интерфейсы.
1.4.1 Менеджер плагинов ищет плагин в кеше
1.4.2 Менеджер плагинов ищет плагин на диске
1.4.2.1 Загружает DLL плагина
1.4.2.2 Получает ссылку на функцию C_DLLFUNNAME_GET_PLUGIN_INTERFACE
1.4.2.3 Вызовом функции получает интерфейс базового плагина IPlugin.
>> Плагин обязан заполнить базовые реквизиты: PluginInfo.
1.4.2.4 Заполняет базовые реквизиты:
>> Id, Handle, PluginPath, PluginsManager
>> PluginsManager - это ссылка на себя (на менеджер плагинов).
1.5 Использует базовые плагины. (Рабочий цикл приложения).
>>
1.6 Выход из программы.

Алгоритм работы плагина:
1. Вне плагина через интерфейс плагина вызывается некое действие.
>> Допустим, программа получила интерфейс к MyPlugin1 и вызвала его действие MyPlugin1Action1.
2. Плагин выполняет некоторый внутренний код.
>> При выполнении кода плагину может потребоваться другой плагин.
>> В таком случае плагин (MyPlugin1) запрашивает у менеджера плагинов интерфейс
>> нужного плагина (допустим MyPlugin2).
>> Получив интервейс вызывает некоторый публичный метод(MyPlugin2Action1, MyPlugin2Action2 ...)
>> И т.д.


Во главе системы стоит заголовочный файл "ZIMPluginInterfaces.h", который описывает базовые интерфейсы плагинов и менеджера плагинов.
Менеджер плагинов  - объект из DLL, который является наследником "IPluginsManager" либо "IPluginsManager_1"либо "IPluginsManager_2" и т.д.
Плагин - объект из DLL,  который является наследником "IPlugin" либо "IPlugin_1"либо "IPlugin_2" и т.д.

Содержимое "ZIMPluginInterfaces.h":
Код

namespace zim {
    namespace plugins {

        const DWORD RESULT_FAIL = 0; // Неудачное завершение
        const DWORD RESULT_OK = 1; // Удачное заверщение
        const DWORD RESULT_ERR = 3; // Какая то ошибка.
        const DWORD RESULT_ERR_UNKNOWN_ACTION = 5;
        const DWORD RESULT_ERR_PLUGIN_NOT_FOUND = 10;
        const DWORD RESULT_ERR_PLUGIN_FILE_NOT_FOUND = 20;
        const DWORD RESULT_ERR_PLUGIN_NOT_LOADED = 30;
        const DWORD RESULT_ERR_PLUGIN_ACTION_NOT_FOUND = 40;
        const DWORD RESULT_ERR_PLUGIN_FUNCTION_NOT_FOUND = 50;
        const DWORD RESULT_ERR_PLUGIN_INTERFACE_NOT_LOADED = 60;
        const DWORD RESULT_ERR_NOT_MEMORY_FOR_RESULT = 70;
        const DWORD RESULT_ERR_DATA_NOT_FOUND = 80;
        // Локальная для плагина ошибка. Читать информацию из плагина.
        const DWORD RESULT_ERR_PLUGIN_CUSTOM_ERROR = 64000;

        const char C_DLLFUNNAME_GET_PLUGIN_INTERFACE[] = "_GetPluginInterface";
        const char C_DLLFUNNAME_GET_PLUGINS_MANAGER_INTERFACE[] = "_GetPluginsManagerInterface";

        const int C_MAXLEN_GUID = 250;
        const int C_MAXLEN_PLUGIN_NAME = 250;

//----------------------------------------------
        // Реальная информация о плагине.
        // Структуру заполняет сам плагин
        // Идентифицировать плагин можно по GUID, либо по pluginName + pluginVersion;
        struct TPluginInternalInfo {
            char pluginGUID[C_MAXLEN_GUID];
            char pluginName[C_MAXLEN_PLUGIN_NAME];
            int pluginVersion;

            TPluginInternalInfo() {
                // pluginGUID = NULL;
                memset(pluginGUID, '\0', C_MAXLEN_GUID);
                // pluginName = NULL;
                memset(pluginName, '\0', C_MAXLEN_PLUGIN_NAME);
                pluginVersion = -1;
            }
        };

//----------------------------------------------
        struct IPluginsManager;

        // Интерфейс плагина
        struct IPlugin {
            int IPluginVersion;
            int Id;
            HMODULE Handle;
            bool IsInit;
            TPluginInternalInfo PluginInfo;
            IPluginsManager * PluginsManager;
            char PluginPath[MAX_PATH];

            IPlugin() {
                IPluginVersion = 0;
            }

            virtual ~IPlugin() {
            }
        };

//----------------------------------------------
        struct IPlugin_1 : public IPlugin {
            // virtual DWORD IPlugin_GetInfo(TPluginInternalInfo * out_plgInfo) = 0;
            virtual DWORD IPlugin_Init(void) = 0;
            virtual DWORD IPlugin_DoAction(char * actionName) = 0;

            IPlugin_1() {
                IPluginVersion = 1;
            }
        };

//----------------------------------------------
        class TPluginMessage;

        struct IPlugin_2 : public IPlugin_1 {
            // IPluginsManager_2 * PluginsManager;
            virtual DWORD IPlugin_MessageParse(TPluginMessage * message) = 0;

            IPlugin_2() {
                IPluginVersion = 2;
            }
        };

//----------------------------------------------
        /* Базовая структура сообщения плагину.
         * В наследниках упаковывается расширенная информация. В том числе и для возвращаемых данных.
         */
        class TPluginMessage {
        protected:
            // Код сообщения. В наследниках переопределить.
            DWORD fMsgCode;

        public:
            // Ссылка на плагин-отправитель
            IPlugin * pluginSender;

            TPluginMessage() {
                fMsgCode = -1;
            }

            DWORD GetMsgCode(void) {
                return fMsgCode;
            }

            virtual ~TPluginMessage() {
            };
        };
//----------------------------------------------
        struct TPluginLoadInfo {
            char pluginName[C_MAXLEN_PLUGIN_NAME];
            int pluginVersion;
            char pluginFile[MAX_PATH];
        };

//----------------------------------------------
        struct TPluginsManagerInfo {
            char managerGUID[1000];
            int managerVersion;

            TPluginsManagerInfo() {
                // managerGUID = NULL;
                memset(managerGUID, '\0', C_MAXLEN_GUID);
                managerVersion = -1;
            }
        };

//----------------------------------------------
        struct TPluginEvent; // Опережающее объявление
        typedef void(*TOnPluginEvent)(TPluginEvent * eventData, bool*stop);

        const char C_FILETYPE_PLUGIN_INFO[] = "ZIMPluginsSystem;PluginInfo";

//----------------------------------------------
        // Интерфейс менеджера плагинов
        struct IPluginsManager {
            TPluginsManagerInfo managerInfo;

            IPluginsManager() {
                managerInfo.managerVersion = 0;
            };

            virtual ~IPluginsManager() {
            };
        };

//----------------------------------------------
        struct IPluginsManager_1 : public IPluginsManager {
            static const char * GUID;

            // ID менеджера. Используется если менджер является аддоном.
            // TPluginsManagerInfo ManagerInfo;
            // char PluginInfoExt[MAX_PATH];
            // int Id;
            IPluginsManager_1() {
                managerInfo.managerVersion = 1;
                // memcpy(managerInfo.managerGUID, PLUGIN_MANAEGER_1_GUI, sizeof(PLUGIN_MANAEGER_1_GUI));
                strcpy(managerInfo.managerGUID, IPluginsManager_1::GUID);
            };

            virtual DWORD IPlgMgr_GetManagerInfo(TPluginsManagerInfo ** out_MgrInfo) = 0;
            virtual DWORD IPlgMgr_SetDirPlugins(char * dirPlugins) = 0;
            virtual DWORD IPlgMgr_GetDirPlugins(char ** out_DirPlugins) = 0;

            virtual DWORD IPlgMgr_GetPluginInfoExt(char ** out_ext) = 0;
            virtual DWORD IPlgMgr_SetPluginInfoExt(char * newext) = 0;

            virtual DWORD IPlgMgr_GetPlugin(int pluginId, IPlugin ** out_Plugin) = 0;
            virtual DWORD IPlgMgr_GetPluginByNameVer(const char * pluginName, int pluginVer, IPlugin ** out_Plugin) = 0;

            virtual DWORD IPlgMgr_GetPluginByGUID(char * pluginGUID, IPlugin ** out_Plugin) = 0;
            virtual DWORD IPlgMgr_PluginLoad(TPluginLoadInfo * pluginInfo, IPlugin ** out_Plugin) = 0;
            virtual DWORD IPlgMgr_PluginUnLoad(int pluginId) = 0;
        };

        const char * IPluginsManager_1::GUID = "B4EABE54-E19A-4459-A522-932EA1A6382A";
//----------------------------------------------
        struct IPluginsManager_2 : public IPluginsManager_1 {
            static const char * GUID;

            IPluginsManager_2() {
                managerInfo.managerVersion = 2;
                strcpy(managerInfo.managerGUID, IPluginsManager_2::GUID);
            }
            // Отправить извещение всем зарегистрированым плагинам-слушателям
            virtual DWORD IPlgMgr_SendPluginEvent(TPluginEvent *event) = 0;
            // Добавить\удалить слушателя событий плагинов
            virtual DWORD IPlgMgr_AddDelegateOnPluginEvent(TOnPluginEvent delegate) = 0;
            virtual DWORD IPlgMgr_DelDelegateOnPluginEvent(TOnPluginEvent delegate) = 0;
        };

        const char * IPluginsManager_2::GUID = "76BC00FA-CB86-4D0D-A4D6-CA04C229220A";
//----------------------------------------------
        // Прототипы функций DLL.

        // Вертуть интерфейс плагина
        typedef DWORD(*TGetPluginInterface)(IPlugin * *out_Plugin);
        #define DLL_REGISTER_GetPluginInterface extern "C" DWORD DLL_EI GetPluginInterface(IPlugin ** out_Plugin);

        // Вертуть интерфейс менеджера плагинов
        typedef DWORD(*TGetPluginsManagerInterface)(IPluginsManager * *out_PluginsManager);
        #define DLL_REGISTER_GetPluginsManagerInterface extern "C" DWORD DLL_EI GetPluginsManagerInterface(IPluginsManager ** out_PluginsManager);
//----------------------------------------------
        const DWORD C_PLUGIN_EVENT_PLUGIN_TO_PLUGIN = 5;
        const DWORD C_PLUGIN_EVENT_BEFORE_LOAD = 10;
        const DWORD C_PLUGIN_EVENT_AFTER_LOAD = 20;
        const DWORD C_PLUGIN_EVENT_BEFORE_UNLOAD = 30;
        const DWORD C_PLUGIN_EVENT_AFTER_UNLOAD = 40;
//----------------------------------------------
        struct TPluginEvent {
            DWORD eventCode;
            // Плагин, из-за которого произошло событие
            IPlugin * plugin;
        };
//----------------------------------------------
        struct TPluginEventBeforeLoad : public TPluginEvent {
            TPluginLoadInfo loadInfo;
        };
//----------------------------------------------
        struct TPluginEventAfterUnload : public TPluginEvent {
            TPluginInternalInfo pluginInfo;
        };
//----------------------------------------------
        struct TPluginEventPluginToPlugin : public TPluginEvent {
            IPlugin * pluginDest;
        };
//----------------------------------------------

    };
};


Менеджер плагинов в DLL "ZIMPluginsManager.dll"
Код

#include "TPluginsManager.h"
using namespace zim::plugins;
DLL_REGISTER_GetPluginsManagerInterface

HINSTANCE hDll;
TPluginsManager * pluginsManager;

int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved) {
    switch(reason) {
    case DLL_PROCESS_ATTACH:
        pluginsManager = new  TPluginsManager();
        hDll = hinst;
        break;
    case DLL_PROCESS_DETACH:
        delete pluginsManager;
        break;
    }

    return 1;
}
// ---------------------------------------------------------------------------
DWORD GetPluginsManagerInterface(IPluginsManager ** out_PluginsManager) {
    *out_PluginsManager = pluginsManager;
    return RESULT_OK;
}
// ---------------------------------------------------------------------------


Заголовок реализации внутри "ZIMPluginsManager.dll"
Код

        typedef map<int, IPlugin*>TMapOfPlugins;
        typedef map<TOnPluginEvent, TOnPluginEvent>TMapOnPluginEvent;

        class TPluginsManager : public IPluginsManager_2 {
        protected:
            int fGenIdPlugin;
            TMapOfPlugins fPlugins;
            //TPluginsManagerInfo fManagerInfo;
            UnicodeString fDirPlugins;
            UnicodeString fFormatPluginPath;
            TMapOnPluginEvent fMapOnPluginEvent;
            UnicodeString fPluginInfoExt;
        public:
            // Реализация интерфейса IPluginManager_1
            DWORD IPlgMgr_GetManagerInfo(TPluginsManagerInfo ** out_MgrInfo);
            DWORD IPlgMgr_SetDirPlugins(char * dirPlugins);
            DWORD IPlgMgr_GetDirPlugins(char ** out_DirPlugins);

            DWORD IPlgMgr_GetPluginInfoExt(char ** out_ext);
            DWORD IPlgMgr_SetPluginInfoExt(char * newext);


            DWORD IPlgMgr_GetPlugin(int pluginId, IPlugin ** out_Plugin);
            DWORD IPlgMgr_GetPluginByGUID(char * pluginGUID, IPlugin ** out_Plugin);
            DWORD IPlgMgr_GetPluginByNameVer(const char * pluginName, int pluginVer, IPlugin ** out_Plugin);

            DWORD IPlgMgr_PluginLoad(TPluginLoadInfo * pluginInfo, IPlugin ** out_Plugin);
            DWORD IPlgMgr_PluginUnLoad(int pluginId);

            // Реализация интерфейса IPluginManager_2
            DWORD IPlgMgr_SendPluginEvent(TPluginEvent *event);
            DWORD IPlgMgr_AddDelegateOnPluginEvent(TOnPluginEvent delegate);
            DWORD IPlgMgr_DelDelegateOnPluginEvent(TOnPluginEvent delegate);

            // Публичные данные класса TPluginManager
            TPluginsManager(void);
            IPlugin * FindPlugin(UnicodeString pluginName, int pluginVersion);
        };



Программа-оболочка, которая хочет использовать систему плагинов обязана выполнить код, подобный следующему:
Код

    HMODULE hLibPluginsManager;

        hLibPluginsManager = LoadLibrary(pathPluginsManager.t_str());
        if (!hLibPluginsManager) {
            return false;
        }
        TGetPluginsManagerInterface GetPluginsManagerInterface = (TGetPluginsManagerInterface)GetProcAddress(hLibPluginsManager,
            &C_DLLFUNNAME_GET_PLUGINS_MANAGER_INTERFACE[0]);
        if (!GetPluginsManagerInterface) {
            return false;
        }

        DWORD execResult;
        IPluginsManager * iManager;
        execResult = GetPluginsManagerInterface(&iManager);
        if (execResult != RESULT_OK) {
            return false;
        }
        plgManager = dynamic_cast<IPluginsManager_2*>(iManager);
        if (plgManager == NULL) {
            return false;
        }
        plgManager->IPlgMgr_SetDirPlugins(dirPlugins.t_str());

// И загрузить какие-то базовые плагины.
    TPluginLoadInfo plgInfo;
              IPlugin_1 * plgInterfase;

        plgInfo.pluginName = C_PLUGIN_SHELL_NAME;
        plgInfo.pluginVersion = 1;
        plgInfo.pluginFile = "PluginShell.bpl";

        execResult = plgManager->IPlgMgr_PluginLoad(&plgInfo, &plgInterfase);
        if (execResult != RESULT_OK) {
            return;
        }

                            IPluginShell_123 * pluginShell;        
                            pluginShell = dynamic_cast<IPluginShell_123*>(plgInterfase);
        pluginShell->IPlugin_Init();
        //pluginShell->IPlugin_DoAction("SHOW_TEST_FORM");
        pluginShell->IPlgShell_Start();



Ну и пример плагина "PluginShell".

"PluginDriveSchoolDb.cpp" - главный файл плагина "PluginShell".  
Объявлена точка входа в DLL "DllEntryPoint" и функция получения интерфейса плагина "GetPluginInterface".
Код

// ---------------------------------------------------------------------------
#include <basepch.h>
#pragma hdrstop
// ---------------------------------------------------------------------------
#pragma package(smart_init)
// ---------------------------------------------------------------------------

// Package source.
// ---------------------------------------------------------------------------
#pragma argsused
#include "TPluginShell.h"
//---------------------------------------------------------------------------
USEFORM("units\TfrmShellMain.cpp", frmShellMain);
USEFORM("units\TfrmAbout.cpp", frmAbout);
//---------------------------------------------------------------------------
DLL_REGISTER_GetPluginInterface

int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*) {
    switch(reason) {
    case DLL_PROCESS_ATTACH:
        plugin = new  TPluginShell();
        plugin->Handle = hinst;
        GetDllDirectory(sizeof(plugin->PluginPath) - 1, &plugin->PluginPath[0]);
        break;
    case DLL_PROCESS_DETACH:
        delete plugin;
        plugin = NULL;
        break;
    }

    return 1;
}
// ---------------------------------------------------------------------------

DWORD GetPluginInterface(IPlugin ** out_Plugin) {
    *out_Plugin = (IPlugin *)plugin;
    return RESULT_OK;
}


"TPluginShell.H" - заголовочный файл реализации плагина. 
Доступен только внутри плагина "TPluginShell".
Реализовывает публичный интерфейс "IPluginShell_1", который объявлен в публичном заголовочном файле "IPluginShell.h"
Код

// ---------------------------------------------------------------------------

#ifndef TPluginShellH
#define TPluginShellH
// ---------------------------------------------------------------------------
#include "IPluginShell.h"
#include "TfrmShellMain.h"
#include "TMenuManager.h"

struct TPluginShell : public IPluginShell_1 {
protected:
    IPluginMenuFactory_1 * fMenuFactory;
    IPluginMenu_1 * fMenu;
    TMenuManager fMenuManager;
    void __fastcall ParseMenuClick(TObject *Sender);
public:
    // Реализация интерфейса
    DWORD IPlugin_GetInfo(TPluginInternalInfo * out_plgInfo);
    DWORD IPlugin_Init(void);
    DWORD IPlugin_DoAction(char * actionName);
    DWORD IPlugin_MessageParse(TPluginMessage * message);
    //void IPlgShell_SetApplication(TApplication * application);
    void IPlgShell_Start(void);
    TForm * IPlgShell_GetForm(void);
    DWORD IPlgShell_PluginMenuBuild(IPluginMenu * iPluginMenu);
    DWORD IPlgShell_PluginMenuDrop(IPluginMenu * iPluginMenu);
public:
    TPluginShell(void);
    TApplication * fApplication;
    TfrmShellMain *fFrmShellMain;
    void ParsePluginEvent(TPluginEvent *eventData, bool * stop);
};

static TPluginShell * plugin;
#endif


"IPluginShell.h" - публичній заголовочній файл плагина "PluginShell". 
Все другие плагины, которые хотят использовать "PluginShell", обязаны заинклудить "IPluginShell.h"
Код

// ---------------------------------------------------------------------------

#ifndef IPluginShellH
#define IPluginShellH
// ---------------------------------------------------------------------------
#include <Forms.hpp>
// --
#include "ZIMPluginInterfaces.h"
#include "../PluginMenuFactory/common/IPluginMenuFactory.h"

// ---------------------------------------------------------------------------
using namespace zim::plugins;
static char C_PLUGIN_SHELL_ACTION_EXIT[] = "EXIT";
static char C_PLUGIN_SHELL_ACTION_SHOW_FORM_ABOUT[] = "SHOW_FORM_ABOUT";
static char C_PLUGIN_SHELL_ACTION_SHOW_FORM_MAIN[] = "SHOW_FORM_MAIN";
static char C_PLUGIN_SHELL_ACTION_PLUGIN_INIT[] = "PLUGIN_INIT";

const DWORD C_PLGSHELL_MSG_BUILD_PLUGIN_MENU = 10;

// ---------------------------------------------------------------------------
struct TPluginShellMessage_BuildPluginMenu : TPluginMessage {
    char * PathMenuFile;

    TPluginShellMessage_BuildPluginMenu() {
        fMsgCode = C_PLGSHELL_MSG_BUILD_PLUGIN_MENU;
    }
};

// ---------------------------------------------------------------------------
// static char C_PLUGIN_SHELL_NAME[] = "PluginShell";
struct IPluginShell : public IPlugin {
    static const char * C_PLUGIN_NAME;

    IPluginShell() {
        strcpy(PluginInfo.pluginName, IPluginShell::C_PLUGIN_NAME);
        PluginInfo.pluginVersion = 0;
    }
};

const char * IPluginShell::C_PLUGIN_NAME = "PluginShell";
// ---------------------------------------------------------------------------
// static char C_PLUGIN_SHELL_1_GUID[] = "337F8A97-71A2-4CF3-AF2A-DE64EF472BEB";

struct IPluginShell_1 : public IPlugin_2 {
    static const char * C_PLUGIN_GUID;

    IPluginShell_1() {
        strcpy(PluginInfo.pluginName, IPluginShell::C_PLUGIN_NAME);
        strcpy(PluginInfo.pluginGUID, IPluginShell_1::C_PLUGIN_GUID);
        PluginInfo.pluginVersion = 1;
    }
    /* Указать плагину ссылку на объектт класса  ТApplication (VCL) из основного приложения */
    // virtual void IPlgShell_SetApplication(TApplication * application) = 0;
    /* Показать форму, загрузить плагины и т.п. */
    virtual void IPlgShell_Start(void) = 0;
    virtual TForm * IPlgShell_GetForm(void) = 0;
    virtual DWORD IPlgShell_PluginMenuBuild(IPluginMenu * iPluginMenu) = 0;
    virtual DWORD IPlgShell_PluginMenuDrop(IPluginMenu * iPluginMenu) = 0;
};

const char * IPluginShell_1::C_PLUGIN_GUID = "337F8A97-71A2-4CF3-AF2A-DE64EF472BEB";
// ---------------------------------------------------------------------------
#endif



PS: Если найдутся желающие поковырять код - пишите. Выложу весь проект и напишу пару тестовых плагинов.

Это сообщение отредактировал(а) ZVano - 16.9.2011, 12:16


--------------------
НЕ ФЛУДИМ. Пользуемся кнопками "+" или "-" для выражения своего отношения к теме или сообщению.
Гуглим "Как правильно задавать вопросы"
PM MAIL Skype   Вверх
borisbn
Дата 16.9.2011, 18:09 (ссылка) |    (голосов:2) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



1. Интерфейсам нужно явно указать выравнивание.
Код

#pragma pack( push, 4 ) // <---
struct IPlugin {
...
};
#pragma pack( pop ) // <---

2. Всем функциям нужно указать явный тип вызова
Код

  struct IPlugin_1 : public IPlugin {
            // virtual DWORD IPlugin_GetInfo(TPluginInternalInfo * out_plgInfo) = 0;
            virtual DWORD __stdcall IPlugin_Init(void) = 0;
...

3. Зачем в IPlugin все переменные в public ? Они реально все нужны в основной программе ?
4. Я бы добавил ф-цию получения displayName плагина. Т.е. Система работает с плагином по pluginName, а сообщения пользователю выдаёт из displayName.

Ну, это так... на первый взгляд


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
ZVano
Дата 16.9.2011, 18:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 259
Регистрация: 11.12.2006
Где: Украина, Кривой Р ог

Репутация: нет
Всего: 4



Спасибо за комментарий. 

Цитата(borisbn @  16.9.2011,  18:09 Найти цитируемый пост)
1. Интерфейсам нужно явно указать выравнивание.

Не понимаю зачем. Ушел курить маны...

Цитата(borisbn @  16.9.2011,  18:09 Найти цитируемый пост)
2. Всем функциям нужно указать явный тип вызова
Код

  struct IPlugin_1 : public IPlugin {
            // virtual DWORD IPlugin_GetInfo(TPluginInternalInfo * out_plgInfo) = 0;
            virtual DWORD __stdcall IPlugin_Init(void) = 0;
...


__stdcall нужен даже несмотря на то, что IPlugin_Init является методом структуры?
Всегда считал, что помечать __stdcall нужно только экспортные функции DLL.  smile 

Цитата(borisbn @  16.9.2011,  18:09 Найти цитируемый пост)
3. Зачем в IPlugin все переменные в public ? Они реально все нужны в основной программе ?

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

1. Текущий вариант
Код

struct IPlugin {
  // Это не имеет смысла прятать т.к. устанавливается извне (менеджером плагинов).
  IPluginsManager * PluginsManager;
  
  //Устанавлиывается менеджером плагинов.
  //Это вообще можно было хранить только в PluginManager, а вытягивать ориентируясь на адрес объекта-плагина.
  int Id;

  //Все остальное можно сделать приватным и расшарить методами чтения

  HMODULE Handle;
  bool IsInit;
  int IPluginVersion;
  TPluginInternalInfo PluginInfo;
  char PluginPath[MAX_PATH];
};


2. Максимально защищаясь можно сделать так:
Код

struct IPlugin {
  IPluginsManager * PluginsManager;
protected:
  HMODULE fHandle;
  bool fIsInit;
  int fIPluginVersion;
  TPluginInternalInfo fPluginInfo;
  char fPluginPath[MAX_PATH];
public:
  IPlugin(){
    //<< сюда запихнуть установку значений приватных полей
  }
  HMODULE GetHandle(){return fHandle;}  
  bool IsInit(){return fIsInit;}
  int GetIPluginVersion(){return fIPluginVersion;}
  TPluginInternalInfo GetPluginInfo(){return fPluginInfo;}
  char * GetPluginPath(){return &fPluginPath[0];}
};


Нужно хорошо подумать, может все же следует переделать на вариант 2.

Цитата(borisbn @  16.9.2011,  18:09 Найти цитируемый пост)
4. Я бы добавил ф-цию получения displayName плагина. Т.е. Система работает с плагином по pluginName, а сообщения пользователю выдаёт из displayName.

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






--------------------
НЕ ФЛУДИМ. Пользуемся кнопками "+" или "-" для выражения своего отношения к теме или сообщению.
Гуглим "Как правильно задавать вопросы"
PM MAIL Skype   Вверх
mes
Дата 16.9.2011, 20:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(ZVano @  16.9.2011,  17:56 Найти цитируемый пост)
Зачем пользователю вообще видеть имя плагина?

чтоб например в меню выбирать, или отключать.. 



--------------------
PM MAIL WWW   Вверх
newbee
Дата 16.9.2011, 21:19 (ссылка) |    (голосов:2) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бревно
**


Профиль
Группа: Участник
Сообщений: 703
Регистрация: 24.8.2011

Репутация: 4
Всего: 19



Здравствуйте, мои дорогие любители избушек на курьих ножках.

Раньше я тоже была поглощена идеей поработить мир написать убер систему плагинов и пришла к следующему выводу: на С++ сделать одновременно и универсальную, и удобную систему не получится. Что значит универсально? Это возможность плагином внесения любых (читай максимально широких) изменений в ход работы программы и других плагинов. Удобно - значит не париться с магическими идентификаторами плагинов и кодами действий при посылании сообщений другим участникам системы, в идеале - получение полного C++-API любой подсистемы из любой другой. Таскать за каждым плагином заголовочные файлы - не вариант: система из уже полусотни компонент, особенно разных авторов, будет едва ли подъемной, а сопровождать ее и обновлять часть ее подсистем станет просто нереально, а встанет задача поддержки плагином нескольких версий другого - ващще жопа. В рантайме экспортировать все необходимые функции по одной - уже несколько проще, но опять же трудоемко, прощай ООП-интерфейс, прощай name mangling, привет геммор с выяснением типов и количеством аргументов (и привет, бусткодер).

Намного проще расширять программу с помощью встроенного скриптового языка, для краткости назовем его lisp. Из основной программы даем лиспу доступ ко всему необходимому, далее наращиваем функционал системы уже на лиспе, на нем же реализуем систему плагинов, благодаря динамичной природе которого лишенную недостатка строгого следования API и ABI между подсистемами. И на нем же пишем плагины, а какие-то критичные части всегда можно вынести в код на С++. Плюсы очевидны: писать на лиспе намного проще и быстрее, чем на С++; подсистемы общаются между собой на нормальном языке; а не каком-то жалком обрубке вроде системы сообщений; большинство плагинов будут написаны на одном только лиспе, а значит мы получаем офигенскую кроссплатформенность.

Все на правах ИМХи и ващще мне уже пора бежать. Чао!

Это сообщение отредактировал(а) newbee - 16.9.2011, 21:21


--------------------
You're face to face
With man who sold the world
PM   Вверх
borisbn
Дата 17.9.2011, 09:40 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



Цитата(ZVano @  16.9.2011,  18:56 Найти цитируемый пост)
Интерфейсам нужно явно указать выравнивание.
Не понимаю зачем. Ушел курить маны...

Смотри... ты даёшь мне эти h-ники, чтобы я сделал како-то плагин. У тебя в проекте главного приложения (билдер, как я понимаю) по-умолчанию выставлено выравнивание структур на 8 байт. Я создаю проект для плагина в студии, и у меня выравнивание 4 байта. Интерфейсы, которые я создам, на бинарном уровне не будут соответствовать тем, которые ты ожидаешь. Эпик фэйл.
Цитата(ZVano @  16.9.2011,  18:56 Найти цитируемый пост)
__stdcall нужен даже несмотря на то, что IPlugin_Init является методом структуры?

 smile 
Абсолютно то же, что и по п. 1

Цитата(ZVano @  16.9.2011,  18:56 Найти цитируемый пост)
Осознаю, что некорректно написаный плагин (или специально сделанный) может нарушить работу всей системы плагинов, но не уверен что от этого следует защищаться.

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

Цитата(ZVano @  16.9.2011,  11:46 Найти цитируемый пост)
virtual DWORD IPlugin_DoAction(char * actionName) = 0;

почему не const char *actionName ?

Теперь следующее - ты достаточно широко проработал систему подключения плагинов, но обычно плагины должны выполнять какие-то действия над данными, имеющимися в основной программе. Например в фотошопе плагинам передаётся редактируемая картинка, в браузерах - HTML, в плеерах - видеопоток и т.д. У тебя же я этого не нашёл.

И ещё. Из своего опыта. Плагинам иногда необходимо сохранять своё состояние или считывать некие настройки. Они это могут делать сами (тупо открывать ini-шник с заранее известным именем и читать/писать его), но может создаться ситуация, когда потребуется подключить 2 экземпляра одного и того же плагина или 2 разных плагина решат назвать ini-шник config.ini.... Чтобы избежать этого необходимо, чтобы основная программа предоставляла плагинам интерфейс сохранения/считывания настроек. Типа такого
Код

#pragma pack( push, 4 )
struct SaveLoad {
  virtual void __stdcall saveBool( const char * sectionName, const char * paramName, bool value ) = 0;
  virtual void __stdcall saveInt( const char * sectionName, const char * paramName, int value ) = 0;
...
  virtual bool __stdcall loadBool( const char * sectionName, const char * paramName, bool defaultValue = bool() ) = 0;
  virtual int __stdcall loadInt( const char * sectionName, const char * paramName, int defaultValue = int() ) = 0;
...
};
#pragma pack( pop )


Добавлено через 9 минут и 49 секунд
И ещё. Но это уже не относится к системе, а скорее к правилу хорошего тона (что тоже не маловажно).
Обычно принято public-члены классов объявлять в начале описания класса, а private (или protected) - в конце. Людям, которым ты отдаёшь класс для использования, не интересно какие защищённые переменные есть в классе, им интересно как им использовать этот класс, т.е. public-члены.


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
ZVano
Дата 19.9.2011, 11:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 259
Регистрация: 11.12.2006
Где: Украина, Кривой Р ог

Репутация: нет
Всего: 4



Цитата(borisbn @  17.9.2011,  09:40 Найти цитируемый пост)

Интерфейсам нужно явно указать выравнивание.
1. Интерфейсы, которые я создам, на бинарном уровне не будут соответствовать тем, которые ты ожидаешь. 

__stdcall нужен даже несмотря на то, что IPlugin_Init является методом структуры? 
Абсолютно то же, что и по п. 1

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

Благодарю за пояснения.

Цитата(borisbn @  17.9.2011,  09:40 Найти цитируемый пост)

почему не const char *actionName ?

Мое упущение. Надо будет добавить const всем константным параметрам, пока не плагинов немного.

Цитата(borisbn @  17.9.2011,  09:40 Найти цитируемый пост)

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


Плагины взаимодействуют друг с другом напрямую через метод IPlugin_MessageParse.
Код

IPlugin_2 : public IPlugin_1 {
  //...
  virtual DWORD IPlugin_MessageParse(TPluginMessage * message) = 0;
  //...

Т.е. применительно к фотошопу плагин, обрабатывающий картинку, обязан:
1. быть версии "IPlugin_2" или выше 
2. содержать объявление наследника от TPluginMessage, который содержит все необходимые поля для выполнения действия (либо осуществления коммуникации, если подразумевается обратная связь). Пример ниже.
3. Реализовать в методе "MessageParse" распознавание кода fMsgCode и передаци управления функции, которая обслуживает сообщения данного типа.

Напомню интефейс базового сообщения класса TPluginMessage. 
Наследник обязан назначить свой код "DWORD fMsgCode". Код уникален в пределах плагина, который обслуживает сообщение.
Код

        /* Базовая структура сообщения плагину.
         * В наследниках упаковывается расширенная информация. В том числе и для возвращаемых данных.
         */
        class TPluginMessage {
        protected:
            // Код сообщения. В наследниках переопределить.
            DWORD fMsgCode;

        public:
            // Ссылка на плагин-отправитель
            IPlugin * pluginSender;

            TPluginMessage() {
                fMsgCode = -1;
            }

            DWORD GetMsgCode(void) {
                return fMsgCode;
            }

            virtual ~TPluginMessage() {
            };
        };


Пример реализации коммуникации между плагином IPhotoshopEditor - редактор изображения (формочка с рисунком) и IEffectDegradation - эффект размытия изображения.
Загрузка программы:
1. Оболочка грузит все плагины, зарегестрированые в секции "Автозагрузка" конфигурационного файла.
>>Среди них плагин IEffectDegradation.
1.1. Дошла очередь до загрузки IEffectDegradation.
1.1.1. Оболочка загружает DLL с плагином, и получает интерфейс IEffectDegradation вызвав функцию DWORD GetPluginInterface(IPlugin ** out_Plugin); из DLL.
1.1.2. Оболочка приводит "IPlugin ** out_Plugin" к IPlugin_2 (т.к. out_Plugin->IPluginVersion == 2)
1.1.3. Оболочка вызывает метод IEffectDegradation->"virtual DWORD IPlugin_Init(void) = 0;", который достался IPlugin_2 от IPlugin_1.
>>Выполняется инициализация IEffectDegradation
Код

  IPluginsManager_2 * manager;
  manager = dynamic_cast<IPluginsManager_2*>(PluginsManager);
  IPlugin * iPlugin;
  execResult = manager->IPlgMgr_GetPluginByNameVer(IPluginShell::C_PLUGIN_NAME, 1, &(IPlugin*)pluginShell);
 
 //1.1.3.1. Объект IEffectDegradation запрашивает интерфейс плагина IPluginMenuFactory
 IPluginMenuFactory_1 * pluginMenuFactory;
 execResult = manager->IPlgMgr_GetPluginByNameVer(IPluginMenuFactory::C_PLUGIN_NAME, 1, &(IPlugin*)pluginMenuFactory);

 //1.1.3.2. Объект IEffectDegradation запрашивает у IPluginMenuFactory объект класса IPluginMenu
 IPluginMenu_1 * menu;
  execResult = pluginMenuFactory->IPlgMenuFactory_Create(&menu);
  if (execResult == RESULT_OK) {
    menu->plugin = this;
    //1.1.3.4. Объект IEffectDegradation указывает объекту IPluginMenu путь к файлу с менюшкой
    UnicodeString menuPath = ExtractFilePath(UnicodeString(this->PluginPath)) + "config/menu.ini";
    menu->IPlgMenu_SetMenuPath(menuPath.t_str());
    //1.1.3.5. Объект IEffectDegradation вызывает у объекта IPluginMenu  метод Load, который загрузит меню из файла.
    //>> В этот момент информация о меню IEffectDegradation загружается в объект IPluginMenu.
    //>> При этом IEffectDegradation не знает ничего ни о внутренней организации файла с менюхой, ни о внутреннем представлении данных в классе IPluginMenu.
    menu->IPlgMenu_Load();
    //1.1.3.6. Объект IEffectDegradation вызывает у объекта-плагина IPluginShell метод "PluginMenuBuild".
    // Этот метод обязан создать меню плагина IEffectDegradation и связать каждый пункт меню с действием.
    pluginShell->IPlgShell_PluginMenuBuild(menu);
  }


После инизиализации плагинов главное меню оболочки будет содержать пункты меню всех плагинов автозагрузки, которые поддерживают работу с оболочкой и попросили ее (оболочку) зарегистрировать свое меню.
2. Работа приложения.
2.1. Пользователь клоцает мышей по пункту меню. Допустим, это будет пункт "Загрузить изображение", который принадлежит плагину IPhotoshopEditor.
2.1.1. Оболочка ищет ассоциацию "Пункт меню" == "Плагин\Действие".
2.1.2. Оболочка вызывает метод IPhotoshopEditor->IPlugin_DoAction("Название действия, загруженное ранее из конфигурационного файла");
2.1.2.1. Плагин IPhotoshopEditor показывает диалог выбора файлов
2.1.2.2. Плагин IPhotoshopEditor создает новое окно редактора и открывает выбранный пользователем файл.
2.1.2. Возврат управления плагину "Оболочка".
2.2. Пользователь клоцает мышей по пункту "Применить эффект "Размытие"".
2.2.1. Оболочка ассоциирует пункт меню с плагином "IEffectDegradation", действием "Размыть изображение".
2.2.2. Оболочка вызывает метод IEffectDegradation->IPlugin_DoAction("Размыть изображение");
2.2.3. Плагин IEffectDegradation выполняет действие.
2.2.3.1. IEffectDegradation запрашивает у плагина "Оболочка" интерфейс плагина, которому принадлежит текущее активное окно (пусть интерфейс будет в переменной IPlugin * iPluginActive).
2.2.3.2. IEffectDegradation проверяет, умеет ли он работать с данным плагином. Естественно, с IPhotoshopEditor он умеет работать т.к. он писалься для него.
2.2.3.3. IEffectDegradation приводит интерфейс iPluginActive к IPhotoshopEditor нужной версии.
2.2.3.4. IEffectDegradation создает переменную структуры TPhotoshopEditor_MsgGetImage << TPluginMessage, которая объявлена в публичном файле плагина IPhotoshopEditor.
"IPhotoshopEditor.h"
Код

//...
struct IPhotoshopEditor_5 : public IPlugin_2{
  //...
};

class TPhotoshopEditor_MsgGetImage : public TPluginMessage{
  TImage * fImage;
  TPhotoshopEditor_MsgGetImage(){
    fMsgCode = 13;
    fImage = NULL;
  }
};


Пусть переменная будет TPhotoshopEditor_MsgGetImage msgGetImage;

2.2.3.5. IEffectDegradation вызывает метод IPhotoshopEditor->IPlugin_MessageParse(&(TPluginMessage *)msgGetImage)
2.2.3.5.1. IPhotoshopEditor читает fMsgCode переданного сообщения. Он равен 13.
2.2.3.5.2. IPhotoshopEditor  приводит TPluginMessage * message к TPhotoshopEditor_MsgGetImage.
2.2.3.5.3. IPhotoshopEditor записывает в fImage адрес изображения, которое он редактирует. И возвращает управление.
2.2.3.6. IEffectDegradation выполняет размытие изображения, адрес которого получит из msgGetImage->fImage

Финита. Работа выполнена - плагины состыковались, изображение размыто.

Добавлено через 2 минуты и 57 секунд
Цитата(newbee @  16.9.2011,  21:19 Найти цитируемый пост)
и пришла к следующему выводу: на С++ сделать одновременно и универсальную, и удобную систему не получится

Может быть и так, но я попробую smile

Добавлено через 4 минуты и 6 секунд
Цитата(borisbn @  17.9.2011,  09:40 Найти цитируемый пост)
Обычно принято public-члены классов объявлять в начале описания класса, а private (или protected) - в конце

Согласен на 100%. Прийму к сведению.

Добавлено через 8 минут и 25 секунд
Цитата(borisbn @  17.9.2011,  09:40 Найти цитируемый пост)
 Плагинам иногда необходимо сохранять своё состояние или считывать некие настройки. Они это могут делать сами (тупо открывать ini-шник с заранее известным именем и читать/писать его), но может создаться ситуация, когда потребуется подключить 2 экземпляра одного и того же плагина или 2 разных плагина решат назвать ini-шник config.ini.... Чтобы избежать этого необходимо, чтобы основная программа предоставляла плагинам интерфейс сохранения/считывания настроек.

config.ini будет для каждого плагина свой и пути будут относительно папки с файлом DLL плагина. Поэтому пересечение исключено.
Настройки будут через объект класса IOpteoned, который будет содержать методы (Load, Save, Cancel) и форму с настройками для включения в ее как закладки в плагин "МенеджерНастроек".
Но это пока только в планах.


--------------------
НЕ ФЛУДИМ. Пользуемся кнопками "+" или "-" для выражения своего отношения к теме или сообщению.
Гуглим "Как правильно задавать вопросы"
PM MAIL Skype   Вверх
xvr
Дата 19.9.2011, 15:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 60
Всего: 223



Ваша система плагинов очень напоминает попытку создать с нуля COM. Видимо следующей стадией будут библиотеки типов и ActiveX  smile 
Может не стоит изобретать велосипед, а воспользоваться готовым?

PM MAIL   Вверх
ZVano
Дата 19.9.2011, 15:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 259
Регистрация: 11.12.2006
Где: Украина, Кривой Р ог

Репутация: нет
Всего: 4



Цитата(xvr @  19.9.2011,  15:09 Найти цитируемый пост)
Ваша система плагинов очень напоминает попытку создать с нуля COM

Честно говоря, даже не подозревал об этом smile


Цитата(xvr @  19.9.2011,  15:09 Найти цитируемый пост)
Может не стоит изобретать велосипед, а воспользоваться готовым?

С удовольствием. Вот только не нашел я готовых движков.  Тут спрашивал форумчан.


--------------------
НЕ ФЛУДИМ. Пользуемся кнопками "+" или "-" для выражения своего отношения к теме или сообщению.
Гуглим "Как правильно задавать вопросы"
PM MAIL Skype   Вверх
borisbn
Дата 19.9.2011, 15:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



Цитата(xvr @  19.9.2011,  15:09 Найти цитируемый пост)
Ваша система плагинов очень напоминает попытку создать с нуля COM

За исключением одного маленького плюсика (весьма сомнительного, к слову) - кроссплатформенная. 


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
ZVano
Дата 19.9.2011, 15:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 259
Регистрация: 11.12.2006
Где: Украина, Кривой Р ог

Репутация: нет
Всего: 4



Цитата(borisbn @  19.9.2011,  15:44 Найти цитируемый пост)
За исключением одного маленького плюсика (весьма сомнительного, к слову) - кроссплатформенная. 

Кстати, именно кроссплатформенности и хотелось добиться. 
Но знаний для этого у меня не хватает.

Есть мысль замутить опенсорсный движек и разместить его на googlecode.com


--------------------
НЕ ФЛУДИМ. Пользуемся кнопками "+" или "-" для выражения своего отношения к теме или сообщению.
Гуглим "Как правильно задавать вопросы"
PM MAIL Skype   Вверх
newbee
Дата 19.9.2011, 16:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бревно
**


Профиль
Группа: Участник
Сообщений: 703
Регистрация: 24.8.2011

Репутация: 4
Всего: 19



ZVano, тогда быстро, решительно выбрасывай дебилдер и начинай компилировать Gcc! Если гуевая часть заявляется в базовом функционале (извини, я мельком читала твои простыни), используй Qt.


--------------------
You're face to face
With man who sold the world
PM   Вверх
borisbn
Дата 19.9.2011, 16:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



Цитата(ZVano @  19.9.2011,  15:54 Найти цитируемый пост)
Кстати, именно кроссплатформенности и хотелось добиться. 

Что это за HMODULE, DWORD, MAX_PATH в интерфейсе ?
Цитата(newbee @  19.9.2011,  16:05 Найти цитируемый пост)
быстро, решительно выбрасывай дебилдер

+100500.
Цитата(newbee @  19.9.2011,  16:05 Найти цитируемый пост)
используй Qt.

ещё +100500.
итого: +2001000 smile


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
xvr
Дата 19.9.2011, 16:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 60
Всего: 223



Цитата(borisbn @  19.9.2011,  15:44 Найти цитируемый пост)
За исключением одного маленького плюсика (весьма сомнительного, к слову) - кроссплатформенная. 

Тогда XPCOM из Mozilla (FireFox)

Цитата(ZVano @  19.9.2011,  15:35 Найти цитируемый пост)
Вот только не нашел я готовых движков.

Собственно ActiveX и есть ваш готовый движок (ну почти)

PM MAIL   Вверх
ZVano
Дата 19.9.2011, 16:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 259
Регистрация: 11.12.2006
Где: Украина, Кривой Р ог

Репутация: нет
Всего: 4



Цитата(newbee @  19.9.2011,  16:05 Найти цитируемый пост)
ZVano, тогда быстро, решительно выбрасывай дебилдер и начинай компилировать Gcc! Если гуевая часть заявляется в базовом функционале (извини, я мельком читала твои простыни), используй Qt.

Полностью выбросить не получится т.к. начальство не позволяет.
Хотелось бы получить на выходе:
1. кроссплатформенные интерфейсы базового плагина и менеджера плагинов
2. экземпляр менеджера плагинов в dll
А весь остальной функционал в реализациях плагинов на Builder, VS, и т.д.

GUI в базовом функционале не заявляется. Движек GUI это плагин интерфейса IPluginShell. 
Все GUIшные плагины цепляются к нему.

Цитата(borisbn @  19.9.2011,  16:10 Найти цитируемый пост)
Что это за HMODULE, DWORD, MAX_PATH в интерфейсе ?

Это типы из WINDOWS.H, WINDEF.H  smile 
На что ума хватило, то и написал (лучше что-то, чем ничего).

Цитата(xvr @  19.9.2011,  16:15 Найти цитируемый пост)
Тогда XPCOM из Mozilla (FireFox)

Пытался разобраться в исходниках FireFox, но абсолютно ничего не понял. Здоровенные они там.



--------------------
НЕ ФЛУДИМ. Пользуемся кнопками "+" или "-" для выражения своего отношения к теме или сообщению.
Гуглим "Как правильно задавать вопросы"
PM MAIL Skype   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1177 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.