C#开发奇技淫巧二:根据dll文件加载C++或者Delphi插件
原文: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插件的更多相关文章
- 一步一步开发Game服务器(三)加载脚本和服务器热更新(二)完整版
上一篇文章我介绍了如果动态加载dll文件来更新程序 一步一步开发Game服务器(三)加载脚本和服务器热更新 可是在使用过程中,也许有很多会发现,动态加载dll其实不方便,应为需要预先编译代码为dll文 ...
- 给.DLL文件加一个数字签名的方法
给.dll文件加一个数字签名的方法 效果如图所示: 做法: 下载数字签名工具包:http://files.cnblogs.com/babyt/SignTool.rar /Files/JavaC ...
- 伟景行 citymaker 从入门到精通(1)——js开发,最基本demo,加载cep工程文件
开发环境:citymaker 7(以下简称cm),jquery,easyui 1.4(界面),visual studio 2012(没有vs,不部署到IIS也行,html文件在本地目录双击打开可用) ...
- dll的加载方式主要分为两大类,显式和隐式链接
之前简单写过如何创建lib和dll文件及简单的使用(http://blog.csdn.net/betabin/article/details/7239200).现在先再深入点写写dll的加载方式. d ...
- VSTO学习笔记(三) 开发Office 2010 64位COM加载项
原文:VSTO学习笔记(三) 开发Office 2010 64位COM加载项 一.加载项简介 Office提供了多种用于扩展Office应用程序功能的模式,常见的有: 1.Office 自动化程序(A ...
- Android 的 so 文件加载机制
本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 最近碰到一些 so 文件问题,顺便将相关知识点梳理一下. 提问 本文的结论是跟着 System.loadlibrary() 一层层源 ...
- 固定dll的加载基址的方法
调试dll的时候会有一件事情比较烦人,就是dll加载的地址不会很固定(默认设置下编译的dll基址总是0x10000000,多个同基址的dll加载时,后面的肯定会被重定位),这给前后多次调试时对比分析结 ...
- php文件加载、错误处理、方法函数和数组
数组运算符注意:php中,数组的元素的顺序,不是由下标(键名)决定的,而是完全由加入的顺序来决定.联合(+):将右边的数组项合并到左边数组的后面,得到一个新数组.如有重复键,则结果以左边的为准$v1 ...
- 插件化框架解读之so 文件加载机制(四)
阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:https://space.bilibili.com/474380680 提问 本文的结论是跟着 System.loadlibrary() ...
随机推荐
- 集合类 ArrayList实现公司职员薪水管理
package com.test; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStr ...
- sqluldr2linux64.bin的使用
使用sqluldr2linux64.bin的前提是已经安装了Oracle数据库,sqluldr2linux64.bin和Oracle在同一台主机上使用,使用之前需要赋予可执行权限: [root@nod ...
- 【原创】Linux下的ngix服务器安装步骤
1.首先下载ngix的源码linux版本[1.5.8版本] http://nginx.org/en/download.html 2.下载PCRE library,是安装ngix的必备包之一 [root ...
- UVa 10943 How do you add?【递推】
题意:给出n,k,问恰好有k个不超过n的数的和为n的方案数有多少 可以隔板法来做 现在有n个小球放到k个盒子里面,盒子可以为空 那么就是n-k+1个缝隙,放上k-1个隔板(k-1个隔板就分成了k份) ...
- easyui的datagrid右侧没有边框线
做项目时,用的easyui的框架的datagrid,运行时发现右侧没有边框,其它的都有边框,使用网页的审查元素可以看到datagrid样式里的宽度没有自动减去2个像素,这些都是easyui自算的宽高, ...
- (一)React再学习
新公司的技术栈是React,虽然之前对react大概过了一遍,但是自己没有实际落地过项目 再学习一遍react: 一.react全家桶 ·create-react-app ·组件化思维 ·JSX ·开 ...
- JavaScript设计模式(biaoyansu)(2)
单例模式实例 (创建类模式): let elBalance = document.getElementById('balance') function init () { var a = new Di ...
- tinymce原装插件源码分析(一)-hr
tinymce简介 tinymce是一款能方便无限扩展的网页富文本编辑器. tinymce原装插件已经十分丰富,对于文本编辑(blog等文章)是绰绰有余,但是应对一些复杂的应用,比如在上面开发html ...
- BZOJ 2287 【POJ Challenge】消失之物(DP+容斥)
2287: [POJ Challenge]消失之物 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 986 Solved: 572[Submit][S ...
- JVM内存管理简单剖析
Java是一个跨平台语言,屏蔽操作系统的差异,无需关心复杂内存管理,做到编写一次到处运行.其强大的能力源于Java Virtual Machine (虚拟机)默默的付出.代码运行在虚拟机之上,虚拟机运 ...