原文: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          [DllImport("kernel32.dll")]         public static extern bool FreeLibrary(IntPtr lib);          [DllImport("kernel32.dll")]         public static extern IntPtr GetStdHandle(int nStdHandle);          [DllImport("user32", EntryPoint = "CallWindowProc")]         public static extern int CallWindowProc(IntPtr lpPreWndFunc, int hwnd, int msg, int wParam, int lParam);         #endregion          private IntPtr _dllLib;          /// <summary>         /// Initializes a new instance of the <see cref="LoadDll"/> class.         /// </summary>         public LoadDll()         {                      }          /// <summary>         /// Initializes a new instance of the <see cref="LoadDll"/> class.         /// </summary>         /// <param name="path">The path.</param>         public LoadDll(string path)         {             _dllLib = LoadLibrary(path);         }          /// <summary>         /// 注销对象时释放资源         /// <see cref="LoadDll"/> is reclaimed by garbage collection.         /// </summary>         ~LoadDll()         {             FreeLibrary(_dllLib);         }          /// <summary>         /// 初始化dll的路径         /// </summary>         /// <param name="path">The path.</param>         public void InitPath(string path)         {             if (_dllLib == IntPtr.Zero)                 _dllLib = LoadLibrary(path);         }          /// <summary>         /// 根据非托管的dll中的方法名称映射成托管的委托类型         /// </summary>         /// <param name="methodName">非托管的dll中的方法名称</param>         /// <param name="methodType">托管的委托类型</param>         /// <returns></returns>         public Delegate InvokeMethod(string methodName, Type methodType)         {             //获取非托管的dll中方法的地址             var methodPtr = GetProcAddress(_dllLib, methodName);             //将非托管的方法转换为委托             return Marshal.GetDelegateForFunctionPointer(methodPtr, methodType);         }     }

调用:

 loadDll = new LoadDll(path);             stop = (StopHandler)loadDll.InvokeMethod("stop", typeof(StopHandler));             start = (StartHandler)loadDll.InvokeMethod("start", typeof(StartHandler));             init = (InitHandler)loadDll.InvokeMethod("init", typeof(InitHandler));             query = (QueryHandler)loadDll.InvokeMethod("query", typeof(QueryHandler));             setDatabaseInfo = (SetDatabaseInfoHandler)loadDll.InvokeMethod("setDatabaseInfo", typeof(SetDatabaseInfoHandler));             setMonitorInfo = (SetMonitorInfoHandler)loadDll.InvokeMethod("setMonitorInfo", typeof(SetMonitorInfoHandler));

c++中的导出方法:

 /// 插件导出方法 extern "C" __declspec(dllexport) void setDatabaseInfo(LPCTSTR dbServer, LPCTSTR dbUser, LPCTSTR dbPass, LPCTSTR dbName); extern "C" __declspec(dllexport) void setMonitorInfo(LPCTSTR _agentBm, LPCTSTR _com); extern "C" __declspec(dllexport) void init(); extern "C" __declspec(dllexport) void start(); extern "C" __declspec(dllexport) void stop(); extern "C" __declspec(dllexport) LPCTSTR query(LPCTSTR devname, LPCTSTR id);

C#中的委托

 ///<summary>         /// 处理Stop事件         ///</summary>         publicdelegatevoid StopHandler();         ///<summary>         /// 处理Start事件         ///</summary>         publicdelegatevoid StartHandler();         ///<summary>         /// 处理Init事件         ///</summary>         publicdelegatevoid InitHandler();         ///<summary>         /// 处理Query事件         ///</summary>         publicdelegatestring QueryHandler(string devName, string id);         ///<summary>         /// 处理SetDataBaseInfo事件         ///</summary>         publicdelegatevoid SetDatabaseInfoHandler(string server,string user,string password,string dbName);         ///<summary>         /// 处理SetMonitorInfo事件         ///</summary>         publicdelegatevoid SetMonitorInfoHandler(string agentBm, string com);

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

