C#程序调用非托管C++ DLL文件的方法 - Chase的技术博客 - 博客园

来源:百度文库 编辑:神马文学网 时间:2024/04/30 10:42:15
C++中的函数声明',1)">
1 extern "C" __declspec(dllexport) int __stdcall testfunc(char* astr,int* a);
extern ”C”
通常来说,C++编译器可能会改变函数和变量的名字,从而导致严重的链接程序问题。例如,假设使用C++编写一个DLL,当创建DLL时,Microsoft的编译器就会改变函数的名字。函数名将被设置一个前导下划线,再加上一个@符号的前缀,后随一个数字,表示作为参数传递给函数的字节数。例如,下面的函数是作为DLL的输出节中的_MyFunc@8输出的:',2)">
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++代码:
01
#include 
02 using namespace std;
03
04 extern "C"
05 {
06  _declspec(dllexport) int __stdcall testfunc(int a,float b,double c,char d)
07  {
08   cout<09   return 0;
10  }
11 }
12

2.向DLL传入字符串
C#中使用string定义字符串,将字符串对象名传给DLL。
注意:在DLL中更改字符串的值,C#中的值也会改变。
缺点:无法改变字符串的长度,建议使用第3种方法。
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(string a);
09
10     static void Main(string[] args)
11     {
12         string a="Hello World!";
13         testfunc(a);
14         Console.ReadKey();
15     }
16 }
C++代码:
01 #include
02 using namespace std;
03
04 extern "C"
05 {
06  _declspec(dllexport) int __stdcall testfunc(char* astr)
07  {
08   cout<09   *astr='A';//更改字符串的数据
10   cout<11   return 0;
12  }
13 }
3.DLL传出字符串
C#中使用StringBuilder对象创建变长数组,并设置StringBuilder的Capacity为数组最大长度。将此对象名传递给DLL,使用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(StringBuilder abuf);
09
10     static void Main(string[] args)
11     {
12         StringBuilder abuf=new StringBuilder();
13         abuf.Capacity = 100;//设置字符串最大长度
14         testfunc(abuf);
15         Console.ReadKey();
16     }
17
18 }
C++代码:
01 #include
02 using namespace std;
03
04 extern "C"
05 {
06  _declspec(dllexport) int __stdcall testfunc(char* astr)
07  {
08   *astr++='a';
09   *astr++='b';//C#中abuf随astr改变
10   *astr='\0';
11
12   return 0;
13  }
14 }
4.DLL传递结构体(需要在C#中重新定义,不推荐使用)
C#中使用StructLayout重新定义需要使用的结构体。
注意:在DLL改变结构体成员的值,C#中随之改变。
C#代码:
01 using System;
02 using System.Text;
03 using System.Runtime.InteropServices;
04
05 [StructLayout(LayoutKind.Sequential)]
06 public struct Point
07 {
08     public double x;
09     public double y;
10 }
11
12 class Program
13 {
14     [DllImport(@"E:\Projects\testdll\debug\testdll.dll")]
15     public static extern int testfunc(Point p);
16
17     static void Main(string[] args)
18     {
19         Point p;
20         p.x = 12.34;
21         p.y = 43.21;
22         testfunc(p);
23         Console.ReadKey();
24     }
25 }
C++代码:
01 #include
02 using namespace std;
03
04 struct Point
05 {
06     double x;
07     double y;
08 };
09
10 extern "C"
11 {
12  _declspec(dllexport) int __stdcall testfunc(Point p)
13  {
14   cout<15   return 0;
16  }
17 }
C#程序调用非托管C++ DLL文件的方法 - Chase的技术博客 - 博客园 [C#/C ]C#调用非托管DLL的APIs - .NET人字拖 - 博客园 C#调用DLL的方法 - 51CTO.COM C#调用C++编写的COM DLL 利用.net反射动态调用指定程序集的中的方法 - 系统架构与NET技术 - 博客园 利用.net反射动态调用指定程序集的中的方法 - 系统架构与NET技术 - 博客园 关于在C#中调用C DLL 时的参数传递 VB调用.NET DLL(一) - skila的日志 - 网易博客 C#的内存管理:堆栈、托管堆与指针 (转) - 笨蛋学习的地方 - 博客园 在C#工程中调用C++的DLL - Learning - 新言云语 在C#工程中调用C++的DLL Delphi调用C#类库 - chenghm2003 - 博客园 【C++】编写动态链接库(DLL) __stdcall_【wjxgzz的博客】 C#多线程退出程序 - longkai178的日志 - 网易博客 regsvr32 注册.dll的用法 - carywu - 51CTO技术博客 C#中常用的经典文件操作方法 - 小柯Atlas - 博客园 C#后台调用前台javascript的五种方法 C#动态调用Web服务的3种方法 C#动态调用Web服务的3种方法 Inblogit—介于托管和独立博客之间的Blogging方式?-非寒编程网 系统DLL文件或注册表受损的快速恢复 - 闲人SGM的日志 - 网易博客 C程序的运行环境 - rocky的日志 - 网易博客 SYSTEM32 下DLL文件的简单说明 赛迪网技术社区 谁有《C 高级实用程序设计》- C程序汉字显示技术 那一章的源代码 C/C / 非技术区 - CSDN社区 community.csdn.net