写一个远程桌面控制器是一个非常复杂的任务,需要熟悉许多网络协议、图像处理技术以及用户界面设计等知识。这里给出的是一个基本的框架,你可以在此基础上进行扩展和完善。

首先,我们需要用到一些库来帮助我们实现远程桌面控制器。在这里,我们假设你使用的是 Windows 系统,并使用了以下几个库:

  • WinSock:用于实现网络通信。
  • GDI+:用于处理图像。
  • MFC:用于创建图形用户界面。

下面是使用这些库编写远程桌面控制器的基本步骤:

  1. 创建一个 MFC 应用程序。
  2. 使用 WinSock 库创建一个网络连接。
  3. 使用 GDI+ 库获取远程桌面的屏幕截图。
  4. 将屏幕截图显示在 MFC 窗口中。
  5. 为用户提供一组控制命令,例如鼠标移动、鼠标单击、键盘输入等。
  6. 使用 WinSock 库将用户的控制命令发送到远程桌面。

下面是使用这些库编写远程桌面控制器的示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
#include <winsock2.h>
#include <gdiplus.h>
#include <afxwin.h> // 包含 MFC 的头文件

using namespace Gdiplus;

// 定义一个 Socket 类,用于封装网络通信相关的操作
class Socket
{
private:
WSADATA m_wsaData;
SOCKET m_sock;
sockaddr_in m_serverAddr;

public:
Socket() : m_sock(INVALID_SOCKET) {}
// 初始化 WinSock 库
bool Init()
{
if (WSAStartup(MAKEWORD(2, 2), &m_wsaData) != 0)
{
return false;
}
return true;
}

// 创建套接字
bool Create(int af, int type, int protocol)
{
m_sock = socket(af, type, protocol);
if (m_sock == INVALID_SOCKET)
{
return false;
}
return true;
}

// 连接到服务器
bool Connect(const char* ip, unsigned short port)
{
m_serverAddr.sin_family = AF_INET;
m_serverAddr.sin_port = htons(port);
m_serverAddr.sin_addr.S_un.S_addr = inet_addr(ip);
if (connect(m_sock, (sockaddr*)&m_serverAddr, sizeof(m_serverAddr)) == SOCKET_ERROR)
{
return false;
}
return true;
}

// 发送数据
int Send(const char* buf, int len)
{
return send(m_sock, buf, len, 0);
}

// 接收数据
int Receive(char* buf, int len)
{
return recv(m_sock, buf, len, 0);
}

// 关闭套接字
void Close()
{
closesocket(m_sock);
m_sock = INVALID_SOCKET;
}

// 清理 WinSock 库
void Cleanup()
{
WSACleanup();
}
};

// 定义一个 RemoteDesktop 类,用于控制远程桌面
class RemoteDesktop
{
private:
Socket m_socket; // 用于网络通信的套接字
Image* m_image; // 当前屏幕截图

public:
RemoteDesktop() : m_image(NULL) {}
// 连接到远续桌面服务器
bool Connect(const char* ip, unsigned short port)
{
if (!m_socket.Init())
{
return false;
}
if (!m_socket.Create(AF_INET, SOCK_STREAM, IPPROTO_TCP))
{
return false;
}
if (!m_socket.Connect(ip, port))
{
return false;
}
return true;
}
// 断开与远程桌面服务器的连接
void Disconnect()
{
m_socket.Close();
m_socket.Cleanup();
delete m_image;
m_image = NULL;
}

// 获取远程桌面的屏幕截图
bool GetScreenshot()
{
// 先发送获取屏幕截图的命令
const char* cmd = "screenshot";
m_socket.Send(cmd, strlen(cmd));

// 接收屏幕截图的大小
int size;
m_socket.Receive((char*)&size, sizeof(size));

// 分配内存空间,准备接收屏幕截图的数据
char* data = new char[size];

// 接收屏幕截图的数据
int bytesReceived = 0;
while (bytesReceived < size)
{
int count = m_socket.Receive(data + bytesReceived, size - bytesReceived);
if (count <= 0)
{
delete[] data;
return false;
}
bytesReceived += count;
}

// 将接收到的数据转换为 GDI+ 图像
delete m_image;
m_image = new Image(data, size);
delete[] data;

return true;
}

// 获取当前屏幕截图
Image* GetImage() const
{
return m_image;
}

// 发送鼠标移动命令
void MoveMouse(int x, int y)
{
// 封装命令格式,发送命令
const char* cmd = "mouse move";
m_socket.Send(cmd, strlen(cmd));
m_socket.Send((char*)&x, sizeof(x));
m_socket.Send((char*)&y, sizeof(y));
}

// 发送鼠标单击命令
void ClickMouse(int x, int y)
{
// 封装命令格式,发送命令
const char* cmd = "mouse click";
m_socket.Send(cmd, strlen(cmd));
m_socket.Send((char*)&x, sizeof(x));
m_socket.Send((char*)&y, sizeof(y));
}

// 发送键盘输入命令
void InputKey(int keyCode)
{
// 封装命令格式,发送命令
const char* cmd = "key input";
m_socket.Send(cmd, strlen(cmd));
m_socket.Send((char*)&keyCode, sizeof(keyCode));
}
};