C#开发奇技淫巧二:根据dll文件加载C++或者Delphi插件的更多相关文章

  1. 一步一步开发Game服务器(三)加载脚本和服务器热更新(二)完整版

    上一篇文章我介绍了如果动态加载dll文件来更新程序 一步一步开发Game服务器(三)加载脚本和服务器热更新 可是在使用过程中,也许有很多会发现,动态加载dll其实不方便,应为需要预先编译代码为dll文 ...

  2. 给.DLL文件加一个数字签名的方法

     给.dll文件加一个数字签名的方法 效果如图所示:   做法: 下载数字签名工具包:http://files.cnblogs.com/babyt/SignTool.rar  /Files/JavaC ...

  3. 伟景行 citymaker 从入门到精通(1)——js开发,最基本demo,加载cep工程文件

    开发环境:citymaker 7(以下简称cm),jquery,easyui 1.4(界面),visual studio 2012(没有vs,不部署到IIS也行,html文件在本地目录双击打开可用) ...

  4. dll的加载方式主要分为两大类,显式和隐式链接

    之前简单写过如何创建lib和dll文件及简单的使用(http://blog.csdn.net/betabin/article/details/7239200).现在先再深入点写写dll的加载方式. d ...

  5. VSTO学习笔记(三) 开发Office 2010 64位COM加载项

    原文:VSTO学习笔记(三) 开发Office 2010 64位COM加载项 一.加载项简介 Office提供了多种用于扩展Office应用程序功能的模式,常见的有: 1.Office 自动化程序(A ...

  6. Android 的 so 文件加载机制

    本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 最近碰到一些 so 文件问题,顺便将相关知识点梳理一下. 提问 本文的结论是跟着 System.loadlibrary() 一层层源 ...

  7. 固定dll的加载基址的方法

    调试dll的时候会有一件事情比较烦人,就是dll加载的地址不会很固定(默认设置下编译的dll基址总是0x10000000,多个同基址的dll加载时,后面的肯定会被重定位),这给前后多次调试时对比分析结 ...

  8. php文件加载、错误处理、方法函数和数组

    数组运算符注意:php中,数组的元素的顺序,不是由下标(键名)决定的,而是完全由加入的顺序来决定.联合(+):将右边的数组项合并到左边数组的后面,得到一个新数组.如有重复键,则结果以左边的为准$v1 ...

  9. 插件化框架解读之so 文件加载机制(四)

    阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:https://space.bilibili.com/474380680 提问 本文的结论是跟着 System.loadlibrary() ...

随机推荐

  1. 乌班图 之 apt命令 及 VMware共享文件夹

    apt是Advanced Packaging Tool ,是Ubuntu下的一个安装包管理工具 大部分软件的安装.更新.卸载 都是利用apt命令来实现 直接在终端输入apt即可查阅命令的帮助信息 常用 ...

  2. js 拼接字符串,table等

    var userTableStr=''; userTableStr +='<table width="750" height="33" border=&q ...

  3. Windows 安装PostgreSQL

    下载二进制包:https://www.enterprisedb.com/download-postgresql-binaries 直接解压到C盘 Microsoft Windows [版本 6.3.9 ...

  4. Swift 中的协议

    Swift 中的协议协议是为方法.属性等定义一套规范,没有具体的实现,类似于Java中的抽象接口,它只是描述了方法或属性的骨架,而不是实现.方法和属性实现还需要通过定义类,函数和枚举完成. 协议定义 ...

  5. 联想lenovo 家用电脑安装win7 无法引导问题(新电脑安装系统时提示File:\Boot\BCD错误解决方案)

    安装方式 : 1.进入 PE 2.用 EasyimageX 恢复 GHO镜像 3.重启后出现  原因: 主要 是安装win7 时,格式 化选择为GUID模式. 处理: win7 以后,格式华时选择MB ...

  6. UE4自学随笔(一)

    本文及后续均为个人学习记录所用,难免毫无章法零零碎碎,希望看到此文的诸君勿怪. 一.Actor与Pawn Actor类 在UE4中,Actor类是可以放到游戏场景中的游戏对象的基本类型.你如果想放置任 ...

  7. 魔兽争霸RPG游戏-军团战争-游戏经验总结

    终于要写这篇了,上一篇是个意外. 2015年关注,一代鬼王Xun和GGL比赛.晚上11点之后,经常有水友赛.主播xun,会带着一帮小弟,玩一些游戏.比如魔兽争霸6v6,2v2,RPG游戏-军团战争,疯 ...

  8. Qt之水平/垂直布局(QBoxLayout、QHBoxLayout、QVBoxLayout)

    简述 QBoxLayout可以在水平方向或垂直方向上排列控件,由QHBoxLayout.QVBoxLayout所继承. QHBoxLayout:水平布局,在水平方向上排列控件,即:左右排列. QVBo ...

  9. Qt之自定义布局管理器(QCardLayout)

    简述 手动布局另一种方法是通过继承QLayout类编写自己的布局管理器. 下面我们详细来举一个例子-QCardLayout.它由同名的Java布局管理器启发而来.也被称之为卡片布局,每个项目偏移QLa ...

  10. JavaWeb利用cookie记住账号

    JavaWeb利用cookie记住账号. 首先,来看看界面什么样子. 记住账号最普遍的做法,就是在点击登录时,将账号保存到cookie中. 材料准备 <script src="${ct ...