起因

开发中经常需要动态调用一些导出函数,试着利用C++11特性封装一下

尝试

常规使用

typedef int WINAPI (*TMessageBoxA)(HWND hWnd,LPCSTR lpText,LPCSTR lpCaption,UINT uType);
if (HMODULE m = LoadLibraryA("user32")) {
if (FARPROC proc = GetProcAddress(m,"MessageBoxA")) {
TMessageBoxA msgBox = reinterpret_cast<TMessageBoxA>(fn);
msgBox(0,0,0,0); // call it ...
}
FreeLibrary(m);
}

流程很清晰,只是写多了看着不爽

曾经利用 decltype function bind 实现过另个版本,这次尝试更纯粹一些

解决

参考std::function实现方式,仅使用"Variadic Templates"

#include <windows.h>

template<typename _T> class Api;
template<typename _Res, typename... _ArgTypes>
class Api<_Res(_ArgTypes...)> {
public:
Api(const char* dllName, const char* funcName) {
_M_module = LoadLibraryA(dllName);
_M_func = reinterpret_cast<_Func>(GetProcAddress(_M_module, funcName));
}
~Api() {
if (_M_module) FreeLibrary(_M_module);
}
_Res operator()(_ArgTypes... __args) const {
return _M_func(__args...);
}
private:
typedef _Res (*_Func)(_ArgTypes...);
_Func _M_func;
HMODULE _M_module;
}; int main()
{
Api<int(HWND,LPCTSTR,LPCTSTR,UINT)> msgbox("user32", "MessageBoxA");
msgbox(0,0,0,0);
}

注意,为了最小利用特性,这里没有利用final、delete进行使用限制,也没有对HMODULE进行缓存管理,生产环境请自行抉择。

有更好的方式,请留言交流;-)

还是附上另一种更常用的方法

#include <map>
#include <string>
#include <functional>
#include <windows.h> class WinDll {
public:
WinDll(const char* dll) {
mMoudle = LoadLibraryA(dll);
}
WinDll(const wchar_t* dll) {
mMoudle = LoadLibraryW(dll);
}
~WinDll() {
if (mMoudle) FreeLibrary(mMoudle);
} FARPROC RawApi(const std::string& fn) {
auto it = mFuncCaches.find(fn);
if (it == mFuncCaches.end()) {
FARPROC func = GetProcAddress(mMoudle, fn.c_str());
if (!func) throw "not found!";
mFuncCaches[fn] = func;
return func;
}
return it->second;
} template<typename _T>
std::function<_T> ApiFunc(const std::string& fn) {
return std::function<_T>(reinterpret_cast<_T*>(RawApi(fn)));
} private:
HMODULE mMoudle;
std::map<std::string,FARPROC> mFuncCaches;
}; int main()
{
WinDll user32("user32");
using TMessageBoxA = int(HWND,LPCTSTR,LPCTSTR,UINT);
auto msgBox = user32.ApiFunc<TMessageBoxA>("MessageBoxA");
msgBox(0,0,0,0);
}

