我一直在将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
的值不是&#39}。 t正确传递或在其他地方更改。
希望我能够清楚地说出问题,因为我在与上述代码作战后已经非常缺乏逻辑。
答案 0 :(得分:0)
主要问题在于您的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
和const char*
。
[DllImport("...", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr mySock_Create(string IP, int prt);