您现在的位置是:首页 > 文章详情

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

日期:2018-07-27点击:314
原文: 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);

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

原文链接:https://yq.aliyun.com/articles/678162
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章