2011-11-03 23 views
2

如何使用DLL函數中的複雜返回類型調用後實現的函數(例如,在消費應用程序中實現的函數指針或虛函數)?調用消費應用程序中實現的函數的C++ DLL

我試了下面的方案,但有錯誤。

Test.h:

#ifdef _DLL_IMPL 
#define DLL_EXPORT __declspec(dllexport) 
#else 
#define DLL_EXPORT __declspec(dllimport) 
#endif 
typedef string (*test)(void); 
extern DLL_EXPORT test __test; 
DLL_EXPORT int launch(); 

Test.cpp的:

#define _DLL_IMPL 
#include "Test.h" 
test __test = 0; 
int launch() 
{ 
    string a = __test(); 
    return 0; 
} 

而消費應用程序是這樣:

Main.cpp的:

#include "Test.h" 
#pragma comment(lib, "Test.lib") 
string test_impl() 
{ 
    string a = "test"; 
    return a; 
} 
int main(int args, char** argv) 
{ 
    __test = &test_impl; 
    return launch(); 
} 

我有一個後續的錯誤信息:

Windows has triggered a breakpoint in TestRun.exe. 

This may be due to a corruption of the heap, which indicates a bug in 
TestRun.exe or any of the DLLs it has loaded. 

This may also be due to the user pressing F12 while TestRun.exe has focus. 

The output window may have more diagnostic information. 

我不知道究竟發生了什麼。當我嘗試使用新操作符在消費應用程序中創建的字符指針的返回類型時,也會發生錯誤,並且會使用delete []運算符在DLL函數中釋放它。

有人可以解釋爲什麼錯誤發生的原因,並建議我一些解決方案,這種方案?謝謝!

+0

我不相信你可以在新的應用程序,在dll中刪除。這會導致堆損壞。 – JoeFish

+0

是的,我也相信這就是它不起作用的原因。我真的不知道如何實現我描述的方案(即調用在應用中實現的功能)。 – bestmike007

回答

1

在exe和dll之間傳遞C++對象實際上並不是一個好主意,更重要的是,如果對象基於模板類和/或具有內聯方法,甚至更多,如果對象在內部分配內存。如果你需要這種應用程序和庫之間的接口,那麼我建議你將你的dll切換到一個靜態庫,然後你就可以避免大部分問題。

如果您需要將dll保存爲dll,那麼我建議您只在exe和dll之間傳遞本地類型。在你的例子中,將string的所有用法切換爲char*可能會解決崩潰問題。

同樣從Jim Rhodes那裏得到很好的建議,並且聲明一個明確的調用約定,即使你發現在這種情況下這不是問題。

+0

真的非常感謝您的建議。 – bestmike007

0

也許你有一個調用約定不匹配。也許字符串test_impl()應該是字符串__stdcall test_impl()。

+0

感謝您的關注,但似乎沒有解決這個問題。我試圖修改: Test.h: typedef string(__stdcall * test)(void); Main.cpp: string __stdcall test_impl()... 錯誤仍然存​​在。 – bestmike007

0

您很可能正在與不同版本的C運行時庫鏈接,從而阻止共享堆的使用。確保應用程序和dll都鏈接到C運行時庫的相同「風格」(動態或靜態) - 如果您不確定應選擇哪一個,請將它們設置爲動態。請參閱Strange problems with new/delete in an app that uses my DLL

0

你真的想要導出/導入不清楚。你從main.cpp中導出test_impl並從test.cpp導入main.cpp中的啓動

無論如何,你應該也可以導出類(std :: string)。

下面的代碼工作完美:

//test.cpp 
typedef __declspec(dllimport) std::string  (*test)(void); 

    extern __declspec(dllexport) test __test; 

    test __test = 0; 

extern __declspec(dllexport) int launch() {  std::string a = __test();  
std::cout << a << std::endl ; 
return 0; } 

// main.cpp 
typedef __declspec(dllexport) std::string  (*test)(void); 
extern __declspec(dllimport) test __test; 
extern __declspec(dllimport) test __test; 

__declspec(dllimport) int launch(); 

__declspec(dllexport) 
std::string test_impl() { 
    std::string a = "test"; 
    return a; } 

int main(int args, char** argv) { 
    __test = &test_impl;  
    return launch(); } 

檢查然而,這兩個項目都具有相同的機型(/ MTD,/噸)編譯

+0

我試過你的代碼,但是,錯誤依然如此:'這可能是由於堆的腐敗,這表明TestRun.exe或它已加載的任何DLL的錯誤。「我認爲@Miguel可能是正確的,我編譯我的代碼到一個靜態庫,它的工作原理。我的主要目的是隱藏我的代碼,讓其他人實現我提供的接口,然後整合整個系統。我真的不在乎它是靜態庫還是DLL。儘管如此,我仍然想知道它編譯到DLL時出錯的原因。 – bestmike007

相關問題