2010-12-13 103 views
4

我的問題是有點一般,所以我不是在尋找一個確切的答案,但可能還有一些方向考慮,這將有助於我...C#的DllImport麻煩

在我工作的地方我編程主要是在C#。 我們有這個第三方公司,這給了我們一個我們需要使用的Native C++ dll。由於我需要的C++方法沒有以易於從C#引用的方式公開,所以我將dll封裝在另一個本機C++ Dll中。

所以,現在我有2倍本機C++的DLL中,一個包裹其他。

我創建的調用我在C++中創建的方法的小C#控制檯應用程序。 我的方法簽名如下所示:

[DllImport("HashMethodWrapper.dll")] 
[return: MarshalAs(UnmanagedType.LPStr)] 
private static extern string CreateHash(
      string input, 
      [MarshalAs(UnmanagedType.LPStr)]StringBuilder output); 

在我的控制檯應用程序,一切工作正常,我總是收到串IM在結果期待。

但是,當我將它移動到一個Web服務或我創建了一個Web應用程序(因爲這是我真的需要它),我看到字符串IM接收就是垃圾,甚至並不一致。看來,如果即時得到只是一些參考對丟失或類似的東西的內存,但是這僅僅是我的猜測......

我不知道爲什麼會這樣,因爲在我的控制檯應用程序一切正常精細。

沒有人有可能會幫助我一個方向??? ...

由於提前, gillyb

編輯: 我想這可能與一些未鎖定的對象做,所以我試圖在固定的聲明中調用方法,如:

unsafe public static string CreateHashWrap(string pass) 
{ 
    String bb; 
    StringBuilder outPass = new StringBuilder(); 
    fixed (char* resultStr = CreateHash(pass, outPass)) 
    { 
     bb = new String(resultStr); 
    } 
    return bb; 
} 

...但這仍然沒有爲我做。這是固定物體的正確方法嗎?

第二編輯: 在C++中的方法,簽名看起來像這樣:

extern "C" __declspec(dllexport) char *CreateRsaHash(char *inputPass, char *hashPass); 

第三編輯: 我改變的方法的簽名是

extern "C" __declspec(dllexport) bool CreateRsaHash(char *inputPass, char *hashPass); 

和返回值im尋找放在*hashPass參數。

現在,我創建了一個簡單的控制檯應用程序來測試它。當將DllImport插入到我的主類中,並直接調用該方法時,一切都很好,但是當我移動DllImport並將該方法包裝在不同的類中並從Console'Main'方法中調用該類時,出現StackOverflow異常!

任何人有任何想法,爲什麼發生這種情況?

+0

您能告訴我們如何在C/C++中聲明函數頭嗎?這可以幫助:) – 2010-12-13 09:11:15

+0

殺死API的作者,有一個非常明顯的內存泄漏發生... – leppie 2010-12-13 10:37:47

+0

爲什麼?你能解釋一下爲什麼,以及爲什麼從簽名中如此清楚?希望我們仍然可以解決它! – gillyb 2010-12-13 10:41:32

回答

0

我找到了解決我的問題,現在我覺得有點(如果不是真的!)愚蠢的...: - |

我在C++中使用LoadLibrary()方法來動態調用其他本地dll的方法。問題是我沒有給這個方法任何路徑,只是dll文件名。在.net中,它會在當前文件夾中搜索,但似乎在本地代碼中,這不起作用。

在我的編程實踐中的更大的問題顯然是我沒有完全覆蓋我的本機C++ DLL中的錯誤處理!

所有我這個頁面上收到的asnwers是不是沒有,但...

一旦我發現我有問題的目錄路徑,我遇到了不同的異常有關試圖訪問損壞內存,等等。然後我需要創建固定的對象,併爲我的StringBuilder對象聲明一個大小。

感謝大家的幫助!

:)

+0

不錯。做得好。 – 2010-12-16 19:57:07

1

這真的很難從稀疏的信息知道,但如果我猜我會說,你需要確保你釘扎輸出對象。另外,我可能會將輸出參數更改爲某種其他類型,看起來很奇怪StringBuilder的工作是坦率的。

我知道如果你分配一個對象,它會得到一個指針,但這並不意味着它不會移動。因此,如果您嘗試將指向託管對象的指針傳遞到非託管環境中,則需要確保告訴GC「鎖定」內存,使其不會從內部移出。

這裏是什麼,我的意思是一個非常粗糙的版本由釘住:

string input = "..."; 
StringBuilder output = new StringBuilder(); 
var handle = System.Runtime.InteropServices.GCHandle.Alloc(output, GCHandleType.Pinned); 
try 
{ 
    CreateHash(input, output); 
} 
finally 
{ 
    handle.Free(); 
} 
+0

那麼,關於StringBuilder,我讀了一個地方,如果值發生變化,我需要一個stringbuilder,因爲'String'是不可變的,在這種情況下不會執行這個任務。這是真的 ? – gillyb 2010-12-13 08:17:31

+0

關於固定的對象,我認爲這可能是問題,所以我試圖做一些固定。我會將它添加到我的問題中,請問您能告訴我我做了什麼和您向GCHandle顯示的內容有什麼區別。 – gillyb 2010-12-13 08:17:58

+0

有兩件事:你固定了char *而不是StringBuilder。另外爲什麼你有StringBuilder,它被稱爲「輸出」,也是一個返回值?看起來好像你完全忽略了StringBuilder,只是返回返回值。 – 2010-12-13 08:26:10

0

我會考慮到C#的共享組件/ DLL,而不是C++ DLL裏面彎曲,然後嘗試讓你的控制檯應用程序與dll一起工作。無論如何,以這種方式封裝外部依賴關係是一種很好的做法。
否則,一些傳統的問題是32比64位,共享庫的負載路徑。它真的只是一個字符串或更復雜的東西嗎?