// 定义一个 RemoteDesktopDialog 类,用于显示远程桌面的界面
class RemoteDesktopDialog : public CDialog
{
private:
RemoteDesktop m_rd; // 用于控制远程桌面的对象

public:
// 使用 MFC 对话框的基本操作
RemoteDesktopDialog() : CDialog(IDD_DIALOG1) {}

protected:
virtual void DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
}

public:
// 连接到远程桌面服务器
bool Connect(const char* ip, unsigned short port)
{
return m_rd.Connect(ip, port);
}

// 断开与远程桌面服务器的连接
void Disconnect()
{
m_rd.Disconnect();
}
protected:
// 绘制远程桌面的界面
afx_msg void OnPaint()
{
CPaintDC dc(this); // 用于绘制的设备上下文
CRect rect;
GetClientRect(&rect); // 获取对话框的客户区域
// 获取屏幕截图,并绘制到界面上
Image* image = m_rd.GetImage();
if (image != NULL)
{
Graphics graphics(dc);
graphics.DrawImage(image, rect);
}
}

// 处理鼠标移动事件
afx_msg void OnMouseMove(UINT nFlags, CPoint point)
{
m_rd.MoveMouse(point.x, point.y);
}
// 处理鼠标单击事件
afx_msg void OnLButtonDown(UINT nFlags, CPoint point)
{
m_rd.ClickMouse(point.x, point.y);
}

// 处理键盘输入事件
afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
m_rd.InputKey(nChar);
}
DECLARE_MESSAGE_MAP()
};

BEGIN_MESSAGE_MAP(RemoteDesktopDialog, CDialog)
ON_WM_PAINT()
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONDOWN()
ON_WM_KEYDOWN()
END_MESSAGE_MAP()

int main()
{
// 初始化 GDI+
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
// 创建对话框并运行
RemoteDesktopDialog dlg;
dlg.DoModal();

// 清理 GDI+
GdiplusShutdown(gdiplusToken);
return 0;
}

在这段代码中,我们定义了三个类:Socket、RemoteDesktop 和 RemoteDesktopDialog。Socket 类封装了网络通信的相关操作,RemoteDesktop 类用于控制远程桌面,RemoteDesktopDialog 类用于显示远程桌面的界面。

使用这个远程桌面控制器的流程如下:

  1. 调用 Socket 类的 Init 函数初始化 WinSock 库。
  2. 调用 Socket 类的 Create 函数创建一个套接字。
  3. 调用 Socket 类的 Connect 函数连接到远程桌面服务器。
  4. 调用 RemoteDesktop 类的 GetScreenshot 函数获取远程桌面的屏幕截图。
  5. 调用 RemoteDesktop 类的 MoveMouse、ClickMouse 或 InputKey 函数发送控制命令。
  6. 重复步骤 4 和 5,实时更新远程桌面的屏幕截图并发送控制命令。
  7. 当远程桌面控制结束时,调用 RemoteDesktop 类的 Disconnect 函数断开与远程桌面服务器的连接,并调用 Socket 类的 Cleanup 函数清理 WinSock 库。

