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#中,我们定义相关的接口,在方法实现中调用相应的委托,这样,一个插件对象就完成了。下面给出相应的类库和使用实例。
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 }
调用:
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++中的导出方法:
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#中的委托
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);
接下来怎么搞,你们都懂的
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
关于JS和JSON
讲得不准确! 看网课,JS也算是面向对象的一门语言,不过其是解释性的脚本语言. JSON是把用JS的表示法将数据包装起来进行传递用的. JS语法是松散型的,没有int String这些像JAVA里的类型去定义某个变量, 只需要var定义,但是还是分数据类型的,比如 var a = 10,那么typeof a 就是number var b = "112" ,那么typeof b 就是string类型.. 等等. JS的逻辑性方面跟所有语言一样,所以总体的话不是太难学js. 只需要将Java的一些理论概念来分析一下,动手做一下,基础JS算能入门. JSON看了一天的W3C,其是可以用来传递数据的,如果使用Java的Servlet,service,dao,以及实体类,进行数据的查询传递,返回前端,难免显得臃肿, 关键是JSON的传递还不是很明白,不过总体来看JS这样的脚本语言的传递数值和字符串的话相对JAVA要显得娇小一些. 而且JSON也可以配合AJAX去进行局部刷新,那么总体上它们之间存在何种关系呢? (JAVA JS JSON AJAX) 将编程看作是一门艺术,而不单单是个技术。 敲...
- 下一篇
C#开发奇技淫巧一:调试windows系统服务
原文: C#开发奇技淫巧一:调试windows系统服务 windows系统服务不能直接运行,只能在安装完服务之后启动、暂停、继续、停止服务,导致服务的调试不能使用一般的断点调试。 要调试系统服务,可以采用附加到进程的方式:在VS的工具栏中找到“调试”这个选项,然后选取“附加到进程” 然后选择相应的服务附加,再启动服务即可调试(前提是已经在服务的代码中打上了断点) 不过以上方法不能调试OnStart方法,即服务的启动并不能被调试到,这个时候,需要在OnStart方法中加上Debugger.Launch().这里有介绍:http://www.cnblogs.com/xzwplus/archive/2009/07/06/1129452.html
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS7设置SWAP分区,小内存服务器的救世主
- Docker安装Oracle12C,快速搭建Oracle学习环境
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- Mario游戏-低调大师作品
- 2048小游戏-低调大师作品
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程