Я работаю над приложением, которое должно поддерживать архитектуру плагина. Это первый раз, когда я это сделал, поэтому я не совсем уверен, как мне нужно это делать.Создание интерфейса плагина
How to create some class from dll(constructor in dll)?(с++) Предлагает мне просто создать класс, состоящий из полностью виртуальных функций, и позволить DLL реализовать это в пользовательском классе и вернуть этот настраиваемый объект с помощью метода GetPluginObject()
или тому подобного. Тем не менее, C++ DLL plugin interface говорит, что не будет достаточно, и что собственно (совместимый по нескольким составителей) подход потребует следующее:
- только основные типы данных могут использоваться
- Что-то вроде СОМ QueryInterface должны быть выставлены таким образом, плагин DLL, может правильно определить, какой интерфейс (ы) он реализует
- Некоторые формы подсчета ссылок требуется
- Все методы предпочтительно должны быть помечены как STDCALL
- Любые Структуры должны быть предоставлены фиксированной выравнивания
Что мне нужно для плагина, достаточно просто: мне нужен только один массив структур, возвращаемых из одной функции.
struct InternalCommand
{
int commandValue;
std::wstring commandName;
std::wstring commandHandlerFunctionName; //I'm planning on using GetProcAddress with the provided function name to get the individual command handler
}
std::vector<InternalCommand> GetEmergeInternalCommands();
Учитывая ограничения и требования в приведенном выше списке, используя другой интерфейс этого проекта в качестве шаблона, кажется, мне нужно определить это следующим образом:
#define MAX_LINE_LENGTH 4096
#ifdef __GNUC__
#define ALIGNOF(type) __alignof__(type)
#else
#define ALIGNOF(type) __alignof(type)
#endif
#ifdef __GNUC__
#define ALIGNED(size) __attribute__((aligned (size)))
#else
#define ALIGNED(size) __declspec(align(size))
#endif
#include <windows.h>
// {b78285af-c62f-4cff-9e15-f790a4a219ee}
const IID IID_IEmergeInternalCommand = {0xB78285AF, 0xC62F, 0x4CFF, {0x9E, 0x15, 0xF7, 0x90, 0xA4, 0xA2, 0x19, 0xEE}};
#ifdef __cplusplus
extern "C"
{
#endif
struct ALIGNED((ALIGNOF(int) + ALIGNOF(wchar_t) + ALIGNOF(wchar_t))) EmergeInternalCommandInformation
{
int commandValue;
wchar_t commandName[MAX_LINE_LENGTH];
wchar_t commandHandlerFunctionName[MAX_LINE_LENGTH];
};
#undef INTERFACE
#define INTERFACE IEmergeInternalCommandProvider
DECLARE_INTERFACE_(IEmergeInternalCommandProvider, IUnknown)
{
STDMETHOD(QueryInterface)(THIS_ REFIID, LPVOID*) PURE;
STDMETHOD_(ULONG, AddRef)(THIS) PURE;
STDMETHOD_(ULONG, Release)(THIS) PURE;
STDMETHOD_(int, GetEmergeInternalCommandCount)(THIS) PURE;
STDMETHOD_(EmergeInternalCommandInformation, GetEmergeInternalCommandInformation)(THIS_ int) PURE;
};
#undef INTERFACE
typedef IEmergeInternalCommandProvider* LPEMERGEINTERNALCOMMANDPROVIDER;
#ifdef __cplusplus
}
#endif
А потом, на стороне хоста, я бы использовал GetProcAddress
в DLL плагина для вызова DLL QueryInterface
, затем с помощью указателя QueryInterface
вернется к работе с плагином.
Это похоже на много излишних и многих уродливых, хотя. Например, я не думаю, что я могу правильно передать std :: vector в или из, поэтому я застрял, используя возврат одного элемента для GetEmergeInternalCommandInformation()
и функцию полного счета GetEmergeInternalCommandCount()
, чтобы я мог пропустить команды плагина один одним. Есть ли другой способ, я могу безопасно получить массив структуры как возвращаемое значение, не нарушая правила?
Кроме того, я не совсем уверен, что я определил правильно-структуру, как с точки зрения наличия в wchar_t
массивов (я ограничен выделим wchar_t
с?) И с точки зрения стоимости выравнивания.
Я также не совсем уверен в том, как предполагается реализовать эту DLL-плагин. Я думаю, что нужно только #include
заголовок интерфейса, а затем создать класс, наследующий от интерфейса, не так ли?
#include "EmergeInternalCommandInterface.h"
class EmergeInternalCommands : public IEmergeInternalCommandProvider
//class definition goes here
Я также не уверен, что мне нужно зарегистрировать этот интерфейс с помощью COM или если я могу просто использовать его. Интерфейс, который я использовал в качестве шаблона, является полнофункциональным COM-интерфейсом и зарегистрирован как таковой, но я не знаю, нужно ли мне что-то, что продвинулось для базовой системы плагинов.
И последнее, но не в последнюю очередь - я делаю этот путь более сложным, чем это должно быть?
Еще один подход, который вы можете рассмотреть, - это не реализовать плагины с C++ вообще, а вместо этого использовать встроенный язык сценариев, такой как lua. Идея заключается в том, что вы связываете и выставляете базовые строительные блоки или примитивы в vm, чтобы плагин мог получить доступ Они сами могут быть либо чистым сценарием lua, либо модулем расширения lua, написанным на C или C++. Обычно требования не требуют, чтобы ваше приложение и плагин были написаны на одном языке. – greatwolf
Пока я играя с идеей использования Lua, я собираюсь чтобы реализовать плагиновую систему на C++, поскольку мое приложение и его будущие плагины активно используют Windows API. Я не уверен, что Lua сможет провести здесь свое дело. – computerfreaker
Взгляните на ffi LuaJIT - он позволяет вам легко связывать функции winapi прямо из lua.Обычно вам нужно предоставить предварительно обработанный заголовок, содержащий интересующие объявления функции win32. – greatwolf