需要注意的是,这段代码使用了 MFC 库来绘制界面,因此需要在 Visual Studio 中创建一个 MFC 应用程序,并在对话框资源中添加一个对话框。然后将上面的代码放入主窗口类的 .cpp 文件中,并在 .h 文件中声明相应的消息映射函数。

以下是服务端代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
#include <Windows.h>
#include <GdiPlus.h>
#include <winsock2.h>
#include<iostream>
#pragma comment(lib, "gdiplus.lib")
#pragma comment(lib, "ws2_32.lib")
using namespace std;
using namespace Gdiplus;

// 定义一个 Socket 类,用于封装网络通信相关的操作
class Socket
{
private:
WSADATA m_wsaData;
SOCKET m_sock;
sockaddr_in m_serverAddr;
sockaddr_in m_clientAddr;

public:
Socket() : m_sock(INVALID_SOCKET) {}
// 初始化 WinSock 库
bool Init()
{
if (WSAStartup(MAKEWORD(2, 2), &m_wsaData) != 0)
{
return false;
}
return true;
}

// 创建套接字
bool Create(int af, int type, int protocol)
{
m_sock = socket(af, type, protocol);
if (m_sock == INVALID_SOCKET)
{
return false;
}
return true;
}
// 绑定套接字到本地地址和端口
bool Bind(unsigned short port)
{
memset(&m_serverAddr, 0, sizeof(m_serverAddr));
m_serverAddr.sin_family = AF_INET;
m_serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
m_serverAddr.sin_port = htons(port);
if (bind(m_sock, (sockaddr*)&m_serverAddr, sizeof(m_serverAddr)) == SOCKET_ERROR)
{
return false;
}
return true;
}
// 监听套接字
bool Listen(int backlog)
{
if (listen(m_sock, backlog) == SOCKET_ERROR)
{
return false;
}
return true;
}

// 接受客户端的连接
bool Accept(Socket& client)
{
int addrLen = sizeof(m_clientAddr);
client.m_sock = accept(m_sock, (sockaddr*)&m_clientAddr, &addrLen);
if (client.m_sock == INVALID_SOCKET)
{
return false;
}
return true;
}

// 接收数据
int Receive(char* buffer, int len)
{
return recv(m_sock, buffer, len, 0);
}

// 发送数据
int Send(const char* buffer, int len)
{
return send(m_sock, buffer, len, 0);
}

// 关闭套接字
void Close()
{
closesocket(m_sock);
m_sock = INVALID_SOCKET;
}

// 清理 WinSock 库
void Cleanup()
{
WSACleanup();
}
};

