2014-11-21 98 views
-1

我正在研究一個C++ DLL,它應該能夠接收並將一些參數傳遞迴C#應用程序。從C#傳遞參數到C++ Dll並返回的正確方法是什麼?

我能夠做到這一點,這是工作正常。至少我是這麼想的。代碼在我的電腦上工作正常,但不在我的同事的個人電腦上。在他的PC上,相同的代碼(在我的電腦上運行時沒有錯誤)會產生不同的輸出,或產生錯誤。基本上它表現得很怪異。

C++函數:

extern "C" 
{ 
    __declspec(dllexport) BOOL __stdcall MyFunction(char * StringIn, char *StringOut, BOOL bState); 
} 

我用這種方式在C#:

[DllImport(@"PathToMyDll.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)] 
    public static extern bool MyFunction(string StringToDLL, StringBuilder StringFromDLL, bool bState); 

    static void Main(string[] args) 
    { 
     int bufferSize = 16384; 

     string StringToDLL = "This is a sample string"; 
     StringBuilder StringFromDLL = new StringBuilder(bufferSize); 

     Console.WriteLine("Return value  = " + MyFunction(StringToDLL, StringFromDLL, true).ToString()); 
     Console.WriteLine("Sent to DLL  = " + StringToDLL.ToString()); 
     Console.WriteLine("Returned from DLL = " + StringFromDLL.ToString()); 

     Console.ReadLine(); 
    } 

所以我的問題是:
我做錯什麼了嗎?還是有一些Visual Studio中的設置可能導致這種行爲?另外,我應該如何正確地爲C#中的StringOut分配內存?有一種情況可能出現在StringOut會比buffersize大的地方,但我不知道它到底有多大?(我只知道它在DLL裏面) 有沒有人有任何想法爲什麼相同的代碼會自動運行不同地在不同的PC上?

在此先感謝!

+0

您允許將C#中聲明的字符串直接轉換爲char *隱式嗎?有一次,我使用C++/CLI爲本地C++類編寫了包裝器(請參閱本教程:http://www.codeguru.com/cpp/cpp/cpp_managed/interop/article.php/c6867/Consuming-Unmanaged-C-Class -Libraries-from-Net-Clients.htm),我必須非常小心編譯本機C++端和C++/CLI管理端之間的類型。 – Ian 2014-11-21 23:08:03

+0

@Ian是的,你可以。這是P/Invoke層的一部分。 – cdhowie 2014-11-21 23:14:18

+0

看起來這個代碼沒有問題。可能你應該在其他地方尋找問題。順便說一句,你可以省略調用約定--stdcall是默認的。 – Nikolay 2014-11-21 23:14:36

回答

1

考慮到問題中的信息,您的代碼是正確的。這個問題可能在別處。顯而易見的地方是非託管代碼。我建議你調試一下。

您的代碼是等待發生的緩衝區溢出。如果被調用者不知道其大小,如何避免被緩衝區溢出?選項包括:

  1. 將緩衝區長度傳遞給非託管代碼。
  2. 使用BSTR通過分配共享COM堆的方式允許任意長的字符串。
+0

另一種選擇是使DLL函數的一個版本返回需要分配的緩衝區的最大大小。然後對函數的後續調用是使用適當大小的緩衝區完成的。有點過時,但這是一些API的工作方式。 – PaulMcKenzie 2014-11-22 13:27:41

+0

@Paul這是實現選項1的正常方法 – 2014-11-22 13:37:33

+0

@DavidHeffernan:基本上你說的是,我應該重寫我的代碼,以保持字符串長度的額外參數。然後我應該打電話給它兩次。第一次,它應該返回長度,第二次,我應該通過正確的長度,只有然後我應該返回字符串?我理解正確嗎?感謝idee,但這仍然不能解釋它在我的電腦上工作。而且我返回的字符串比緩衝區大小更短。 – kampi 2014-11-22 15:57:57

0

如果這有幫助,這是我如何將我的基於C++的DLL接口到C#。

[DllImport("MyDLL.DLL", CharSet=CharSet.Ansi,ExactSpelling=true, 
      CallingConvention=CallingConvention.StdCall)] 
public static extern int MyFunction 
(MarshalAs(UnmanagedType.LPTStr)]StringBuilder strinIn, 
[MarshalAs(UnmanagedType.LPStr)]StringBuilder stringOut); 

所以區別在於我指定了編組類型。然後

C++的DLL(導出爲 'C' 功能)將具有以下原型:

LONG WINAPI MyFunction(const char *In, char *Out); 

注:我不一個 C#專家。這是我需要做的,以便讓我的C++ DLL函數被C#應用程序調用。

+1

你的MarshalAs言論在這裏毫無意義。更重要的是你應該使用字符串作爲in參數。 – 2014-11-22 06:50:40

+0

使用'string'而不是'StringBuilder'作爲輸入參數。 FWIW,該問題指出本機代碼是C++。當然對於互操作,'std :: string'是不合適的。 – 2014-11-22 13:17:35

相關問題