【问题标题】:C# Marshalling for C Struct and Function用于 C 结构和函数的 C# 编组
【发布时间】:2011-05-11 09:08:25
【问题描述】:

我有以下 C 标头/代码示例:


头文件


struct category_info {
 int id;
 const char *name;
 const char *description;
};


DLLEXPORT
void* xyz_categories_info(struct category_info **info, size_t *info_count);

示例 C 代码段


struct category_info *catinfo;

size_t catcount;
size_t i;
int max_name_len = 0;
void *catmem = xyz_categories_info(&catinfo, &catcount)


我想转换成 c#...

我的第一个猜测(以及它的猜测)是:

[StructLayout(LayoutKind.Sequential)]
    public struct category_info
    {
        int id;
        [MarshalAs(UnmanagedType.LPStr)]
        StringBuilder name;
        [MarshalAs(UnmanagedType.LPStr)]
        StringBuilder description;
    };

[DllImport("mydll.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr xyz_categories_info([Out]category_info cat, [Out]int catSize);

但它看起来不正确..

任何建议.. 一旦在 C# 中正确声明了上述内容.. 在 C# 中应该如何访问它

category_info catinfo;

catmem = xyz_categories_info(out catinfo, out catcount);

??????

非常感谢任何帮助。

谢谢

================================================ ===================================

更新 2

在 xyz_categories_info 中分配的内存使用这个 C 调用释放:

void xyz_categories_info_free(void *p);

下面是它在 C 中使用的一个例子......希望这能解释得更多......

    category_buffer = xyz_categories_info(&category_info, &category_count);

if( !category_buffer ) 
    {
    // Failed Log a message and exit.
    exit(1);
}

for(j=0; j<category_count; j++) 
    {
    if( category_info[j].id == 0 )
        continue;

    printf("id: %d name: '%s' description: '%s'\n",
        category_info[j].id,
        category_info[j].name,
        category_info[j].description
    );
}

xyz_categories_info_free(category_buffer);

【问题讨论】:

  • xyz_categories_info 到底是什么?查看它的原型,我可以猜测它分配了 category_info 结构数组并将指向该数组的指针及其大小放置到输出参数中。它返回什么?您的 C 代码 sn-p 不包含此信息。
  • 请发布完整的 C 代码 sn-p 显示如何使用和释放此函数返回的信息。使用低级 Marshal 函数和 IntPtr 类型,我们几乎可以编写 C 所做的所有事情,尽管在 C++/CLI 中这样做确实要好得多。

标签: c# marshalling


【解决方案1】:

此代码已编译,但未经测试。如果你懂 C,你就会明白这里发生了什么,这只是翻译成 C# 的相同 C 代码。

使用系统; 使用 System.Collections.Generic; 使用 System.Text; 使用 System.Runtime.InteropServices; 命名空间 ConsoleApplication1 { 公共结构类别信息 { 公共 int id; 公共 IntPtr 名称; 公共 IntPtr 描述; }; 课堂节目 { [DllImport("mydll.dll", CallingConvention = CallingConvention.Cdecl)] 公共静态外部 IntPtr xyz_categories_info(ref IntPtr cat, ref int catSize); [DllImport("mydll.dll", CallingConvention = CallingConvention.Cdecl)] 公共静态外部无效xyz_categories_info_free(IntPtr cat); 静态无效主要(字符串 [] 参数) { IntPtr 类别 = IntPtr.Zero; IntPtr category_buffer = IntPtr.Zero; int category_count = 0; 类别信息信息=新类别信息(); IntPtr 电流; 尝试 { category_buffer = xyz_categories_info(ref categories, ref category_count); if (category_buffer == IntPtr.Zero) { 返回; } 如果 (category_count == 0) { 返回; } for (int j = 0; j

【讨论】:

    【解决方案2】:

    这对于导入 DLL 的函数是正确的

        [DllImport("mydll.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
    public static extern IntPtr xyz_categories_info([Out]category_info cat, [Out]int catSize);
    

    但不确定OUT

    你的 C 代码

    struct category_info {
     int id;
     const char *name;
     const char *description;
    };
    

    我 bilive 应该是 C# 类

    public class category_info
    {
        public const string name {get; set};
        public const string description {get; set};
        public int id {get; set;}
    
        public category_info(int id, const string name, const string description){
            this.name = name;
            this.description = description;
            this.id = id;
        }
    }
    

    至于使用它和使用代码,我不确定你要做什么

    size_t catcount;
    size_t i;
    int max_name_len = 0;
    void *catmem = xyz_categories_info(&catinfo, &catcount)
    

    这在 C# 中我不确定,因为 size_t 必须是 C# 中的一个类,但是该类必须与 DLL 类完全匹配,否则会出现类型不匹配这是加载交叉语言的问题动态链接库

    那个 DLL 应该做什么?也许我们可以帮忙

    【讨论】:

      猜你喜欢
      • 2020-09-05
      • 2016-12-09
      • 2023-03-15
      • 1970-01-01
      • 1970-01-01
      • 2017-06-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多