c# - C# 中的 typedef 等效于使用 C++ DLL

标签 c# c++ dll typedef dllimport

我正在尝试从 C# 代码调用导出到 DLL 的 C++ 结构

这是我要调用的方法的 C++ 接口(interface):

typedef void *Handle;
typedef void (*Callback)(Info *info);
typedef void (*Timeout)(Info *info);

typedef struct {
    WORD port;
    WORD flag;
    char name[16];
} Info;

__declspec(dllexport) Handle open(Info *info, Callback c,
                           Timeout timeout);

This article教我如何在 C# 中声明信息结构:

[StructLayout(LayoutKind.Explicit,
    Pack=1,Size=36)]
public struct Info
{
    [FieldOffset(0)]
        public ushort port;
    [FieldOffset(2)]
        public ushort flag;
    [FieldOffset(4)]
        public char name;
}

然后我会在 C# 中导入方法:

[DllImport ("MyDLL")] private static extern void Handle open(Info
*info, Callback c, Timeout timeout);

然后我卡住了,因为我不知道如何将 Handle、Callback 和 Timeout 的 typedef 转移到 C#。有什么建议吗?

最佳答案

它相当复杂......试试这个......它可能会爆炸,但你可以告诉我它是如何爆炸的,我可以帮助你:

public class MyDllhelper
{
    [StructLayout(LayoutKind.Sequential)]
    public unsafe struct Info
    {
        public ushort port;
        public ushort flag;
        public fixed byte name[16];

        public unsafe string Name
        {
            get
            {
                fixed (byte* ptr = name)
                {
                    IntPtr ptr2 = (IntPtr)ptr;
                    return Marshal.PtrToStringAnsi(ptr2, 16).TrimEnd('\0');
                }
            }

            set
            {
                fixed (byte* ptr = name)
                {
                    IntPtr ptr2 = (IntPtr)ptr;

                    byte[] bytes = Encoding.Default.GetBytes(value);
                    int length = Math.Min(15, bytes.Length);
                    Marshal.Copy(bytes, 0, ptr2, length);
                    ptr[length] = 0;
                }
            }
        }
    }

    public VoidRefInfoDelegate C { get; set; }
    public VoidRefInfoDelegate Timeout { get; set; }

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate void VoidRefInfoDelegate(ref Info info);

    [DllImport("MyDLL", CallingConvention = CallingConvention.Cdecl)]
    private static extern IntPtr open(ref Info info, VoidRefInfoDelegate c, VoidRefInfoDelegate timeout);

    public IntPtr Open(ref Info info, VoidRefInfoDelegate c, VoidRefInfoDelegate timeout)
    {
        C = c;
        Timeout = timeout;
        return open(ref info, C, Timeout);
    }
}

请注意,您必须执行以下操作:

public void CMethod(ref MyDllhelper.Info info)
{
    Console.WriteLine("C method called");
}

public void TimeoutMethod(ref MyDllhelper.Info info)
{
    Console.WriteLine("Timeout method called");
}

var info = new MyDllhelper.Info();
info.Name = "012345678901234567890"; // Use Name, not name!
info.flag = 1;
info.port = 2;

var helper = new MyDllhelper();
IntPtr handle = helper.Open(ref info, CMethod, TimeoutMethod); // Use Open, not open!

您需要使用属性->构建->允许不安全代码来编译代码。

代码中有两三个有趣的地方:C 数组已转换为固定 字节数组。我添加了一个 getter/setter Name 来处理从 Ansi/ASCII 到 Unicode 的转换以及返回。

C 函数有两个回调方法(ctimeout)。要使用它们,您需要在 C# 端的某处“保存”您将使用的委托(delegate),否则垃圾收集器将释放委托(delegate),并且您将收到一个异常(参见示例 https://stackoverflow.com/a/6193914/613130 )。 CTimeout 属性用于此目的。

关于c# - C# 中的 typedef 等效于使用 C++ DLL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29977861/

相关文章:

c++ - 如何使用特定版本的 zlib 在 ubuntu 上构建 openssl?

c++ - C 指针数组作用域和函数调用

networking - 我可以编写 go 库以供其他语言使用吗?

browser - 在 Inno Setup 中嵌入 Internet Explorer 窗口(Web 浏览器控件)

c# mocking IFormFile CopyToAsync() 方法

java - Exception.Message 属性应该直接显示给用户吗?

c# - 我应该如何在 VS 2010 中创建多语言文本翻译编辑器?

c# - 如何有效地比较列表?

c++ - 为什么 'this' 指针不能用在构造函数初始值设定项列表中?

c++ - dllimport 从 VC++ 到 VB 函数的转换,由于缺少链接库,dll 返回错误