博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C#开发奇技淫巧二:根据dll文件加载C++或者Delphi插件
阅读量:6388 次
发布时间:2019-06-23

本文共 4209 字,大约阅读时间需要 14 分钟。

原文:

      这两天忙着把框架改为支持加载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);

接下来怎么搞,你们都懂的

转载地址:http://bqdha.baihongyu.com/

你可能感兴趣的文章
Connection is read-only问题的产生原因与解决方法
查看>>
Proxmox VE 部署维护
查看>>
Linux软件包安装与卸载
查看>>
centos5.x安装sphinx
查看>>
3分钟搭建Ant Design Pro前端开发环境( MyClouds的前端选型)
查看>>
Scala各种用法
查看>>
Linux系统常用命令(二)
查看>>
简单的工厂模式学习
查看>>
温习如何画E-R图
查看>>
eclispe注释模板
查看>>
Thymeleaf教程 (三) 创建一个多语言的首页
查看>>
OSChina 周六乱弹 ——你们猜狗的舌头有多长
查看>>
OSChina 周日乱弹 —— 爱丽丝爱吃京酱肉丝
查看>>
2018.11月微信小程序优质开源项目
查看>>
IOS 未来几年的认知
查看>>
解决中文乱码--加密
查看>>
浅析全民社交创业梦
查看>>
Java操纵MongoDB_1(环境设置)
查看>>
C#字符串操作--获取字符或字符串的位置、数量
查看>>
php - 字符串处理
查看>>