远程桌面项目

在这里插入图片描述

一. 远程控制系统

  1. 编译代码,生成可执行程序。注意Debug和Release的区别。
    Debug我们称调试版本,编译链接生成程序时,包含了调试信息,程序的体积比较大。
    调试程序比较方便,但是运行时,没有Release版本快。通常在开发程序时,选择Debug
    模式。
    Release我们称发布版本,编译链接生成程序时,不包含调试信息,编译器也会对代码优化,
    程序的体积比较小。由于没有调试信息,所以在调试程序时不方便,但是运行的速度快。
    通常开发完成后,生成Release版本交付用户使用。

  2. 首先启动Server端(被控端),注意设置它的屏幕分辨率为1024*768。启动后,看到Server端的IP地址。然后从client目录中查找client.ini文件,拷贝到解决方案下面的debug目录下,也就是说和client.exe同一目录下,修改该文件中的IP地址为Server端地址。启动客户端,点击 "截屏"按钮,然后在客户端就可以控制Server端了。

  3. 项目描述
    远程控制系统是一个典型的C/S架构系统,功能类似于windows自带的远程连接和QQ上
    的远程协助。具体实现时,使用的是TCP通信。TCP服务器端作为被控端首先启动,在
    指定的端口监听,等待客户端连接。TCP客户端作为控制端启动后,连接服务器。连接后,
    服务器将屏幕数据发送到客户端,在客户端的视图客户区显示;用户在客户端操作键盘或
    鼠标,产生键盘/鼠标的消息。把该消息的数据发送给服务器,服务器收到后,调用相关的
    API函数,执行键盘/鼠标的消息的处理。

二、解决方案设置

  1. 新建项目,在其它项目类型中,选择Visual Studio解决方案,名称为RemoteCtrl。
  2. 右击解决方案,选择添加新建项目。选择Win32项目,名称为Server,直接点击完成。

三、远程控制Server端步骤

1.使用socket库

  1. 在stdafx.h中加入以下代码:
    #include <winsock2.h>
    #pragma comment(lib,“ws2_32.lib”)
    2. 在项目中添加GlobalHead.h和GlobalHead.cpp文件用于定义一些全局变量
    –编译工程–

2.在server.cpp中完成互斥、事件并初始化socket库

首先包含头文件,#include “globalhead.h”。

  1. 创建互斥体,保证程序只运行一个实例
      if ((hOnlyInstance=CreateMutex(NULL,false,"JFY's PeerYou"))==NULL)
             return -1;
      else if (GetLastError()==ERROR_ALREADY_EXISTS)
             return -1;
      ```
    
  2. 创建用于退出程序的事件
      if ((hExitEvent=WSACreateEvent())==WSA_INVALID_EVENT)
      {
         
           CloseHandle(hOnlyInstance);
            return -1;
      }
      ```
    
  3. 初始化socket库
      WSADATA wsaData;
      if (WSAStartup(MAKEWORD(2,2),&wsaData)!=0) 
      {
         
      CloseHandle(hOnlyInstance);
      CloseHandle(hExitEvent);
      return -1;
      }
    
  4. 在InitInstance()函数中,如果创建窗口失败,关闭句柄,卸载socket库
      if (!hWnd)
      {
         
          CloseHandle(hOnlyInstance);
          WSACloseEvent(hExitEvent);
          WSACleanup();
          return FALSE;
    }
    
  5. 在最后程序退出前,关闭句柄,卸载socket库
    CloseHandle(hOnlyInstance);
    WSACloseEvent(hExitEvent);
    WSACleanup();
    –编译工程–

3.在窗口处理函数中处理

WM_CREATE、WM_PAINT、WM_CLOSE消息

  1. case WM_CREATE:
    // 1 获取主机名称和IP
    // 2 创建线程

  2. case WM_PAINT:
    // 显示主机名称和IP

  3. case WM_CLOSE:
    // 资源清理工作

4.socket通信处理

在工程中添加PeerSocket.h和PeerSocket.cpp文件完成服务器端通信函数的实现

#define PEER_STREAM SOCK_STREAM
#define PEER_DGRAM  SOCK_DGRAM
#define PEER_RAW	SOCK_RAW 

