能够减肥的瑜伽视频:C#程序调用非托管C++ DLL文件的方法 - Chase的技术博客 - 博客园

来源:百度文库 编辑:九乡新闻网 时间:2024/04/25 17:07:24

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++代码:

01
class=brush:cpp>#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 }