我需要从C DLL导出功能。这是我写的例子

typedef struct tag_struct {
  unsigned char first;
  unsigned char second;
} st_struct;

__declspec(dllexport) unsigned char Func( st_struct *ptr )
{
    return ptr->first + ptr->second;
}


这是我用来导入上述功能的C#代码。

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace ImportTest
{
    [Serializable]
    [StructLayout(LayoutKind.Sequential)]
    public class st_struct
    {
        public byte first;
        public byte second;
    }

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            st_struct x = new st_struct();

            x.first = 1;
            x.second = 2;

            byte result = Func(ref x);
        }

        [DllImport("MarshalTest.dll")]
        protected static extern byte Func(ref st_struct inputs);
    }
}


我的问题是Func的返回值不是3,应该是(1 + 2)。

我正在使用调试器查看DLL中的值-它们是不同的(不是我提供的1和2)。

当我像这样更改C#代码时,函数返回正确的值:

public Form1()
{
    InitializeComponent();

    st_struct x = new st_struct();

    x.first = 1;
    x.second = 2;

    byte result = Func(x);
}

[DllImport("MarshalTest.dll")]
protected static extern byte Func(st_struct inputs);


当我删除参考时,问题消失了。但是我不明白为什么。

你能解释一下吗?

最佳答案

正如@kennyzx所提到的,由于您的st_struct是一个类,因此它已经是引用类型,并将作为指针传递。我怀疑在其上抛出ref会给你一个双指针,这在混合托管和非托管代码时没有多大意义。如果指针发生变化,编组器可能会处理该问题并为您创建一个新对象,但这似乎是一件很粗略的事情。

因此,当传递不带ref的类时,它会按预期工作(C代码获取一个指针)。如果将其更改为struct,则在不使用ref的情况下传递它应该将其传递到堆栈上,而在使用ref的条件下传递它将作为指针传递。

在您的情况下,使用struct似乎是显而易见的选择,因为它可以直接传递(CLR只需将其固定并传递一个指针)即可。我怀疑使用class会涉及更多的编组。

关于c# - 如何正确地将结构指针从C#传递到C DLL,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31702766/

10-12 12:36
查看更多