本文共 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/