GetProcAddress给函数指针赋值

根本不是什么新技术,也不是什么新应用,只是嫌麻烦,所以……

起因是这样的,用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*)是接近万能的指针啊

发表评论