使用DLL将C#StringBuilder / string传递给C ++ char *

时间:2016-12-28 23:36:53

标签: c# c++ dll pinvoke

我一直在将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正确传递或在其他地方更改。

希望我能够清楚地说出问题,因为我在与上述代码作战后已经非常缺乏逻辑。

1 个答案:

答案 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而言,你滥用StringBuilderchar*。当您具有被调用者修改的调用者分配的缓冲区时,它们将配对。对于传入C ++代码的字符串,请使用stringconst char*

[DllImport("...", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr mySock_Create(string IP, int prt);