ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

VC远程控制源码解析:WINLOGON与GetInfo双工程实战

VC远程控制源码解析:WINLOGON与GetInfo双工程实战 简介这份资源是面向VC初学者与网络编程进阶者的远程控制软件完整源码包基于Visual C与Windows API实现帮助读者理解屏幕共享、文件传输、键鼠模拟等远程控制核心功能的底层原理。压缩包共30个文件约37KB以h头文件与cpp源文件为主体另含ico图标、bmp位图、rc资源脚本及dsp、dsw工程文件可直接用Visual Studio打开编译。源码按WINLOGON与GetInfo两大模块组织前者涉及登录会话与权限验证后者负责获取远程计算机系统状态与硬件配置并借助Winsock套接字完成客户端与服务器端通信。目前已有686人学习下载适合希望从零梳理远程控制架构、研究网络通信与多线程处理、或对照源码调试排错的开发者参考也可作为课程设计或毕业设计的实践素材。1. 从一份 VC 远程控制源码包说起WINLOGON 与 GetInfo 到底能跑出什么很多人第一次拿到visual c vc编写远程控制软件源码.zip第一反应是「这不就是个老掉牙的 MFC 工程吗」。但真把压缩包解开看到WINLOGON.dsw、GetInfo.dsw两个工作区加上WINLOGONView.cpp、GetInfoDlg.cpp这些典型 VC6 风格的源文件就会意识到这是一套完整的双模块结构一个负责会话与登录态相关的宿主端一个负责采集远端机器信息。它解决的不是「写个 Socket 发字符串」这种玩具需求而是把远程控制里最核心的三件事——连接建立、屏幕/信息采集、事件回传——拆成了可编译、可调试的工程骨架。适合谁适合已经会一点 C、想搞明白远程控制底层怎么落地的人也适合需要一套能直接改的 MFC 框架做二次开发的人。它不承诺开箱即用但给了你一个能跑起来的起点。2. 拆开 WINLOGON 与 GetInfoMFC 双工程结构怎么读2.1 两个 .dsw 的分工与依赖关系压缩包里最显眼的是两个工作区文件WINLOGON.dsw和GetInfo.dsw。很多人会以为这是同一个程序的两个版本其实不是。WINLOGON是一个标准的 MFC 单文档SDI工程从MainFrm.cpp、WINLOGONDoc.cpp、WINLOGONView.cpp这套三件套就能看出来它承担的是主界面和会话管理GetInfo则是一个基于对话框的工程核心是GetInfoDlg.cpp负责弹窗式地采集和展示远端信息。为什么这么拆常见做法是主控端需要长时间驻留、有菜单和工具栏Toolbar.bmp、WINLOGON.rc2就是证据所以用 SDI而被控端或信息采集端只需要一个轻量对话框启动快、依赖少用 Dialog Based 更合适。两个工程各自有独立的Resource.h、StdAfx.cpp、res目录说明它们可以单独编译也可以由主工程通过进程或 Socket 去拉起另一个。读源码的顺序建议是先看GetInfo因为它逻辑闭环短从GetInfoDlg.cpp的OnInitDialog进去能很快看到它怎么初始化网络和采集本机信息再回头看WINLOGON从WINLOGON.cpp的InitInstance入手理清主框架怎么创建、View 怎么挂上去。2.2 从 WINLOGONView 看屏幕与事件回传的落点WINLOGONView.cpp是整个包里最值得逐行读的文件。MFC 的 View 类天然适合做绘制远程控制里的屏幕回传通常就落在这里。常见做法是在 View 里起一个定时器或者独立线程周期性抓取桌面位图压缩后通过 Socket 发出去同时重写OnKeyDown、OnMouseMove这些消息处理函数把本地输入事件打包发到远端。源码里没有直接给出完整的抓屏函数但WINLOGONView.h的成员变量声明会暴露意图——如果看到CClientSocket或类似的成员说明网络层是嵌在 View 里的。参数上要留意两点一是抓屏的间隔太短会吃满 CPU太长操作延迟明显一般 50 到 100 毫秒是常见起点二是位图格式VC6 环境下多用CreateCompatibleBitmap配合BitBlt传输前往往要转成 JPEG 或简单的 RLE 压缩否则一帧 1920×1080 的原始位图能到好几 MB网络根本扛不住。2.3 GetInfo 对话框里的信息采集路径GetInfoDlg.cpp里的采集逻辑通常分两类一类是调用 Windows API 直接拿比如GetSystemInfo取 CPU 架构、GlobalMemoryStatus取内存、GetComputerName取机器名另一类是读注册表或 WMI拿操作系统版本和已安装软件列表。源码里GetInfo.h和GetInfoDlg.h的成员函数命名会告诉你它采了哪些字段。这里有个容易忽略的点VC6 默认的StdAfx.h里包含的 Windows 头文件版本较老如果你在 Win10/Win11 上编译某些结构体字段可能对不上。常见做法是保留StdAfx.cpp的预编译头机制但把_WIN32_WINNT宏调到0x0501以上否则GetSystemInfo返回的部分信息会缺失。// GetInfoDlg.cpp 中典型的信息采集片段示意 void CGetInfoDlg::CollectSystemInfo() { // 获取计算机名 char szName[MAX_COMPUTERNAME_LENGTH 1]; DWORD dwSize sizeof(szName); GetComputerNameA(szName, dwSize); m_strComputerName szName; // 获取内存状态 MEMORYSTATUS memStatus; memStatus.dwLength sizeof(MEMORYSTATUS); GlobalMemoryStatus(memStatus); m_dwTotalMemMB memStatus.dwTotalPhys / (1024 * 1024); // 获取系统信息 SYSTEM_INFO sysInfo; GetSystemInfo(sysInfo); m_dwProcessorCount sysInfo.dwNumberOfProcessors; UpdateData(FALSE); // 刷新到对话框控件 }这段代码的逻辑很直白先拿机器名再拿内存和 CPU 核数最后UpdateData(FALSE)把成员变量刷到界面。参数上注意MEMORYSTATUS必须先设dwLength否则GlobalMemoryStatus直接失败MAX_COMPUTERNAME_LENGTH在 VC6 里是 15如果你的机器名超过 15 个字符得自己把缓冲区开大。3. 把源码跑起来VC6 到 VS2022 的编译与网络初始化3.1 工程升级与字符集踩坑这套源码是典型的 VC6 工程.dsp和.dsw在 VS2022 里不能直接打开。常见做法是用 VS2022 的「打开项目」选.dsw让它自动转换转换完会生成.vcxproj。转换后第一件事是检查字符集——VC6 默认多字节MBCS而新版 VS 默认 Unicode。如果源码里大量用了char和sprintf强行切 Unicode 会报一堆C2664无法转换参数的错误。稳妥的做法是在项目属性里把「字符集」改成「使用多字节字符集」同时确保安装了「MFC 和 ATL 支持」组件。如果 VS2022 提示找不到afxwin.h就是 MFC 组件没装去 Visual Studio Installer 里勾上「适用于最新 v143 生成工具的 C MFC」。# 检查本机是否已安装 MFC以 VS2022 为例 dir C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\*\atlmfc\include\afxwin.h这条命令只是确认头文件在不在。如果返回「找不到文件」别急着改代码先去装组件。装完再编译能省掉一半的玄学报错。3.2 Winsock 初始化与连接参数远程控制的地基是网络。VC6 时代用 Winsock 1.1 或 2.2初始化套路固定WSAStartup起手socket建套接字bind/listen/accept或connect走流程。源码里WINLOGON.cpp的InitInstance附近通常会有AfxSocketInit()这是 MFC 对WSAStartup的封装省去了手动清理的麻烦。参数上要盯住三个端口号、缓冲区大小、超时。端口一般选 1024 以上避免权限问题缓冲区建议 8192 或 16384太小会导致频繁分包太大在弱网下容易卡超时用setsockopt设SO_RCVTIMEO不设的话recv会一直阻塞界面直接假死。// WINLOGON.cpp 中典型的 Socket 初始化示意 BOOL CWinlogonApp::InitInstance() { if (!AfxSocketInit()) // 初始化 Winsock { AfxMessageBox(_T(Winsock 初始化失败)); return FALSE; } CWinlogonDlg dlg; m_pMainWnd dlg; dlg.DoModal(); return FALSE; }AfxSocketInit必须在任何 Socket 调用之前执行放在InitInstance开头是最稳的。如果返回 FALSE多半是ws2_32.lib没链接去项目属性里加上即可。3.3 编译产物与运行依赖编译成功后GetInfo.exe和WINLOGON.exe会分别落在各自的Debug或Release目录。VC6 工程默认静态链接 MFC 的话exe 可以直接拷走如果用的是动态链接目标机器上得有对应的 MFC 运行库。这也是为什么很多人搜microsoft visual c redistributable——缺了运行库程序双击就报「找不到 mfc42.dll」。判断方法很简单看项目属性里「MFC 的使用」是「在静态库中使用 MFC」还是「在共享 DLL 中使用 MFC」。前者体积大但独立后者体积小但依赖运行库。做远程控制这种要往别人机器上放的工具静态链接更省心。4. 避坑与排查编译、连接、抓屏里的血泪经验4.1 现象VS2022 打开 .dsw 后大量 afx 头文件报错原因MFC 组件未安装或者工程转换时字符集被强制改成 Unicode而源码是 MBCS 写的。解决先在 Visual Studio Installer 里确认「C MFC for latest v143 build tools」已勾选再在项目属性 → 高级 → 字符集里改回「使用多字节字符集」。两步做完afxwin.h和afxext.h的报错基本消失。4.2 现象程序能编译但一运行就提示「Winsock 初始化失败」原因AfxSocketInit调用时机不对或者ws2_32.lib没链接。解决把AfxSocketInit挪到InitInstance的第一行然后在项目属性 → 链接器 → 输入 → 附加依赖项里加上ws2_32.lib。如果还不行检查是不是在DllMain里调用了 Socket那种场景下 Winsock 还没准备好。4.3 现象连接建立后屏幕画面卡顿或花屏原因抓屏间隔太短导致 CPU 占满或者位图压缩没做好网络带宽被原始数据打满。解决把抓屏定时器从 10ms 调到 50~100ms传输前用CImage或简单的 JPEG 编码压一下。如果花屏检查BitBlt的源 DC 和目标 DC 是否兼容以及CreateCompatibleBitmap用的 DC 是不是屏幕 DC。4.4 现象GetInfo 采集的内存和 CPU 信息为 0 或异常值原因MEMORYSTATUS结构体没设dwLength或者_WIN32_WINNT宏太低导致 API 行为不一致。解决调用GlobalMemoryStatus前必须写memStatus.dwLength sizeof(MEMORYSTATUS);在StdAfx.h里把_WIN32_WINNT定义为0x0501或更高重新编译。4.5 现象在 Win10/Win11 上运行界面正常但键盘鼠标事件发不出去原因VC6 时代的keybd_event/mouse_event在新系统上受 UIPI 限制普通权限进程无法向高权限窗口发送输入。解决这不是源码 bug是系统安全机制。测试时让两端进程权限一致如果确实需要跨权限得走SendInput并确保进程有足够权限。远程控制场景下常见做法是让被控端以服务方式运行避免权限断层。5. 进阶把 GetInfo 改造成可扩展的信息通道源码里的GetInfo只采了基础字段但它的对话框结构其实很适合扩展。我一般会做三件事第一把采集逻辑从GetInfoDlg.cpp里抽出来单独放一个CSystemInfoCollector类这样主控端和被控端都能复用第二加一个简单的 TLVType-Length-Value协议让信息字段可以按需增减不用改通信层第三给采集函数加超时和异常捕获因为 WMI 查询在部分机器上会卡住。// 扩展后的信息采集接口示意 struct InfoField { int type; // 字段类型如 1机器名 2内存 std::string value; // 字段值 }; class CSystemInfoCollector { public: std::vectorInfoField CollectAll() { std::vectorInfoField fields; // 机器名 char szName[MAX_COMPUTERNAME_LENGTH 1]; DWORD dwSize sizeof(szName); if (GetComputerNameA(szName, dwSize)) { fields.push_back({1, szName}); } // 内存 MEMORYSTATUS memStatus; memStatus.dwLength sizeof(MEMORYSTATUS); GlobalMemoryStatus(memStatus); fields.push_back({2, std::to_string(memStatus.dwTotalPhys / (1024 * 1024))}); return fields; } };这样改完GetInfoDlg只负责展示采集逻辑独立可测。TLV 协议的好处是以后想加「已安装软件列表」或「磁盘剩余空间」只要新增一个 type老版本收到不认识的 type 直接跳过不会崩。验证方法也简单在本机起两个GetInfo.exe一个当服务端监听一个当客户端连接看采集字段能不能完整传过去。如果字段丢失先查 TLV 的长度字段是不是按网络字节序发的——这是最常见的翻车点x86 是小端网络是大端忘了htonl就会读出天文数字。从那以后我每次拿到这种老 VC 工程都强制先跑一遍「字符集 MFC 组件 Winsock 链接」三件套检查再动代码。希望帮到你。本文还有配套的精品资源点击获取
返回列表