bool PeerCreateSocket(SOCKET *pNewSocket,int iSockType);//创建
bool PeerBindSocket(SOCKET BindSocket,char *szHostAddr,int iHostPort);//绑定
bool PeerListenSocket(SOCKET ListenSocket);//监听
bool PeerAcceptSocket( SOCKET *pTravelSocket, SOCKADDR_IN *psockAddr, SOCKET ListenSock );//接收客户端连接
bool PeerShutDownSocket(SOCKET nowSocket);//断开连接
bool PeerCloseSocket(SOCKET nowSocket);//关闭连接
bool PeerSendData(SOCKET socket,char *data,DWORD len,DWORD *retlen);//发送数据
bool PeerRecvData(SOCKET socket,char *data,DWORD len,DWORD *retlen);//接收数据
bool PeerSendDataS(SOCKET socket,char *data,DWORD len,DWORD *retlen);//服务器端发送数据,调用发送数据函数
bool PeerRecvDataS(SOCKET socket,char *data,DWORD len,DWORD *retlen);//服务器端接收数据,调用接收数据函数

5.添加屏幕捕获的处理

在工程中添加CaptureScreen.h和CaptureScreen.cpp文件
void CleanScreenInfo(void);
bool GetScreenData(int nBits);

6.添加鼠标键盘和屏幕处理函数

在工程中添加ScreenCtrl.h和ScreenCtrl.cpp文件
bool PeerScreenMouseKey(SOCKET s);
bool PeerScreenGet(SOCKET s);

7.线程处理

  1. 在工程中添加command.h文件,定义用于封装传输信息的结构体
  2. 添加PeerThread.头文件,添加与线程相关的结构体、列表和线程函数的声明
  3. 添加PeerThread.cpp文件,添加线程函数的实现

8.在server.cpp和stdafx.h中添加相关的头文件包含




四、远程控制端Client步骤

右击解决方案,选择添加新建项目。
选择MFC项目,单文档、MFC标准、不使用unicode库,在用户界面设置,选择使用经典菜单。

1.使用TrueColorToolBar类创建工具栏

  1. 将TrueColorToolBar.h和TrueColorToolBar.cpp拷贝到Client目录下,并包含到当前项目中。
  2. 在CMainFrame类中包含头文件#include “TrueColorToolBar.h”,添加成员变量CTrueColorToolBar m_wndToolBar;
  3. 插入工具栏资源,修改工具栏按钮大小为32*32.将3个相关图片拷贝到当前目录,并导入到项目,修改图片的ID。
  4. 在OnCreate函数中完成工具栏的创建

2.添加socket库,创建事件

  1. 项目的头文件stdafx.h中添加以下代码:
    #include <winsock2.h>
    #pragma comment(lib,“ws2_32.lib”)

  2. App类的InitInstance()函数中,初始化socket库

     if ((hExitEvent=WSACreateEvent())==WSA_INVALID_EVENT)
     {
         
        return -1;
     }
     WSAStartup(...); 
    
  3. App类的ExitInstance()函数中,卸载socket库
    WSACleanup();
    WSACloseEvent(hExitEvent);

3.在项目中,添加command.h文件

用于定义在客户端和服务器之间传递的数据的结构体。

4.socket通信处理

在工程中添加PeerSocket.h和PeerSocket.cpp文件完成客户端通信函数的实现

5.全局变量的定义

  1. 在Client.cpp中添加全局变量
    WSAEVENT hExitEvent;
    char ADDRESS[16];
    BOOL g_ExitThread = FALSE;
    CWinThread *hThreadScreen = NULL;
  2. 在stdafx.h中添加全局变量的外部声明
    extern WSAEVENT hExitEvent;
    extern char ADDRESS[16];
    extern BOOL g_ExitThread;
    extern CWinThread *hThreadScreen;

6.在视图类中添加鼠标/键盘事件处理

7.在CMainFrame类中添加工具栏按钮的消息处理函数

8.注意的问题:ini 文件中的配置信息




参考代码

Server端:

// Server.cpp : 定义应用程序的入口点。
//

#include "stdafx.h"
#include "Server.h"
#include "globalhead.h"
#include "CaptureScreen.h"
#include "PeerSocket.h"
#include "PeerThread.h"
#include "command.h"
#define MAX_LOADSTRING 100

// 全局变量:
HINSTANCE hInst;								// 当前实例
TCHAR szTitle[MAX_LOADSTRING];					// 标题栏文本
TCHAR szWindowClass[MAX_LOADSTRING];			// 主窗口类名

