NET互操作 -
更新时间:2023-10-07 00:21:01 阅读量: 综合文库 文档下载
- 互联互通互操作推荐度:
- 相关推荐
NET互操作(一) ——平台调用
前言:由于历史原因,.NET出现之前,开发人员已经编写了大量经历严格测试的非托管代码。它们以C库函数、C++类库已经COM组件的形式存在于应用程序和框架之中。但是,由于在非托管和托管对象模型之间,数据类型、方法签名和错误处理机制存在很大差异,从而是两种编程模型之间大门互用和移植便得很复杂。
因此,在相当长的时间内,开发人员(尤其是PC软件开发人员),必须面对.NET与非托管代码长期共存的局面。在很多情况下,重用已有的非托管代码成了最有效、可行的解决方案。
总论:NET提供3类主要互操作技术:
? 平台调用技术(P/Invoke): 主要用于处理在托管代码中调用C库函数及Win32 API函数等
非托管函数的情形。
? C++ Interop: 适用于在托管代码与C++类库、核心算法库之间进行高效、灵活的互操作过
程。一方面托管代码可以通过包装类机制使用C++类库,另一方面非托管代码可以通 过包装模板机制使用托管对象。
? COM Interop:该技术用于处理托管代码与COM之间的交互过程。托管代码通过运行库
可调用包装(RCW)使用非托管COM组件。反过来,非托管COM客 户端可以通过COM可调用包装(CCW)使用托管程序集。
托管环境平台调用技术P/InvokeC++ Interop托管包装类非托管环境C库函数Win32 API.NET应用程序C++类库核心算法库COM InteropRCW/CCWCOM组件
图1:NET提供3类主要互操作技术
由于不同的非托管对象,其设计和运行机制等存在很多差异。因此,托管代码与这些非托管对象进行交互操作时,在数据类型处理、错误处理机制、创建和销毁对象 的规则以及互操作方法上,都需要根据不同的情况,分别进行不同的处理。
平台调用
一、 基础知识
平台调用技术(P/Invoke): 主要用于处理在托管代码中调用C/C++库函数及Win32 API函数等非托管函数的情形 一、基本要素
一个简单例子: C++声明:
extern \实现:
int Multiply(int factorA, int factorB) {
return factorA * factorB; }
托管代码(C#)调用此非托管声明: class Invoker {
//声明非托管函数
[DllImport(\ static extern int Multiply(int factorA, int factorB); }
总结: (声明托管函数) 1.函数声明:
extern修饰符和static修饰符 2.DllImport属性 (常用)
指定动态库:指明平台要调用的dll名称,此项不可缺少。 指定入口点:EntryPoint 字段按名称或序号指定 DLL 函数,可以使用与原dll中不同名称,不填此项,默认为跟原函数名称一致。
指定字符集:CharSet 字段控制字符串封送处理并确定平台调用在 DLL 中查找函数名的方式。有窄版本 (ANSI) 和宽版本 (Unicode)。MSDN如下说明:
成员名称 Ansi Auto
说明
以多字节字符串的形式封送字符串。
针对目标操作系统适当地自动封送字符串。在 Windows NT、Windows 2000、Windows XP 和 Windows Server 2003 系列上默认值为 Unicode;在 Windows 98 和 Windows Me 上默认值为 Ansi。尽管公共语言运行库默认值为 Auto,使用语言可重写此默认值。例如,默认情况下,C# 将所有方法和类型都标记为 Ansi。
此值已过时,它与 CharSet.Ansi 具有相同的行为。
None
Unicode 以 Unicode 2 字节字符形式封送字符串。
指定调用约定:CallingConvention字 段指定调用在非托管代码中实现的方法所需的调用约定。动态链接库导出的一般有两种调用协议,__stdcall和_cdecl。__cdecl是 C/C++和MFC程序默认使用的调用约定:采用__cdecl约定时,函数参数按照从右到左的顺序入栈,并且由调用函数者把参数弹出栈以清理堆栈。因 此,实现可变参数的函数只能使用该调用约定。
__stdcall调用约定用于调用Win32 API函数。采用__stdcal约定时,函数参数按照从右 到左的顺序入栈,被调用的函数在返回前清理传送参数的栈,函数参数个数固定。MSDN如下说明:
成员名称 Cdecl
说明
调用方清理堆栈。这使您能够调用具有 varargs 的函数(如 Printf),使之可用于接受可变数目的参数的方法。
FastCall 不支持此调用约定。
StdCall 被调用方清理堆栈。这是使用平台 invoke 调用非托管函数的默认约定。 ThisCall 第一个参数是 this 指针,它存储在寄存器 ECX 中。其他参数被推送到堆栈
上。此调用约定用于对从非托管 DLL 导出的类调用方法。 Winapi
此成员实际上不是调用约定,而是使用了默认平台调用约定。例如,在 Windows 上默认为 StdCall,在 Windows CE.NET 上默认为 Cdecl。
3、注意事项:
参 数个数、顺序、类型必须保持“等价”一致,函数名称和参数名称可以不一致。
二、 参数封送:字符串
可以说新手使用P-INVOKE最开始的头疼就是C#和C++的字符串传递,由于不同编程语言对字符串处理的机制不同,因此导致托管代码的平台调用必须对字符串进行特殊的封送处理。本节将阐述以下几个问题:
(1)、C#的string和C++的字符串首指针如何对应 (2)、字符串还有ANSI和UNICODE(宽字符串)之分 (3)、封送字符串数组
1、通过CharSet字段控制字符串封送行为: C++:
void __cdecl TestString1(char* hello);
void __cdecl TestString2(const wchar_t* str,wchar_t* outStr,int size);
MSDN上给出C/C++字符串类型与C#字符串类型的对应关系
Wtypes.h 中类型 CHAR LPSTR
非托管C/C++ char char*
托管类名 说明
用 ANSI 修饰。
System.Char
System.String 或 System.Text.StringBuilder
用 ANSI 修饰。 LPCSTR
Const char*
System.String 或 System.Text.StringBuilder
用 ANSI 修饰。 LPWSTR
wchar_t*
System.String 或 System.Text.StringBuilder
用 Unicode 修饰。 LPCWSTR
Const wchar_t*
System.String 或 System.Text.StringBuilder
用 Unicode 修饰。 C#
[DllImport(\CharSet.Ansi)] public static extern voidTestString1(string hello);
[DllImport(\CharSet.Unicode)] public static extern voidTestString2(stringstr,StringBuilder outStr,int size) 2、使用MarshalAs属性控制字符串封送行为:
CharSet字段影响的是整个函数过程的字符串封送行为,MarshalAs属性只影响其作用
的字符串参数。因此,当一个非托管函数的参数即由ANSI字符串,又有Unicode字符串时,就只能用MarshalAs属性来控制封送行为。 C++:
void __cdecl TestString3(const char* str1,const wchar_t* str2,wchar_t* outStr,int size);
MSDN给出MarshalAs属性控制字符串封送行为:
枚举类型 非托管格式说明
UnmanagedType.AnsiBStr 长度前缀为双字节的 Unicode字符的COM样式的BSTR。。 UnmanagedType.LPStr 单字节、null空终止的 ANSI 字符数组的指针。(默认值)
UnmanagedType.LPTStr null空终止与平台相关的字符数组的指针。 UnmanagedType.LPWStr null空终止与Unicode的字符数组的指针。 UnmanagedType.TBStr 一个有长度前缀的与平台相关的 COM样式的BSTR。
需要注意的是:此表只适用于string类型,对于StringBuilder而言,能够允许的选项只有:LPStr、LPTStr、LPWStr。 C#:
[DllImport(\public static extern voidTestString3( [MarshalAs(UnmanagedType.LPStr)]string str1, [MarshalAs(UnmanagedType.LPWStr)]string str2,
[MarshalAs(UnmanagedType.LPWStr)]stringoutStr,int size); 3、封送作为返回值的字符串: C++:
char* __cdecl GetStringReturn1(); wchar_t*__cdecl GetStringReturn2(); 这里,有两种声明方法: (1)、直接用string类型对应:
[DllImport(\CharSet.Ansi)] public static externstringGetStringReturn1();
[DllImport(\EntryPoint = \CharSet = CharSet.Unicode)] public static externstring GetStringReturn2(); (2)、用IntPtr指针对应:
[DllImport(\CharSet.Ansi)] public static externIntPtrGetStringReturn1();
[DllImport(\EntryPoint = \CharSet = CharSet.Unicode)]
正在阅读:
NET互操作 -10-07
完整的锡伯族姓氏对照表04-21
安全系统工程课程设计12-18
我家乡的杨絮作文500字07-16
网络安全知识测试题10-12
捕捉文本读写契合点,设计写作训练09-13
武广高铁武衡段沿线建设考察报告05-14
EdgeCAM进入加工模式的方法10-01
小学语文教案的创意设计与编写05-22
与身外之物保持距离11-03
- 多层物业服务方案
- (审判实务)习惯法与少数民族地区民间纠纷解决问题(孙 潋)
- 人教版新课标六年级下册语文全册教案
- 词语打卡
- photoshop实习报告
- 钢结构设计原理综合测试2
- 2014年期末练习题
- 高中数学中的逆向思维解题方法探讨
- 名师原创 全国通用2014-2015学年高二寒假作业 政治(一)Word版
- 北航《建筑结构检测鉴定与加固》在线作业三
- XX县卫生监督所工程建设项目可行性研究报告
- 小学四年级观察作文经典评语
- 浅谈110KV变电站电气一次设计-程泉焱(1)
- 安全员考试题库
- 国家电网公司变电运维管理规定(试行)
- 义务教育课程标准稿征求意见提纲
- 教学秘书面试技巧
- 钢结构工程施工组织设计
- 水利工程概论论文
- 09届九年级数学第四次模拟试卷
- 操作
- NET
- 木工教案
- 环境保护、水土保持应急预案
- 果酒和果醋的制作知识清单及小练习
- 实验一 分治与递归算法的应用
- 基于ASPNET的校园二手拍卖系统的开发
- 压力表使用规范() - 图文
- 第八章 相关与回归分析习题
- 生活垃圾处理行业深度分析与“十三五”战略规划研究2018-2023年(目录) - 图文
- 产业园区赴外招商指南
- 1500V直流柜进线柜
- 实验三 Java面向对象高级编程
- 08-32捣固车常用故障处理分析手册
- 数理统计试题
- 环境监测复习资料
- 郑州福友遥控车位锁合同书
- 保阜高速公路保定至阜平(冀晋界)段路基、桥涵工程施工组织设计
- 大型超市购物篮问题
- STM32全面学习总结 - 图文
- 国家知识产权局办公室关于开展2014年知识产权分析评议服务示范机构培育工作的通知全文-国家规范性文件
- 深度分析中国铁建沙特麦加轻轨项目41亿巨亏原因