用于 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# 编组的主要内容,如果未能解决你的问题,请参考以下文章
创建要在 C# 中编组的 C++ Dll 的最佳实践 [关闭]