zoukankan      html  css  js  c++  java
  • 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         publicdelegatevoid StopHandler();
    5         ///<summary>
    6         /// 处理Start事件
    7         ///</summary>
    8         publicdelegatevoid StartHandler();
    9         ///<summary>
    10         /// 处理Init事件
    11         ///</summary>
    12         publicdelegatevoid InitHandler();
    13         ///<summary>
    14         /// 处理Query事件
    15         ///</summary>
    16         publicdelegatestring QueryHandler(string devName, string id);
    17         ///<summary>
    18         /// 处理SetDataBaseInfo事件
    19         ///</summary>
    20         publicdelegatevoid SetDatabaseInfoHandler(string server,string user,string password,string dbName);
    21         ///<summary>
    22         /// 处理SetMonitorInfo事件
    23         ///</summary>
    24         publicdelegatevoid SetMonitorInfoHandler(string agentBm, string com);

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

  • 相关阅读:
    vscode settings
    AutomaticPrefetchPlugin
    echarts 文字超长换行
    webpack篇(三):serve启动 打印台友好提示
    webpack篇(二):webpack 5 (变化)
    webpack篇(一):webpack 5 热更新体验
    面试(保存一些面试相关的网址链接,方便之后复习)
    路由传递参数的常见的两种形式
    组件缓存注意事项 ---keep-alive
    从css属性和布局来说明一下,行类元素和行类块元素和块元素的区别
  • 原文地址:https://www.cnblogs.com/marvin/p/loadunmanageddll.html
Copyright © 2011-2022 走看看