这是输出:
g++ -DDEBUG -DUNITTEST -IC:/Users/Steven/Dropbox/Programming/entropy_p5_makefile/cpp/game/../include/ -O0 -g3 -Wall -c -fmessage-length=0 -o Input.o ..\Input.cpp
..\Input.cpp: In function 'void mousehookCustomRoutine(E_thread*, void*)':
..\Input.cpp:78:93: error: invalid conversion from 'LRESULT (*)(int, WPARAM, LPARAM)' to 'LRESULT (*)(int, WPARAM, LPARAM)'
..\Input.cpp:78:93: error: initializing argument 2 of 'void* SetWindowsHookExA(int, LRESULT (*)(int, WPARAM, LPARAM), HINSTANCE__*, DWORD)'
Build error occurred, build is stopped
这是代码:
LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) {
//...
}
void mousehookCustomRoutine(E_thread *me, void *arg = (void *)&MouseHookProc) {
// arg is the ptr to LL Mouse Routine
me->sendMessage(0x14,me,(void*)GetCurrentThreadId());
// send message to self in order for my parent to know how to identify me via threadID
HHOOK mousehook = SetWindowsHookEx(WH_MOUSE_LL, (LRESULT (*)(int,WPARAM,LPARAM))arg,NULL, 0); // I am line 78
if (mousehook == NULL) printf("Mousehook error %lu\n",GetLastError());
//...
}
这没有任何意义,因为我正在投射到它期望接收的确切类型,没有任何限定符或任何不同的东西。这可能会发生什么?
答案 0 :(得分:3)
编译器忽略了错误消息中的调用约定 - SetWindowsHookEx
想要一个LRESULT (__stdcall *)(int,WPARAM,LPARAM)
,但是你传递的是LRESULT (__cdecl *)(int,WPARAM,LPARAM)
。
答案 1 :(得分:2)
首先,不要将函数指针强制转换为void *
。在将一种类型的函数转换为另一种函数之后调用它是永远不会安全的,因此很少(如果有的话)需要将它们设置为void *
。
其次,你可能会看到调用约定的差异。正确说明了钩子参数的类型(LRESULT (CALLBACK *) (int, WPARAM, LPARAM))
,或简称为HOOKPROC
。函数的原型应该看起来像LRESULT CALLBACK MouseHookProc(int, WPARAM, LPARAM)
。很可能gcc不会打印调用约定说明符,但在检查类型等价时会检查它。像这样的微妙问题是不抛出函数指针的另一个原因 - 如果你使用(HOOKPROC)
强制转换,你就没有编译时错误,但可能在运行时崩溃了...... but only on certain versions of windows。