// 定义一个 RemoteDesktopServer 类,用于提供远程桌面服务
class RemoteDesktopServer
{
private:
Socket m_socket; // 用于网络通信的套接字

public:
// 初始化远程桌面服务器
bool Init(unsigned short port)
{
if (!m_socket.Init())
{
return false;
}
if (!m_socket.Create(AF_INET, SOCK_STREAM, IPPROTO_TCP))
{
return false;
}
if (!m_socket.Bind(port))
{
return false;
}
if (!m_socket.Listen(10))
{
return false;
}
return true;
}
// 运行远程桌面服务器
void Run()
{
// 不断循环,接受客户端的连接
while (true)
{
Socket client;
if (!m_socket.Accept(client))
{
continue;
}

// 为客户端创建一个线程,用于处理客户端的请求
HANDLE hThread = CreateThread(NULL, 0, ClientThreadProc, &client, 0, NULL);
if (hThread == NULL)
{
client.Close();
continue;
}
CloseHandle(hThread);
}
}
private:
// 客户端线程的回调函数,用于处理客户端的请求
static DWORD WINAPI ClientThreadProc(LPVOID lpParam)
{
Socket* pClient = (Socket*)lpParam;
// 不断循环,处理客户端的请求
while (true)
{
// 接收客户端的命令
char cmd[256];
int len = pClient->Receive(cmd, sizeof(cmd));
if (len <= 0)
{
break;
}

// 根据命令类型执行相应的操作
if (strcmp(cmd, "screenshot") == 0)
{
// 处理屏幕截图请求
HandleScreenshotRequest(*pClient);
}
else if (strcmp(cmd, "mouse move") == 0)
{
// 处理鼠标移动请求
int x, y;
pClient->Receive((char*)&x, sizeof(x));
pClient->Receive((char*)&y, sizeof(y));
HandleMouseMoveRequest(x, y);
}
else if (strcmp(cmd, "mouse click") == 0)
{
// 处理鼠标单击请求
int x, y;
pClient->Receive((char*)&x, sizeof(x));
pClient->Receive((char*)&y, sizeof(y));
HandleMouseClickRequest(x, y);
}
else if (strcmp(cmd, "key input") == 0)
{
// 处理键盘输入请求
char key;
pClient->Receive(&key, sizeof(key));
HandleKeyInputRequest(key);
}
else
{
break;
}
}
// 关闭客户端的套接字
pClient->Close();
delete pClient;
return 0;
}

// 处理屏幕截图请求
static void HandleScreenshotRequest(Socket& client)
{
// 获取屏幕的宽高
int width = GetSystemMetrics(SM_CXSCREEN);
int height = GetSystemMetrics(SM_CYSCREEN);

// 创建内存 DC
HDC hdcMem = CreateCompatibleDC(NULL);
if (hdcMem == NULL)
{
return;
}

// 创建位图
HBITMAP hbm = CreateCompatibleBitmap(GetDC(NULL), width, height);
if (hbm == NULL)
{
DeleteDC(hdcMem);
return;
}

// 将位图选入内存 DC
HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, hbm);
if (hbmOld == NULL)
{
DeleteObject(hbm);
DeleteDC(hdcMem);
return;
}

// 将屏幕拷贝到内存 DC
if (!BitBlt(hdcMem, 0, 0, width, height, GetDC(NULL), 0, 0, SRCCOPY))
{
SelectObject(hdcMem, hbmOld);
DeleteObject(hbm);
DeleteDC(hdcMem);
return;
}

// 将内存 DC 的图像保存到缓冲区
BITMAPINFOHEADER bih;
memset(&bih, 0, sizeof(bih));
bih.biSize = sizeof(bih);
bih.biWidth = width;
bih.biHeight = -height;
bih.biPlanes = 1;
bih.biBitCount = 24;
bih.biCompression = BI_RGB;
BYTE* pBuf = NULL;
HBITMAP hbmDib = CreateDIBSection(hdcMem, (BITMAPINFO*)&bih, DIB_RGB_COLORS, (void**)&pBuf, NULL, 0);
if (hbmDib == NULL)
{
SelectObject(hdcMem, hbmOld);
DeleteObject(hbm);
DeleteDC(hdcMem);
return;
}
// 将内存 DC 的图像复制到位图中
if (!SelectObject(hdcMem, hbmDib))
{
DeleteObject(hbmDib);
SelectObject(hdcMem, hbmOld);
DeleteObject(hbm);
DeleteDC(hdcMem);
return;
}
// 将位图的图像转换为 JPEG 格式并发送到客户端
if (!SendScreenshot(client, pBuf, width, height))
{
DeleteObject(hbmDib);
SelectObject(hdcMem, hbmOld);
DeleteObject(hbm);
DeleteDC(hdcMem);
return;
}

// 清理资源
DeleteObject(hbmDib);
SelectObject(hdcMem, hbmOld);
DeleteObject(hbm);
DeleteDC(hdcMem);
}

