封送类、结构体和联合体实例
封送类
在.net framework中,类是引用类型,而结构体是值类型。对于类而言,它们只能通过com互操作来封送,并且总是作为接口封送。
当托管类传递给com时,互操作封送处理器会自动使用com代理包装该类,并将由代理生成的类接口传递到com方法调用。
例如:
// 假设有一个非托管的com接口idemointerface [comimport] [guid("...")] interface idemointerface { void dosomething(); } // 定义一个实现该接口的托管类 public class managedclass : idemointerface { public void dosomething() { console.writeline("doing something..."); } } // 在托管代码中创建并传递给非托管代码 var managedinstance = new managedclass(); // 这里假设有一个非托管函数接收idemointerface类型的参数 nativemethods.passtounmanaged(managedinstance);
这里passtounmanaged
是一个平台调用(p/invoke)定义的方法,它负责将managedclass
对象转换成com接口指针传递给非托管代码。
封送结构体
结构体作为值类型,在跨平台调用时也需要适当的封送处理。
为了确保结构体成员按照预期的方式被解释,通常会在结构体上应用structlayoutattribute
属性来指定布局方式。
考虑如下c++定义的结构体:
typedef struct _myperson { char* first; char* last; } myperson, *lp_myperson;
c#封送定义可能是这样的:
[structlayout(layoutkind.sequential, charset = charset.ansi)] public struct myperson { [marshalas(unmanagedtype.lpstr)] public string first; [marshalas(unmanagedtype.lpstr)] public string last; }
这里使用了structlayout
特性指定了顺序布局,并通过marshalas
特性指定了字符串字段如何被封送。
如果要传递此结构体到非托管代码,则可以像下面这样操作:
[dllimport("pinvokelib.dll")] static extern int teststructinstruct([in] myperson2 person2); // 构建myperson实例 var person = new myperson { first = "john", last = "doe" }; // 创建包含person指针的myperson2实例 var person2 = new myperson2 { person = marshal.alloccotaskmem(marshal.sizeof(person)), age = 30 }; // 复制person的内容到分配的非托管内存 marshal.structuretoptr(person, person2.person, false); try { // 调用非托管函数 var result = teststructinstruct(person2); } finally { // 清理非托管资源 marshal.freecotaskmem(person2.person); }
这段代码展示了如何安全地管理非托管内存,并确保正确地封送结构体给非托管函数。
封送联合体
联合体(union)允许在同一段内存空间内存储不同类型的数据成员。这意味着任何时候只有一个成员有效。
在c#中表示联合体通常涉及到使用structlayout(layoutkind.explicit)
特性以及fieldoffset
特性来精确控制成员的位置。
比如,我们有以下c++定义的联合体:
union myunion { int i; double d; };
c#封送定义可以是:
[structlayout(layoutkind.explicit)] public struct myunion { [fieldoffset(0)] public int i; [fieldoffset(0)] public double d; }
这里使用了explicit
布局模式,所有字段都从偏移量0开始,意味着它们共享相同的内存位置。
当需要传递这个联合体到非托管代码时,可以直接使用上述定义,因为.net运行时知道如何正确地封送联合体中的成员。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论