- 1. 第二课,Extjs中Json的应用
- 2. Microsoft Enterprise Library 5.0 系列(四) Logging Application Block
- 3. C#程序调用非托管C++ DLL文件的方法
- 4. Visual Studio 2010 旗舰版免序列号安装体验
- 5. Visual Studio 2010为 C# 开发人员提供的新的IDE功能
- 6. 英文VS2010安装中文版MSDN文档方法
- 7. Debian5 dom0上跑Xen Debian5 lenny domU&Xen ubuntu10.04 Lucid domU--我爱你,飞一般的感觉
- 8. 微软一站式示例代码库 2010-05-31 新增代码示例简介
- 0
- 7
- 21
- 308
- 6892
阅读: 822 评论: 4 作者: Caizhi 发表于 2010-05-31 22:15 原文链接
08年写的一篇文章,当时项目用C#开发,但是有一些希望重用之前的C++代码,于是研究了如何在C#中调用C++的DLL。
C++中的函数声明
1 | extern "C" __declspec ( dllexport ) int __stdcall testfunc( char * astr, int * a); |
extern ”C”
通常来说,C++编译器可能会改变函数和变量的名字,从而导致严重的链接程序问题。例如,假设使用C++编写一个DLL,当创建DLL时,Microsoft的编译器就会改变函数的名字。函数名将被设置一个前导下划线,再加上一个@符号的前缀,后随一个数字,表示作为参数传递给函数的字节数。例如,下面的函数是作为DLL的输出节中的_MyFunc@8输出的:
1 | __declspec ( dllexport ) LONG __stdcall MyFunc( int a, int b); |
如果用另一个供应商的工具创建了一个可执行模块,它将设法链接到一个名叫MyFunc的函数,该函数在Microsoft编译器已有的DLL中并不存在,因此链接将失败。
使用extern “C”关键字可以使编译器按照C语言的方式编译DLL文件,即编译时不改变函数名。
__declspec(dllexport)
在 32 位编译器版本中,可以使用__declspec(dllexport) 关键字从DLL导出数据、函数、类或类成员函数。__declspec(dllexport) 会将导出指令添加到对象文件中,因此不需要使用.def文件。
若要导出函数,__declspec(dllexport) 关键字必须出现在调用约定关键字的左边(如果指定了关键字)。例如:
1 | __declspec ( dllexport ) void __cdecl Function1( void ); |
__stdcall
表明被调用方清理堆栈。
C#中的函数声明
1 | using System.Runtime.InteropServices; |
2 | … |
3 | |
4 | public class Program |
5 | { |
6 | [DllImport( @"E:\Projects\testdll\debug\testdll.dll" )] |
7 | public static extern int testfunc(StringBuilder abuf, ref int a); |
8 | } |
using System.Runtime.InteropServices;
System.Runtime.InteropServices 命名空间提供各种各样支持 COM interop 及平台调用服务的成员,使程序可以与非托管代码进行交互操作。
[DllImport(“dllfile path”)]
代码中DllImport关键字作用是告诉编译器入口点在哪里,并将打包函数捆绑在这个类中。在声明的时候还可以添加几个属性:
1 | [DllImport( "MyDLL.dll" , |
2 | EntryPoint= "mySum" , |
3 | CharSet=CharSet.Auto, |
4 | CallingConvention=CallingConvention.StdCall)] |
EntryPoint: 指定要调用的 DLL 入口点。默认入口点名称是托管方法的名称 。
CharSet: 控制名称重整和封送 String 参数的方式 (默认是UNICODE)
CallingConvention指示入口点的函数调用约定(默认WINAPI)
注意:必须在标记为”static”和”extern”的方法上指定”DllImport”属性。
数据传递方法
1.基本数据类型的传递
函数参数和返回值可以是C#和C++的各种基本数据类型,如int, float, double, char(注意不是char*)等。
示例:
C#代码:
01 | using System; |
02 | using System.Text; |
03 | using System.Runtime.InteropServices; |
04 | |
05 | class Program |
06 | { |
07 | [DllImport( @"E:\Projects\testdll\debug\testdll.dll" )] |
08 | public static extern int testfunc( int a, float b, double c, char d); |
09 | |
10 | static void Main( string [] args) |
11 | { |
12 | int a = 1; |
13 | float b = 12; |
14 | double c = 12.34; |
15 | char d = 'A' ; |
16 | testfunc(a,b,c,d); |
17 | Console.ReadKey(); |
18 | } |
19 | } |
C++代码:
001 | <PRE class =brush:cpp minmax_bound= "true" sizcache07219430890837806= "5" sizset= "1" >#include <IOSTREAM minmax_bound= "true" > |
002 | using namespace std; |
003 | |
004 | extern "C" |
005 | { |
006 | _declspec( dllexport ) int __stdcall testfunc( int a, float b, double c, char d) |
007 | { |
008 | cout<<A minmax_bound= "true" sizcache07219430890837806= "5" sizset= "1" ><< ", " <<B minmax_bound= "true" sizcache07219430890837806= "5" sizset= "1" ><< ", " <<C minmax_bound= "true" ><< ", " <<D minmax_bound= "true" ><<ENDL; pre < } 0; return minmax_bound= "true" > |
009 | </PRE> |
010 | <H2 minmax_bound= "true" >2.向DLL传入字符串</H2> |
011 | </A><P minmax_bound= "true" > C#中使用string定义字符串,将字符串对象名传给DLL。<BR minmax_bound= "true" > 注意:在DLL中更改字符串的值,C#中的值也会改变。<BR minmax_bound= "true" > 缺点:无法改变字符串的长度,建议使用第3种方法。<BR minmax_bound= "true" > C#代码:</P> |
012 | <PRE class =brush:csharp minmax_bound= "true" > using System; |
013 | using System.Text; |
014 | using System.Runtime.InteropServices; |
015 | |
016 | class Program |
017 | { |
018 | [DllImport(@ "E:\Projects\testdll\debug\testdll.dll" )] |
019 | public static extern int testfunc(string a); |
020 | |
021 | static void Main(string[] args) |
022 | { |
023 | string a= "Hello World!" ; |
024 | testfunc(a); |
025 | Console.ReadKey(); |
026 | } |
027 | }</PRE> |
028 | <P minmax_bound= "true" > C++代码:</P> |
029 | <PRE class =brush:cpp minmax_bound= "true" sizcache07219430890837806= "5" sizset= "1" >#include <IOSTREAM minmax_bound= "true" > |
030 | using namespace std; |
031 | |
032 | extern "C" |
033 | { |
034 | _declspec( dllexport ) int __stdcall testfunc( char * astr) |
035 | { |
036 | cout<<ASTR minmax_bound= "true" ><<ENDL; cout<<astr 更改字符串的数据 ; *astr= "A" minmax_bound= "true" ><<ENDL; pre < } 0; return minmax_bound= "true" > |
037 | <H3 minmax_bound= "true" >3.DLL传出字符串</H3> |
038 | <P minmax_bound= "true" > C#中使用StringBuilder对象创建变长数组,并设置StringBuilder的Capacity为数组最大长度。将此对象名传递给DLL,使用 char *接收。<BR minmax_bound= "true" > C#代码:</P> |
039 | <PRE class =brush:csharp minmax_bound= "true" > using System; |
040 | using System.Text; |
041 | using System.Runtime.InteropServices; |
042 | |
043 | class Program |
044 | { |
045 | [DllImport(@ "E:\Projects\testdll\debug\testdll.dll" )] |
046 | public static extern int testfunc(StringBuilder abuf); |
047 | |
048 | static void Main(string[] args) |
049 | { |
050 | StringBuilder abuf= new StringBuilder(); |
051 | abuf.Capacity = 100; //设置字符串最大长度 |
052 | testfunc(abuf); |
053 | Console.ReadKey(); |
054 | } |
055 | |
056 | }</PRE> |
057 | <P minmax_bound= "true" > C++代码:</P> |
058 | <PRE class =brush:cpp minmax_bound= "true" >#include <IOSTREAM minmax_bound= "true" > |
059 | using namespace std; |
060 | |
061 | extern "C" |
062 | { |
063 | _declspec( dllexport ) int __stdcall testfunc( char * astr) |
064 | { |
065 | *astr++= 'a' ; |
066 | *astr++= 'b' ; //C#中abuf随astr改变 |
067 | *astr= '\0' ; |
068 | |
069 | return 0; |
070 | } |
071 | } |
072 | |
073 | |
074 | </PRE> |
075 | <H3 minmax_bound= "true" >4.DLL传递结构体(需要在C#中重新定义,不推荐使用)</H3> |
076 | <P minmax_bound= "true" > C#中使用StructLayout重新定义需要使用的结构体。<BR minmax_bound= "true" > 注意:在DLL改变结构体成员的值,C#中随之改变。<BR minmax_bound= "true" > C#代码:</P> |
077 | <PRE class =brush:csharp minmax_bound= "true" > using System; |
078 | using System.Text; |
079 | using System.Runtime.InteropServices; |
080 | |
081 | [StructLayout(LayoutKind.Sequential)] |
082 | public struct Point |
083 | { |
084 | public double x; |
085 | public double y; |
086 | } |
087 | |
088 | class Program |
089 | { |
090 | [DllImport(@ "E:\Projects\testdll\debug\testdll.dll" )] |
091 | public static extern int testfunc(Point p); |
092 | |
093 | static void Main(string[] args) |
094 | { |
095 | Point p; |
096 | p.x = 12.34; |
097 | p.y = 43.21; |
098 | testfunc(p); |
099 | Console.ReadKey(); |
100 | } |
101 | } |
102 | |
103 | |
104 | </PRE> |
105 | <P minmax_bound= "true" >C++代码:</P> |
106 | <PRE class =brush:cpp minmax_bound= "true" sizcache07219430890837806= "5" sizset= "1" >#include <IOSTREAM minmax_bound= "true" > |
107 | using namespace std; |
108 | |
109 | struct Point |
110 | { |
111 | double x; |
112 | double y; |
113 | }; |
114 | |
115 | extern "C" |
116 | { |
117 | _declspec( dllexport ) int __stdcall testfunc(Point p) |
118 | { |
119 | cout<<P.X minmax_bound= "true" ><< ", " <<P.Y minmax_bound= "true" ><<ENDL; pre < } 0; return minmax_bound= "true" ><IMG style= "WIDTH: 1px; HEIGHT: 1px; maxWidth: 640px; minmaxWidth: 1px; minmaxHeight: 1px" height=1 alt= "" src= "http://www.cnblogs.com/Chase/aggbug/1748596.html?type=1" width=1 minmax_bound= "true" ><P minmax_bound= "true" sizcache07219430890837806= "3" sizset= "44" >评论: 4 <A href= "http://www.cnblogs.com/Chase/archive/2010/05/31/1748596.html#pagedcomment" target=_blank minmax_bound= "true" >查看评论</A> <A href= "http://www.cnblogs.com/Chase/archive/2010/05/31/1748596.html#commentform" target=_blank minmax_bound= "true" >发表评论</A></P><P minmax_bound= "true" sizcache07219430890837806= "3" sizset= "46" ><A href= "http://job.cnblogs.com/offer/7427/" target=_blank minmax_bound= "true" >沪江网招聘ASP.NET开发工程师</A></P><HR minmax_bound= "true" ><P minmax_bound= "true" sizcache07219430890837806= "3" sizset= "47" >最新新闻:<BR minmax_bound= "true" >· <A href= "http://news.cnblogs.com/n/65438/" target=_blank minmax_bound= "true" >当微博连通大屏幕</A><SPAN style= "COLOR: gray" minmax_bound= "true" >(2010-06-01 12:42)</SPAN><BR minmax_bound= "true" >· <A href= "http://news.cnblogs.com/n/65437/" target=_blank minmax_bound= "true" >从1.0到2.2 细数Android系统18个月历程</A><SPAN style= "COLOR: gray" minmax_bound= "true" >(2010-06-01 12:07)</SPAN><BR minmax_bound= "true" >· <A href= "http://news.cnblogs.com/n/65436/" target=_blank minmax_bound= "true" >只因有你 回眸Qzone五年成长历程</A><SPAN style= "COLOR: gray" minmax_bound= "true" >(2010-06-01 12:04)</SPAN><BR minmax_bound= "true" >· <A href= "http://news.cnblogs.com/n/65435/" target=_blank minmax_bound= "true" >谷歌手机Adsense冻结开发者账户遭质疑</A><SPAN style= "COLOR: gray" minmax_bound= "true" >(2010-06-01 11:58)</SPAN><BR minmax_bound= "true" >· <A href= "http://news.cnblogs.com/n/65434/" target=_blank minmax_bound= "true" >Chrome推送网页至手机功能视频展示</A><SPAN style= "COLOR: gray" minmax_bound= "true" >(2010-06-01 11:55)</SPAN><BR minmax_bound= "true" ></P><P minmax_bound= "true" sizcache07219430890837806= "3" sizset= "52" >编辑推荐:<A href= "http://www.cnblogs.com/topic/51/" target=_blank minmax_bound= "true" >关于Java与.NET的讨论</A><BR minmax_bound= "true" ></P><P minmax_bound= "true" sizcache07219430890837806= "3" sizset= "53" >网站导航:<A href= "http://www.cnblogs.com" target=_blank minmax_bound= "true" >博客园首页</A> <A href= "http://home.cnblogs.com/" target=_blank minmax_bound= "true" >个人主页</A> <A href= "http://news.cnblogs.com" target=_blank minmax_bound= "true" >新闻</A> <A href= "http://home.cnblogs.com/ing/" target=_blank minmax_bound= "true" >闪存</A> <A href= "http://home.cnblogs.com/group/" target=_blank minmax_bound= "true" >小组</A> <A href= "http://space.cnblogs.com/q/" target=_blank minmax_bound= "true" >博问</A> <A href= "http://space.cnblogs.com" target=_blank minmax_bound= "true" >社区</A> <A href= "http://kb.cnblogs.com" target=_blank minmax_bound= "true" >知识库</A></P></PRE></PRE> |
共有 0 条网友评论
尚无网友评论
- 2010/10/01 C#程序调用非托管C DLL文件的方法...
- 2011/06/30 android intent隐式调用之一个应用程...
- 2010/10/01 [CLI/C++].NET托管代码和非托管代码...
- 2010/09/28 动态装载、调用DLL中的非托管函数
- 2011/10/01 程序员技术练级攻略