簡體   English   中英

調用C ++ dll的訪問沖突

[英]Access violation calling C++ dll

我用我在linux(gcc)上編寫的代碼創建了c ++ dll(使用mingw),但是在VC ++中使用它卻有些困難。 dll基本上只公開一個類,我為此創建了純虛擬接口,還創建了工廠函數,該函數創建了如下所示的對象(唯一的導出):

extern "C" __declspec(dllexport) DeviceDriverApi* GetX5Driver(); 

我添加了extern“ C”來防止名稱修改,在我想使用dll的實際代碼中,dllexport替換為dllimport,DeviceDriverApi是純虛擬接口。

現在,我用VC ++寫了簡單的代碼,只調用了工廠函數,然后試圖刪除指針。 它編譯沒有任何問題,但是當我嘗試運行它時,出現訪問沖突錯誤。 如果嘗試調用該對象的任何方法,則會再次出現訪問沖突。

當我在MinGW(gcc)中編譯相同的代碼並使用相同的庫時,它運行時沒有任何問題。 因此,在VC ++代碼如何使用庫和gcc代碼之間必須有一些東西(呵呵,我想實際上有很多區別:))。

有什么想法嗎?

干杯湯姆

編輯:該代碼是:

    DeviceDriverApi* x5Driver = GetX5Driver();


if (x5Driver->isConnected())
    Console::WriteLine(L"Hello World");

delete x5Driver;

當我嘗試調用該方法以及嘗試刪除該指針時,它也崩潰了。 但是,正確創建了對象(第一行)。 創建對象時有一些調試輸出,在得到訪問沖突錯誤之前,我可以看到它們。

  • 您正在為DLL使用一個編譯器(mingw),而為調用代碼使用另一個(VC ++)。
  • 您正在調用“ C”函數,但是返回了指向C ++對象的指針。

將永遠無法工作,因為VTable布局幾乎保證不兼容。 而且,DLL和應用程序可能使用不同的內存管理器,因此您要用一個執行new()用另一個執行delete() 同樣,它只是行不通。

為此,兩個編譯器都需要支持標准的ABI (應用程序二進制接口)。 我認為Windows不存在這種情況。

最好的選擇是通過C函數公開所有DLL對象的方法和屬性(包括一個刪除對象的方法)。 您可以在調用端將其重新包裝為C ++對象。

兩種不同的編譯器可能使用不同的調用約定。 嘗試在客戶端代碼和DLL代碼中將_cdecl放在函數名稱之前,然后重新編譯兩者。

有關呼叫約定的更多信息,請參見: http : //en.wikipedia.org/wiki/X86_calling_conventions

編輯:該問題進行了更詳細的更新,並且看起來問題可能是艾德里安·普里森在回答的結尾描述的內容。 您在一個模塊中創建一個對象,然后在另一個模塊中釋放它,這是錯誤的。

(1)我也懷疑一個呼叫轉換問題,盡管Leo的簡單建議似乎沒有幫助。

isConnected是虛擬的嗎? MinGW和VC ++可能對VTable使用不同的實現,在這種情況下,運氣不好。

嘗試看看您使用調試器能走多遠:它是在調用時還是在返回時崩潰? 您輸入無效的代碼嗎? (如果您知道要閱讀匯編,通常這些問題會很有幫助。)

或者,將trace語句添加到各種方法中,以了解您能走多遠。

(2)對於公共DLL接口,永遠不要釋放被調用方分配的調用方中的內存(反之亦然)。 DLL可能以完全不同的堆運行,因此指針是未知的。

如果要依賴該行為,則需要確保:

  • 調用者和被調用者(在您的情況下,即DLL和主程序)使用相同版本的sam編譯器進行編譯
  • 對於所有受支持的編譯器,您已經配置了編譯選項,以確保調用方和被調用方使用相同的共享運行時庫狀態。

因此,最好的方法是將您的API更改為:

extern "C" __declspec(dllexport) DeviceDriverApi* GetX5Driver(); 
extern "C" __declspec(dllexport) void FreeDeviceDriver(DeviceDriverApi* driver); 

然后在調用者站點以某種方式包裝(例如,在boost::intrusive_ptr )。

請嘗試從DLL和客戶端可執行文件中查看導入的庫。 (您可以使用“ 依賴關系查看器”dumpbin或您喜歡的任何其他工具)。 驗證DLL和客戶端代碼都使用相同的C ++運行時。

如果不是這種情況,則確實可能會遇到一些問題,因為兩種內存之間的管理方式可能有所不同,從而導致從一個運行時釋放從另一運行時分配的指針時崩潰。

如果這確實是您的問題,請嘗試不破壞客戶端可執行文件中的指針,而是在DLL中聲明並導出一個函數,該函數將負責破壞指針。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM