Gh0st通信协议解析
Hart协议 通讯基础知识

现代工业生产中存在着多种不同的主机和现场设备,要想很好地使用他们,完善的通讯协议是必须的。
HART协议最初是由美国Rosemount公司开发,已应用了多年。
HART协议使用FSK技术,在4~20mA信号过程量上叠加一个频率信号,成功地把模拟信号和数字信号双向同时通讯,而不互相干扰。
HART协议参照了国际标准化组织的开放性互连模型,使用OSI标准的物理层、数据链路层、应用层。
HART协议规定了传输的物理形式、消息结构、数据格式和一系列操作命令,是一种主从协议。
当通讯模式为“问答式”的时候,一个现场设备只做出被要求的应答。
HART协议允许系统中存在2个主机(比如说,一个用于系统控制,另一个用于HART通信的手操仪),如果不需要模拟信号,多点系统中的一对电缆线上最多可以连接15个从设备。
物理层附件: 您所在的用户组无法下载或查看附件物理层规定了信号的传输方法、传输介质。
采用Bell202标准的FSK频移键控信号,在低频的4~20mA模拟信号上叠加一个频率数字信号进行双向数字通信。
数字信号的幅度为0 . 5 m A,数据传输率为1200bps,1200Hz代表逻辑“1”,2200Hz代表逻辑“0”。
数字信号波形如上图所示。
数据链路层数据链路层规定HART协议帧的格式,可寻址范围0~15,“0”时,处于4~20mA及数字信号点对点模式,现场仪表与两个数字通信主设备(也称作通信设备或主设备)之间采用特定的串行通信,主设备包括PC机或控制室系统和手持通信器。
单站操作中,主变量(过程变量)可以以模拟形式输出,也可以以数字通信方式读出,以数字方式读出时,轮询地址始终为0。
也就是说,单站模式时数字信号和4~20mA模拟信号同时有效。
“1~15”处于全数字通信状态,工作在点对多点模式,通信模式有“问答”式、“突发”式(点对点、自动连续地发送信息)。
按问答方式工作时的数据更新速率为2~3次/s,按突发方式工作时的数据更新速率为3~4次/s。
Gh0st源代码详细剖析

声明:首先声明,这篇文章完全是根据自己对gh0st源代码的理解写出来的,如果有理解上的偏差或者表述上的错误本人不负责,仅供参考!前言:在我刚学习gh0st源代码的时候,觉得这东西好难,三个工程放在一起不说,还有那么多文件,当时就懵了。
这怎么看呢?从何下手呢?我想大部分刚学习gh0st源代码的同胞们都有和我一样的想法,我废话不多说了,下面就为大家详细讲解gh0st源代码。
思路:首先我会讲解gh0st的整体框架,包括三个工程之间的关系和每个工程的作用;然后再根据程序的执行顺序,从入口函数WinMain开始逐步向下讲解。
框架:gh0st有三个工程,分别是gh0st、install和svchost。
那么这三个工程有什么作用呢?首先gh0st这个工程,是生成控制端的一个工程,换句话说就是用MFC写的界面。
但是你千万不要小看它。
因为它绝不仅仅是一个界面那么简单,在这个控制端里面还包括IOCP完成端口、网络socket和控制端与服务端之间的数据传输;install这个工程较其他两个工程就简单多了,因为它只有一个.h文件和一个.cpp文件。
这个工程是整个程序的入口,因为WinMain函数就在这里,它的主要功能就是生成一个exe文件,而这个exe文件的工程就是安装和启动dll里面的服务的;接下来就是第三个工程了,前面所说的dll就是这个工程。
它的主要功能就是执行服务函数,并完成与控制端的通信。
所以用一句话来概括gh0st的功能就是:exe安装并启动dll里面的服务,dll执行服务并与控制端进行通信,从而实现各项远程功能。
代码解读:首先看install这个工程:(红色部分为源代码)int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow){// 让启动程序时的小漏斗马上消失GetInputState();PostThreadMessage(GetCurrentThreadId(),NULL,0,0);MSG msg;GetMessage(&msg, NULL, NULL, NULL);char *lpEncodeString = NULL;char *lpServiceConfig = NULL;char *lpServiceDisplayName = NULL;char *lpServiceDescription = NULL;这个WinMain函数就是程序的入口,四个参数分别是hInstance应用程序当前的实例句柄、hPrevInstance应用程序先前的实例句柄、lpCmdLine指定传给应用程序的命令行参数、nCmdShow指定窗口如何显示;首先是GetInputState()这个API函数,它的功能是要让小漏斗马上消失,这是因为以前的cpu运行速度很慢,所以当你打开一个程序的时候会有一个小漏斗在屏幕上显示,直到程序打开漏斗才消失;然后是PostThreadMessage(GetCurrentThreadId(),NULL,0,0)这个函数,大家首来先看GetCurrentThreadId这个函数,这个函数的功能是获得当前线程的PID,也就是获得当前正在运行线程的唯一标示符;而PostThreadMessage这个函数呢就是把当前线程的唯一标示符送入系统的消息队列中。
fota技术原理

FOTA技术原理解析1. 引言FOTA(Firmware Over-The-Air)是指通过无线网络远程升级设备固件的技术。
它可以实现在设备运行期间无需物理连接,直接通过网络下载和安装新的固件版本。
FOTA技术在智能手机、物联网设备等领域得到广泛应用,为用户提供了便利的固件升级方式。
本文将详细解释FOTA技术的基本原理,包括传输协议、固件分发、安全性等方面,以帮助读者全面了解FOTA技术的工作原理。
2. FOTA传输协议在进行FOTA过程中,选择合适的传输协议对于成功完成固件升级至关重要。
常见的FOTA传输协议有以下几种:2.1 HTTP/HTTPSHTTP(Hypertext Transfer Protocol)是一种应用层协议,常用于Web浏览器和服务器之间的通信。
HTTPS则是在HTTP基础上加入了SSL/TLS加密机制。
HTTP/HTTPS可以通过普通的HTTP服务器或者CDN(Content Delivery Network)来进行固件分发。
设备可以通过发送HTTP GET请求来获取最新版本的固件文件,并进行下载和安装。
优点:简单易用,广泛支持,适用于各种设备和场景。
缺点:不支持断点续传,对于大文件的传输效率较低。
2.2 MQTTMQTT(Message Queuing Telemetry Transport)是一种轻量级的发布/订阅协议,常用于物联网设备之间的通信。
在FOTA过程中,设备可以通过MQTT客户端订阅一个特定的主题(Topic),服务器将固件文件发布到该主题上。
设备收到固件文件后进行下载和安装。
优点:适用于低带宽、不稳定网络环境,支持断点续传。
缺点:相对复杂一些,需要额外的MQTT服务器支持。
2.3 CoAPCoAP(Constrained Application Protocol)是一种专门为物联网设备设计的轻量级应用层协议。
与HTTP类似,CoAP也是基于RESTful架构风格的。
hssl通讯原理

hssl通讯原理
HTTPS通信原理如下:
HTTPS(HTTP over SSL/TLS)是HTTP应用层协议和TCP传输层协议之间增加了一个安全套接层SSL/TLS。
SSL/TLS层负责客户端和服务器之间的加解密算法协商、密钥交换、通信连接的建立。
在传输数据之前,客户端(浏览器)与服务端(网站)之间需要完成一次握手过程。
在这个过程中,将确立双方加密传输数据的密码信息。
具体过程如下:
1. 客户端生成随机数,发送给服务器端。
2. 服务器端使用公钥对随机数进行签名,并将签名回传给客户端。
3. 客户端使用自己持有的公钥对服务器返回的随机数签名进行验证,如果验证通过,说明该服务器确实拥有对应的私钥,此时可以判定该服务器的身份是合法的。
双方身份合法之后,需要建立安全的会话。
在这个过程中,客户端会生成会话密钥,使用服务器公钥进行加密,然后服务器用自己的私钥解密后,用会话密钥加密数据进行传输。
此外,TLS/SSL协议不仅仅是一套加密传输的协议,更是一件经过艺术家精心设计的艺术品,其中使用了非对称加密、对称加密以及HASH算法等。
以上信息仅供参考,建议咨询专业人士以获得准确信息。
盛科higig协议(2024精)

盛科Higig协议简介盛科Higig(HiGigabitInterface)协议是一种高性能的数据通信协议,用于在网络设备之间传输数据。
它被广泛应用于网络交换机、路由器等网络设备中,提供高速、可靠的数据传输功能。
本文将介绍Higig协议的起源、工作原理以及在网络设备中的应用。
起源盛科Higig协议最初由Broadcom公司开发,旨在解决高性能网络设备之间的数据通信需求。
在当时,传统的以太网协议已经无法满足高速网络设备的需求,因此需要一种新型的协议来保证数据传输的高速和可靠性。
而Higig协议应运而生,成为了解决高性能网络设备通信问题的重要方案。
工作原理Higig协议在物理层和数据链路层之间起到了桥梁的作用,使得高性能网络设备能够以高速进行数据传输。
它使用一种特殊的帧格式来将数据包进行打包和解包,确保数据的可靠传输。
在物理层,Higig协议使用了高速串行连接,通常为光纤或者高速差分对。
这样可以实现更高的数据传输速率和较长的传输距离。
在数据链路层,Higig协议将数据包进行封装,通过添加一些特殊的字段来标示数据包的类型和属性。
这些特殊字段包括包头、包尾、校验和等。
这样,接收端能够根据这些字段来正确解析数据包,保证数据的正确性。
Higig协议还支持流控制和拥塞控制等机制,用于处理高速数据传输时出现的问题。
例如,当网络设备的接收端缓冲区已满时,发送端可以通过流控制机制通知发送速率。
这样可以避免数据丢失和传输延迟过大。
应用Higig协议在网络设备中有着广泛的应用。
它被用于各种网络设备,包括网络交换机、路由器、光纤通信设备等。
在网络交换机中,Higig协议被用于连接不同交换机之间的上行链路。
通过使用Higig协议,交换机之间可以高速、可靠地进行数据传输,实现网络中大数据量的快速交换。
在路由器中,Higig协议被用于连接不同路由器之间的数据传输。
它可以将数据包从一个路由器传输到另一个路由器,实现网络之间的连接。
HART协议传输原理和特点

HART协议传输原理和特点HART(Highway Addressable Remote Transducer,可寻址远程传感器高速通道)的开放通信协议,是美国Rosement公司于1985年推出的一种用于现场智能仪表和控制室设备之间的通信协议。
HART装置提供具有相对低的带宽,适度响应时间的通信,经过10多年的发展,HART技术在国外已经十分成熟,并已成为全球智能仪表的工业标准。
1、HART协议的传输原理HART协议采用基于Be11202标准的FSK频移键控信号,在低频的4-20mA模拟信号上叠加幅度为0.5mA的音频数字信号进行双向数字通信,数据传输率为1.2Mbps。
由于FSK信号的平均值为O,不影响传送给控制系统模拟信号的大小,保证了与现有模拟系统的兼容性。
在HART协议通信中主要的变量和控制信息由4-20mA模拟信号传送,在需要的情况下,另外的测量、过程参数、设备组态、校准、诊断信息通过HART协议访问。
图1 HART协议的传输原理2、HART协议的三类命令HART通信采用的是半双工的通信方式,其特点是在现有模拟信号传输线上实现数字信号通信,属于模拟系统向数字系统转变过程中过渡性产品,因而在当前的过渡时期具有较强的市场竞争能力,得到了较快发展。
HART规定了一系列命令,按命令方式工作。
它有三类命令,第一类称为通用命令,这是所有设备都理解、都执行的命令;第二类称为一般行为命令,所提供的功能可以在许多现场设备(尽管不是全部)中实现,这类命令包括最常用的现场设备的功能库;第三类称为特殊设备命令,以便于工作在某些设备中实现特殊功能,这类命令既可以在基金会中开放使用,又可以为开发此命令的公司所独有。
在一个现场设备中通常可发现同时存在这三类命令。
3、HART协议的优点①HART采用统一的设备描述语言DDL现场设备开发商采用这种标准语言来描述设备特性,由HART基金会负责登记管理这些设备描述并把它们编为设备描述字典,主设备运用DDL技术来理解这些设备的特性参数而不必为这些设备开发专用接口。
Gh0st3.75远程控制的原理和使用

Gh0st3.75远程控制的原理和使用【摘要】Gh0st3.75免杀远控是一款功能十分强大的远程控制的软件,可实现远程电脑控制,键盘记录,文件浏览和音频聊天等功能。
本文首先简单介绍了远程控制的原理和用途,之后简单介绍了Gh0st3.75免杀远控的功能和应用,然后通过实例演示了Gh0st3.75免杀远控的配置使用过程,并对该软件做出了总结与评价。
【关键字】Gh0st3.75免杀远控;远程控制原理;远程控制应用1.远程控制简介远程控制软件,主要用于pc管理和服务,是在网络上由一台电脑(主控端 /客户端)远距离去控制另一台电脑(被控端 Host/服务器端)的应用软件,使用时客户端程序向被控端电脑中的服务器端程序发出信号,建立一个特殊的远程服务,然后通过这个远程服务,使用各种远程控制功能发送远程控制命令,控制被控端电脑中的各种应用程序运行。
具有强大的内网穿透功能。
1.1远程控制的原理远控软件一般分客户端程序(Client)和服务器端程序(Server)两部分,通常将客户端程序安装到主控端的电脑上,将服务器端程序安装到被控端的电脑上。
使用时客户端程序向被控端电脑中的服务器端程序发出信号,建立一个特殊的远程服务,然后通过这个远程服务,使用各种远程控制功能发送远程控制命令,控制被控端电脑中的各种应用程序运行。
用户连接到网络上,通过远程访问的客户端程序发送客户身份验证信息和与远程主机连接的要求,远程主机的服务器端程序验证客户身份,如果验证通过,那么就与客户建立连接,并向用户发送给验证通过和已建立连接的信息。
那么这个时候,用户便可以通过客户端程序监控或向远程主机发送要执行的指令,而服务器端程序则执行这些指令,并把键盘、鼠标和屏幕刷新数据传给客户端程序,客户端程序通过运算把主机的屏幕等信息显示给用户看,使得用户可以在远程主机上进行工作。
如果没有通过身份验证的话,就是没有与用户建立连接,用户也就不能远程控制远程主机了。
gh0st源码笔记 详解

免费的!MICROSOFT SPEECH SDK 5.1\INCLUDEMICROSOFT SPEECH SDK 5.1\LIB以上两个目录是教程里面提到的,可以不使用,一样可以编译第一节课新建MFC工程,单文档模式,基类用CListView,其余默认即可打开gh0stView.cpp找到void CGh0stView::OnInitialUpdate()函数新建一个结NONCLIENTMETRICS ncm;NONCLIENTMETRICS这个结构就包含了非客户区的一些属性对ncm变量进行初始化memset(&ncm, 0, sizeof(NONCLIENTMETRICS));对这个结构的成员函数进行设置ncm.cbSize = sizeof(NONCLIENTMETRICS); //指定了ncm的大小使用宏VERIFY(::SystemParametersInfo(SPI_GETNONCLIENTMETRICS,sizeof(NONCLIENTMETRICS), &ncm,0));其目的是方便调试,在Debug版本中,如果计算的表达式为0则中断程序,并打印出错误信息,如果在Release版本中,出现表达式为0的时候,则不做任何的处理,当没有发生::SystemParametersInfo调用系统函数,查询或是设置系统参数,或是修改用户的一个外观,返回值是一个BOOL类型第一个参数是获取非客户区参数第二个参数是整个的非客户区结构的大小第三个参数是将获得到的信息保存在ncm这个地址中第四个参数由于是为了获取信息写0即可,如果是设置信息为目的,就需要换成其它参考MSDN第二节课在gh0stView.h中声明一个私有成员变量公有成员可以被所有类访问受保护成员只能在类内部或其子类可以访问私有成员只能在类内部访问,其子类是不可以访问的private:CListCtrl* m_pListCtrl;私有的列表控件的指针,为什么要声明这个呢,我们之前提到了基类是CListView,因此在这个里声明了一个指针CPP是执行文件,H是头文件接下来对我们在CPP文件中声明的私有成员变量进行赋值m_pListCtrl=&GetListCtrl();GetListCtrl()这个函数的原型是CListView::GetListCtrlCListCtrl& GetListCtrl() const; 得到一个和视图相关联的一个列表控件的引用引用的使用方法:引用相当于是一个别名,周瑜和周公谨是一个人,引用和变量也相当于是一个东西int m;int &n = m; //为变量m定义了一个引用n,m是被引用,对n的操作就相当于对m来进行操作了,这里n既不是m的一个拷贝,又不是指向m的一个指针,而n就是m,作用就是用于函数的型参和返回值上,引用也是使用了一个地址传递的方式,比值传递的速度要快指针与引用的区别:主要是吴国的水军大都督是周瑜,那么这个吴国的水军大都督可看成是一个指针,引用被创建的时候是必须要进行初始化的,而指针是在任何时候被初始化的另一个引用不可以是NULL,必须有一个合法的存储单位和引用相关联,而指针是可以有NULL的。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
界面篇等我先搞完这个通信协议解析再说,要不我老觉得自己是在扯淡。
在这里我也给自己这两天搞的协议解析找个网络存储做一下备份。
Gh0st通信协议解析(1)正所谓蛇打七寸,今天我们对gh0st的通信协议进行一个完整的解析,看看gh0st这款远控的核心技术的来龙去脉。
************************************************************************ *******从主控端初始化IOCP服务器开始讲起[cpp]view plaincopyprint?1.// 启动IOCP服务器2.int nPort = m_IniFile.GetInt("Settings", "ListenPort");3.int nMaxConnection = m_IniFile.GetInt("Settings", "MaxConnection");4.if (nPort == 0)5. nPort = 80;6.if (nMaxConnection == 0)7. nMaxConnection = 10000;8.9.if (m_IniFile.GetInt("Settings", "MaxConnectionAuto"))10. nMaxConnection = 8000;11.12.((CMainFrame*) m_pMainWnd)->Activate(nPort, nMaxConnection); IOCP服务器是在CGh0stApp::InitInstance这个函数中被调用的,实际上是调用了CMainFrame的一个成员函数:CMainFrame::Active。
看看这个函数都做了哪些事情。
[cpp]view plaincopyprint?1.void CMainFrame::Activate(UINT nPort, UINT nMaxConnections)2.{3. CString str;4.5.if (m_iocpServer != NULL)6. {7. m_iocpServer->Shutdown();8.delete m_iocpServer;9.10. }11. m_iocpServer = new CIOCPServer;12.13.// 开启IPCP服务器14.if (m_iocpServer->Initialize(NotifyProc, this, 100000, nPort))15. {16.17.char hostname[256];18. gethostname(hostname, sizeof(hostname));19. HOSTENT *host = gethostbyname(hostname);20.if (host != NULL)21. {22.for ( int i=0; ; i++ )23. {24. str += inet_ntoa(*(IN_ADDR*)host->h_addr_list[i]);25.if ( host->h_addr_list[i] + host->h_length >= host->h_name )26.break;27. str += "/";28. }29. }30.31. m_wndStatusBar.SetPaneText(0, str);32. str.Format("端口: %d", nPort);33. m_wndStatusBar.SetPaneText(2, str);34. }35.else36. {37. str.Format("端口%d绑定失败", nPort);38. m_wndStatusBar.SetPaneText(0, str);39. m_wndStatusBar.SetPaneText(2, "端口: 0");40. }41.42. m_wndStatusBar.SetPaneText(3, "连接: 0");43.}首先判断这个m_iocpServer全局变量是否已经指向了一个CIOCPServer,如果是的话,就要先关闭它,并且删除掉这个CIOCPServer所占的内存空间。
到这里我有些犹豫要不要去追踪这个CIOCPServer::Shutdown函数呢,一方面,如果去追踪的话,我们将不得不深入到CIOCPServer这个类里面去抽丝剥茧,寻找Shutdown函数,以及这个函数内部所调用的一系列的函数,这样我不得不深度遍历整个调用过程。
另一方面,如果追踪吧,会使得这篇文章的主线凌乱掉,如果不追踪吧,我自己会凌乱掉,思前想后,宁可让大家疯掉,也不能让我疯掉,因为我疯掉了就写不出这个分析文章了……好了,我们接下来看看这个CIOCPServer::Shutdown这个函数内部的一个执行逻辑。
[cpp]view plaincopyprint?1.void CIOCPServer::Shutdown()2.{3.if (m_bInit == false)4.return;5.6. m_bInit = false;7. m_bTimeToKill = true;8.9.// Stop the listener10. Stop();11.12.13. closesocket(m_socListen);14. WSACloseEvent(m_hEvent);15.16.17. CloseCompletionPort();18.19. DeleteCriticalSection(&m_cs);20.21.while (!m_listFreePool.IsEmpty())22.delete m_listFreePool.RemoveTail();23.24.}先来看看这个CIOCPServer::m_bInit这个变量。
这个变量有什么作用呢,看这些个地方:1:在CIOCPSserver的构造函数中有这么一句:m_bInit = false;2:在CIOCPServer::Initialize这个函数中有这么一句:m_bInit = true;3:在CIOCPServer::Shutdown这个函数中有这么一句:m_bInit = false;4:在CIOCPServer::IsRunning这个函数中有这么一句:return m_bInit;从以上的各个地方我们可以知道,这个m_bInit就是一个记录CIOCPServer这个服务器的运行状态的,它只有两个意思:开启或者关闭。
当CIOCPServer服务器初始化完毕的时候,此值将会被设为true。
在关闭的时候,此值将会被设为false,其它的时候此值作为CIOCPServer运行状态的一个考量。
首先判断这个m_binit是否为false,如果为false那CIOCPServer本身就没有开启,还关闭个屁,如果为true的话,接下来就将其运行状态设为false。
然后看看CIOCPServer::m_bTimeToKill这个变量。
这个变量的作用:1:在CIOCPSserver的构造函数中有这么一句:m_bTimeToKill = false;2:在CIOCPServer::Shutdown这个函数中有这么一句:m_bTimeToKill = true;3:在核心的完成端口循环中有这么一句:for (BOOL bStayInPool = TRUE; bStayInPool && pThis->m_bTimeToKill == false; )可以看出,m_bTimeToKill这个值就是一个记录是否结束掉在完成端口的所有等待线程的这么一个哨兵值,如果该值被设置为true,那么所有等待在完成端口上的线程都将结束并退出,这样,就不会再有工作线程来处理这个完成端口上的所有Read、Write、Initize的请求,在这里要明白一点:工作线程数是跟运行主控端的机子上的核心数相关的。
接下来,我们程序的流程就到了CIOCPSserver::Stop这个函数里了,这个函数的一个主要的功能就是结束掉这个监听的socket,已达到后续的连接请求不再受理。
我们看看在这个函数里CIOCPServer都做了哪些处理:[cpp]view plaincopyprint?1.void CIOCPServer::Stop()2.{3. ::SetEvent(m_hKillEvent);4. WaitForSingleObject(m_hListenThread, INFINITE);5. CloseHandle(m_hListenThread);6. CloseHandle(m_hKillEvent);7.}首先来看看这个CIOCPServer::m_hKillEvent这个变量的用途1:在CIOCPServer的构造函数中有这么一句调用m_hKillEvent = CreateEvent(NULL, TRUE, FALSE, NULL);在构造函数中创建了一个人工置信、初始状态为未受信的、未命名的事件对象。
2:在CIOCPServer::ListenThreadProc这个函数中有这么一句调用if (WaitForSingleObject(pThis->m_hKillEvent, 100) == WAIT_OBJECT_0)break;在监听上线的线程中的无限循环中,这一句的作用就是,当m_hKillEvent受信的时候,这个无限循环结束3:在一个关键的地方,就是在CIOCPServer::Stop中SetEvent(m_hKillEvent)的调用。
通过以上的分析我们可以看出,这个变量存在的意义,就是承担得起当要关闭CIOCPServer 这个服务器的时候,使得监听线程结束监听这么一个功能。
再来看看这个CIOCPServer::m_hThread这个变量的用途1:在CIOCPServer::Initialize函数中,有以下的这个调用[cpp]view plaincopyprint?1.m_hThread =(HANDLE)_beginthreadex(NULL,// Security2.3. 0, // Stack size - use default4.5. ListenThreadProc, // Thread fn entry point6.7. (void*) this,8.9. 0,// Init flag10.11. &dwThreadId); // Thread address2:在CIOCPServer::Stop中,有WaitForSingleObject(m_hThread, INFINITE)的调用。