Windows2003-3790/enduser/netmeeting/av/rrcm/rtp/ws2emul.cpp
2020-09-30 16:53:55 +02:00

841 lines
20 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <rrcm.h>
#include <queue.h>
// Forward declarations
DWORD WINAPI WS1MsgThread (LPVOID );
LRESULT CALLBACK WS1WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
BOOL StartWS1MsgThread();
BOOL StopWS1MsgThread();
void __stdcall SendRecvCompleteAPC(ULONG_PTR dw);
class CWS2EmulSock;
#define WM_WSA_READWRITE (WM_USER + 100)
// structure used to store WSASendTo/WSARecvFrom parameters
struct WSAIOREQUEST {
WSAOVERLAPPED *pOverlapped;
WSABUF wsabuf[2];
DWORD dwBufCount;
union {
struct {
struct sockaddr *pRecvFromAddr;
LPINT pRecvFromLen;
};
struct sockaddr SendToAddr;
};
};
// global Winsock emulation state
struct WS2Emul {
#define MAX_EMUL_SOCKETS 10
CWS2EmulSock *m_pEmulSocks[MAX_EMUL_SOCKETS];
int numSockets;
HWND hWnd;
HANDLE hMsgThread;
HANDLE hAckEvent;
// external crit sect serializes the WS2EmulXX apis
// to make them multi-thread safe
CRITICAL_SECTION extcs;
// internal crit sect serializes access between
// MsgThread and WS2EmulXX apis
// Never claim extcs while holding intcs.
// (Is there a more elegant way to do this?)
CRITICAL_SECTION intcs;
} g_WS2Emul;
/*
CWS2EmulSock -
WS2 socket emulation class
Manages queues of overlapped i/o requests
*/
class CWS2EmulSock
{
public:
CWS2EmulSock(int myIndex) : m_myIndex(myIndex), m_RecvThreadId(0),m_SendThreadId(0),
m_hRecvThread(NULL), m_hSendThread(NULL), m_sock(INVALID_SOCKET)
{ ZeroMemory(&m_SendOverlapped, sizeof(m_SendOverlapped));}
;
BOOL NewSock(int af, int type, int protocol);
int Close();
int RecvFrom(
LPWSABUF lpBuffers,DWORD dwBufferCount, LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags,
struct sockaddr FAR * lpFrom, LPINT lpFromlen,
LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
int SendTo(
LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesSent,DWORD dwFlags,
const struct sockaddr FAR * lpTo, int iTolen,
LPWSAOVERLAPPED lpOverlapped,LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
LRESULT HandleMessage(WPARAM wParam, LPARAM lParam); // WS1 window msg handler
SOCKET GetSocket() { return m_sock;}
WSAOVERLAPPED *GetSendOverlapped() {return &m_SendOverlapped;}
private:
SOCKET m_sock; // real socket handle
int m_myIndex; // fake socket handle
QueueOf<WSAIOREQUEST> m_RecvQ; // queue of overlapped recv requests
QueueOf<WSAIOREQUEST> m_SendQ; // queue of overlapped send requests
WSAOVERLAPPED m_SendOverlapped; // used only for synchronous send calls
// the following fields are used to issue Send/Recv APCs
DWORD m_RecvThreadId;
DWORD m_SendThreadId;
HANDLE m_hRecvThread; // thread issuing receive requests
HANDLE m_hSendThread; // thread issuing send requests
};
void WS2EmulInit()
{
InitializeCriticalSection(&g_WS2Emul.extcs);
InitializeCriticalSection(&g_WS2Emul.intcs);
}
void WS2EmulTerminate()
{
DeleteCriticalSection(&g_WS2Emul.extcs);
DeleteCriticalSection(&g_WS2Emul.intcs);
}
BOOL
CWS2EmulSock::NewSock(int af,int type, int protocol)
{
m_sock = socket(af,type,protocol);
if (m_sock != INVALID_SOCKET)
{
WSAAsyncSelect(m_sock, g_WS2Emul.hWnd, WM_WSA_READWRITE+m_myIndex, FD_READ|FD_WRITE);
}
return m_sock != INVALID_SOCKET;
}
int
CWS2EmulSock::RecvFrom(
LPWSABUF lpBuffers,
DWORD dwBufferCount,
LPDWORD lpNumberOfBytesRecvd,
LPDWORD lpFlags,
struct sockaddr FAR * lpFrom,
LPINT lpFromlen,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{
WSAIOREQUEST ioreq;
int error = 0;
if (lpCompletionRoutine) {
DWORD thid = GetCurrentThreadId();
HANDLE hCurProcess;
if (thid != m_RecvThreadId) {
// need to create a thread handle for QueueUserAPC
// typically this will only happen once
if (!m_RecvQ.IsEmpty())
{
// dont allow simultaneous recv access by more than one thread
error = WSAEINVAL;
}
else
{
if (m_hRecvThread)
CloseHandle(m_hRecvThread);
m_hRecvThread = NULL;
hCurProcess = GetCurrentProcess();
m_RecvThreadId = thid;
if (!DuplicateHandle(
hCurProcess, // handle to process with handle to duplicate
GetCurrentThread(), // handle to duplicate
hCurProcess, // handle to process to duplicate to
&m_hRecvThread, // pointer to duplicate handle
0, // access for duplicate handle
FALSE, // handle inheritance flag
DUPLICATE_SAME_ACCESS // optional actions
))
{
error = WSAEINVAL;
m_RecvThreadId = 0;
}
}
}
}
if (error || dwBufferCount != 1 || !lpOverlapped)
{
WSASetLastError(WSAENOBUFS);
return SOCKET_ERROR;
}
ioreq.pOverlapped = lpOverlapped;
if (lpOverlapped) // cache away ptr to completion routine
lpOverlapped->Pointer = lpCompletionRoutine;
ioreq.pRecvFromAddr = lpFrom;
ioreq.pRecvFromLen = lpFromlen;
ioreq.wsabuf[0] = lpBuffers[0];
ioreq.dwBufCount = dwBufferCount;
m_RecvQ.Put(ioreq);
//LOG((LOGMSG_RECVFROM1,(UINT)lpOverlapped));
// signal WS1 send/recv thread
PostMessage(g_WS2Emul.hWnd, WM_WSA_READWRITE+m_myIndex, m_sock, FD_READ);
WSASetLastError(ERROR_IO_PENDING);
return SOCKET_ERROR;
}
int CWS2EmulSock::SendTo(
LPWSABUF lpBuffers,
DWORD dwBufferCount,
LPDWORD lpNumberOfBytesSent,
DWORD dwFlags,
const struct sockaddr FAR * lpTo,
int iTolen,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{
WSAIOREQUEST ioreq;
int error = 0;
if (lpCompletionRoutine) {
DWORD thid = GetCurrentThreadId();
HANDLE hCurProcess;
if (thid != m_SendThreadId) {
// need to create a thread handle for QueueUserAPC
if (!m_SendQ.IsEmpty())
{
// dont allow simultaneous send access by more than one thread
error = WSAEINVAL;
}
else
{
if (m_hSendThread)
CloseHandle(m_hSendThread);
m_hSendThread = NULL;
hCurProcess = GetCurrentProcess();
m_SendThreadId = thid;
if (!DuplicateHandle(
hCurProcess, // handle to process with handle to duplicate
GetCurrentThread(), // handle to duplicate
hCurProcess, // handle to process to duplicate to
&m_hSendThread, // pointer to duplicate handle
0, // access for duplicate handle
FALSE, // handle inheritance flag
DUPLICATE_SAME_ACCESS // optional actions
))
{
error = WSAEINVAL;
m_SendThreadId = 0;
}
}
}
}
if (error || dwBufferCount != 1 || iTolen != sizeof(struct sockaddr) || !lpOverlapped)
{
WSASetLastError(WSAEINVAL);
return SOCKET_ERROR;
}
ioreq.pOverlapped = lpOverlapped;
if (lpOverlapped) // cache away ptr to completion routine
lpOverlapped->Pointer = lpCompletionRoutine;
ioreq.SendToAddr = *lpTo;
ioreq.wsabuf[0] = lpBuffers[0];
ioreq.dwBufCount = dwBufferCount;
m_SendQ.Put(ioreq);
// signal WS1 send/recv thread
PostMessage(g_WS2Emul.hWnd, WM_WSA_READWRITE+m_myIndex, m_sock, FD_WRITE);
WSASetLastError(ERROR_IO_PENDING);
return SOCKET_ERROR;
}
/*
Close - close the socket and cancel pending i/o
*/
int
CWS2EmulSock::Close()
{
WSAIOREQUEST ioreq;
int status;
status = closesocket(m_sock);
m_sock = NULL;
while (m_SendQ.Get(&ioreq))
{
// complete the request
ioreq.pOverlapped->Internal = WSA_OPERATION_ABORTED;
// if there is a callback routine, its address is cached in pOverlapped->Offset
if (ioreq.pOverlapped->Pointer)
{
QueueUserAPC(SendRecvCompleteAPC,m_hSendThread,(DWORD_PTR)ioreq.pOverlapped);
}
else
{
SetEvent((HANDLE)ioreq.pOverlapped->hEvent);
}
}
while (m_RecvQ.Get(&ioreq))
{
// complete the request
ioreq.pOverlapped->Internal = WSA_OPERATION_ABORTED;
if (ioreq.pOverlapped->Pointer)
{
QueueUserAPC(SendRecvCompleteAPC,m_hRecvThread,(DWORD_PTR)ioreq.pOverlapped);
}
else
{
SetEvent((HANDLE)ioreq.pOverlapped->hEvent);
}
}
if (m_hSendThread)
{
CloseHandle(m_hSendThread);
m_hSendThread = NULL;
}
if (m_hRecvThread)
{
CloseHandle(m_hRecvThread);
m_hRecvThread = NULL;
}
return 0;
}
LRESULT
CWS2EmulSock::HandleMessage(WPARAM sock, LPARAM lParam)
{
WORD wEvent= (WSAGETSELECTEVENT(lParam));
WORD wError= (WSAGETSELECTERROR(lParam));
int iRet;
int status;
WSAIOREQUEST ioreq;
HANDLE hThread;
// make sure the message is intended for this socket
if ((SOCKET) sock != m_sock)
return 0;
// get the first RecvFrom or SendTo request, but leave it on the queue
// in case the request blocks
//if (wEvent == FD_READ)
// LOG((LOGMSG_ONREAD1, (UINT)sock));
if (wEvent == FD_READ && m_RecvQ.Peek(&ioreq))
{
//LOG((LOGMSG_ONREAD2, (UINT)ioreq.pOverlapped));
iRet = recvfrom(m_sock, ioreq.wsabuf[0].buf, ioreq.wsabuf[0].len, 0, ioreq.pRecvFromAddr, ioreq.pRecvFromLen);
}
else if (wEvent == FD_WRITE && m_SendQ.Peek(&ioreq))
{
iRet = sendto(m_sock, ioreq.wsabuf[0].buf, ioreq.wsabuf[0].len, 0, &ioreq.SendToAddr, sizeof(ioreq.SendToAddr));
}
else // some other event or no queued request
return 1;
// complete send and recv
if(iRet >=0)
{
status = 0;
ioreq.pOverlapped->InternalHigh = iRet; // numBytesReceived
} else {
// error (or "would block") case falls out here
ASSERT(iRet == SOCKET_ERROR);
status = WSAGetLastError();
ioreq.pOverlapped->InternalHigh = 0;
}
// check the error - it could be blocking
if (status != WSAEWOULDBLOCK)
{
ioreq.pOverlapped->Internal = status;
// pull request off the queue
if (wEvent == FD_READ)
{
m_RecvQ.Get(NULL);
hThread = m_hRecvThread;
//LOG((LOGMSG_ONREADDONE1, (UINT)ioreq.pOverlapped));
}
else // wEvent == FD_WRITE
{
m_SendQ.Get(NULL);
hThread = m_hSendThread;
}
// complete the request
if (ioreq.pOverlapped->Pointer)
{
// if there is a callback routine, its address is cached in pOverlapped->Offset
QueueUserAPC(SendRecvCompleteAPC,hThread, (DWORD_PTR)ioreq.pOverlapped);
}
else
{
SetEvent((HANDLE)ioreq.pOverlapped->hEvent);
}
}
return 1;
}
void __stdcall
SendRecvCompleteAPC(ULONG_PTR dw)
{
WSAOVERLAPPED *pOverlapped = (WSAOVERLAPPED *)dw;
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
= (LPWSAOVERLAPPED_COMPLETION_ROUTINE) pOverlapped->Pointer;
//LOG((LOGMSG_RECVFROM2,(UINT)pOverlapped));
lpCompletionRoutine((DWORD)pOverlapped->Internal, (DWORD)pOverlapped->InternalHigh, pOverlapped, 0);
}
inline
CWS2EmulSock *
EmulSockFromSocket(SOCKET s)
{
return ( ((UINT) s < MAX_EMUL_SOCKETS) ? g_WS2Emul.m_pEmulSocks[s] : NULL);
}
inline SOCKET MapSocket(SOCKET s)
{
return (((UINT) s < MAX_EMUL_SOCKETS) && g_WS2Emul.m_pEmulSocks[s] ? g_WS2Emul.m_pEmulSocks[s]->GetSocket() : INVALID_SOCKET);
}
SOCKET
PASCAL
WS2EmulSocket(
int af,
int type,
int protocol,
LPWSAPROTOCOL_INFO lpProtocolInfo,
GROUP,
DWORD)
{
SOCKET s = INVALID_SOCKET;
int i;
CWS2EmulSock *pESock;
if (g_WS2Emul.numSockets == MAX_EMUL_SOCKETS)
return s;
EnterCriticalSection(&g_WS2Emul.extcs);
if (af == FROM_PROTOCOL_INFO)
af = lpProtocolInfo->iAddressFamily;
if (type == FROM_PROTOCOL_INFO)
type = lpProtocolInfo->iSocketType;
if (protocol == FROM_PROTOCOL_INFO)
protocol = lpProtocolInfo->iProtocol;
for (i=0;i<MAX_EMUL_SOCKETS;i++)
{
if (g_WS2Emul.m_pEmulSocks[i] == NULL)
{
pESock = new CWS2EmulSock(i);
if (pESock) {
if (++g_WS2Emul.numSockets == 1)
{
StartWS1MsgThread();
}
if (pESock->NewSock(af,type,protocol))
{
g_WS2Emul.m_pEmulSocks[i] = pESock;
s = (SOCKET)i;
} else {
delete pESock;
if (--g_WS2Emul.numSockets == 0)
{
StopWS1MsgThread();
}
}
}
break;
}
}
LeaveCriticalSection(&g_WS2Emul.extcs);
return s;
}
int
PASCAL
WS2EmulRecvFrom(
SOCKET s,
LPWSABUF lpBuffers,
DWORD dwBufferCount,
LPDWORD lpNumberOfBytesRecvd,
LPDWORD lpFlags,
struct sockaddr FAR * lpFrom,
LPINT lpFromlen,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
)
{
CWS2EmulSock *pESock;
int iret;
EnterCriticalSection(&g_WS2Emul.extcs);
if (pESock = EmulSockFromSocket(s))
{
EnterCriticalSection(&g_WS2Emul.intcs);
iret = pESock->RecvFrom(lpBuffers, dwBufferCount, lpNumberOfBytesRecvd,
lpFlags,
lpFrom, lpFromlen,
lpOverlapped, lpCompletionRoutine);
LeaveCriticalSection(&g_WS2Emul.intcs);
}
else
{
WSASetLastError(WSAENOTSOCK);
iret = SOCKET_ERROR;
}
LeaveCriticalSection(&g_WS2Emul.extcs);
return iret;
}
/*----------------------------------------------------------------------------
* Function: WS2EmulSendCB
* Description: private Winsock callback
* This is only called if WS2EmulSendTo is called in synchronous mode
* (i.e.) lpOverlapped == NULL. In that case, the sync call is converted to async
* using a private Overlapped struct, and the WS2EmulSendTo api blocks until
* this routine sets the hEvent field to TRUE;
* Input:
*
* Return: None
*--------------------------------------------------------------------------*/
void CALLBACK WS2EmulSendCB (DWORD dwError,
DWORD cbTransferred,
LPWSAOVERLAPPED lpOverlapped,
DWORD dwFlags)
{
lpOverlapped->Internal = dwError;
lpOverlapped->InternalHigh = cbTransferred;
lpOverlapped->hEvent = (WSAEVENT) TRUE;
}
int
PASCAL
WS2EmulSendTo(
SOCKET s,
LPWSABUF lpBuffers,
DWORD dwBufferCount,
LPDWORD lpNumberOfBytesSent,
DWORD dwFlags,
const struct sockaddr FAR * lpTo,
int iTolen,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
)
{
CWS2EmulSock *pESock;
int iret;
BOOL fSync = FALSE;
EnterCriticalSection(&g_WS2Emul.extcs);
if (pESock = EmulSockFromSocket(s))
{
if (!lpOverlapped)
{
// synchronous call - we use our own overlapped struct to issue the
// send request.
lpOverlapped = pESock->GetSendOverlapped();
lpOverlapped->hEvent = (WSAEVENT) FALSE; // will be set to TRUE in Callback
lpCompletionRoutine = &WS2EmulSendCB;
fSync = TRUE;
}
EnterCriticalSection(&g_WS2Emul.intcs);
iret = pESock->SendTo(lpBuffers, dwBufferCount, lpNumberOfBytesSent,
dwFlags,
lpTo, iTolen,
lpOverlapped, lpCompletionRoutine);
LeaveCriticalSection(&g_WS2Emul.intcs);
if (fSync) {
DWORD dwError;
if (iret == SOCKET_ERROR)
{
dwError = WSAGetLastError();
if (dwError != WSA_IO_PENDING) {
// there was an error so there will not be a callback
lpOverlapped->hEvent = (WSAEVENT) TRUE;
lpOverlapped->Internal = dwError;
}
}
// wait for the call to complete
// WS2EmulSendCB sets the hEvent field to TRUE and sets the Internal field to
// the completion status
while (!lpOverlapped->hEvent)
{
dwError =SleepEx(5000,TRUE); // WARNING: sleeping inside a Critical Section
ASSERT(dwError == WAIT_IO_COMPLETION);
}
WSASetLastError((int)lpOverlapped->Internal);
if (lpNumberOfBytesSent)
*lpNumberOfBytesSent = (DWORD)lpOverlapped->InternalHigh;
iret = lpOverlapped->Internal ? SOCKET_ERROR : 0;
}
}
else
{
WSASetLastError(WSAENOTSOCK);
iret = SOCKET_ERROR;
}
LeaveCriticalSection(&g_WS2Emul.extcs);
return iret;
}
int
PASCAL
WS2EmulCloseSocket(SOCKET s)
{
CWS2EmulSock *pESock;
int iret;
EnterCriticalSection(&g_WS2Emul.extcs);
if (pESock = EmulSockFromSocket(s))
{
// shut out access to this socket
// by the MsgThread
EnterCriticalSection(&g_WS2Emul.intcs);
g_WS2Emul.m_pEmulSocks[s] = NULL;
pESock->Close();
delete pESock;
LeaveCriticalSection(&g_WS2Emul.intcs);
if (--g_WS2Emul.numSockets == 0)
{
// cant stop the thread with while holding intcs
StopWS1MsgThread();
}
iret = 0;
}
else
{
WSASetLastError(WSAENOTSOCK);
iret = SOCKET_ERROR;
}
LeaveCriticalSection(&g_WS2Emul.extcs);
return iret;
}
int
PASCAL
WS2EmulSetSockOpt(
SOCKET s, int level,int optname,const char FAR * optval,int optlen)
{
return setsockopt(MapSocket(s), level, optname, optval, optlen);
}
int
PASCAL
WS2EmulBind( SOCKET s, const struct sockaddr FAR * name, int namelen)
{
return bind(MapSocket(s), name, namelen);
}
int
PASCAL
WS2EmulGetSockName( SOCKET s,
struct sockaddr * name,
int * namelen )
{
return getsockname(MapSocket(s), name, namelen);
}
int
PASCAL
WS2EmulHtonl(
SOCKET s,
u_long hostlong,
u_long FAR * lpnetlong
)
{
*lpnetlong = htonl(hostlong);
return 0;
}
int
PASCAL
WS2EmulHtons(
SOCKET s,
u_short hostshort,
u_short FAR * lpnetshort
)
{
*lpnetshort = htons(hostshort);
return 0;
}
int
PASCAL
WS2EmulNtohl(
SOCKET s,
u_long netlong,
u_long FAR * lphostlong
)
{
*lphostlong = ntohl(netlong);
return 0;
}
int
PASCAL
WS2EmulNtohs(
SOCKET s,
u_short netshort,
u_short FAR * lphostshort
)
{
*lphostshort = ntohs(netshort);
return 0;
}
int
PASCAL
WS2EmulGetHostName(char *name, int namelen)
{
return gethostname(name, namelen);
}
struct hostent FAR *
PASCAL
WS2EmulGetHostByName(const char * name)
{
return gethostbyname(name);
}
SOCKET
PASCAL
WS2EmulJoinLeaf(
SOCKET s,
const struct sockaddr FAR * name,
int namelen,
LPWSABUF lpCallerData,
LPWSABUF lpCalleeData,
LPQOS lpSQOS,
LPQOS lpGQOS,
DWORD dwFlags
)
{
ASSERT(0);
return (-1);
}
int
PASCAL
WS2EmulIoctl(SOCKET s, DWORD dwIoControlCode, LPVOID lpvInBuffer,
DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer,
LPDWORD lpcbBytesReturned, LPWSAOVERLAPPED, LPWSAOVERLAPPED_COMPLETION_ROUTINE
)
{
ASSERT(0);
return -1;
}
BOOL StartWS1MsgThread()
{
DWORD threadId;
DWORD dwStatus;
ASSERT(g_WS2Emul.hMsgThread == 0);
g_WS2Emul.hAckEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
g_WS2Emul.hMsgThread = CreateThread(NULL,0, WS1MsgThread, 0, 0, &threadId);
dwStatus = WaitForSingleObject(g_WS2Emul.hAckEvent,INFINITE);
return dwStatus == WAIT_OBJECT_0;
}
BOOL StopWS1MsgThread()
{
if (g_WS2Emul.hMsgThread && g_WS2Emul.hWnd)
{
PostMessage(g_WS2Emul.hWnd, WM_CLOSE, 0, 0);
WaitForSingleObject(g_WS2Emul.hMsgThread,INFINITE);
CloseHandle(g_WS2Emul.hMsgThread);
CloseHandle(g_WS2Emul.hAckEvent);
g_WS2Emul.hMsgThread = NULL;
g_WS2Emul.hAckEvent = NULL;
}
return TRUE;
}
LRESULT CALLBACK WS1WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
int i;
CWS2EmulSock *pESock;
EnterCriticalSection(&g_WS2Emul.intcs);
if (pESock = EmulSockFromSocket(msg - WM_WSA_READWRITE))
{
LRESULT l = pESock->HandleMessage(wParam, lParam);
LeaveCriticalSection(&g_WS2Emul.intcs);
return l;
}
LeaveCriticalSection(&g_WS2Emul.intcs);
if (msg == WM_DESTROY)
PostQuitMessage(0);
return (DefWindowProc(hWnd, msg, wParam, lParam));
}
DWORD WINAPI WS1MsgThread (LPVOID )
{
HRESULT hr;
BOOL fChange = FALSE;
MSG msg;
// Register hidden window class:
WNDCLASS wcHidden =
{
0L,
WS1WindowProc,
0,
0,
GetModuleHandle(NULL),
NULL,
NULL,
NULL,
NULL,
"WS1EmulWindowClass"
};
if (RegisterClass(&wcHidden)) {
// Create hidden window
// Create a hidden window for event processing:
g_WS2Emul.hWnd = ::CreateWindow( "WS1EmulWindowClass",
"",
WS_POPUP, // not visible!
0, 0, 0, 0,
NULL,
NULL,
GetModuleHandle(NULL),
NULL);
}
if(!g_WS2Emul.hWnd)
{
hr = GetLastError();
goto CLEANUPEXIT;
}
//SetThreadPriority(m_hRecvThread, THREAD_PRIORITY_ABOVE_NORMAL);
// This function is guaranteed to create a queue on this thread
PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
// notify thread creator that we're ready to recv messages
SetEvent(g_WS2Emul.hAckEvent);
// Wait for control messages or Winsock messages directed to
// our hidden window
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
g_WS2Emul.hWnd = NULL;
hr = S_OK;
CLEANUPEXIT:
UnregisterClass("WS1EmulWindowClass",GetModuleHandle(NULL));
SetEvent(g_WS2Emul.hAckEvent);
return hr;
}