原文:
C#开发奇技淫巧二:根据dll文件加载C++或者Delphi插件
这两天忙着把框架改为支持加载C++和Delphi的插件,来不及更新blog了。
原来的写的框架只支持c#插件,这个好做,直接用c#的反射功能便可。但是公司不是所有人都搞C#,也不是所有的程序C#都能很好的完成,又或者其他公司提供的API不是C#的,这个时候,就需要这个框架能够支持多种语言了。
废话不多说,进入正题。
上网一搜,C#加载非托管的dll,无非就是使用 DllImportAttribute 。然而,这个属性里面要指明dll所在的路径,因为又是写在属性中,因此是在编译的时候就已经把路径写死了,不能动态指定路径加载。
于是又找了下,终于发现了c#中的一个函数:Marshal.GetDelegateForFunctionPointer。这个函数的功能就是将非托管的函数指针转换为委托。至此,任务完成。Dll的功能无非提提供各种函数,组成所谓的API,有了上述的方法之后,在C#中定义相关的委托(方法的参数列表和参数类型要跟非托管的Dll的参数类型和参数列表对应,具体的对应请google),然后调用上述方法,将非托管的dll转换为相应的委托,这样就能调用非托管的dll了。
在C#中,我们定义相关的接口,在方法实现中调用相应的委托,这样,一个插件对象就完成了。下面给出相应的类库和使用实例。
1
public
class
LoadDll
2
{
3
#region
Win32 API : Load dll
4
[DllImport(
"
kernel32.dll
"
)]
5
public
static
extern
IntPtr LoadLibrary(
string
path);
6
7
[DllImport(
"
kernel32.dll
"
)]
8
public
static
extern
IntPtr GetProcAddress(IntPtr lib,
string
funcName);
9
10
[DllImport(
"
kernel32.dll
"
)]
11
public
static
extern
bool
FreeLibrary(IntPtr lib);
12
13
[DllImport(
"
kernel32.dll
"
)]
14
public
static
extern
IntPtr GetStdHandle(
int
nStdHandle);
15
16
[DllImport(
"
user32
"
, EntryPoint
=
"
CallWindowProc
"
)]
17
public
static
extern
int
CallWindowProc(IntPtr lpPreWndFunc,
int
hwnd,
int
msg,
int
wParam,
int
lParam);
18
#endregion
19
20
private
IntPtr _dllLib;
21
22
///
<summary>
23
///
Initializes a new instance of the
<see cref="LoadDll"/>
class.
24
///
</summary>
25
public
LoadDll()
26
{
27
28
}
29
30
///
<summary>
31
///
Initializes a new instance of the
<see cref="LoadDll"/>
class.
32
///
</summary>
33
///
<param name="path">
The path.
</param>
34
public
LoadDll(
string
path)
35
{
36
_dllLib
=
LoadLibrary(path);
37
}
38
39
///
<summary>
40
///
注销对象时释放资源
41
///
<see cref="LoadDll"/>
is reclaimed by garbage collection.
42
///
</summary>
43
~
LoadDll()
44
{
45
FreeLibrary(_dllLib);
46
}
47
48
///
<summary>
49
///
初始化dll的路径
50
///
</summary>
51
///
<param name="path">
The path.
</param>
52
public
void
InitPath(
string
path)
53
{
54
if
(_dllLib
==
IntPtr.Zero)
55
_dllLib
=
LoadLibrary(path);
56
}
57
58
///
<summary>
59
///
根据非托管的dll中的方法名称映射成托管的委托类型
60
///
</summary>
61
///
<param name="methodName">
非托管的dll中的方法名称
</param>
62
///
<param name="methodType">
托管的委托类型
</param>
63
///
<returns></returns>
64
public
Delegate InvokeMethod(
string
methodName, Type methodType)
65
{
66
//
获取非托管的dll中方法的地址
67
var methodPtr
=
GetProcAddress(_dllLib, methodName);
68
//
将非托管的方法转换为委托
69
return
Marshal.GetDelegateForFunctionPointer(methodPtr, methodType);
70
}
71
}
1
loadDll
=
new
LoadDll(path);
2
stop
=
(StopHandler)loadDll.InvokeMethod(
"
stop
"
,
typeof
(StopHandler));
3
start
=
(StartHandler)loadDll.InvokeMethod(
"
start
"
,
typeof
(StartHandler));
4
init
=
(InitHandler)loadDll.InvokeMethod(
"
init
"
,
typeof
(InitHandler));
5
query
=
(QueryHandler)loadDll.InvokeMethod(
"
query
"
,
typeof
(QueryHandler));
6
setDatabaseInfo
=
(SetDatabaseInfoHandler)loadDll.InvokeMethod(
"
setDatabaseInfo
"
,
typeof
(SetDatabaseInfoHandler));
7
setMonitorInfo
=
(SetMonitorInfoHandler)loadDll.InvokeMethod(
"
setMonitorInfo
"
,
typeof
(SetMonitorInfoHandler));
c++中的导出方法:
1
///
插件导出方法
2
extern
"
C
"
__declspec(dllexport)
void
setDatabaseInfo(LPCTSTR dbServer, LPCTSTR dbUser, LPCTSTR dbPass, LPCTSTR dbName);
3
extern
"
C
"
__declspec(dllexport)
void
setMonitorInfo(LPCTSTR _agentBm, LPCTSTR _com);
4
extern
"
C
"
__declspec(dllexport)
void
init();
5
extern
"
C
"
__declspec(dllexport)
void
start();
6
extern
"
C
"
__declspec(dllexport)
void
stop();
7
extern
"
C
"
__declspec(dllexport) LPCTSTR query(LPCTSTR devname, LPCTSTR id);
C#中的委托
1
///
<summary>
2
///
处理Stop事件
3
///
</summary>
4
public
delegate
void
StopHandler();
5
///
<summary>
6
///
处理Start事件
7
///
</summary>
8
public
delegate
void
StartHandler();
9
///
<summary>
10
///
处理Init事件
11
///
</summary>
12
public
delegate
void
InitHandler();
13
///
<summary>
14
///
处理Query事件
15
///
</summary>
16
public
delegate
string
QueryHandler(
string
devName,
string
id);
17
///
<summary>
18
///
处理SetDataBaseInfo事件
19
///
</summary>
20
public
delegate
void
SetDatabaseInfoHandler(
string
server,
string
user,
string
password,
string
dbName);
21
///
<summary>
22
///
处理SetMonitorInfo事件
23
///
</summary>
24
public
delegate
void
SetMonitorInfoHandler(
string
agentBm,
string
com);
接下来怎么搞,你们都懂的
🎥在VS中进行调用DLL文件
🚩第一步:先来新建一个项目
🚩第二步:复制firstDLLTest.dll和firstDLLTest.lib文件和上一个项目的头文件firstDLLTest.h
🚩第三步:在新项目里面添加C++代码
🚩第四步:添加头文件firstDLLTest.h和firstDLLTest.
最近一个项目要开发网页端人脸识别项目,人脸识别的算法已经写好,是C++版,但是网页端要求使用Java后台,这就涉及到Java调用DLL的问题。经过查找,实现了一个简单的例子。
1、第一步,先在Java中新建一个类
如上图,其中注意这句System.loadLibrary("javaCallcpp");,这就是加载dll文件的代码了。