之前说到了如何从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. lambda表达式查询经验:IN 和groupby的使用

    lambda In的用法: lambda表达式查询没有IN这个方法,可以变通一下,in查询的数组是否包含在映射对象里面的集合里: 如下代码: var departmentIDs = input.Dep ...

  2. Java Web(七) JSTL标签库

    在之前我们学过在JSP页面上为了不使用脚本,所以我们有了JSP内置的行为.行为只能提供一小部分的功能,大多数的时候还是会用java脚本,接着就使用了EL表达式,基本上EL表达式看似能满足我们的要求,它 ...

  3. 学习git的使用--在当地的简单命令--01

    <----------git安装完成后操作-----------------> git config --global user.name "scy"添加用户名git ...

  4. HTML5拖放加入购物车

    H5拖放事件巩固实例: 1.简单布局一下,商品信息放入一个ul中:div为购物车,后续会创建元素 <ul> <li draggable="true"> &l ...

  5. Ichars制作数据统计图

    数据统计图基本上每个网站的后台都要做,不仅要做还要的非常详细才行,这样才能全面的具体的了解网站数据.之前用的jfreechart没有iChartjs用着方便,也没有iChartjs的效果炫,所以果断弃 ...

  6. Oracle Jdbc驱动下载及安装本地maven仓库

    由于二进制许可 binary license的限制,oracle jdbc驱动不能通过共有仓库来获取,所以你可以下载下来添加到自己的本地仓库或私有仓库中. 添加到本地仓库步骤如下: 下载Oracle ...

  7. [HDOJ2572]终曲

    Problem Description 最后的挑战终于到了!站在yifenfei和MM面前的只剩下邪恶的大魔王lemon一人了!战胜他,yifenfei就能顺利救出MM.Yifenfei和魔王lemo ...

  8. python3.4 安装 scrapy 报错 VS2010

    安装scrapy框架报错是常见问题 还好,本人只碰到其中一个bug,以下是此次安装经验 环境 py3.4 windows7 64位 安装有VS2010 pip包管理(pycharm) 报错信息 安装l ...

  9. 1179: [Apio2009]Atm

    1179: [Apio2009]Atm Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 1629  Solved: 615[Submit][Status ...

  10. Docker基础入门及示例

    Docker近几年的发展可谓一日千里,特别从是2013年随着一个基于LXC的高级容器引擎开源,到现在,其在linux和windows上都有了很好的支持,并且已经有很多公司将docker用于实际的生产环 ...