自己寫遠端控制軟體之鍵鼠響應

LiuYinChina發表於2013-01-31
上一篇說影象壓縮和顯示的時候,大家已經看到了在客戶端的捕捉鍵鼠訊息的程式碼,這裡就直接說在伺服器的實現了。

程式碼其實很簡單但是需要注意的是,在網路接收訊息後,不要在網路回撥裡,直接 mouse_event或者keybd_event 做其它事情也不行,除了緩衝區取一個緩衝區,然後 Post 到 IOCP 以外,否則,輕則影響效率,重則死鎖當然接收的資料還是要處理的,用的是執行緒池函式 QueueUserWorkItem,你懂的。不過,QueueUserWorkItem 有時,有點問題(有時有 .Net 程式執行的時候,CPU 很高,原因不明,可能是要和 .Net 強執行緒吧),不過,我有仿 QueueUserWorkItem 的函式,可以避免這個問題,這裡就不說了

DWORD WINAPI RunCommand(LPVOID lpParam)
{
	SOCKET_POST_CTRL *pRecv = (SOCKET_POST_CTRL *) lpParam;
	switch (pRecv->remoteCtrl.dwCtrl) {
		case CTRL_MOUSE:
			SetCursorPos(pRecv->remoteCtrl.x * GetSystemMetrics(SM_CXSCREEN) / pRecv->remoteCtrl.dwWidth, 
						 pRecv->remoteCtrl.y * GetSystemMetrics(SM_CYSCREEN) / pRecv->remoteCtrl.dwHeight);

			mouse_event(pRecv->remoteCtrl.dwFlags, 0, 0, 0, 0);
			break;
		case CTRL_KEYBOARD:
			::keybd_event((BYTE) pRecv->remoteCtrl.nChar, (BYTE) pRecv->remoteCtrl.nChar, pRecv->remoteCtrl.nFlags, 0);
			break;
		default:
			break;
	}
	SQ_PushBack(pRecv->hQueue, ForceCast<DWORD>(pRecv));
	return 0;
}


VOID OnRecv(SOCKET_POST *pPost)
{
	SOCKET_POST_CTRL *pRecv = (SOCKET_POST_CTRL *) pPost;
	if (pRecv->dwBytesTrans == 0) {
		IOCP_Close(pRecv->pInfo);
		SQ_PushBack(pRecv->hQueue, ForceCast<DWORD>(pRecv));
	}
	else {
		pRecv->dwLeftSize -= pRecv->dwBytesTrans;
		if (pRecv->dwLeftSize > 0) {
			pRecv->pWSABuf		= &(pRecv->wsaBuf[0]);
			pRecv->dwBufCount	= ItemCount(pRecv->wsaBuf);
			pRecv->wsaBuf[0].len= pRecv->dwLeftSize;
			pRecv->wsaBuf[0].buf= (PCHAR) &(pRecv->pktHead);
			pRecv->wsaBuf[0].buf+= (sizeof(pRecv->pktHead) + sizeof(pRecv->remoteCtrl) - pRecv->dwLeftSize);

			IOCP_PostRecv(m_hIOCP, pRecv->pInfo, pRecv);
		}
		else {
			switch (pRecv->pktHead.dwStamp) {
				case STAMP_PACKET:
					QueueUserWorkItem(RunCommand, pRecv, 0);
					SQ_PopFront(m_hQueueRecv, ForceCast<LPDWORD>(&pRecv));
					PostRecv(m_pInfo, pRecv);
					break;
				default:
					IOCP_Close(pRecv->pInfo);
					SQ_PushBack(pRecv->hQueue, ForceCast<DWORD>(pRecv));
					break;
			}
		}
	}
}



相關文章