У меня есть компонент COM, реализованный на C++ с ATL, который использует ввод-вывод с перекрывающимися сокетами. Сразу после установления соединения с сервером он начинает перекрывающееся чтение сокета с таким кодом:
// Pass pointer to this instance as hEvent parameter, for use by callback
m_recvOverlapped.hEvent = reinterpret_cast<HANDLE>(this);
int rc = ::WSARecv(m_s, &wsabuf, 1, &m_recvNumberOfBytes, &m_recvFlags, &m_recvOverlapped, RecvCallback);
if (rc == SOCKET_ERROR)
{
// If error is WSA_IO_PENDING, then the I/O is still in progress. Otherwise, something bad happened.
int error = ::WSAGetLastError();
if (error != WSA_IO_PENDING)
{
ReceiveError(error);
}
}
И у меня есть функция обратного вызова, которая выглядит примерно так:
void CALLBACK CMySocket::RecvCallback(DWORD dwError, DWORD cbTransferred, LPWSAOVERLAPPED lpOverlapped, DWORD dwFlags)
{
CMySocket* socket = reinterpret_cast<CMySocket*>(lpOverlapped->hEvent);
ATLASSERT(socket != 0);
if (!socket)
return;
socket->ReceiveCompleted(dwError, cbTransferred, lpOverlapped, dwFlags);
}
Этот COM-компонент отлично работает в модульных тестах, при использовании в приложении командной строки и при использовании в приложении .NET GUI (через COM-взаимодействие). Однако, когда я использую этот компонент в приложении MFC, RecvCallback
никогда не вызывается, когда сервер отправляет ему данные.
WSARecv()
возвращает SOCKET_ERROR
, а WSAGetLastError()
возвращает WSA_IO_PENDING
, как и ожидалось для асинхронного чтения с перекрытием.
Когда я использую приложение SysInternals TcpView для наблюдения за происходящим, оно указывает, что клиент получает данные. Но обратный вызов никогда не вызывается.
Отправка данных на сервер через подключенный сокет работает нормально.
Я вызываю CoInitializeEx()
и WSAStartup()
в методе InitInstance()
моего приложения MFC.
Любые идеи?