博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
libusb源码学习:几个函数加载的宏(windows)
阅读量:4181 次
发布时间:2019-05-26

本文共 4778 字,大约阅读时间需要 15 分钟。

首先,我们复习一下C语言中的函数指针:

//C语言中的函数指针#include 
// 下面typeFunc就一个函数指针,指向的函数类型 f 为// void f(void)typedef void (*typeFunc)(void);void realFunc(void) { std::cout << "test" << std::endl;}int main() { typeFunc myf = realFunc; myf(); // 相当于调用realFunc(); return 0;}

然后我们看一下libusb中定义的那几个宏

/* * Macros for handling functions within a DLL */#define DLL_FUNC_NAME(name) __dll_##name##_func_t#define DLL_DECLARE_FUNC_PREFIXNAME(api, ret, prefixname, name, args)	\	typedef ret (api * DLL_FUNC_NAME(name))args;			\	static DLL_FUNC_NAME(name) prefixname = NULL#define DLL_DECLARE_FUNC(api, ret, name, args)				\	DLL_DECLARE_FUNC_PREFIXNAME(api, ret, name, name, args)#define DLL_DECLARE_FUNC_PREFIXED(api, ret, prefix, name, args)		\	DLL_DECLARE_FUNC_PREFIXNAME(api, ret, prefix##name, name, args)#define DLL_LOAD_FUNC_PREFIXNAME(dll, prefixname, name, ret_on_failure)	\	do {								\		HMODULE h = DLL_HANDLE_NAME(dll);			\		prefixname = (DLL_FUNC_NAME(name))GetProcAddress(h,	\				DLL_STRINGIFY(name));			\		if (prefixname)						\			break;						\		prefixname = (DLL_FUNC_NAME(name))GetProcAddress(h,	\				DLL_STRINGIFY(name) DLL_STRINGIFY(A));	\		if (prefixname)						\			break;						\		prefixname = (DLL_FUNC_NAME(name))GetProcAddress(h,	\				DLL_STRINGIFY(name) DLL_STRINGIFY(W));	\		if (prefixname)						\			break;						\		if (ret_on_failure)					\			return FALSE;					\	} while (0)#define DLL_LOAD_FUNC(dll, name, ret_on_failure)			\	DLL_LOAD_FUNC_PREFIXNAME(dll, name, name, ret_on_failure)#define DLL_LOAD_FUNC_PREFIXED(dll, prefix, name, ret_on_failure)	\	DLL_LOAD_FUNC_PREFIXNAME(dll, prefix##name, name, ret_on_failure)

我们发现,本来调用的函数名称如:SetupDiGetClassDevsA,

现在统统都加上了指针前缀,变成:pSetupDiGetClassDevsA

这些函数是在windows_usb.h中定义的,展开其中的一个定义,过程如下,

DLL_DECLARE_FUNC_PREFIXED(WINAPI, HDEVINFO, p, SetupDiGetClassDevsA, (LPCGUID, PCSTR, HWND, DWORD));

<==等价于==>
DLL_DECLARE_FUNC_PREFIXNAME(WINAPI, HDEVINFO, pSetupDiGetClassDevsA, SetupDiGetClassDevsA, (LPCGUID, PCSTR, HWND, DWORD))
<==等价于==>
typedef HDEVINFO (WINAPI * __dll_SetupDiGetClassDevsA_func_t)(LPCGUID, PCSTR, HWND, DWORD);
static __dll_SetupDiGetClassDevsA_func_t pSetupDiGetClassDevsA = NULL

就是说,

pSetupDiGetClassDevsA相当于定义了一个函数指针,类型为__dll_SetupDiGetClassDevsA_func_t的变量:

问题是,__dll_SetupDiGetClassDevsA_func_t这个函数指针类型是在哪里定义的呢?

