我正在开发一个需要支持插件架构的应用程序。这是我第一次这样做,所以我不完全确定我需要怎么做。
How to create some class from dll(constructor in dll)?(с++)建议我只需要创建一个由完全虚函数组成的类,让DLL在自定义类中实现它,并通过GetPluginObject()
方法等返回该自定义对象。但是,C++ DLL plugin interface表示这还不够,并且正确的(跨多个编译器兼容)方法需要以下内容:
我需要一个插件做的事情很简单:我只需要从一个函数返回一个结构数组。
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
然后,在主机端,我在插件DLL上使用GetProcAddress
来调用DLL的QueryInterface
,然后使用指针QueryInterface
返回以使用插件。
这看起来像是很多的过度杀戮和很多的丑陋。例如,我认为我不能正确地传入或传出std :: vector,所以我坚持使用GetEmergeInternalCommandInformation()
的单项返回和总计数函数GetEmergeInternalCommandCount()
所以我可以逐个遍历插件的命令。有没有不同的方法我可以安全地将struct数组作为返回值而不违反规则?
另外,我完全不确定我是否正确地定义了结构,包括wchar_t
数组(我是否限制为单wchar_t
s?)和对齐方面值。
我也不完全确定插件DLL应该如何实现它。我认为它只需要#include
接口定义头,然后创建一个继承自接口的类,对吗?
#include "EmergeInternalCommandInterface.h"
class EmergeInternalCommands : public IEmergeInternalCommandProvider
//class definition goes here
我也不确定是否需要向COM注册此接口,或者我是否可以使用它。我用作模板的接口是一个成熟的COM接口,并且已经注册,但我不知道是否需要任何基本插件系统的高级功能。
最后但绝对不是最不重要的 - 我是否比这更复杂?
答案 0 :(得分:4)
在https://github.com/jbandela/cppcomponents查看我的项目cppcomponents。我专门为你的场景创建了这个库,因为我发现当前可用的解决方案缺乏。
它是一个仅适用于Windows和Linux的头文件c ++ 11库。
它需要一个相当合规的C ++ 11编译器,如MSVC 2013,Gcc 4.7.2或Clang 3.2
这是写出你想要的最简单方法
首先在CommandProvider.h中定义接口和插件
#include <cppcomponents/cppcomponents.hpp>
#include <tuple>
#include <vector>
typedef std::tuple<int, std::wstring, std::wstring> Command;
struct ICommandProvider:cppcomponents::define_interface<cppcomponents::uuid<0xf4b4056d, 0x37a8, 0x4f32, 0x9eea, 0x03a31ed55dfa>>
{
std::vector<Command>GetEmergeInternalCommands();
CPPCOMPONENTS_CONSTRUCT(ICommandProvider, GetEmergeInternalCommands)
};
inline std::string CommandProviderId(){ return "CommandProvider"; }
typedef cppcomponents::runtime_class<CommandProviderId, cppcomponents::object_interfaces<ICommandProvider>> CommandProvider_t;
typedef cppcomponents::use_runtime_class<CommandProvider_t> CommandProvider;
然后在ImplementCommandProvider.cpp中将编译成CommandProviderDll.dll
#include "CommandProvider.h"
struct ImplementCommandProvider :cppcomponents::implement_runtime_class<ImplementCommandProvider, CommandProvider_t>
{
ImplementCommandProvider(){}
std::vector<Command>GetEmergeInternalCommands(){
std::vector<Command> vec;
vec.push_back(std::make_tuple(1, L"Test", L"TestFunction"));
vec.push_back(std::make_tuple(2, L"Test2", L"TestFunction2"));
vec.push_back(std::make_tuple(3, L"Test3", L"TestFunction3"));
return vec;
}
};
CPPCOMPONENTS_REGISTER(ImplementCommandProvider)
CPPCOMPONENTS_DEFINE_FACTORY()
以下是如何使用它
#include "CommandProvider.h"
#include <iostream>
int main(){
std::string dllName;
std::cout << "Enter dll name without the .dll extension\n";
std::cin >> dllName;
auto p = CommandProvider::dynamic_creator(dllName, "CommandProvider")();
for (auto& c : p.GetEmergeInternalCommands()){
std::wcout << L"Value " << std::get<0>(c) << L" Name " << std::get<1>(c) << L" Function " << std::get<2>(c) << L"\n";
}
}
以下是如何从命令行构建它 我假设你在3个文件的目录中,并且MSVC编译器在你的路径中
这是如何构建主程序
cl MainProgram.cpp /I c:\Users\jrb\Source\Repos\cppcomponents /EHsc
这是如何构建Dll
cl ImplementCommandProvider.cpp /I c:\Users\jrb\Source\Repos\cppcomponents /EHsc /link /dll /OUT:CommandProviderDll.dll
然后,当您运行该程序时,输入CommandProviderDll
作为您的dllname
如果你想定义一个自定义结构,那么我可以帮助你。
该库目前缺少文档(正在处理它:(),但我可以帮助您解决有关库的任何问题。该库是根据Boost许可证发布的,因此您可以将它用于商业应用程序