如何正确地将结构指针从C#传递给C DLL

时间:2015-07-29 14:02:30

标签: c# c dllimport

我需要从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);

删除ref时问题消失了。但我不明白为什么。

你可以解释一下吗?

2 个答案:

答案 0 :(得分:2)

您可能认为passing parameter by reference需要st_struct关键字才能ref。但由于st_struct被定义为引用类型(类是引用类型),因此参数是通过引用传递的,而不是通过值传递的。您不需要struct关键字。

如果ref被定义为server { auth_basic "closed site"; auth_basic_user_file /tmp/.htpasswd.txt; listen 81 default_server; listen [::]:80 default_server ipv6only=on; root /var/www/path/to/root index index.html index.htm; server_name ipaddress; ,您可能会在使用<?php require_once('config.php'); $posts = array(); /* require the user as the parameter */ if(isset($_GET['roll']) and isset($_GET['name'])) { /* soak in the passed variable or set our own */ $roll = $_GET['roll']; //no default $name = $_GET['name']; //no default /* grab the posts from the db */ if($roll!="" and $name!="") { $query = "INSERT INTO STUDENT VALUES('$roll','$name')"; if(mysql_query($query,$dblink)) { $posts[] = array('status'=>'Data Inserted'); } else { $posts[] = array('status'=>'Not Inserted'); } } else { $posts[] = array('status'=>'Null Value sent'); } /* disconnect from the db */ @mysql_close($db); } else { $posts[] = array('status'=>'Please check the arguments'); } /* output in necessary format */ header('Content-type: application/json'); echo json_encode(array('posts'=>$posts)); ?> 关键字时发现它有用。

答案 1 :(得分:1)

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

因此,当传递没有ref的类时,它按预期工作(C代码获取指针)。如果将其更改为struct,则在没有ref的情况下传递它应该将其传递到堆栈并使用ref传递它将其作为指针传递。

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