libusb源码学习:几个函数加载的宏(windows)
首先,我们复习一下C语言中的函数指针:
//C语言中的函数指针
#include <iostream>
// 下面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)