您的位置:首页 > 编程语言 > C#

C#程序调用非托管C DLL文件的方法

2010-10-01 00:00 633 查看

C++中的函数声明

viewsource

print
?

1extern"C"__declspec(dllexport)int__stdcalltestfunc(char*astr,int*a);
extern”C”

通常来说,C++编译器可能会改变函数和变量的名字,从而导致严重的链接程序问题。例如,假设使用C++编写一个DLL,当创建DLL时,Microsoft的编译器就会改变函数的名字。函数名将被设置一个前导下划线,再加上一个@符号的前缀,后随一个数字,表示作为参数传递给函数的字节数。例如,下面的函数是作为DLL的输出节中的_MyFunc@8输出的:

viewsource

print
?

1__declspec(dllexport)LONG__stdcallMyFunc(inta,intb);
如果用另一个供应商的工具创建了一个可执行模块,它将设法链接到一个名叫MyFunc的函数,该函数在Microsoft编译器已有的DLL中并不存在,因此链接将失败。

使用extern“C”关键字可以使编译器按照C语言的方式编译DLL文件,即编译时不改变函数名。

__declspec(dllexport)

在32位编译器版本中,可以使用__declspec(dllexport)关键字从DLL导出数据、函数、类或类成员函数。__declspec(dllexport)会将导出指令添加到对象文件中,因此不需要使用.def文件。

若要导出函数,__declspec(dllexport)关键字必须出现在调用约定关键字的左边(如果指定了关键字)。例如:

viewsource

print
?

1__declspec(dllexport)void__cdeclFunction1(void);
__stdcall

表明被调用方清理堆栈。

C#中的函数声明

viewsource

print
?

1usingSystem.Runtime.InteropServices;
2
3
4publicclassProgram
5{
6[DllImport(@"E:\Projects\testdll\debug\testdll.dll")]
7publicstaticexterninttestfunc(StringBuilderabuf,refinta);
8}
usingSystem.Runtime.InteropServices;

System.Runtime.InteropServices命名空间提供各种各样支持COMinterop及平台调用服务的成员,使程序可以与非托管代码进行交互操作。

[DllImport(“dllfilepath”)]

代码中DllImport关键字作用是告诉编译器入口点在哪里,并将打包函数捆绑在这个类中。在声明的时候还可以添加几个属性:

viewsource

print
?

1[DllImport("MyDLL.dll",
2EntryPoint="mySum",
3CharSet=CharSet.Auto,
4CallingConvention=CallingConvention.StdCall)]
EntryPoint:指定要调用的DLL入口点。默认入口点名称是托管方法的名称。
CharSet:控制名称重整和封送String参数的方式(默认是UNICODE)
CallingConvention指示入口点的函数调用约定(默认WINAPI)

注意:必须在标记为”static”和”extern”的方法上指定”DllImport”属性。

数据传递方法

1.基本数据类型的传递

函数参数和返回值可以是C#和C++的各种基本数据类型,如int,float,double,char(注意不是char*)等。
示例:
C#代码:

viewsource

print
?

01usingSystem;
02usingSystem.Text;
03usingSystem.Runtime.InteropServices;
04
05classProgram
06{
07[DllImport(@"E:\Projects\testdll\debug\testdll.dll")]
08publicstaticexterninttestfunc(inta,floatb,doublec,chard);
09
10staticvoidMain(string[]args)
11{
12inta=1;
13floatb=12;
14doublec=12.34;
15chard='A';
16testfunc(a,b,c,d);
17Console.ReadKey();
18}
19}
C++代码:

viewsource

print
?

01<preclass="brush:cpp">#include<iostream>
02usingnamespacestd;
03
04extern"C"
05{
06_declspec(dllexport)int__stdcalltestfunc(inta,floatb,doublec,chard)
07{
08cout<<a<<","<<b<<","<<c<<","<<d<<endl;
09return0;
10}
11}
12</pre>

2.向DLL传入字符串

C#中使用string定义字符串,将字符串对象名传给DLL。
注意:在DLL中更改字符串的值,C#中的值也会改变。
缺点:无法改变字符串的长度,建议使用第3种方法。
C#代码:

viewsource

print
?

01usingSystem;
02usingSystem.Text;
03usingSystem.Runtime.InteropServices;
04
05classProgram
06{
07[DllImport(@"E:\Projects\testdll\debug\testdll.dll")]
08publicstaticexterninttestfunc(stringa);
09
10staticvoidMain(string[]args)
11{
12stringa="HelloWorld!";
13testfunc(a);
14Console.ReadKey();
15}
16}
C++代码:

viewsource

print
?

01#include<iostream>
02usingnamespacestd;
03
04extern"C"
05{
06_declspec(dllexport)int__stdcalltestfunc(char*astr)
07{
08cout<<astr<<endl;
09*astr='A';//更改字符串的数据
10cout<<astr<<endl;
11return0;
12}
13}

3.DLL传出字符串

C#中使用StringBuilder对象创建变长数组,并设置StringBuilder的Capacity为数组最大长度。将此对象名传递给DLL,使用char*接收。
C#代码:

viewsource

print
?

01usingSystem;
02usingSystem.Text;
03usingSystem.Runtime.InteropServices;
04
05classProgram
06{
07[DllImport(@"E:\Projects\testdll\debug\testdll.dll")]
08publicstaticexterninttestfunc(StringBuilderabuf);
09
10staticvoidMain(string[]args)
11{
12StringBuilderabuf=newStringBuilder();
13abuf.Capacity=100;//设置字符串最大长度
14testfunc(abuf);
15Console.ReadKey();
16}
17
18}
C++代码:

viewsource

print
?

01#include<iostream>
02usingnamespacestd;
03
04extern"C"
05{
06_declspec(dllexport)int__stdcalltestfunc(char*astr)
07{
08*astr++='a';
09*astr++='b';//C#中abuf随astr改变
10*astr='\0';
11
12return0;
13}
14}

4.DLL传递结构体(需要在C#中重新定义,不推荐使用)

C#中使用StructLayout重新定义需要使用的结构体。
注意:在DLL改变结构体成员的值,C#中随之改变。
C#代码:

viewsource

print
?

01usingSystem;
02usingSystem.Text;
03usingSystem.Runtime.InteropServices;
04
05[StructLayout(LayoutKind.Sequential)]
06publicstructPoint
07{
08publicdoublex;
09publicdoubley;
10}
11
12classProgram
13{
14[DllImport(@"E:\Projects\testdll\debug\testdll.dll")]
15publicstaticexterninttestfunc(Pointp);
16
17staticvoidMain(string[]args)
18{
19Pointp;
20p.x=12.34;
21p.y=43.21;
22testfunc(p);
23Console.ReadKey();
24}
25}
C++代码:

viewsource

print
?

01#include<iostream>
02usingnamespacestd;
03
04structPoint
05{
06doublex;
07doubley;
08};
09
10extern"C"
11{
12_declspec(dllexport)int__stdcalltestfunc(Pointp)
13{
14cout<<p.x<<","<<p.y<<endl;
15return0;
16}
17}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: