I m using following two structures
Code:
typedef struct _PER_HANDLE_DATA 
{
	SOCKET	Socket;
	SOCKADDR_IN  ClientAddr;
	// Other information useful to be associated with the handle
	UINT ID;
} PER_HANDLE_DATA, * LPPER_HANDLE_DATA;

typedef struct _PER_IO_DATA
{
    OVERLAPPED Overlapped;
	char   Buffer[DATA_BUFSIZE];
    int	   BufferLen;
    int    OperationType;
} PER_IO_DATA, * LPPER_IO_DATA;
Actually When we start an operation just like sending or receiving we need some buffer to post, so through out the program we need saveral buffers may be simultaniously for each socket. So we preffer to make two structures one is PER_IO_DATA and other is PER_HANDLE_DATA .
PER_IO_DATA as its name describe (PER IO = For Each IO ). for each IO we need one PER_IO_DATA object. And PER_HANDLE_DATA contain socket and all the information associated with that socket, and it remains same through out the socket life.

Here is the code for Completion thread with above two structures, it may helps u . Its just for testing purpose.
Code:
DWORD WINAPI ServerWorkerProc(LPVOID lp)
{
	HANDLE CompletionPort = (HANDLE)lp;
	PER_IO_DATA  *PerIoData=NULL;
	OVERLAPPED   *lpOverlapped=NULL;
	LPPER_HANDLE_DATA PerHandleData=NULL;

	PerIoData=(LPPER_IO_DATA)GlobalAlloc(GPTR,sizeof(PER_IO_DATA));
    DWORD BytesTransferred;
    WSABUF wsb;
    DWORD Flags=0,bytes;
	UINT Ret;
	while(TRUE)
	{
		Ret=GetQueuedCompletionStatus(CompletionPort,
            &BytesTransferred,(LPDWORD)&PerHandleData,
            &lpOverlapped, INFINITE);
		PerIoData = CONTAINING_RECORD(lpOverlapped, PER_IO_DATA,Overlapped);

		if (BytesTransferred == 0 &&
            (PerIoData->OperationType == RECV_POSTED ||
             PerIoData->OperationType == SEND_POSTED))
        {
			closesocket(PerHandleData->Socket);
	        continue;

		}
		else if (PerIoData->OperationType == RECV_POSTED)
        {
  			ZeroMemory(&PerIoData->Overlapped,sizeof(PerIoData->Overlapped));
			string data=">";
			data+=PerIoData->Buffer;
			wsb.buf=PerIoData->Buffer;
			wsb.len=DATA_BUFSIZE;     //1024
			PerIoData->OperationType=RECV_POSTED;
			ZeroMemory(&PerIoData->Buffer,sizeof(PerIoData->Buffer));
			WSARecv(PerHandleData->Socket,&wsb,1,&bytes,&Flags,&PerIoData->Overlapped,NULL);
			MessageBox(hMainWnd,data.c_str(),"DataReceived",MB_OK);
			

	   }
		else if (PerIoData->OperationType == SEND_POSTED)
		{
			
			// Write code for dealing send operations
		
		}

	}
	return 0;
}