C#开发奇技淫巧二:根据dll文件加载C++或者Delphi插件

简介: 原文:C#开发奇技淫巧二:根据dll文件加载C++或者Delphi插件       这两天忙着把框架改为支持加载C++和Delphi的插件,来不及更新blog了。      原来的写的框架只支持c#插件,这个好做,直接用c#的反射功能便可。
原文: 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);

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

目录
相关文章
|
9月前
|
XML 测试技术 API
利用C#开发ONVIF客户端和集成RTSP播放功能
利用C#开发ONVIF客户端和集成RTSP播放功能
4706 123
|
物联网 数据处理 C#
C#实现上位机开发,串口通信,读写串口数据并处理16进制数据
C#实现上位机开发,串口通信,读写串口数据并处理16进制数据。在自动化、物联网以及工业控制行业中,上位机开发是一项重要的技能。本教程主要介绍使用C#进行上位机开发,重点在于串口通信和数据处理。
2892 82
|
前端开发 JavaScript 安全
C#一分钟浅谈:Blazor WebAssembly 开发
Blazor WebAssembly 是一个客户端框架,允许开发者使用C#和Razor语法构建Web应用。本文介绍了Blazor WebAssembly的基本概念、常见问题及解决方案,包括路由配置、数据绑定、异步操作、状态管理和性能优化等方面的内容,并分享了一些易错点及如何避免的方法。希望这些内容能帮助你在Blazor WebAssembly开发中少走弯路,提高开发效率。
560 51
|
SQL 小程序 API
如何运用C#.NET技术快速开发一套掌上医院系统?
本方案基于C#.NET技术快速构建掌上医院系统,结合模块化开发理念与医院信息化需求。核心功能涵盖用户端的预约挂号、在线问诊、报告查询等,以及管理端的排班管理和数据统计。采用.NET Core Web API与uni-app实现前后端分离,支持跨平台小程序开发。数据库选用SQL Server 2012,并通过读写分离与索引优化提升性能。部署方案包括Windows Server与负载均衡设计,确保高可用性。同时针对API差异、数据库老化及高并发等问题制定应对措施,保障系统稳定运行。推荐使用Postman、Redgate等工具辅助开发,提升效率与质量。
598 0
|
缓存 算法 安全
精选10款C#/.NET开发必备类库(含使用教程),工作效率提升利器!
精选10款C#/.NET开发必备类库(含使用教程),工作效率提升利器!
734 12
|
缓存 C# 开发者
C# 一分钟浅谈:Blazor Server 端开发
本文介绍了 Blazor Server,一种基于 .NET 的 Web 开发模型,允许使用 C# 和 Razor 语法构建交互式 Web 应用。文章从基础概念、创建应用、常见问题及解决方案、易错点及避免方法等方面详细讲解,帮助开发者快速上手并提高开发效率。
546 2
|
开发框架 缓存 .NET
C# 一分钟浅谈:Blazor Server 端开发
Blazor Server 是基于 ASP.NET Core 的框架,允许使用 C# 和 Razor 语法构建交互式 Web 应用。本文介绍 Blazor Server 的基本概念、快速入门、常见问题及解决方案,帮助开发者快速上手。涵盖创建应用、基本组件、数据绑定、状态管理、跨组件通信、错误处理和性能优化等内容。
1079 1
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
|
编译器 C++ 容器
【c++11】c++11新特性(上)(列表初始化、右值引用和移动语义、类的新默认成员函数、lambda表达式)
C++11为C++带来了革命性变化,引入了列表初始化、右值引用、移动语义、类的新默认成员函数和lambda表达式等特性。列表初始化统一了对象初始化方式,initializer_list简化了容器多元素初始化;右值引用和移动语义优化了资源管理,减少拷贝开销;类新增移动构造和移动赋值函数提升性能;lambda表达式提供匿名函数对象,增强代码简洁性和灵活性。这些特性共同推动了现代C++编程的发展,提升了开发效率与程序性能。
545 12
|
人工智能 机器人 编译器
c++模板初阶----函数模板与类模板
class 类模板名private://类内成员声明class Apublic:A(T val):a(val){}private:T a;return 0;运行结果:注意:类模板中的成员函数若是放在类外定义时,需要加模板参数列表。return 0;
283 0