2012-06-01 65 views
2

我已經在C++中編寫了一個DLL。其中一個函數寫入字符數組。將字符串從原生C++ DLL傳遞到C#應用程序

C++函數

EXPORT int xmain(int argc, char argv[], char argv2[]) 
{ 
    char pTypeName[4096]; 
    ... 
    //Other pTypeName ends up populated with "Portable Network Graphics" 
    //This code verifies that pTypeName is populated with what I think it is: 
    char szBuff[64]; 
    sprintf(szBuff, pTypeName, 0); 
    MessageBoxA(NULL, szBuff, szBuff, MB_OK); 
    //The caption and title are "Portable Network Graphics" 

    ... 
    //Here, I attempt to copy the value in pTypeName to parameter 3. 
    sprintf(argv2, szBuff, 0); 

    return ret; 
} 

C#導入

//I believe I have to use CharSet.Ansi because by the C++ code uses char[], 
    [DllImport("FirstDll.dll", CharSet=CharSet.Ansi)] 
    public static extern int xmain(int argc, string argv, ref string zzz); 

C#函數

private void button2_Click(object sender, EventArgs e) 
{ 
    string zzz = ""; 
    int xxx = xmain(2, @"C:\hhh.bmp", ref zzz); 
    MessageBox.Show(zzz); 

    //The message box displays 
    //MessageBox.Show displays "IstuÈst¼ÓstÄstlÄstwÄstiÑstõÖstwÍst\ 
    // aÖst[ÖstÃÏst¯ÄstÐstòÄstŽÐstÅstpÅstOleMainThreadWndClass" 

} 

我試圖通過引用傳遞從C#的參數和有C++ DLL填充參數。即使我已經驗證該值在DLL中是正確的,亂碼仍會傳遞給C#應用程序。

如何才能將正確的字符串值寫入C#字符串?

+0

嘗試創建在C#項目 「不安全」 的空間。 – dotTutorials

回答

5

使用StringBuilder傳遞本地代碼可以填寫的字符數組(請參見Fixed-Length String Buffers)。

聲明功能:

[DllImport("FirstDll.dll", CharSet=CharSet.Ansi)] 
public static extern int xmain(int argc, string argv, StringBuilder argv2); 

使用它:

// allocate a StringBuilder with enough space; if it is too small, 
// the native code will corrupt memory 
StringBuilder sb = new StringBuilder(4096); 
xmain(2, @"C:\hhh.bmp", sb); 
string argv2 = sb.ToString(); 
+0

該解決方案解決了我的問題。我期望我可以使用像char [] ch = new char [4096]這樣的字符數組,但是失敗了。任何想法爲什麼? –

+0

IIRC,'char []'總是被編組爲16位字符(本機類型爲「WCHAR」)的數組,並且不參與由'CharSet'爲'string' /'StringBuilder'執行的ANSI/Unicode轉換。 Ansi'。此外,我認爲傳遞'char []'不會自動將指針傳遞給數組中的第一個元素(C代碼需要);爲了強制執行,您可以在'DllImport'簽名中將參數指定爲'ref char',並在方法調用中使用'ref ch [0]'調用它。 –

1

給DLLImport調用一些其他信息。看看我自己的下面的例子:

[DllImport("tcpipNexIbnk.dll", EntryPoint = "SendData", CallingConvention = CallingConvention.Cdecl)] 
    public static extern int Send([MarshalAs(UnmanagedType.LPWStr)]string message); 

注意兩件事情,在CallingConvention參數: CallingConvention = CallingConvention.Cdecl)

使用,因爲它是。

然後僅次於C#字符串類型,你可以使用的MarshalAs指令不同的非託管類型的發揮,將在您的C#字符串參數轉換爲你在C有本地字符串類型++程序:

public static extern int Send([MarshalAs(UnmanagedType.LPWStr)]string message); 

希望它有幫助。

+1

當選擇CallingConvention.Cdecl選項時,我必須確保我的DLL使用__declspec(dllexport)導出函數。那是對的嗎?使用MarshalAs關鍵字本身並不能解決問題,但是當我轉向Unicode合規性時,我想我必須記住它。 –

相關問題