用于 C 结构和函数的 C# 编组

Posted

技术标签:

【中文标题】用于 C 结构和函数的 C# 编组【英文标题】:C# Marshalling for C Struct and Function 【发布时间】: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 中这样做确实要好得多。 【参考方案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 应该做什么?也许我们可以帮忙

【讨论】:

以上是关于用于 C 结构和函数的 C# 编组的主要内容,如果未能解决你的问题,请参考以下文章

如何编组包含未知大小的 int 数组的结构?

创建要在 C# 中编组的 C++ Dll 的最佳实践 [关闭]

将 C++ 类编组为结构

C++ 到 C# 回调结构编组

通过非默认 AppDomain 中的 C# 函数调用编组 C++ 指针接口

C# 编组、不平衡堆栈和正确获取 PInvoke 签名