C#程序調用非託管C DLL文件的方法

C++中的函數聲明

1 extern "C" __declspec(dllexport) int __stdcall testfunc(char* astr,int* a);

  

extern 」C」html

一般來講,C++編譯器可能會改變函數和變量的名字,從而致使嚴重的連接程序問題。例如,假設使用C++編寫一個DLL,當建立DLL 時,Microsoft的編譯器就會改變函數的名字。函數名將被設置一個前導下劃線,再加上一個@符號的前綴,後隨一個數字,表示做爲參數傳遞給函數的字 節數。例如,下面的函數是做爲DLL的輸出節中的_MyFunc@8輸出的:ios

1 __declspec(dllexport) LONG __stdcall MyFunc(int a, int b);

若是用另外一個供應商的工具建立了一個可執行模塊,它將設法連接到一個名叫MyFunc的函數,該函數在Microsoft編譯器已有的DLL中 並不存在,所以連接將失敗。數組

使用extern 「C」關鍵字能夠使編譯器按照C語言的方式編譯DLL文件,即編譯時不改變函數名。app

 

__declspec(dllexport)函數

在 32 位編譯器版本中,能夠使用__declspec(dllexport) 關鍵字從DLL導出數據、函數、類或類成員函數。__declspec(dllexport) 會將導出指令添加到對象文件中,所以不須要使用.def文件。工具

若要導出函數,__declspec(dllexport) 關鍵字必須出如今調用約定關鍵字的左邊(若是指定了關鍵字)。例如:ui

1 __declspec(dllexport) void __cdecl Function1(void);

 

__stdcallspa

代表被調用方清理堆棧。debug

 

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;code

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 <pre class="brush:cpp">#include <iostream>
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<<a<<", "<<b<<", "<<c<<", "<<d<<endl;
09   return 0;
10  }
11 }
12 </pre>

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 <iostream>
02 using namespace std;
03  
04 extern "C"
05 {
06  _declspec(dllexport) int __stdcall testfunc(char* astr)
07  {
08   cout<<astr<<endl;
09   *astr='A';//更改字符串的數據
10   cout<<astr<<endl;
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 <iostream>
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 <iostream>
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<<p.x<<", "<<p.y<<endl;
15   return 0;
16  }
17 }
相關文章
相關標籤/搜索