static BOOL init_dlls(void){	DLL_GET_HANDLE(Cfgmgr32);	DLL_LOAD_FUNC(Cfgmgr32, CM_Get_Parent, TRUE);	DLL_LOAD_FUNC(Cfgmgr32, CM_Get_Child, TRUE);	// Prefixed to avoid conflict with header files	DLL_GET_HANDLE(AdvAPI32);	DLL_LOAD_FUNC_PREFIXED(AdvAPI32, p, RegQueryValueExW, TRUE);	DLL_LOAD_FUNC_PREFIXED(AdvAPI32, p, RegCloseKey, TRUE);	DLL_GET_HANDLE(OLE32);	DLL_LOAD_FUNC_PREFIXED(OLE32, p, IIDFromString, TRUE);	DLL_GET_HANDLE(SetupAPI);	DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetClassDevsA, TRUE);	DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiEnumDeviceInfo, TRUE);	DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiEnumDeviceInterfaces, TRUE);	DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetDeviceInstanceIdA, TRUE);	DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetDeviceInterfaceDetailA, TRUE);	DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetDeviceRegistryPropertyA, TRUE);	DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiDestroyDeviceInfoList, TRUE);	DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiOpenDevRegKey, TRUE);	DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiOpenDeviceInterfaceRegKey, TRUE);	return TRUE;}

其中,DLL_GET_HANLE相当于LoadLibraryA(),

#define DLL_GET_HANDLE(name)					\	do {							\		DLL_HANDLE_NAME(name) = DLL_LOAD_LIBRARY(name);	\		if (!DLL_HANDLE_NAME(name))			\			return FALSE;				\	} while (0)//API macros - leveraged from libusb-win32 1.x#ifndef _WIN32_WCE#define DLL_STRINGIFY(s) #s  //把传入的名称字符串化:名称变成字符串)#define DLL_LOAD_LIBRARY(name) LoadLibraryA(DLL_STRINGIFY(name))#else#define DLL_STRINGIFY(s) L#s#define DLL_LOAD_LIBRARY(name) LoadLibrary(DLL_STRINGIFY(name))#endif

核心是这个DLL_LOAD_FUNC_PREFIXED的定义;在这里定义了类型为__dll_SetupDiGetClassDevsA_func_t的变量pSetupDiGetClassDevsA,并且其函数地址为GetProcAddress(h, "SetupDiGetClassDevsA");

其相应的宏展开过程如下所示,

DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetClassDevsA, TRUE);<==eqivalent to ==>DLL_LOAD_FUNC_PREFIXNAME(SetupAPI, pSetupDiGetClassDevsA, SetupDiGetClassDevsA, TRUE)	\	do {		HMODULE h = DLL_HANDLE_NAME(SetupAPI);		pSetupDiGetClassDevsA = (DLL_FUNC_NAME(SetupDiGetClassDevsA))GetProcAddress(h,				DLL_STRINGIFY(SetupDiGetClassDevsA));		if (pSetupDiGetClassDevsA)			break;		pSetupDiGetClassDevsA = (DLL_FUNC_NAME(SetupDiGetClassDevsA))GetProcAddress(h,				DLL_STRINGIFY(SetupDiGetClassDevsA) DLL_STRINGIFY(A));		if (pSetupDiGetClassDevsA)			break;		pSetupDiGetClassDevsA = (DLL_FUNC_NAME(SetupDiGetClassDevsA))GetProcAddress(h,				DLL_STRINGIFY(SetupDiGetClassDevsA) DLL_STRINGIFY(W));		if (pSetupDiGetClassDevsA)			break;		if (TRUE)			return FALSE;	} while (0)

 

转载地址:http://spwoi.baihongyu.com/

你可能感兴趣的文章
evacuate-instance-automatically
查看>>
pycharm常用设置(keymap设置及eclipse常用快捷键总结)
查看>>
关于在openstack的环境变量.bashrc自定自己简化命令
查看>>
Openstack Heat Project介绍(转)
查看>>
How to Perform an Upgrade from Icehouse to Juno(ice升级到juno)
查看>>
高扩展性网站的50条原则(转)-思维导图
查看>>
解决openstack novnc一段时间后自动挂断登录不上问题,novncproxy dead but pid file exists
查看>>
构建OpenStack的云基础架构:ManageIQ(转)
查看>>
云管理软件 ManageIQ(转)
查看>>
CentOS 7.0,启用iptables防火墙(转)
查看>>
svn忽略ignore文件记住方式(转)
查看>>
web缓存相关知识(转)
查看>>
Understanding Spring MVC Model and Session Attributes
查看>>
Spring MVC中Session的正确用法之我见(转)
查看>>
Spring2.5 访问 Session 属性的四种策略
查看>>
Spring MVC 3.0 深入及对注解的详细讲解(转)
查看>>
ModelMap和ModelAndView的作用(转)
查看>>
DISCUZ浅析之COOKIE篇
查看>>
实战DDD(Domain-Driven Design领域驱动设计:Evans DDD)
查看>>
SSH中各个框架的作用以及Spring AOP,IOC,DI详解
查看>>