【问题标题】:dllimport : c code affect a struct passed by reference (c#)dllimport : c 代码影响通过引用传递的结构 (c#)
【发布时间】:2013-12-17 13:25:14
【问题描述】:

我有一个包含公开函数的 c dll,它接受三个参数:

int ParseInput(char* opt_path, char* input, SENNA_RESULT_ARRAY* result);

我想从 C# 中调用它,它确实有效。问题是结果结构不受影响。 这是c代码中定义的结构:

    typedef struct RESULT_
{
    char* word;
    int pos_start;
    int pos_end;
    char* pos;
    char* chk;
    char* ner;
    char* psg;

} RESULT;

typedef struct RESULT_ARRAY_
{
    int size;
    RESULT* Results;    
} RESULT_ARRAY;

还有我的 c# 代码:

[StructLayout(LayoutKind.Sequential)]
    public struct SENNA_RESULT
    {
        [MarshalAs(UnmanagedType.LPStr)]
        public string word;
        [MarshalAs(UnmanagedType.I4)]
        public int pos_start;
        [MarshalAs(UnmanagedType.I4)]
        public int pos_end;
        [MarshalAs(UnmanagedType.LPStr)]
        public string pos;
        [MarshalAs(UnmanagedType.LPStr)]
        public string chk;
        [MarshalAs(UnmanagedType.LPStr)]
        public string ner;
        [MarshalAs(UnmanagedType.LPStr)]
        public string psg;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct SENNA_RESULT_ARRAY
    {
        public SENNA_RESULT[] Results;     
        public int size;
    }

    [DllImport("Senna-32.dll", CharSet = CharSet.Ansi)]
    static extern int Parse(string msg, string stream, ref SENNA_RESULT_ARRAY results);

Parse(@"path", "sentence", ref result_array)

我尝试了很多方法,例如: 1-使用类而不是没有 ref 关键字的结构 2-使用指针而不是传递结构

每次我遇到不同的错误,例如 数组不是指定类型 低级错误(损坏的堆)

即使我没有在第一个结构中指定数组,size 成员也没有正确的值(C 代码在控制台中打印该值)

有什么建议吗?

谢谢

【问题讨论】:

  • 我不能肯定地说,但我相信正确的语法是out SENNA_RESULT_ARRAY results
  • 成员的顺序不同,size是C结果数组结构体的第一个元素,C#结果数组结构体的最后一个元素。订单不应该相等吗?
  • 这个函数几乎不可能在 C 程序中正确使用,当你在 C# 中使用时它并没有变得更好。存在严重的内存管理问题,需要再次释放数组和所有这些字符串。这要求调用者使用与被调用者相同的内存分配器,C# 中从来没有这种情况,C 中很少使用这种情况。
  • Klas 你是对的,但这不是问题,我尝试按顺序与成员以相同的顺序排列,但没有任何改变。这里的序列顺序来自我对 Explicit 和 fieldoffset 属性所做的测试。
  • Michael,我一开始就试过了,我会再试一次,因为我对 c 代码做了一些改动。

标签: c# c interop dllimport


【解决方案1】:

考虑使用下面的代码。

[StructLayout(LayoutKind.Sequential)]
public struct SENNA_RESULT
{
    public IntPtr word;
    public int pos_start;
    public int pos_end;
    public IntPtr pos;
    public IntPtr chk;
    public IntPtr ner;
    public IntPtr psg;
}

[StructLayout(LayoutKind.Sequential)]
public struct SENNA_RESULT_ARRAY
{
    public IntPtr Results;     
    public int size;
}

[DllImport("Senna-32.dll")]
static extern int Parse(string msg, string stream, out SENNA_RESULT_ARRAY results);

这里是使用示例

        SENNA_RESULT_ARRAY array = new SENNA_RESULT_ARRAY();
        int result = Parse("path", "sentence", out array);
        if (result == SUCCESS && array.Results != IntPtr.Zero)
        {
            for (int index = 0; index < array.size; index++)
            {
                IntPtr offset = (IntPtr)((int)array.Results + index * Marshal.SizeOf(typeof(SENNA_RESULT)));
                SENNA_RESULT senna = (SENNA_RESULT)Marshal.PtrToStructure(offset, typeof(SENNA_RESULT));
            }
        }

我希望你明白这只是想法。确保代码正常工作,然后对其进行改进以使其更易于使用。我说的是用string 替换IntPtr

【讨论】:

    猜你喜欢
    • 2013-05-12
    • 2011-02-02
    • 1970-01-01
    • 1970-01-01
    • 2015-11-14
    • 2012-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多