当前位置: 首页 > news >正文

C#封送类

封送类(Marshaling classes)在.NET框架中扮演着至关重要的角色,尤其是在托管代码与非托管代码之间进行数据交换时。封送过程涉及到将托管环境中的对象转换为非托管环境中可以理解的形式,并且反之亦然。这一过程确保了两种不同类型的代码能够有效地通信和协作。

以下是封送类、结构和联合

类型描述示例
按值传递类将具有整数成员的类传递为In/Out参数,与托管的情形相似。SysTime 示例
按值传递结构将结构作为In参数传递。结构示例
按引用传递结构将结构作为In/Out参数传递。OSInfo 示例
具有内嵌结构(平展)的结构传递非托管函数中表示内嵌结构的结构的类。此结构再托管的原型中将平展为一个的结构。FindFile 示例
具有指向另一结构的指针的结构将包含指向第二结构的指针的结构作为成员传递。结构示例
按值传递具有整数的结构数组将仅包含整数的结构数组作为In/Out参数进行传递。可以更改数组的成员。数组示例
按引用传递具有整数和字符串的结构数组将包含整数和字符串的结构数组作为Out参数参数。被调用的函数为数组分配内存。OutArrayOfStructs 示例
具有值类型的联合传递具有值类型(整数和双精度)的联合。联合示例
具有混合类型的联合传递具有混合类型(整数和字符串)的联合。联合示例
具有特定平台的布局的结构使用本机打包的传递类型。平台示例
结构中的null值传递空引用(Visual Basic中为Nothing),而不传递对值类型的引用。HandleRef 示例

类的封送

当涉及到类的封送时,需要注意的是,在.NET Framework中,类是引用类型,而结构体是值类型。这意味着类实例通过引用传递,而结构体则是通过复制整个结构体的内容来传递。对于类而言,默认情况下它们只能通过COM互操作来进行封送,并总是作为接口被封送。

对于类而言,默认情况下它们只能通过COM互操作来进行封送,并总是作为接口被封送。具体来说:

  • 向COM传递类:当托管类传递给COM时,互操作封送处理程序会自动使用COM代理包装该类,并将由代理生成的类接口传递到COM方法调用。代理负责委托对类接口的所有调用返回给托管对象,并公开其他不由类显式实现的接口,如IUnknownIDispatch

  • 向.NET代码传递类:当接口传递回托管代码时,互操作封送处理程序负责用适当的包装器包装接口,并将这个包装器传递给托管方法。每个COM对象实例都有一个唯一的包装器,无论该对象实现了多少个接口。例如,如果一个COM对象实现了五个不同的接口,则只有一个包装器实例存在,它公开所有这五个接口。

封送类的默认行为

对于某些特定的.NET类型,如数组、布尔值、字符、委托、类、对象、字符串和结构等,默认的封送规则已经定义好了。这些规则决定了数据如何在托管和非托管内存之间传递。例如,.NET数组通常会被封送成指向数组元素本机表示形式的指针;而对于字符串,默认情况下会根据上下文选择合适的编码方式(如UTF-16, ANSI, UTF-8等),并且可以通过设置MarshalAs属性来指定更具体的封送选项。

自定义封送

尽管有默认的封送规则,但在很多实际应用场景下,开发者可能需要更加精细地控制封送过程。这时就可以利用MarshalAsAttribute属性来指定参数或字段应该怎样被封送。例如,如果你想要将字符串作为以null结尾的UTF-8字符串发送,你可以这样做:

[LibraryImport("somenativelibrary.dll")]
static extern int MethodA([MarshalAs(UnmanagedType.LPStr)] string parameter);
//或者
[LibraryImport("somenativelibrary.dll", StringMarshalling = StringMarshalling.Utf8)]
static extern int MethodB(string parameter);

示例:封送具有嵌套结构的类

假设我们有一个C++ DLL导出了一个名为MYPERSON3的结构体,其中包含了另一个结构体MYPERSON以及一个整数成员age。要在C#中正确地封送这样的结构体,我们可以定义相应的托管结构如下:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct MyPerson
{public string first;public string last;
}[StructLayout(LayoutKind.Sequential)]
public struct MyPerson3
{public MyPerson person;public int age;
}

接着,我们需要为非托管函数创建一个托管原型,并确保正确地处理结构体的封送。如果我们知道函数接受的是按值传递的MYPERSON3结构体,那么我们的C#声明可能会像这样:

private static class NativeMethods
{[DllImport("..\\LIB\\PinvokeLib.dll")]public static extern void TestStructInStruct3(MyPerson3 person3);
}

在这个例子中,MyPerson3结构体会作为一个整体被复制到非托管堆栈上,然后传递给非托管函数。如果函数修改了结构体的内容,那么这些更改不会反映回原始的托管副本,除非我们将参数标记为refout,从而允许双向的数据流动。

总结:

封送类涉及到了解托管与非托管边界上的数据传输机制,包括但不限于上述提到的各种细节。正确地配置和管理这些细节可以帮助避免潜在的问题,确保应用程序之间的互操作性顺畅无误。

http://www.lryc.cn/news/512898.html

相关文章:

  • 2024年度学习总结
  • 我的博客年度之旅:感恩、成长与展望
  • undefined symbol: __nvJitLinkComplete_12_4, version libnvJitLink.so.12
  • 【OTA】论文笔记--《智能网联汽车整车OTA功能设计研究》智能网联汽车OTA系统设计分析报告
  • c#String和StringBuilder
  • 【Linux】HTTP协议
  • 计算机网络 (14)数字传输系统
  • 《向量数据库指南》——Milvus Cloud 2.5:Sparse-BM25引领全文检索新时代
  • Unity3D 网络框架设计详解
  • 网络渗透测试实验四:CTF实践
  • Wend看源码-Java-Collections 工具集学习
  • [JAVA]MyLogger
  • 玩转OCR | 腾讯云智能结构化OCR初次体验
  • 记一次 dockerfile 的循环依赖错误
  • Trimble天宝X9三维扫描仪为建筑外墙检测提供了全新的解决方案【沪敖3D】
  • 【MySQL】深度学习数据库开发技术:使用CC++语言访问数据库
  • LabVIEW化工实验室设备故障实时监测
  • 单例模式懒汉式、饿汉式(线程安全)
  • Cursor登录按钮点击没反应
  • 论文实现:Reactive Nonholonomic Trajectory Generation via Parametric Optimal Control
  • 基于单片机中药存放环境监测系统的实现
  • 九垠赢+商业管理系统 Common.ashx 文件上传致RCE漏洞复现
  • 速盾:服务器CDN加速解析的好处有哪些呢?
  • C++ 设计模式:备忘录模式(Memento Pattern)
  • Android 系统 Activity 系统层深度定制的方法、常见问题以及解决办法
  • PDF怎么压缩得又小又清晰?5种PDF压缩方法
  • YK人工智能(三)——万字长文学会torch深度学习
  • 关于CISP报名费用详情
  • vim 按下esc后取消高亮
  • SwiftUI:多语言实现富文本插值