【好文章要分享】C#程序调用非托管C++ DLL文件的方法
来源:互联网 发布:互联网大数据面试题 编辑:程序博客网 时间:2024/05/17 08:52
传送:
Chase的技术博客
:http://www.cnblogs.com/Chase/archive/2010/05/31/1748596.htmlC#程序调用非托管C++ DLL文件的方法
2010-05-31 22:15 by Caizhi, 12196 阅读, 14 评论, 收藏, 编辑08年写的一篇文章,当时项目用C#开发,但是有一些希望重用之前的C++代码,于是研究了如何在C#中调用C++的DLL。
C++中的函数声明
extern
"C"
__declspec
(
dllexport
)
int
__stdcall testfunc(
char
* astr,
int
* a);
extern ”C”
通常来说,C++编译器可能会改变函数和变量的名字,从而导致严重的链接程序问题。例如,假设使用C++编写一个DLL,当创建DLL时,Microsoft的编译器就会改变函数的名字。函数名将被设置一个前导下划线,再加上一个@符号的前缀,后随一个数字,表示作为参数传递给函数的字节数。例如,下面的函数是作为DLL的输出节中的_MyFunc@8输出的:
__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) 关键字必须出现在调用约定关键字的左边(如果指定了关键字)。例如:
__declspec
(
dllexport
)
void
__cdecl Function1(
void
);
__stdcall
表明被调用方清理堆栈。
C#中的函数声明
using
System.Runtime.InteropServices;
…
public
class
Program
{
[DllImport(
@"E:\Projects\testdll\debug\testdll.dll"
)]
public
static
extern
int
testfunc(StringBuilder abuf,
ref
int
a);
}
using System.Runtime.InteropServices;
System.Runtime.InteropServices 命名空间提供各种各样支持 COM interop 及平台调用服务的成员,使程序可以与非托管代码进行交互操作。
[DllImport(“dllfile path”)]
代码中DllImport关键字作用是告诉编译器入口点在哪里,并将打包函数捆绑在这个类中。在声明的时候还可以添加几个属性:
[DllImport(
"MyDLL.dll"
,
EntryPoint=
"mySum"
,
CharSet=CharSet.Auto,
CallingConvention=CallingConvention.StdCall)]
EntryPoint: 指定要调用的 DLL 入口点。默认入口点名称是托管方法的名称 。
CharSet: 控制名称重整和封送 String 参数的方式 (默认是UNICODE)
CallingConvention指示入口点的函数调用约定(默认WINAPI)
注意:必须在标记为”static”和”extern”的方法上指定”DllImport”属性。
数据传递方法
1.基本数据类型的传递
函数参数和返回值可以是C#和C++的各种基本数据类型,如int, float, double, char(注意不是char*)等。
示例:
C#代码:
using
System;
using
System.Text;
using
System.Runtime.InteropServices;
class
Program
{
[DllImport(
@"E:\Projects\testdll\debug\testdll.dll"
)]
public
static
extern
int
testfunc(
int
a,
float
b,
double
c,
char
d);
static
void
Main(
string
[] args)
{
int
a = 1;
float
b = 12;
double
c = 12.34;
char
d =
'A'
;
testfunc(a,b,c,d);
Console.ReadKey();
}
}
C++代码:
<pre
class
=
"brush:cpp"
>#include <iostream>
using
namespace
std;
extern
"C"
{
_declspec(
dllexport
)
int
__stdcall testfunc(
int
a,
float
b,
double
c,
char
d)
{
cout<<a<<
", "
<<b<<
", "
<<c<<
", "
<<d<<endl;
return
0;
}
}
</pre>
2.向DLL传入字符串
C#中使用string定义字符串,将字符串对象名传给DLL。
注意:在DLL中更改字符串的值,C#中的值也会改变。
缺点:无法改变字符串的长度,建议使用第3种方法。
C#代码:
using
System;
using
System.Text;
using
System.Runtime.InteropServices;
class
Program
{
[DllImport(
@"E:\Projects\testdll\debug\testdll.dll"
)]
public
static
extern
int
testfunc(
string
a);
static
void
Main(
string
[] args)
{
string
a=
"Hello World!"
;
testfunc(a);
Console.ReadKey();
}
}
C++代码:
#include <iostream>
using
namespace
std;
extern
"C"
{
_declspec(
dllexport
)
int
__stdcall testfunc(
char
* astr)
{
cout<<astr<<endl;
*astr=
'A'
;
//更改字符串的数据
cout<<astr<<endl;
return
0;
}
}
3.DLL传出字符串
C#中使用StringBuilder对象创建变长数组,并设置StringBuilder的Capacity为数组最大长度。将此对象名传递给DLL,使用char*接收。
C#代码:
using
System;
using
System.Text;
using
System.Runtime.InteropServices;
class
Program
{
[DllImport(
@"E:\Projects\testdll\debug\testdll.dll"
)]
public
static
extern
int
testfunc(StringBuilder abuf);
static
void
Main(
string
[] args)
{
StringBuilder abuf=
new
StringBuilder();
abuf.Capacity = 100;
//设置字符串最大长度
testfunc(abuf);
Console.ReadKey();
}
}
C++代码:
#include <iostream>
using
namespace
std;
extern
"C"
{
_declspec(
dllexport
)
int
__stdcall testfunc(
char
* astr)
{
*astr++=
'a'
;
*astr++=
'b'
;
//C#中abuf随astr改变
*astr=
'\0'
;
return
0;
}
}
4.DLL传递结构体(需要在C#中重新定义,不推荐使用)
C#中使用StructLayout重新定义需要使用的结构体。
注意:在DLL改变结构体成员的值,C#中随之改变。
C#代码:
using
System;
using
System.Text;
using
System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential)]
public
struct
Point
{
public
double
x;
public
double
y;
}
class
Program
{
[DllImport(
@"E:\Projects\testdll\debug\testdll.dll"
)]
public
static
extern
int
testfunc(Point p);
static
void
Main(
string
[] args)
{
Point p;
p.x = 12.34;
p.y = 43.21;
testfunc(p);
Console.ReadKey();
}
}
C++代码:
#include <iostream>
using
namespace
std;
struct
Point
{
double
x;
double
y;
};
extern
"C"
{
_declspec(
dllexport
)
int
__stdcall testfunc(Point p)
{
cout<<p.x<<
", "
<<p.y<<endl;
return
0;
}
}
- 【好文章要分享】C#程序调用非托管C++ DLL文件的方法
- C#程序调用非托管C++ DLL文件的方法
- C#程序调用非托管C++ DLL文件的方法
- C#程序实现动态调用非托管的DLL文件
- C#程序实现动态调用非托管的DLL文件
- C#程序实现动态调用非托管的DLL文件
- C#程序实现动态调用非托管的DLL文件
- C#调用非托管C++DLL的两种方法
- [C#/C++]C#调用非托管DLL的APIs
- [C#/C++]C#调用非托管DLL的APIs
- [C#/C++]C#调用非托管DLL的APIs
- C#调用非托管C编写DLL的数据类型转换
- C#调用非托管C++生成的DLL文件
- 非托管C++代码调用C#编写的dll方法
- 非托管C++代码调用C#编写的dll方法
- 非托管C++代码调用C#编写的dll方法
- C#调用非托管DLL的APIs
- C#调用非托管DLL的APIs
- A/B 扩展欧几里得的运用
- Apt-get command not found in terminal?
- iOS开发—初识多线程
- CoreText实现图文混排和点击事件
- Linux进程控制——exec函数族
- 【好文章要分享】C#程序调用非托管C++ DLL文件的方法
- 娱乐为主这样也蛮酷
- 在Eclipse中使用Maven配置WebDriver+Testng(二)
- 字典树入门及实现(JAVA)<转>
- (intermediate) 网络流:矩阵模型 UVA 11082 - Matrix Decompressing
- c++基础2
- js获取日期
- Hibernate annotation多对多相关要点总结
- oracle 创建视图添加表中没有的数据但不影响表