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)

 

發佈了184 篇原創文章 · 獲贊 110 · 訪問量 40萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章