2012-01-12 63 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

相關問題