根本不是什么新技术,也不是什么新应用,只是嫌麻烦,所以……
起因是这样的,用LoadLibrary+GetProcAddress动态调用DLL里的函数已经是很经典的用法了。但是GetProcAddress返回类型是FARPROC,明显没办法适应各种函数的,所以要进行强制转换才行。MSDN上的例子是这样,也是最常见到的写法
typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO); PGNSI pGNSI; pGNSI = (PGNSI) GetProcAddress( GetModuleHandle(TEXT("kernel32.dll")), "GetNativeSystemInfo");
这当然没什么问题,但是那一句typedef挺烦人。为了定义一个函数指针,又多了一种类型出来,对于强迫症的人来说实在有点……
于是呢,typedef其实只是把类型用另一种方式表示而已,所以完全可以不用的。不用的话,代码就变成这样子
void (WINAPI *pGNSI)(LPSYSTEM_INFO); pGNSI = (void (WINAPI *)(LPSYSTEM_INFO)) GetProcAddress( GetModuleHandle(TEXT("kernel32.dll")), "GetNativeSystemInfo");
那一长串的“类型”…………这转换写得有点累人啊。这一个参数的还好,到了CreateRemoteThread啊CreateFile啊CreateProcess啊,写起来实在体力活
HANDLE (WINAPI *pCRT)(HANDLE, LPSECURITY_ATTRIBUTES, SIZE_T, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD); pCRT = (HANDLE (WINAPI *)(HANDLE, LPSECURITY_ATTRIBUTES, SIZE_T, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD)) GetProcAddress(hKernel32, "CreateRemoteThread");
…………(捂脸
因为很麻烦,所以我前前后后用了好多种方式来对付。比如说,C的共用体。
union { HANDLE (WINAPI *pCRT)(HANDLE, LPSECURITY_ATTRIBUTES, SIZE_T, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD); void* val; } u; u.val = GetProcAddress(hKernel32, "CreateRemoteThread");
这样就是用起来的时候,前面还得跟着 u. ,挺烦的。虽然转换是不用转了;
再比如说,C++的模板,
template<class T1, class T2> void AssignFuncPtr(T1& a, T2 b) { a = (T1) b; } ... HANDLE (WINAPI *pCRT)(HANDLE, LPSECURITY_ATTRIBUTES, SIZE_T, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD); AssignFuncPtr(pCRT, GetProcAddress(hKernel32, "CreateRemoteThread"));
稍微舒服了一点,但是前面还得写个模板。
前一段时间,尝试在VC6不装GdiPlus SDK的情况下调用GdiPlus,又遇上了这样的事情。于是,
LRESULT (WINAPI* GdipCreateBitmapFromFile)(LPCWSTR, LPVOID*); void* faddr = GetProcAddress(hGdiPlus, "GdipCreateBitmapFromFile"); memcpy(&GdipCreateBitmapFromFile, &faddr, sizeof(faddr));
已经很舒服了,不需要管类型了?但是一个faddr多出来,而且还要调用memcpy,嗯…………
今天脑子一抽,来了这个
LRESULT (WINAPI* GdipCreateBitmapFromFile)(LPCWSTR, "LPVOID*); *(LPVOID*)&GdipCreateBitmapFromFile" = GetProcAddress(hGdiPlus, "GdipCreateBitmapFromFile");
卧槽老子为什么这么屌(锤锤锤)你转过去很麻烦那我转过去不就得了,因为LPVOID(void*)是接近万能的指针啊