// 将位图的图像转换为 JPEG 格式并发送到客户端
static bool SendScreenshot(Socket& client, BYTE* pBuf, int width, int height)
{
// 初始化 GDI+
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

// 将位图的图像转换为 JPEG 格式
Bitmap bmp(width, height, width * 3, PixelFormat24bppRGB, pBuf);
CLSID clsid;
GetEncoderClsid(L"image/jpeg", &clsid);
IStream* pStream = NULL;
bmp.Save(L"screenshot.jpg", &clsid, NULL);
if (CreateStreamOnHGlobal(NULL, TRUE, &pStream) != S_OK)
{
GdiplusShutdown(gdiplusToken);
return false;
}
bmp.Save(pStream, &clsid, NULL);
HGLOBAL hGlobal = NULL; // 修改为 HGLOBAL 类型
if (GetHGlobalFromStream(pStream, &hGlobal) != S_OK) // 修改为 HGLOBAL 类型
{
pStream->Release();
GdiplusShutdown(gdiplusToken);
return false;
}
ULONG cbSize = GlobalSize(hGlobal); // 修改为 HGLOBAL 类型
BYTE* pJpegBuf = (BYTE*)GlobalLock(hGlobal); // 修改为 HGLOBAL 类型
if (pJpegBuf == NULL)
{
pStream->Release();
GdiplusShutdown(gdiplusToken);
return false;
}
LARGE_INTEGER li;
li.QuadPart = 0;
if (pStream->Seek(li, STREAM_SEEK_SET, NULL) != S_OK)
{
GlobalFree(pJpegBuf);
pStream->Release();
GdiplusShutdown(gdiplusToken);
return false;
}
if (pStream->Read(pJpegBuf, cbSize, NULL) != S_OK)
{
GlobalFree(pJpegBuf);
pStream->Release();
GdiplusShutdown(gdiplusToken);
return false;
}
pStream->Release();
GdiplusShutdown(gdiplusToken);
// 将 JPEG 数据的长度发送到客户端
if (client.Send((char*)&cbSize, sizeof(cbSize)) <= 0)
{
GlobalFree(pJpegBuf);
return false;
}

// 将 JPEG 数据发送到客户端
if (client.Send((char*)pJpegBuf, cbSize) <= 0)
{
GlobalFree(pJpegBuf);
return false;
}

// 清理资源
GlobalFree(pJpegBuf);
return true;
}

// 获取图像编码器的 CLSID
static void GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
UINT num = 0, size = 0;
GetImageEncodersSize(&num, &size);
if (size == 0)
{
return;
}
ImageCodecInfo* pImageCodecInfo = (ImageCodecInfo*)malloc(size);
if (pImageCodecInfo == NULL)
{
return;
}
GetImageEncoders(num, size, pImageCodecInfo);
for (UINT i = 0; i < num; ++i)
{
if (wcscmp(pImageCodecInfo[i].MimeType, format) == 0)
{
*pClsid = pImageCodecInfo[i].Clsid;
free(pImageCodecInfo);
return;
}
}
free(pImageCodecInfo);
}
// 处理鼠标移动请求
static void HandleMouseMoveRequest(int x, int y)
{
// 获取屏幕的宽高
int width = GetSystemMetrics(SM_CXSCREEN);
int height = GetSystemMetrics(SM_CYSCREEN);

// 计算相对于屏幕的坐标
double fx = (double)x / 65535.0;
// 移动鼠标
SetCursorPos(x, y);
}

// 处理鼠标单击请求
static void HandleMouseClickRequest(int x, int y)
{
// 获取屏幕的宽高
int width = GetSystemMetrics(SM_CXSCREEN);
int height = GetSystemMetrics(SM_CYSCREEN);

// 计算相对于屏幕的坐标
double fx = (double)x / 65535.0;
double fy = (double)y / 65535.0;
int cx = (int)(fx * width);
int cy = (int)(fy * height);

// 移动鼠标
SetCursorPos(cx, cy);

// 发送鼠标左键单击消息
INPUT input;
memset(&input, 0, sizeof(input));
input.type = INPUT_MOUSE;
input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP;
SendInput(1, &input, sizeof(input));
}

// 处理键盘输入请求
static void HandleKeyInputRequest(char key)
{
// 获取键盘的输入模式
HKL layout = GetKeyboardLayout(0);
UINT vk = MapVirtualKeyExA(VkKeyScanExA(key, layout), 0, layout);

// 发送键盘输入消息
INPUT input;
memset(&input, 0, sizeof(input));
input.type = INPUT_KEYBOARD;
input.ki.wVk = vk;
SendInput(1, &input, sizeof(input));
}
private:
Socket m_socket; // 监听套接字
};

int main()
{
RemoteDesktopServer server;
if (!server.Init(5555))
{
cout<<"启动服务器失败!"<<endl;
return 1;
}
server.Run();
return 0;
}


希望这些代码能帮到你!

更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

jdjwzx233 微信支付

微信支付

jdjwzx233 支付宝

支付宝

jdjwzx233 QQ支付

QQ支付