(原创)一个简洁通用的调用DLL函数的帮助类
来源:互联网 发布:java string == equal 编辑:程序博客网 时间:2024/05/01 20:22
本次介绍一种调用dll函数的通用简洁的方法,消除了原来调用方式的重复与繁琐,使得我们调用dll函数的方式更加方便简洁。用过dll的人会发现c++中调用dll中的函数有点繁琐,调用过程是这样的:在加载dll后还要定义一个对应的函数指针类型,再调用GetProcAddress获取函数地址,再转成函数指针,最后调用该函数。下面是调用dll中Max和Get函数的例子。
void TestDll(){typedef int(*pMax)(int a,int b);typedef int(*pGet)(int a);HINSTANCE hMode =LoadLibrary("MyDll.dll");if(hMode==nullptr)return;PMax Max = (PMax)GetProcAddress(hDLL,"Max");if(Max==nullptr)return;int ret =Max(5,8); //8PMin Get = (PMin)GetProcAddress(hDLL,"Get");if(Get==nullptr)return;int ret =Get(5); //5FreeLibrary(hDLL);}
这段代码看起来很繁琐,因为我没每用一个函数就需要先定义一个函数指针,然后再根据名称获取函数地址,最后调用。如果一个dll中有上百个函数的话,这种重复而繁琐的定义会让人吐的。其实获取函数地址和调用函数的过程是重复逻辑,应该消除,我不想每次都定义一个函数指针和调用GetProcAddress,我觉得可以用一种简洁通用的方式去调用dll中的函数。我希望调用dll中的函数就像调用普通的函数一样,即传入一个函数名称和函数的参数就可以实现函数的调用了。就类似于:
Ret CallDllFunc(const string&funName, T arg)
如果以这种方式调用的话,我就能避免繁琐的函数指针定义以及反复的调用GetProcAddress了。
一种可行的解决方案
如果要按照
Ret CallDllFunc(const string& funName, T arg)
这种方式调用的话,首先我要把函数指针转换成一种函数对象或者泛型函数,这里我们可以用std::function去做这个事情,即通过一个函数封装GetProcAddress,这样通过函数名称我就能获取一个泛型函数std::function,我希望这个function是通用的,不论dll中是什么函数都可以转换成这个function, 最后调用这个通用
的function就可以了。但是调用这个通用的function还有两个问题需要解决:
- 不同函数的不同类型返回值怎么处理,因为函数的返回值可能是某些类型,如何以一种通用的返回值来消除这种不同返回值导致的差异呢?
- 函数的入参数目可能任意个数,且类型也不尽相同,如何来消除入参个数和类型的差异呢?
我们一个个解决问题吧,首先看看如何封装GetProcAddress,将函数指针转换成std::function。通过如下代码就可以了。
template <typename T>std::function<T> GetFunction(const string&funcName){FARPROC funAddress = GetProcAddress(m_hMod, funcName.c_str());return std::function<T>((T*)(funAddress));}
其中T是std::function的模板参数,即函数类型的签名。如果我们要获取上面例子中,Max和Get函数,则可以这样获取:
auto fmax = GetFunction<int(int, int)>("Max");auto fget = GetFunction<int(int)>("Get");
这种方式比之之前先定义函数指针再调用GetProcAddress的方式更简洁通用。
再看看如何解决函数返回值和入参不统一的问题,关于这个问题,其实在前面的博文中就讲到了,不知道的童鞋看这里:
(原创)C++11改进我们的程序之简化我们的程序(一)
是的,还是通过result_of和可变参数模板来搞定。最终的调用函数是这样的:
template <typename T, typename... Args>typename std::result_of<std::function<T>(Args...)>::type ExcecuteFunc(const string& funcName,Args&&... args){return GetFunction<T>(funcName)(args...);}
上面的例子中要调用Max和Get函数,这样就行了:
auto max = ExcecuteFunc<int(int, int)>("Max", 5, 8);auto ret = ExcecuteFunc<int(int)>("Get", 5);
怎么样,比之之前的调用方式是不是简洁直观多了,没有了繁琐的函数指针的定义,没有了反复的调用GetProcAddress及其转换和调用。
如果要限定调用方式就在参数前面加,如
ExcecuteFunc<int __stdcall(int, int)>
最后看看完整的代码吧。
#include <Windows.h>#include <string>#include <map>#include <functional>using namespace std;class DllParser{public: DllParser() { } ~DllParser() { UnLoad(); } bool Load(const string& dllPath) { m_hMod = LoadLibrary(dllPath.data()); if (nullptr == m_hMod) { printf("LoadLibrary failed\n"); return false; } return true; } bool UnLoad() { if (m_hMod == nullptr) return true; auto b = FreeLibrary(m_hMod); if (!b) return false; m_hMod = nullptr; return true; } template <typename T> T* GetFunction(const string& funcName) { auto addr = GetProcAddress(m_hMod, funcName.c_str()); return (T*) (addr); } template <typename T, typename... Args> typename std::result_of<std::function<T>(Args...)>::type ExcecuteFunc(const string& funcName, Args&&... args) { auto f = GetFunction<T>(funcName); if (f == nullptr) { string s = "can not find this function " + funcName; throw std::exception(s.c_str()); } return f(std::forward<Args>(args)...); }private: HMODULE m_hMod; std::map<string, FARPROC> m_map;};
- (原创)一个简洁通用的调用DLL函数的帮助类
- 一个简洁通用的调用DLL函数的帮助类
- 一个 ORACLE 调用 DLL 的例子(原创)
- 2010.5.22 写一个通用的字符串帮助类
- 一个高效简洁的Struts分页方法(原创)
- 浅谈JNI的使用--java调用dll(原创)
- 一个通用的存储过程调用类
- 关于Net Advanctage 的一些通用函数(原创)
- 一个简洁的通用前端输入数据校验方法
- java中调用 dll 动态库的简洁方法 JNative
- Java中调用dll动态库的简洁方法
- [原创]如何在Delphi中调用.Net编写的DLL中的函数(Function)、过程(Procedure)
- vb动态加载dll的一个类,实现vb动态加载dll并动态调用dll导出的函数的一个方便办法
- 函数的DLL调用方式
- [.NET]c#调用DLL类中成员函数的一个例子
- 【原创】VS2005调用matlab R2010b生成的DLL
- 一个通用快速的反射方法调用
- 最简洁的日历控件(原创)
- POJ 1176 Party Lamps (DFS)
- xcodex项目配置说明
- 在Linux进行IO的正确姿势
- Cocos2dx一步一步实现Android端热更新(C++)
- STL 算法接口及用法说明
- (原创)一个简洁通用的调用DLL函数的帮助类
- 正确理解ThreadLocal
- android数据存储之SQLite
- Redis和Memcache的区别分析
- Redis中5种数据结构的使用场景介绍
- pdm数据库设计导出excel
- UVa--1636 Headshot(概率)
- collection.toArray(new String[0])中new String[0]的作用
- URL ajax 传递带有特殊符号参数的问题