// 此代码模块中包含的函数的前向声明:
ATOM				MyRegisterClass(HINSTANCE hInstance);
BOOL				InitInstance(HINSTANCE, int);
LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK	About(HWND, UINT, WPARAM, LPARAM);


HWND	  hMainWnd;//主框架窗口句柄
int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
   
	
	//	1 创建互斥体,保证只有一个实例		
	if ((hOnlyInstance=CreateMutex(NULL,false,"JFY's PeerYou"))==NULL)
		return -1;
	else if (GetLastError()==ERROR_ALREADY_EXISTS)
		return -1;


	//	2 创建用于退出程序的事件句柄
	if ((hExitEvent=WSACreateEvent())==WSA_INVALID_EVENT){
   
		CloseHandle(hOnlyInstance);
		return -1;
	}
	//	3 初始化socket库
	WSADATA wsaData;
	if (WSAStartup(MAKEWORD(2,2),&wsaData)!=0) {
   
		//	无可用WinSock DLL. 
		CloseHandle(hOnlyInstance);
		CloseHandle(hExitEvent);
		return -1;
	}
	
	
	
	
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);

 	// TODO: 在此放置代码。
	MSG msg;
	HACCEL hAccelTable;

	// 初始化全局字符串
	LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
	LoadString(hInstance, IDC_SERVER, szWindowClass, MAX_LOADSTRING);
	MyRegisterClass(hInstance);

	// 执行应用程序初始化:
	if (!InitInstance (hInstance, nCmdShow))
	{
   
		return FALSE;
	}

	hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_SERVER));


	InitializeCriticalSection(&csCaptureScreen);
	// 主消息循环:
	while (GetMessage(&msg, NULL, 0, 0))
	{
   
		if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
		{
   
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}
	CloseHandle(hOnlyInstance);
	WSACloseEvent(hExitEvent);
	DeleteCriticalSection(&csCaptureScreen);
	WSACleanup();
	return (int) msg.wParam;
}



//
//  函数: MyRegisterClass()
//
//  目的: 注册窗口类。
//
//  注释:
//
//    仅当希望
//    此代码与添加到 Windows 95 中的“RegisterClassEx”
//    函数之前的 Win32 系统兼容时,才需要此函数及其用法。调用此函数十分重要,
//    这样应用程序就可以获得关联的
//    “格式正确的”小图标。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
   
	WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX);

	wcex.style			= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc	= WndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInstance;
	wcex.hIcon			= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_SERVER));
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszMenuName	= MAKEINTRESOURCE(IDC_SERVER);
	wcex.lpszClassName	= szWindowClass;
	wcex.hIconSm		= LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

	return RegisterClassEx(&wcex);
}

//
//   函数: InitInstance(HINSTANCE, int)
//
//   目的: 保存实例句柄并创建主窗口
//
//   注释:
//
//        在此函数中,我们在全局变量中保存实例句柄并
//        创建和显示主程序窗口。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   
   HWND hWnd;

   hInst = hInstance; // 将实例句柄存储在全局变量中

   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

   if (!hWnd)
   {
   
       CloseHandle(hOnlyInstance);
	   WSACloseEvent(hExitEvent);
	   WSACleanup();
	   return FALSE;
   }
   hMainWnd=hWnd;
   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

//
//  函数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  目的: 处理主窗口的消息。
//
//  WM_COMMAND	- 处理应用程序菜单
//  WM_PAINT	- 绘制主窗口
//  WM_DESTROY	- 发送退出消息并返回
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
   
	int wmId, wmEvent;
	PAINTSTRUCT ps;
	HDC hdc;

	switch (message)
	{
   
	case WM_COMMAND:
		wmId    = LOWORD(wParam);
		wmEvent = HIWORD(wParam);
		// 分析菜单选择:
		switch (wmId)
		{
   
		case IDM_ABOUT:
			DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
			break;
		case IDM_EXIT:
			DestroyWindow(hWnd);
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
		}
		break;
	case WM_CREATE:
		//得到主机名称
		int nComputerNameLen;
		nComputerNameLen=MAX_COMPUTERNAME_LENGTH + 1;
		if(SOCKET_ERROR==gethostname(szHostName,nComputerNameLen))
			return -1;
	
		//得到主机IP地址
		HOSTENT *hentThisHost;
		hentThisHost=NULL;
		if(!(hentThisHost=gethostbyname(
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值