利用C++11可变模板,封装调用dll导出函数的更多相关文章

  1. python利用or在列表解析中调用多个函数.py

    python利用or在列表解析中调用多个函数.py """ python利用or在列表解析中调用多个函数.py 2016年3月15日 05:08:42 codegay & ...

  2. DLL模块例1:使用.def模块导出函数,规范修饰名称,显示连接调用dll中函数

    以下内容,我看了多篇文章,整合在一起,写的一个例子,关于dll工程的创建,请参考博客里另一篇文章:http://www.cnblogs.com/pingge/articles/3153571.html ...

  3. AFX_MANAGE_STATE(AfxGetStaticModuleState())DLL导出函数包含MFC资源

    AFX_MANAGE_STATE(AfxGetStaticModuleState()) 先看一个例子: .创建一个动态链接到MFC DLL的规则DLL,其内部包含一个对话框资源.指定该对话框ID如下: ...

  4. dll 导出函数名的那些事

    dll 导出函数名的那些事 关键字: VC++  DLL  导出函数 经常使用VC6的Dependency或者是Depends工具查看DLL导出函数的名字,会发现有DLL导出函数的名字有时大不相同,导 ...

  5. C# 遍历DLL导出函数

    C#如何去遍历一个由C++或E语言编写的本地DLL导出函数呢 不过在这里我建议对PE一无所知的人 你或许应先补补这方面的知识,我不知道为什么PE方面的 应用在C#中怎么这么少,我查阅过相关 C#的知识 ...

  6. Dll 导出函数那些破事

    经常使用VC6的Dependency查看DLL导出函数的名字,会发现有DLL导出函数的名字有时大不相同,导致不同的原因大多是和编译DLL时候指定DLL导出函数的界定符有关系. VC++支持两种语言:即 ...

  7. DLL导出函数和类的定义区别 __declspec(dllexport)

    DLL导出函数和类的定义区别 __declspec(dllexport) 是有区别的, 请看 : //定义头文件的使用方,是导出还是导入 #if defined(_DLL_API) #ifndef D ...

  8. dll导出函数的两种方式的比较

    最初的网页链接已经挂了, 在此贴一个中间的转载链接 https://blog.csdn.net/zhazhiqiang/article/details/51577523 一 概要 vs中导出 dll的 ...

  9. DLL导出函数

    使用DEF文件从DLL导出 模块定义(.def)文件时包含一个或多个描述DLL各种属性的Module语句的文本文件.如果不使用_declspec(dllexport)关键字导出DLL的函数,则DLL需 ...

随机推荐

  1. Golang获取CPU、内存、硬盘使用率

    Golang获取CPU.内存.硬盘使用率 工具包 go get github.com/shirou/gopsutil 实现 func GetCpuPercent() float64 { percent ...

  2. Terraform插件Provider管理,搜索、定义、下载

    我最新最全的文章都在南瓜慢说 www.pkslow.com,欢迎大家来喝茶! 简介 最近工作中用到了Terraform,权当学习记录一下,希望能帮助到其它人. Terraform系列文章如下: Ter ...

  3. 【春节歌曲回味 | STM32小音乐盒 】PWM+定时器驱动无源蜂鸣器(STM32 HAL库)

    l  STM32通过PWM与定时器方式控制无源蜂鸣器鸣响 l  STM32小音乐盒,歌曲进度条图形显示与百分比显示,歌曲切换 l  编程使用STM32 HAL库 l  IIC OLED界面编程,动画实 ...

  4. Cobra框架使用手册

    cobra框架使用手册 cobra是go语言的一个库,可以用于编写命令行工具. 概念 Cobra 结构由三部分组成:命令 (commands).参数 (arguments).标志 (flags).最好 ...

  5. 不藏了,这些Java反射用法总结都告诉你们

    摘要:Java反射是一种非常强大的机制,它可以在同一个系统中去检测内部的类的字段.方法和构造函数.它非常多的Java框架中,都大量应用了反射技术,如Hibernate和Spring.可以说,反射机制的 ...

  6. Tomcat 中文乱码,设置UTF-8

    1.修改tomcat的conf目录下 server.xml文件加上 URIEncoding="UTF-8" <Connector port="8080" ...

  7. redis-cluster集群安装(windows)

    在此先奉上安装包(链接:https://pan.baidu.com/s/1QHYQPkYPuiRWhdj9APbjnw 提取码:jv8x ) 1. 安装ruby 下载 rubyinstaller-2. ...

  8. hadoop学习(二)hadoop集群的启动

    一.完全分布式集群环境的搭建 1.配置hosts文件:将三台集群服务器的主机名与IP的对应关系互相配置到对方的hosts文件中,以便对方服务器能通过主机名寻找IP,hosts文件在/etc目录下. 2 ...

  9. Centos中安装Node.Js

    NodeJs安装有好几种方式: 第一种: 最简单的是用yum命令,可惜我现在用的时候 发现 镜像中没有nodejs:所以这种方式放弃: 第二种:去官网下载源码,然后自己编译:编译过程中可能会出现问题, ...

  10. 安卓开发--探究碎片Fragment

    简述: 最近做开发的时候又遇到了Fragment,发现太久没写,都快忘了,就抓紧写个笔记(我太懒的了233) Fragment可以简单的看成迷你的活动,它和活动一样都有布局和生命周期,它可以嵌入活动之 ...