源码下载:http://user.qzone.qq.com/58408454/blog/1255252449
//
//*
//*工程: 远程监视器
//*作者: 童方
//*时间: 2009-9-11
//*说明: 1 客户端,即: 主监视端
//* 2 未做数据压缩处理(如果您为本例程加入压缩算法或扩展功能,希望您可以发给我一份您更新后的源码)
//* 3 愿我的代码给您带来小小的启发和帮助
//* 4 也希望您给我提供宝贵的意见,互相学习,共同进步
//*
//*联系方式: QQ 58408454 Email shfhere@qq.com
//*
//
#include "stdafx.h"
#include "MonitorClient.h"
#include "MonitorClientDlg.h"
//#include "../zlib/zlib.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/
// CAboutDlg dialog used for App About
//*工作线程,用于实时接收服务端图象,并实时绘制
UINT WorkThread(LPVOID lpParam)
{
CMonitorClientDlg* me = (CMonitorClientDlg*)lpParam;
return me->WorkProc();
}
//*
BOOL MySend(SOCKET sock, LPVOID lpData, int nSize)
{
//*自订义数据发送,直到发送完成时才返回
char* Buf = (char*)lpData;
int nLen = nSize;
int n;
int nIndex = 0;
while(nLen > 0)
{
n = send(sock, &Buf[nIndex], nLen, 0);
if(n == SOCKET_ERROR)
return FALSE;
nIndex += n;
nLen -= n;
}
return TRUE;
}
BOOL MyReceive(SOCKET sock, LPVOID lpData, int nSize)
{
//*自订义数据接收,直到接收到指定大小的数据后才返回
char* Buf = (char*)lpData;
int nLen = nSize;
int n;
int nIndex = 0;
while(nLen > 0)
{
n = recv(sock, &Buf[nIndex], nLen, 0);
if(n == SOCKET_ERROR)
return FALSE;
nIndex += n;
nLen -= n;
}
return TRUE;
}
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// Dialog Data
//{{AFX_DATA(CAboutDlg)
enum { IDD = IDD_ABOUTBOX };
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CAboutDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
//{{AFX_MSG(CAboutDlg)
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
//{{AFX_DATA_INIT(CAboutDlg)
//}}AFX_DATA_INIT
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAboutDlg)
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
//{{AFX_MSG_MAP(CAboutDlg)
// No message handlers
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/
// CMonitorClientDlg dialog
CMonitorClientDlg::CMonitorClientDlg(CWnd* pParent /*=NULL*/)
: CDialog(CMonitorClientDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CMonitorClientDlg)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CMonitorClientDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CMonitorClientDlg)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CMonitorClientDlg, CDialog)
//{{AFX_MSG_MAP(CMonitorClientDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_COMMAND(ID_RD_CONNECT, OnRdConnect)
ON_COMMAND(ID_RD_EXIT, OnRdExit)
ON_WM_TIMER()
ON_WM_HSCROLL()
ON_WM_VSCROLL()
ON_WM_CLOSE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/
// CMonitorClientDlg message handlers
BOOL CMonitorClientDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
//*初始化窗口大小和位置(本例程为:800×600大小的窗口,超出部分拖滚动条查看)
CRect RectWindow, RectClient;
GetClientRect(&RectClient);
GetWindowRect(&RectWindow);
int w = RectWindow.Width() - RectClient.Width();
int h = RectWindow.Height() - RectClient.Height();
SetWindowPos(&wndTop, 0, 0, w + 800, h + 600, SWP_DRAWFRAME);
//*初始化标志
bRunning = FALSE;
//*初始化缓存
BitmapBuffer = NULL;
ZipBuffer = NULL;
return TRUE; // return TRUE unless you set the focus to a control
}
void CMonitorClientDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CMonitorClientDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
if(!BitmapBuffer)
{
CDialog::OnPaint();
return;
}
else
{
csMem.Lock();
CClientDC dc(this);
dc.BitBlt(0, 0, 800, 600, &MemDC, GetScrollPos(SB_HORZ), GetScrollPos(SB_VERT), SRCCOPY);
csMem.Unlock();
}
}
}
// The system calls this to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CMonitorClientDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
void CMonitorClientDlg::OnOK()
{
// TODO: Add extra validation here
CDialog::OnOK();
}
void CMonitorClientDlg::OnCancel()
{
// TODO: Add extra cleanup here
CDialog::OnCancel();
}
void CMonitorClientDlg::OnRdConnect()
{
// TODO: Add your command handler code here
//*如果已经连接,则直接返回
if(bRunning)
return;
//*输入要连监视的主机IP
if(dlgIP.DoModal() != IDOK)
return;
IP = dlgIP.IP;
bRunning = TRUE;
//*启动工作线程
AfxBeginThread(WorkThread, this);
}
void CMonitorClientDlg::OnRdExit()
{
// TODO: Add your command handler code here
SendMessage(WM_CLOSE);
}
UINT CMonitorClientDlg::WorkProc()
{
//*工作线程,用于连接到主机,并读取主机传来的屏幕图象,并绘制
//*建立套接字
SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
SOCKADDR_IN SockAddr;
SockAddr.sin_family = AF_INET;
SockAddr.sin_port = htons(3517);
SockAddr.sin_addr.s_addr =inet_addr(IP);
int SockAddrLen = sizeof(sockaddr);
int nZero = 0;
setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)&nZero, sizeof(int));
//*连接到目标主机
if(connect(sock, (SOCKADDR*)&SockAddr, SockAddrLen) == SOCKET_ERROR)
{
closesocket(sock);
AfxMessageBox(_T("连接不到服务器..."));
bRunning = FALSE;
AfxEndThread(0);
return 0;
}
while(bRunning)
{
//*接收图象
if(!ProcessReceive(sock))
{
//*接收失败,则退出线程
closesocket(sock);
break;
}
//*处理解压过程
// ProcessUncompress();
//*内存DC锁
csMem.Lock();
//*向内存DC和内存位图绘制接收来的图象
SetDIBits(MemDC.GetSafeHdc(), (HBITMAP)MemBitmap.GetSafeHandle(), 0, BitmapInfoHeader.biHeight, (LPVOID)BitmapBuffer, (LPBITMAPINFO)&BitmapInfoHeader, DIB_RGB_COLORS);
//*内存DC解锁
csMem.Unlock();
//*更新画面
Invalidate(FALSE);
}
//*退出线程时,释放各种资源
bRunning = FALSE;
if(BitmapBuffer)
delete [] BitmapBuffer;
if(ZipBuffer)
delete [] ZipBuffer;
BitmapBuffer = NULL;
ZipBuffer = NULL;
MemDC.DeleteDC();
MemBitmap.DeleteObject();
AfxEndThread(0);
return 0;
}
void CMonitorClientDlg::ProcessUncompress()
{
//*处理解压
// if(BitmapBuffer)
// uncompress(BitmapBuffer, &BitmapBufferSize, ZipBuffer, ZipBufferSize);
}
void CMonitorClientDlg::ProcessFirst()
{
//*首包数据,分配用于绘图的内存资源
csMem.Lock();
CDC DeskDC;
DeskDC.CreateDC("DISPLAY", NULL, NULL, NULL);
MemDC.CreateCompatibleDC(&DeskDC);
MemBitmap.CreateCompatibleBitmap(&DeskDC, BitmapWidth, BitmapHeight);
MemDC.SelectObject(&MemBitmap);
DeskDC.DeleteDC();
csMem.Unlock();
//*根据对方桌面分辨率,处理滚动条信息
CRect Rect;
//*得到客户区大小
GetClientRect(&Rect);
if(Rect.Width() < BitmapWidth)
{
SCROLLINFO si = {0};
si.cbSize = sizeof(SCROLLINFO);
//*设置掩码
si.fMask = SIF_ALL;
//*滚动条最小值
si.nMin = 0;
//*滚动条中可拖动按钮的大小(页大小)
si.nPage = Rect.Width()/(BitmapWidth / (BitmapWidth - Rect.Width()));
if(si.nPage == 0)
si.nPage = Rect.Width();
//*滚动条最大值
si.nMax = BitmapWidth - Rect.Width() + si.nPage;
//*滚动条当前位置
si.nPos = 0;
si.nTrackPos = 0;
//*设置为水平滚动条信息
SetScrollInfo(SB_HORZ, &si, TRUE);
}
if(Rect.Height() < BitmapHeight)
{
SCROLLINFO si = {0};
si.cbSize = sizeof(SCROLLINFO);
//*设置掩码
si.fMask = SIF_ALL;
//*滚动条最小值
si.nMin = 0;
//*滚动条中可拖动按钮的大小(页大小)
si.nPage = Rect.Height()/(BitmapHeight / (BitmapHeight - Rect.Height()));
if(si.nPage == 0)
si.nPage = Rect.Height();
//*滚动条最大值
si.nMax = BitmapHeight - Rect.Height() + si.nPage;
//*滚动条当前位置
si.nPos = 0;
si.nTrackPos = 0;
//*设置为垂直滚动条信息
SetScrollInfo(SB_VERT, &si, TRUE);
}
}
BOOL CMonitorClientDlg::ProcessReceive(SOCKET sock)
{
//*接收包头
if(!ReceivePackageHead(sock))
return FALSE;
//*接收位图头
if(!ReceiveBitmapHead(sock))
return FALSE;
//*接收位图数据
if(!ReceiveBitmapData(sock))
return FALSE;
//*接收包尾
if(!ReceivePackageTail(sock))
return FALSE;
return TRUE;
}
BOOL CMonitorClientDlg::ReceivePackageHead(SOCKET sock)
{
//*接收并校验包头
char PackageHead[] = "TF Remote Package Head.../0";
char Buf[512];
int nLen = strlen(PackageHead);
if(MyReceive(sock, Buf, nLen) == FALSE)
return FALSE;
Buf[nLen] = '/0';
if(strcmp(Buf, PackageHead) != 0)
return FALSE;
return TRUE;
}
BOOL CMonitorClientDlg::ReceiveBitmapHead(SOCKET sock)
{
//*接位图头
//*位图缓存大小
if(MyReceive(sock, &BitmapBufferSize, 4) == FALSE)
return FALSE;
BOOL First = FALSE;//*首幅图标志
if(!BitmapBuffer)
{
//*如果位图缓存为空,则说明是首幅图象,分配缓存资源
BitmapBuffer = new BYTE[BitmapBufferSize];
//*计算压缩缓存大小,当前没有进行压缩
// ZipBufferSize = compressBound(BitmapBufferSize);
ZipBufferSize = BitmapBufferSize;
//*分配压缩缓存
ZipBuffer = new BYTE[ZipBufferSize];
//*当前为连接后第一幅图
First = TRUE;
}
//*压缩数据大小
if(MyReceive(sock, &ZipBufferSize, 4) == FALSE)
return FALSE;
//*位图宽
if(MyReceive(sock, &BitmapWidth, 2) == FALSE)
return FALSE;
//*位图高
if(MyReceive(sock, &BitmapHeight, 2) == FALSE)
return FALSE;
//*位图信息
if(MyReceive(sock, &BitmapInfoHeader, sizeof(BITMAPINFOHEADER)) == FALSE)
return FALSE;
if(First)
{
//*如果第一幅图,则初始化绘图信息
ProcessFirst();
}
return TRUE;
}
BOOL CMonitorClientDlg::ReceiveBitmapData(SOCKET sock)
{
//*如果压缩数据,则接收压缩缓存
// return MyReceive(sock, ZipBuffer, ZipBufferSize);
//*当前例程未进行压缩,则直接将数据接收至位图缓存
return MyReceive(sock, BitmapBuffer, BitmapBufferSize);
}
BOOL CMonitorClientDlg::ReceivePackageTail(SOCKET sock)
{
//*接收并校验包尾
char PackageTail[] = "TF Remote Package Tail.../0";
char Buf[512];
int nLen = strlen(PackageTail);
if(MyReceive(sock, Buf, nLen) == FALSE)
return FALSE;
Buf[nLen] = '/0';
if(strcmp(Buf, PackageTail) != 0)
return FALSE;
return TRUE;
}
void CMonitorClientDlg::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
CDialog::OnTimer(nIDEvent);
}
void CMonitorClientDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
// TODO: Add your message handler code here and/or call default
//*处理水平滚动条事件
SCROLLINFO si;
GetScrollInfo(SB_HORZ, &si, SIF_ALL);
switch (nSBCode)
{
case SB_LEFT:
case SB_LINELEFT:
si.nPos -= si.nMax/20;
if(si.nPos < si.nMin)
si.nPos = si.nMin;
ScrollWindow(si.nPos, 0);
SetScrollInfo(SB_HORZ, &si, TRUE);
break;
case SB_RIGHT:
case SB_LINERIGHT:
si.nPos += si.nMax/20;
if(si.nPos > si.nMax)
si.nPos = si.nMax;
ScrollWindow(si.nPos, 0);
SetScrollInfo(SB_HORZ, &si, TRUE);
break;
case SB_PAGELEFT:
si.nPos -= si.nPage;
if(si.nPos < si.nMin)
si.nPos = si.nMin;
ScrollWindow(si.nPos, 0);
SetScrollInfo(SB_HORZ, &si, TRUE);
break;
case SB_PAGERIGHT:
si.nPos += si.nPage;
if(si.nPos > si.nMax)
si.nPos = si.nMax;
ScrollWindow(si.nPos, 0);
SetScrollInfo(SB_HORZ, &si, TRUE);
break;
case SB_THUMBPOSITION:
break;
case SB_THUMBTRACK:
ScrollWindow((si.nPos-nPos)*10, 0);
si.nPos = nPos;
SetScrollInfo(SB_HORZ, &si, SIF_ALL);
break;
case SB_ENDSCROLL:
break;
}
CDialog::OnHScroll(nSBCode, nPos, pScrollBar);
}
void CMonitorClientDlg::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
// TODO: Add your message handler code here and/or call default
//*处理垂直滚动条事件
SCROLLINFO si;
GetScrollInfo(SB_VERT,&si,SIF_ALL);
switch (nSBCode)
{
case SB_TOP:
case SB_LINEUP:
si.nPos -= si.nMax/20;
if(si.nPos < si.nMin)
si.nPos = si.nMin;
ScrollWindow(0, si.nPos);
SetScrollInfo(SB_VERT, &si, TRUE);
break;
case SB_BOTTOM:
case SB_LINEDOWN:
si.nPos += si.nMax/20;
if(si.nPos > si.nMax)
si.nPos = si.nMax;
ScrollWindow(0, si.nPos);
SetScrollInfo(SB_VERT, &si, TRUE);
break;
case SB_PAGEUP:
si.nPos -= si.nPage;
if(si.nPos < si.nMin)
si.nPos = si.nMin;
ScrollWindow(0, si.nPos);
SetScrollInfo(SB_VERT, &si, TRUE);
break;
case SB_PAGEDOWN:
si.nPos += si.nPage;
if(si.nPos > si.nMax)
si.nPos = si.nMax;
ScrollWindow(0, si.nPos);
SetScrollInfo(SB_VERT, &si, TRUE);
break;
case SB_THUMBPOSITION:
break;
case SB_THUMBTRACK:
ScrollWindow(0, (si.nPos-nPos)*10);
si.nPos = nPos;
SetScrollInfo(SB_VERT, &si, SIF_ALL);
break;
case SB_ENDSCROLL:
break;
}
CDialog::OnVScroll(nSBCode, nPos, pScrollBar);
}
void CMonitorClientDlg::OnClose()
{
// TODO: Add your message handler code here and/or call default
CDialog::OnClose();
}