2009-02-03 123 views
10

Sooooo我正在編寫腳本解釋器。基本上,我想存儲在一個DLL一些類和函數,但我想的DLL來尋找那些被鏈接到它,就像節目中的函數,使用gcc編譯DLL

 program    dll 
---------------------------------------------------- 
send code to dll-----> parse code 
           | 
           v 
          code contains a function, 
          that isn't contained in the DLL 
           | 
list of functions in <------/ 
program 
     | 
     v 
corresponding function, 
user-defined in the 
program--process the 
passed argument here 
     | 
     \--------------> return value sent back 
          to the parsing function 

基本上,我是想知道,我怎麼編譯一個使用gcc的DLL?那麼,我正在使用gcc的windows端口。一旦我編譯了一個包含我的類和函數的.dll,我該如何鏈接到我的程序?我如何使用DLL中的類和函數? DLL可以調用鏈接到它的程序的函數嗎?如果我創建一個類{...}對象;在DLL中,然後當程序加載DLL時,程序是否可以使用對象?在此之前感謝,我真的需要知道如何在C++中使用DLL,然後才能繼續此項目。

「你可以添加更多的細節,你爲什麼要DLL調用主程序中的函數嗎?」

我以爲這個圖解釋了它......使用DLL的程序將一段代碼傳遞給解析代碼的DLL,並且如果在所述代碼中找到函數調用,那麼DLL中的相應函數是調用...例如,如果我傳遞「a = sqrt(100)」,那麼DLL解析器函數將查找對sqrt()的函數調用,並且在該DLL內將會有一個相應的sqrt()函數,傳遞給它的參數的根,然後它將從該函數獲取返回值並將其放入變量a中,就像其他程序一樣,但是如果沒有在sqrt()函數中找到相應的處理函數該DLL(將有一個本地支持的函數列表),那麼它會調用一個類似的函數,它將駐留在使用該DLL的程序中,以查看是否有該名稱的用戶定義函數。

因此,假設您將DLL加載到程序中,讓您的程序能夠解釋此特定語言的腳本,程序可以調用DLL來處理單行代碼或將腳本的文件名處理爲...但是如果你想添加一個命令到適合程序目的的腳本中,你可以說在DLL中設置一個布爾值,告訴它你正在爲它的語言添加函數,然後在你的代碼中創建一個函數,你要添加的函數(DLL會用它想要的函數的名字來調用它,如果這個函數是你的代碼中包含的用戶定義的函數的話,函數會調用相應的函數,並使用由DLL傳遞給它的參數,將用戶定義函數的返回值返回給DLL,如果它不存在,它將返回錯誤代碼或NULL或s omething)。我開始看到,我必須找到解決這個另一種方式讓函數調用走一條路只有

+0

哇,我甚至不知道有一個海灣合作委員會的勝利端口。我會嘗試使用gcc與windows作爲平臺目標。 – cbrulak 2009-02-03 00:22:03

+0

你應該指定你正在使用的確切編譯器。該編譯器的文檔可能會告訴你如何製作DLL。 – SoapBox 2009-02-03 00:23:01

+0

它被稱爲mingw或mingw32我猜...我會嘗試找到gcc文檔,但我對C和C++相當陌生,所以它的某些方面仍然很難理解 – user61721 2009-02-03 00:35:36

回答

8

This link解釋如何做到這一點在一個基本的方式。

在大圖中,當你製作一個dll時,你正在製作一個在運行時加載的庫。它包含一些導出的符號。這些符號通常是對方法或函數的引用,加上編譯器/鏈接器goo。

當你通常建立一個靜態庫時,至少有一個粘性鏈接器,鏈接器將它需要的代碼拉入並在你的可執行文件中重新包裝它。

