使用dll将C#StringBuilder / String传递给C char*

Passing C# StringBuilder / string to C++ char* using DLL

本文关键字:char String dll C#StringBuilder 使用      更新时间:2023-10-16

我一直在将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#TextBox。

,如果确实有一个硬编码的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 Call的持续时间内有效。

的确,即使您仅在C 中使用此课程,它的设计也是不可行的。您的班级需要拿起字符串的副本,而不是指针的副本。

该解决方案是您的C 代码专门使用std::string。让该课程照顾记忆管理和复制。仅在P/Indoke Interop边界处使用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*。当您分配了由Callee修改的呼叫者缓冲区时,它们是配对的。对于传递到C 代码的字符串,请使用stringconst char*

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