2012-01-12 45 views
1

这是我正在探索的一个插件框架场景:是否可以从XML文件中动态构建函数声明?

第三方插件开发人员设计了一个具有已知入口点和任意参数的DLL。它们还提供XML文件中入口点和参数的详细信息,并提供数据,当插件被调用时,它们将被我的程序回调。他们可以在XML中使用一组可扩展的变量,我的程序将扩展并通过它们指定的参数传递给它们。

我知道在win32中,我可以使用LoadLibrary/GetProcAddress来获取它们定义的函数。我不太清楚的是,我是否可以从他们定义的参数中动态生成一个函数规范,我可以用它来回调它们。任何人都知道这是可能的吗?

回答

1

我决定做的就是使插件接受一个简单的接口:

DWORD func (LPARAM pBuf, DWORD size); 

这将允许用户在XML中指定的参数,然后定义他们希望我的结构通过他们,例如

typedef struct 
{ 
    int a; 
    float b; 
    double c; 
    wchar_t * d; 
} test1; 

当他们从我那里得到这条消息时,他们可以在使用缓冲区之前检查大小,以确保XML和结构匹配。

正如我解析XML,我使用这个类模板的方法来动态地构造对象:

class DynamicStructure 
{ 
public: 

    template <typename T> 
    void addField(const T & field) 
    { 
     m_mapPtrSize.push_back(std::make_pair(reinterpret_cast<const LPARAM>(&field), sizeof(T))); 
    } 

    DWORD getSize() 
    { 
     // 
     // Work out the combined size of all the fields 
     DWORD sSize = 0; 
     for (auto it = m_mapPtrSize.cbegin(); it != m_mapPtrSize.cend(); it++) 
     { 
      sSize += it->second; 
     } 

     return sSize; 
    } 

    LPARAM getBuffer() 
    { 
     // Create a buffer big enough for all the fields 
     // 
     LPARAM pBuf = reinterpret_cast<LPARAM> (new (std::nothrow) BYTE[getSize()]); 

     if (pBuf == NULL) 
      return NULL; 

     DWORD offset = 0; 
     for (auto it = m_mapPtrSize.cbegin(); it != m_mapPtrSize.cend(); it++) 
     { 
      // Copy the fields one at a time, offsetting into the buffer 
      // 
      memcpy((void*) (pBuf + offset), (const void*) it->first, it->second); 
      offset += it->second; 
     } 

     return pBuf; 
    } 

protected: 
private: 
    std::vector<std::pair<const LPARAM, DWORD>> m_mapPtrSize; 
}; 

这让我为我解析XML执行以下操作类型:

DynamicStructure dynStruct; 
int a = 1; 
float b = 2.3f; 
double c = 3.5; 
wchar_t * d = L"bob"; 

dynStruct.addField(a); 
dynStruct.addField(b); 
dynStruct.addField(c); 
dynStruct.addField(d); 

// Test - does the dymanic structure match the user's structure? 
LPARAM pBuf = dynStruct.getBuffer(); 
test1 * pTest1 = (test1 *) pBuf; 

std::wcout << pTest1->a << " " << pTest1->b << " " << pTest1->c << " " << pTest1->d << std::endl; 

这并不完美,它有点老派,但至少它很简单,并提供了一个合理的安全水平。

0

你不能在运行时建立函数,所以你留下了编译时选项,如模板元编程。

1

C++不支持反射。

但是,通过使用pococapsule库可能(在某种程度上)。


This article完全覆盖了如何构建插件框架。

+0

我不会认为如果您知道它是参数,那么需要全反射API来以朦胧的方式调用函数。毕竟,如果你知道调用约定(我这么做),从理论上来说,在汇编器中做“足够”就够了。我只是想知道是否有一个好的方法来在标准C++中做到这一点。我想我可以使用一大堆void *风格的函数,并选择我需要的那一个,然后他们必须将指针投回......但这似乎有点废话。 – Benj 2012-01-12 11:47:46

+0

@Benj不,你不需要全面反思。我可能误解了这个问题。该标准没有说明如何加载库并使用它的符号(这取决于平台)。因为你需要投,因为你只能访问c函数 – 2012-01-12 12:08:45

+0

@Benj你问的是超复杂的问题。我链接了可以帮助你构建一个良好的插件框架的文章。 – 2012-01-12 12:11:09

相关问题