在一個dll中,實際上你會得到兩個最終產品(三個真的只是等待):一個dll和一個存根庫。該存根是一個靜態庫,看起來完全像常規靜態庫,不同之處在於不是執行代碼,而是每個存根通常是對常規例程的跳轉指令。常見的例程加載你的dll,獲取你想調用的例程的地址,然後修補原始跳轉指令到那裏,所以當你再次調用它時,你最終會進入你的dll。

第三個最終產品通常是一個頭文件,告訴你所有關於庫中數據類型的信息。

所以你的步驟是:創建你的頭和代碼,建立一個DLL,從頭/代碼/一些導出函數列表建立一個存根庫。結束代碼將鏈接到存根庫,它將加載dll並修復跳轉表。

編譯器/連接咕包括像確保運行時庫需要它們的地方,確保靜態構造函數執行,確保靜態析構函數註冊了以後執行,等,等,等

現在就你的主要問題:如何在dll中編寫可擴展代碼?有許多可能的方法 - 一種典型的方法是定義一個純粹的抽象類(aka接口),它定義了一個行爲並將其傳遞給一個處理例程或創建一個例程來註冊接口來完成工作,然後處理常規要求註冊服務機構處理一件工作。

2

關於你計劃解決的細節,也許你應該看看像lua這樣的可擴展解析器,而不是構建自己的解析器。

給你更具體的焦點。
一個DLL(通常是?)本身就是完整的,或者明確知道要使用其他庫來完成自己。

我的意思是說,你不能讓調用應用程序隱式提供一個方法來完成DLL功能。

然而,您可以使API的一部分從調用應用程序中提供方法,從而使DLL完全包含並顯式傳遞知識。

如何在DLL中使用類和函數?
在鏈接模塊(exe或其他dll)時,在代碼中包含標題,檢查dll的完整性。

DLL可以調用鏈接到它的程序的函數嗎?
是的,但必須在運行時告訴他們。

如果我創建一個類{...}對象;在DLL中,然後當程序加載DLL時,程序是否可以使用對象?
是的,它將可用,但有一些限制,你需要注意。如在存儲器管理領域,重要的是無論是:

  • 鏈接所有的模塊具有相同的存儲器管理DLL(通常是c運行時)
  • 確保內存分配,只在dealloccated共享存儲器相同的模塊。
  • 分配在堆棧上

例子!
下面是將函數傳遞給dll的一個基本思想,然而在你的情況下可能不是最有用的,因爲你需要知道你想要提供的其他函數。

// parser.h 
struct functions { 
    void *fred (int); 
}; 

parse(string, functions); 

// program.cpp 
parse("a = sqrt(); fred(a);", functions); 

你需要的是註冊函數的方法(和它們的細節與DLL) 這裏的更大的問題是細節位。但跳過你可能會做類似wxWidgets的類註冊。當method_fred被你的應用程序構造時,它將調用構造函數並通過用法off methodInfo註冊到dll。解析器可以查找methodInfo的可用方法。

// parser.h 
class method_base { }; 
class methodInfo { 
    static void register(factory); 
    static map<string,factory> m_methods; 
} 

// program.cpp 
class method_fred : public method_base { 
    static method* factory(string args); 
    static methodInfo _methoinfo; 
} 
methodInfo method_fred::_methoinfo("fred",method_fred::factory); 
0

這聽起來像是一個數據結構的工作。

創建一個包含關鍵字和與每個關聯的函數的結構體。

struct keyword { 
    const char *keyword; 
    int (*f)(int arg); 
}; 

struct keyword keywords[max_keywords] = { 
    "db_connect", &db_connect, 
} 

然後寫在你的DLL中的函數,你通過這個數組的地址:

plugin_register(keywords); 

然後DLL裏面可以做:

keywords[0].f = &plugin_db_connect; 

使用這種方法,處理腳本關鍵字的代碼保留在主程序中,而DLL操作數據結構以獲取其自己的函數。

把它帶到C++,使結構變成一個類,而不是包含一個std :: vector或std :: map或任何關鍵字和一些函數來操縱它們。