之前说到了如何从C函数声明通过简单的查找替换生成一份C#的静态引用声明(C#与非托管——初体验),因为只是简单说明,所以全部采用的是基础类型匹配和自动封送。自动封送虽然能省去我们不少编码时间,但如果不理解自动封送背后的实际行为,那就如同看魔术师的黑盒子,知其然不知其所以然。而且,自动封送也不是永远有效的万能药,因此这里记录一下封送相关的理解。

非基础类型在C#与Native代码交互时需要进行封送处理,一般的封送处理方式有内存拷贝、固定内存地址,总结如下:

  1. 针对string,可以使用Marshal.StringToHGlobalAnsi、Marshal.StringToHGlobalAuto、Marshal.StringToHGlobalUni把string封送到非托管函数,之后需要调用Marshal.FreeHGlobal释放内存;或者使用Marshal.PtrToStringAnsi、Marshal.PtrToStringAuto、Marshal.PtrToStringUni从非托管函数里面取出string。

  2. 针对byte[](或基础类型的数组),可以使用Marshal.Copy从byte[]拷贝封送到非托管函数或者从非托管函数拷贝封送到byte[]。此外从byte[]封送到非托管函数还可以采取固定内存直接传送byte[]的原始地址(省去了申请内存和拷贝的开销,速度更快),方法是使用GCHandle并指定GCHandleType.Pinned类型。

  3. 针对委托,可以使用Marshal.GetFunctionPointerForDelegate从delegate封送到非托管函数,或者使用Marshal.GetDelegateForFunctionPointer从非托管函数里面取出。和byte[]一样,在封送到非托管函数时需要确保GC不要回收委托(需要保持引用但不需要Pinned)。

  4. 针对结构体,可以在C#中按一样的顺序和对应的数据类型声明一个同样的struct(只能使用基础类型和固定长度的数组),并且标记StructLayout的LayoutKind.Sequential属性,然后使用Marshal.StructureToPtr和Marshal.PtrToStructure进行封送。

  5. C#的对象不能在Native中进行处理,只能保存以待之后再传回给C#调用,保存的方式为C#用GCHandle引用对象,然后把GCHandle转成IntPtr,传给Native作为指针保存。

当C#声明的extern函数返回类型和参数类型中有托管类型时(如string、byte[]、委托等),就会进行自动封送处理,因此可以省写大部分的封送代码。不过有几种情况还是需要手动进行封送的,如:

  1. string的编码是utf8之类的非ansi非utf16编码,则必须手动进行封送同时转换编码。
  2. 委托转换成函数指针的操作比较耗时,如果有频繁的对同一委托进行封送调用,则预存转换后的结果能够很显著的提升性能。

[原]C#与非托管——封送和自动封送的更多相关文章

  1. [原]C#与非托管——初体验

    P/Invokes初看起来非常简单,利用DllImport进行extern函数的声明,程序就可以在调用extern函数的时候自动查询调用到对应的非托管函数,有些类似Java的native函数,但更为简 ...

  2. [原]C#与非托管——动机

    Unity3D采用C#作为脚本开发语言,本来是可以直接提供代码局部更新机制的,可惜Mono和Unity3D迫于苹果的压力,在iOS上采用AOT模式运行,断绝了代码局部更新的路(任何一个具有很高知名度的 ...

  3. (转)C#调用非托管Win 32 DLL

    转载学习收藏,原文地址http://www.cnblogs.com/mywebname/articles/2291876.html 背景 在项目过程中,有时候你需要调用非C#编写的DLL文件,尤其在使 ...

  4. VB.NET 内存指针和非托管内存的应用

    介绍 Visual Basic 从来不像在C或C++里一样灵活的操纵指针和原始内存.然而利用.NET框架中的structures 和 classes,可以做许多类似的事情.它们包括 IntPtr,   ...

  5. C#引用非托管.dll

    C#里调用非托管的Dll 今天花了一些精力来调查了一下C#里调用非托管的Dll,C#里调用非托管的Dll要使用P/Invoke平台调用技术, 这里先简单介绍一下P/Invoke平台调用技术.    由 ...

  6. 在VS2010上使用C#调用非托管C++生成的DLL文件

    背景 在项目过程中,有时候你需要调用非C#编写的DLL文件,尤其在使用一些第三方通讯组件的时候,通过C#来开发应用软件时,就需要利用DllImport特性进行方法调用.本篇文章将引导你快速理解这个调用 ...

  7. [转]C# 之DLL调用(托管与非托管)

    每种编程语言调用DLL的方法都不尽相同,在此只对用C#调用DLL的方法进行介绍.首先,您需要了解什么是托管,什么是非托管.一般可以认为:非托管代码主要是基于win 32平台开发的DLL,activeX ...

  8. 非托管C++互操作

    .NET简谈互操作(一:开篇介绍) .NET简谈互操作(二:先睹为快) .NET简谈互操作(三:基础知识之DllImport特性) .NET简谈互操作(四:基础知识之Dispose非托管内存) .NE ...

  9. 托管DLL和非托管DLL的区别

    首先解释一下,托管DLL和非托管DLL的区别.狭义解释讲,托管DLL就在Dotnet环境生成的DLL文件.非托管DLL不是在Dotnet环 境生成的DLL文件. 托管DLL文件,可以在Dotnet环境 ...

