Программирование на Visual C++Источник: cybergururu
В этой статье описываются принципы и решения, применяемые при проектировании приложений, которые будут использовать внешние, динамически подключаемые, модули. Эта статья более ориентирована на тех, кто хочет использовать механизмы подключения/отключения функциональности приложения, наподобии механизма Aobe Photoshop или Far, а не просто многократного использования кода в разных приложениях. Динамически подключаемые модули (DLL) - это модули, которые содержат функции и данные. Эти модули загружаются во время выполнения программы, использующей эти модули (хоста). В ОС Windows модули содержат внутренние и экспортируемые функции (в UNIX подобных системах все функции являются экспортируемыми). Экспортируемые функции доступны для вызова хостом, а внутренние нет. Хотя данные тоже могут быть экспортируемыми, но обычно используются экспортируемые функции для доступа данным. Некоторые, особенно начинающие разработчики ПО, и не представляют, что при создании приложения, уже используют внешние модули. Хотя при разработке MFC приложений этот факт более очевиден. Просто компилятор сам вставляет код, который загружает системные библиотеки, иначе любое Windows приложение было бы на 20-30 Мб больше. Итак, перейдем непосредственно к созданию механизма для использования в Ваших приложениях плагинов. Создайте новое DLL приложение (Builder и VC позволяют выбрать тип при создании нового проекта). Каждая библиотека имеет точку входа (но можно ее и не описывать), как функция main() в обычном приложении. Вот обычное ее описание: HINSTANCE hDllInstance=NULL; При присоединении к вызвавшему ее процессу, в эту функцию передается instance. Т.е. Вы сможете использовать ресурсы библиотеки. Используйте в этой функции только простые задачи по инициализации! Эта функция очень уязвимое место в модуле. Для связи хоста и модуля предлагаю использовать две функции: первая функция будет взаимодействовать с хостом при инициализации (определять версию, совместимость с текущей версией хоста, передавать текст для пункта в меню и т.д.), а вторая будет обслуживать запросы хоста и реагировать на переданные данные: анализировать, обрабатывать и возвращать результат соей работы. Другой подход в написании плагинов - использовать несколько различных функций, для каждого из действий, но лично мне нравится первый. Например, один из возможных вариантов этих двух функций: #ifdef __cplusplus Ключевые слова __declspec( dllexport ) обозначают, что функции являются экспортируемыми. Этот блок определений можно помещать в самом исходном файле, после секции подключения заголовочных файлов. Вот пример структуры, передаваемой при инициализации: struct PluginInfo { А вот пример функции, которая находится в плагине и заполняет эту структуру: void GetPluginInfo(PluginInfo* pPluginInfo, DWORD *pdwResult) { Функция-обработчик в плагине: void PluginHandler(DWORD dwCode,HostInfo *pHostInfo,DWORD *pdwResult); Первый параметр будет определять цель, с которой вызвана функция, второй параметр определяет входные данные, причем для каждого кода могут быть инициализированы различные члены структуры. Ну а третий параметр - результат работы. void PluginHandler(DWORD dwCode,HostInfo *pHostInfo,DWORD *pdwResult) { Если плагин не знает переданного кода операции, он просто вернет код "Не поддерживается" и не выполнит некорректных действий. Посмотрим, какие действия необходимо выполнить в программе-хосте для того, что бы воспользоваться функциями, расположенных в плагинах. Загрузим библиотеку хостом: // приходится создавать тип для каждой экспортируемой функции Итак, плагин загружен и готов к работе, ожидаем когда пользователь выберет пункт меню. Помещаем в обработчик меню следующий код: PluginHandlerType PluginHandler; Вот собственно и все описание простого примера использования плагинов в своих программах. Я хочу добавить несколько советов для разработчиков:
А вот пример функции, которая рекурсивно находит все файлы в папке с плагинами: // Массив со всеми файлами, включая путь относительно папки с плагинами Покрашенко Александр
|