c# - 如何将 C++ 非托管 DLL 转换为 C#

标签 c# c++ unmanagedexports

我在 C++ 中有非托管 dll,它工作正常,我尝试用 C# 重新实现它,但出现以下错误:

System.ArgumentException: Value does not fall within the expected range

at System.StubHelpers.ObjectMarshaler.ConvertToNative(Object objSrc, IntPtr pDstVariant)  
at Demo.on_session_available(Int32 session_id) in C:\\Users\\Peyma\\Source\\Repos\\FastViewerDataClient\\FastViewerDataClient\\Demo.cs:line 69

ExceptionMethod: 8
ConvertToNative
mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.StubHelpers.ObjectMarshaler
Void ConvertToNative(System.Object, IntPtr)

HResult:-2147024809

Source: mscorlib

C++代码如下:

typedef void(*func_ptr)(
int sId,
unsigned char cId,
const unsigned char* buf,
int len,
void* context);

struct configuration
{
  func_ptr send;
};

struct send_operation
{
  int session_id;
  unsigned char channel_id;
  std::string data;
};

 auto op = new send_operation();
 op->sId = sessionId;
 op->cId = channelId;
 op->data = "Some Text";

 configuration.send(
    sessionId,
    channelId,
    reinterpret_cast<const unsigned char*>(op->data.c_str()),
    op->data.length(),
    op);

然后在C#中翻译如下:

[StructLayout(LayoutKind.Sequential)]
public struct Configuration
{
    public Send send { get; set; }
}

[StructLayout(LayoutKind.Sequential)]
public struct send_operation
{
    public int session_id { get; set; }
    public sbyte channel_id { get; set; }
    public string data { get; set; }
};

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void Send(int sessionId, sbyte channelId, sbyte[] buffer, int len, object context);


 var op = new send_operation
        {
            session_id = session_id,
            channel_id = 0,
            data = "This is a test message!!"
        };

        var bytes = Encoding.UTF8.GetBytes(op.data);

        config.send(sessionId, 0, Array.ConvertAll(bytes, Convert.ToSByte), op.data.Length, op);

更新:

public static void on_session_available(int session_id)
{
    WriteOnFile($"Open session id:{session_id}");

    try
    {
        var op = new send_operation
        {
            session_id = session_id,
            channel_id = 0,
            data = "This is a test message!!"
        };


        var bytes = Encoding.UTF8.GetBytes(op.data);

        config.send_data(session_id, op.channel_id, bytes, op.data.Length, op);
    }
    catch (Exception e)
    {
        WriteOnFile($"Error in sending data:{JsonConvert.SerializeObject(e)}");
        if (e.InnerException != null)
        {
            WriteOnFile($"Error in inner sending data:{e.InnerException.Message}");
        }
    }
}

最佳答案

一些变化:

C++,std::stringunsigned char*,因为它很难在 C# 中编码。

struct send_operation
{
    int session_id;
    unsigned char channel_id;
    unsigned char* data;
};

C#,object contextIntPtr context,因为send_operation 是一个struct,这将传递装箱对象而不是struct 数据。

public delegate void Send(int sessionId, sbyte channelId,
    sbyte[] buffer, int len, IntPtr context);

如何通过:

IntPtr ptr = IntPtr.Zero;
try
{
    ptr = Marshal.AllocHGlobal(Marshal.SizeOf(op));
    Marshal.StructureToPtr(op, ptr, false);
    config.send_data(session_id, op.channel_id, bytes, op.data.Length, ptr);
}
finally
{
    Marshal.FreeHGlobal(ptr);
}

关于c# - 如何将 C++ 非托管 DLL 转换为 C#,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57971238/

相关文章:

c++ - 如何将公共(public)接口(interface)的子集暴露给类

c# - 使用 UnmanagedExports 包 [DllExport] 在 VBA 中调用 C# DLL 触发 "Can' t 查找 DLL 入口点”错误

c# - 在非托管 C# .NET 库项目中使用 NuGet 库

c++ - 尝试访问类内部的 bool 值时出现段错误

c# - 使方法代码行更少

c# - BitmapImage - 图像下载问题

c# - 创建循环计时器

c# - 动态成员表达式

c++ - 连接信号和插槽不工作 Qt