[英]Passing C# StringBuilder / string to C++ char* using DLL
我一直在使用C#GUI和用於套接字連接處理的C ++代碼。 問題是將字符串傳遞給C ++ char * DLL會導致它在C ++類(?)中更改其值。
我有一個用於處理套接字的類,它有點改變以查找錯誤原因以及一些函數讓我自己進入類:
extern "C" { __declspec(dllexport)
class mySock
{
int port;
SOCKET littleSock;
public:
char* ipAddress;
mySock() {};
mySock(char* inIP, int inPort);
~mySock();
int initialize();
int sendMsg(char* Msg);
//int addition(int a, int b);
};
}
extern "C" { __declspec(dllexport) mySock* mySock_Create(char* IP, int prt);}
extern "C" { __declspec(dllexport) mySock* mySock_Create1(); }
extern "C" { __declspec(dllexport) int mySock_initialize(mySock* inSocket); }
extern "C" { __declspec(dllexport) int mySock_sendMsg(mySock* inSocket,char* Msg); }
extern "C" { __declspec(dllexport) void mySock_delete(mySock* inSocket); }
extern "C" { __declspec(dllexport) void CopyStr(char* str1, mySock* inSocket)
{
strcpy_s(str1, strlen(str1), inSocket->ipAddress);
};
}
問題發生在使用mySock_Create的某個地方。
基本上它是:
mySock* mySock_Create(char* IP, int prt)
{
return new mySock(IP, prt);
}
調用構造函數:
mySock::mySock(char* inIP, int inPort)
{
ipAddress = inIP;
port = inPort;
}
后來的ipAddress
與inet_addr一起使用並連接到遠程服務器。 無論如何,上面的代碼不允許我連接到服務器,但如果我只是硬編碼這樣的IP地址:
mySock* mySock_Create(char* IP, int prt)
{
return new mySock("192.168.1.164", prt);
}
它工作正常並連接到本地服務器。
因此,為了檢查我添加了你可以在上面的DLL頭代碼中看到的CopyStr,它應該獲取mySock對象的IP地址並將其寫入C#文本框。
如果硬編碼的IP地址確實顯示了IP地址,但是如果從C#傳遞IP地址,它只返回一個未填充的矩形符號,我甚至無法在此處粘貼。
這是用於鏈接和使用DLL的C#代碼:
[DllImport("G:\\socketstraning\\klikacz\\MyFirstDLLyay\\Debug\\MyFirstDLL.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr mySock_Create(StringBuilder IP, int prt);
[DllImport("G:\\socketstraning\\klikacz\\MyFirstDLLyay\\Debug\\MyFirstDLL.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int mySock_initialize(IntPtr value);
[DllImport("G:\\socketstraning\\klikacz\\MyFirstDLLyay\\Debug\\MyFirstDLL.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int mySock_sendMsg(IntPtr value, string Msg);
[DllImport("G:\\socketstraning\\klikacz\\MyFirstDLLyay\\Debug\\MyFirstDLL.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void mySock_delete(IntPtr value);
[DllImport("G:\\socketstraning\\klikacz\\MyFirstDLLyay\\Debug\\MyFirstDLL.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr mySock_Create1();
[DllImport("G:\\socketstraning\\klikacz\\MyFirstDLLyay\\Debug\\MyFirstDLL.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void CopyStr(StringBuilder str1, IntPtr value);
private void button3_Click(object sender, EventArgs e)
{
StringBuilder str = new StringBuilder("192.168.1.164", 50);
IntPtr we = mySock_Create(str, 16999);
StringBuilder str2 = new StringBuilder("255.255.255.255", 25);
CopyStr(str2, we);
textBox1.Text = str2.ToString();
if (mySock_initialize(we) == -2)
button3.Text = "Ups";
mySock_delete(we);
}
我也嘗試使用字符串而不是StringBuilder或在導入選項中添加CharSet = CharSet.Ansi。
在這種情況下,我已經閱讀了很多將字符串傳遞給char*
的問題和解決方案,但我無法理解為什么ipAddress
值未正確傳遞或在其他地方更改。
希望我能夠清楚地說明問題,因為在與上述代碼作戰之后我已經非常缺乏邏輯。
主要問題在於您的C ++構造函數:
mySock::mySock(char* inIP, int inPort)
{
ipAddress = inIP;
port = inPort;
}
在這里,您可以復制指向字符數組的指針。 只要您需要使用ipAddress
,這就要求此指針保持有效。 從C#封送的字符串僅在p / invoke調用期間有效。
實際上,即使你只使用C ++這個類,它的設計也是行不通的。 您的類需要獲取字符串的副本而不是指針的副本。
解決方案是讓您的C ++代碼專門使用std::string
。 讓該類負責內存管理和復制。 僅在p / invoke互操作邊界處使用C字符串。
將ipAddress
更改為std::string
類型,並使構造函數如下所示:
mySock::mySock(const std::string inIP, const int inPort)
{
ipAddress = inIP;
port = inPort;
}
您仍然需要在interop包裝函數中使用C字符串,但這可以使用從const char*
到std::string
的隱式轉換。
mySock* mySock_Create(const char* IP, const int prt)
{
return new mySock(IP, prt);
}
就p / invoke而言,你濫用了StringBuilder
和char*
。 當您具有被調用者修改的調用者分配的緩沖區時,它們將配對。 對於傳入C ++代碼的string
,請使用string
和const char*
。
[DllImport("...", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr mySock_Create(string IP, int prt);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.