MS提供如下API:
BOOL WINAPI ReadFileEx( _In_ HANDLE hFile, _Out_opt_ LPVOID lpBuffer, _In_ DWORD nNumberOfBytesToRead, _Inout_ LPOVERLAPPED lpOverlapped, _In_ LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine );如果需要用到完成例程,则需要通过最后一个参数传入有效的回调函数。
再看LPOVERLAPPED_COMPLETION_ROUTINE的定义:
typedef VOID (WINAPI *LPOVERLAPPED_COMPLETION_ROUTINE)( _In_ DWORD dwErrorCode, _In_ DWORD dwNumberOfBytesTransfered, _Inout_ LPOVERLAPPED lpOverlapped );定义一个符合参数约定的回调函数,并作为回调参数传入,发现每次都崩溃,而且是另外一个地方。
咋一看好像是别的地方出了问题,其实奔溃只是调用约定不一致导致调用栈错误的一种表现而已。
真正的原因是:c和c++默认的调用约定是__cdecl,而API要求的是__stdcall。
解决的办法很简单:在回调函数前添加__stdcall关键字,明确指明调用约定就完了。
类似的问题还经常出现在线程函数上。
HANDLE WINAPI CreateThread( _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, _In_ SIZE_T dwStackSize, _In_ LPTHREAD_START_ROUTINE lpStartAddress, _In_opt_ LPVOID lpParameter, _In_ DWORD dwCreationFlags, _Out_opt_ LPDWORD lpThreadId );而LPTHREAD_START_ROUTINE的定义如下:
DWORD WINAPI ThreadProc( _In_ LPVOID lpParameter );总之,碰到所有包含回调函数参数的MS API,大家都要注意了------------ 千万别忘了调用约定。