随机推荐

  1. UML类图中的关系和表示方法

    类图是用来描述程序中的类以及它们之间的关系的,使用类图可以帮助我们简化对系统的理解.在UML类图中比较常见的关系有六种,它们分别是:依赖.关联.聚合.组合.泛化.实现,这六种关系中类之间的紧密程度是依 ...

  2. CSS3 3D的总结(初学者易懂)

    CSS3 3D案例的总结 如果要说是3D的基础概念,首先我就来说一说rotateX().rotateY().rotateZ()这几个属性 rotateX():对应的是3D模型中的X轴上的旋转,传入的参 ...

  3. java学习之路

    先来说一说我和it之间的不解之缘.准确来说,我接触it是从大二是我买的第一个手机开始的(国产的,展讯平台,能够运行mrp虚拟机),那时候还没有智能手机,或者说还不够普及,总之就是买不起.一次偶然的机会 ...

  4. SaberRD之交流分析

    交流分析(AC Analysis)也叫做小信号(Small-Signal)分析,也即分析电路的小信号频率响应,更严谨的定义是:分析工作在直流偏置电压下的非线性电路对于一定频率范围内的输入小信号的系统响 ...

  5. 学习笔记——Java包装类

    由于Java不能定义基本类型的对象,所以通过包装类提供了各种可用方法的封装. 这一部分的知识,需要能够通过查看Integer.Boolean.Byte.Character.Double.Number类 ...

  6. Asp.net mvc 知多少(九)

    本系列主要翻译自<ASP.NET MVC Interview Questions and Answers >- By Shailendra Chauhan,想看英文原版的可访问http:/ ...

  7. FaceNet---深度学习与人脸识别的二次结合

    今天我给大家带来一篇来自谷歌的文章,众所周知,谷歌是全世界最有情怀,最讲究技术的公司,比我们天朝的莆田广告商良心多了.还有就是前段时间的最强大脑,莆田广告商的那个小机器,也就忽悠忽悠行外人了,懂的人深 ...

  8. 【2017-02-24】循环嵌套、跳转语句、异常语句、迭代穷举、while

    一.循环嵌套 1.格式 for() { for() { } } 2.执行顺序 先执行外边循环进到循环体发现里面的循环,开始执行里面的循环.等到里面的循环执行完毕,再执行外边的循环. 在外面循环第一次, ...

  9. SQL Server-聚焦NOLOCK、UPDLOCK、HOLDLOCK、READPAST你弄懂多少?(三十四)

    前言 时间流逝比较快,博主也在快马加鞭学习SQL Server,下班回来再晚也不忘记更新下博客,时间挤挤总会有的,现在的努力求的是未来所谓的安稳,每学一门为的是深度而不是广度,求的是知识自成体系而不是 ...

  10. 推荐一本书:清华出版的《Modbus软件开发实战指南》

    前言: 最近在研究Modbus开发,如果只是简单的了解了一些modbus基础知识,但是不够系统和全面. 其实,modbus虽然比较简单,但是如果不注意有很多坑,特别是寄存器的位数,大小端处理,浮点数, ...