监听串口的comspy源码分析_应用程序部分
最近项目需要,于是闭门拿了人家的源码改造一下,顺路分析如下:
1.ioctrl.h
构建IO控制码的宏
#define FILE_DEVICE_COMSPY 0x00001001
#define IOCTL_COMSPY_STARTMONITOR \
CTL_CODE(FILE_DEVICE_COMSPY, 0x0801, METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define IOCTL_COMSPY_STOPMONITOR \
CTL_CODE(FILE_DEVICE_COMSPY, 0x0802, METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define IO_REFERENCE_EVENT \
CTL_CODE(FILE_DEVICE_COMSPY, 0x0803, METHOD_NEITHER, \
FILE_ANY_ACCESS)
#define IO_DEREFERENCE_EVENT \
CTL_CODE(FILE_DEVICE_COMSPY, 0x0804, METHOD_NEITHER, \
FILE_ANY_ACCESS)
#define IO_SET_EVENT \
CTL_CODE(FILE_DEVICE_COMSPY, 0x0805, METHOD_NEITHER, \
FILE_ANY_ACCESS)
#define IO_CLEAR_EVENT \
CTL_CODE(FILE_DEVICE_COMSPY, 0x0806, METHOD_NEITHER, \
FILE_ANY_ACCESS)
#define IO_QUERY_EVENT_STATE \
CTL_CODE(FILE_DEVICE_COMSPY, 0x0807, METHOD_NEITHER, \
FILE_ANY_ACCESS)
#define IO_GET_SHAREMEMORY_ADDR \
CTL_CODE(FILE_DEVICE_COMSPY, 0x0808, METHOD_BUFFERED, \
FILE_ANY_ACCESS)
#define IO_CLEAN_SHAREMEMORY_ADDR \
CTL_CODE(FILE_DEVICE_COMSPY, 0x0809, METHOD_BUFFERED, \
FILE_ANY_ACCESS)
2.消息类型的枚举
enum
{
REQ_OPEN,
REQ_READ,
REQ_WRITE,
REQ_CLOSE,
REQ_FLUSH,
REQ_SETBAUDRATE,
REQ_SETLINECONTROL,
};
3.IO_REQ结构体
typedef struct tagIO_REQ
{
ULONG SizeTotal;
ULONG SizeCopied;
// ULONG SizeRequested;
CHAR type;
// LIST_ENTRY entry;
// PVOID pData;
DWORD Reserved1;
DWORD Reserved2;
DWORD Reserved3;
}IO_REQ, *PIO_REQ;
4.串行线路控制结构体
typedef struct _SERIAL_LINE_CONTROL
{
UCHAR StopBits;
UCHAR Parity;
UCHAR WordLength;
} SERIAL_LINE_CONTROL,*PSERIAL_LINE_CONTROL;
全局变量
1.serialspy.cpp
/////////////////////////////////////////////////////////////////////////////
// The one and only CSerialSpyApp object
CSerialSpyApp theApp;
HANDLE m_hDevice=INVALID_HANDLE_VALUE;/*设备句柄*/
HANDLE m_hCommEvent=INVALID_HANDLE_VALUE;/*通讯事件*/
PVOID m_pShareMemory=NULL;/*共享内存*/
2.serialspyview.cpp
#define ID_MONITORTIMERID 2//定时器id
#define MAX_SHOWINFBAK 100//最大行
CPtrList g_plNetDShowMsg;/*显示的message链表*/
static CMutex g_mutexNetDShowMsg(FALSE, (LPCTSTR)"NETD_SHOWMSG");/*链表保护用互斥锁*/
void AddRSDataForShow(int nType, char* pDataBuf, WORD wLen);/*添加捕获的发送接收数据送显示*/
tagNetDShowMsg* RemoveMsgFromNetDShowList();/*从链表获取消息包裹*/
void AddMsgToNetDShowList(tagNetDShowMsg* pShowMsg);/*添加消息包到消息链表*/
void AddMsgForNetDShow(int nType, CString pMsgInf);/*添加cstring的消息到链表*/
CString GetCurrStringTime();/*当前时间*/
3.serialspy.h mailfrm.cpp和设备关联的函数
extern BOOL InstallDevice();
extern void RemoveDevice();
extern BOOL OpenDevice() ;
extern void CloseDevice() ;
extern void QueryEvent();
extern void ClearEvent() ;
extern void SetEvent() ;
视图类对象的成员
class CSerialSpyView : public CRichEditView
{
protected: // create from serialization only
CSerialSpyView();
DECLARE_DYNCREATE(CSerialSpyView)
BOOL m_IsPause;/*暂停*/
CFont m_TextFont;/*显示字体*/
BOOL m_bTracing;// Attributes
public:
CSerialSpyDoc* GetDocument();
HANDLE hEvent; //窗口关闭事件
CWinThread *pThread;/*新线程*/
static DWORD WINAPI TestThread(LPVOID lpParam);/*测试线程*/
void StopThread();
void ProcessData(char* lpBuffer,int dwSize);/*处理数据*/
void ProcessIOReq(IO_REQ *p);/*处理IO请求*/
// Operations
public:
int nOldType;//旧消息类型
void ShowTraceData(tagNetDShowMsg* pMsg);/*显示跟踪数据*/
void Output(CString str, COLORREF color=RGB(0,0,0));/*输出函数*/
void DisplayHex(BYTE *pStr, int size,COLORREF color=RGB(0,0,0),BOOL IsNewLine=TRUE,int NumPerLine=-1);
void DisplayHex1(BYTE *pStr, int size,COLORREF color=RGB(0,0,0),BOOL IsNewLine=TRUE,int NumPerLine=-1);
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CSerialSpyView)
public:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
protected:
virtual void OnInitialUpdate(); // called first time after construct
virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
//}}AFX_VIRTUAL
protected:
// Generated message map functions
protected:
//{{AFX_MSG(CSerialSpyView)
// NOTE - the ClassWizard will add and remove member functions here.
// DO NOT EDIT what you see in these blocks of generated code !
afx_msg void OnDestroy();
afx_msg void OnPause();
afx_msg void OnClear();
afx_msg void OnRButtonUp(UINT nFlags, CPoint point);
afx_msg void OnContinue();
afx_msg void OnMark();
afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
afx_msg void OnTimer(UINT nIDEvent);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
初始化:
初始化顺序,app->doc->mainframe->view->template
// Register the application's document templates. Document templates
// serve as the connection between documents, frame windows and views.
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CSerialSpyDoc),
RUNTIME_CLASS(CMainFrame), // main SDI frame window
RUNTIME_CLASS(CSerialSpyView));
pDocTemplate->SetContainerInfo(IDR_CNTR_INPLACE);
AddDocTemplate(pDocTemplate);
// CSerialSpyApp initialization
BOOL CSerialSpyApp::InitInstance()
{
.....
///////////////////////////////////////////////
if(OpenDevice()==FALSE)/*打开设备,如果失败,调用安装设备安装驱动*/
{
if(InstallDevice()==FALSE)
return FALSE;
}
.....
return TRUE;
}
顺带退出实例时候关闭设备
int CSerialSpyApp::ExitInstance()
{
// TODO: Add your specialized code here and/or call the base class
CloseDevice();
return CWinApp::ExitInstance();
}
view类初始化
// CSerialSpyView construction/destruction
CSerialSpyView::CSerialSpyView()
{
// TODO: add construction code here
m_IsPause=FALSE;/*暂停*/
m_bTracing = FALSE;/*追踪*/
m_TextFont.CreateFont(-12,0,0,0,FW_NORMAL,FALSE,FALSE,FALSE,
134, 3, 2, 1, 2, (LPCTSTR)"System");/*构造字体*/
}
void CSerialSpyView::OnInitialUpdate()
{
CRichEditView::OnInitialUpdate();
// Set the printing margins (720 twips = 1/2 inch).
SetMargins(CRect(720, 720, 720, 720));
//
GetRichEditCtrl().SetReadOnly();/*只读*/
GetRichEditCtrl().SetFont(&m_TextFont);/*设置字体*/
SetTimer(ID_MONITORTIMERID, 200, NULL);/*设置定时器*/
////////////////////////////////////////////
hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);/*创建事件*/
ASSERT(hEvent);
/*开始测试线程*/
pThread=AfxBeginThread((AFX_THREADPROC) TestThread,this,THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);
ASSERT(pThread);
pThread->m_bAutoDelete=FALSE;
pThread->ResumeThread();/*唤醒线程*/
///////////////////////////////
nOldType=-1;
}
按照流程
首先打开设备
/*打开设备*/
BOOL OpenDevice()
{
// TODO: Add your control notification handler code here
m_hDevice = CreateFile(/*首先打开设备获得句柄*/
"\\\\.\\ComSpy",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if(m_hDevice == INVALID_HANDLE_VALUE)
{
AfxMessageBox(_T("Error. Cannot open device comspy"),MB_OK);
return FALSE;
}
/*打开设备comspy OK,创建事件*/
m_hCommEvent = CreateEvent(NULL, false, false, NULL);
/*
WINBASEAPI
HANDLE
WINAPI
CreateEventA(
IN LPSECURITY_ATTRIBUTES lpEventAttributes,
IN BOOL bManualReset,
IN BOOL bInitialState,
IN LPCSTR lpName
);
*/
DWORD dwReturn;
TCHAR szOutputBuffer[4];
//download event object to device driver
/*
WINBASEAPI
BOOL
WINAPI
DeviceIoControl(
IN HANDLE hDevice,
IN DWORD dwIoControlCode,
IN LPVOID lpInBuffer,
IN DWORD nInBufferSize,
OUT LPVOID lpOutBuffer,
IN DWORD nOutBufferSize,
OUT LPDWORD lpBytesReturned,
IN LPOVERLAPPED lpOverlapped
);
*/
/*用IO命令,下载事件句柄到驱动*/
BOOL res=DeviceIoControl(m_hDevice,
IO_REFERENCE_EVENT,
(LPVOID) m_hCommEvent,//IN LPVOID lpInBuffer
0,
NULL,
0,
&dwReturn,
NULL);
if(!res)
return FALSE;
/////////////////////////////////////////////////////////
///获取共享内存的地址放到m_psharememory
res=DeviceIoControl(m_hDevice,
IO_GET_SHAREMEMORY_ADDR,
NULL,
NULL,
szOutputBuffer,//OUT LPVOID lpOutBuffer
sizeof(szOutputBuffer),
&dwReturn,
NULL
);
if(!res)
return FALSE;
m_pShareMemory = *((PVOID *)szOutputBuffer);/*保存共享内存地址*/
/////////////////////////////////////////////////////////
// CreateThread(NULL, 0, &TestThread, this, NULL, (LPDWORD )&m_hThread);
return TRUE;
}
/*如果在打开设备之前已经手动安装了驱动,则不需要调用此函数*/
/*安装设备驱动*/
BOOL InstallDevice()
{
if (m_hDevice!=INVALID_HANDLE_VALUE)
return FALSE;
/*得到系统目录路径C:\WINDOWS\system32\drivers*/
CHAR DriverFileName[80];
if (!GetSystemDirectory(DriverFileName, 55))
{
return FALSE;
}
/*合成文件路径C:\WINDOWS\system32\drivers\ComSpy.sys,拷贝当前目录下的ComSpy.sys到以上路径(覆盖)*/
strcat(DriverFileName,"\\drivers\\ComSpy.sys");
if (!CopyFile(".\\ComSpy.sys", DriverFileName, FALSE))
{
AfxMessageBox(_T("CopyFile.\ComSpy.sys->C:\WINDOWS\system32\drivers\ComSpy.sys ERR!"),MB_OK);
return FALSE;
}
///////////////////////////////////////////////////////////////////////////////////////
/*打开服务控制管理器,NT驱动可手动注册表或者用SCM加载,打开获得SCM句柄*/
SC_HANDLE sc=OpenSCManager(NULL,SERVICES_ACTIVE_DATABASE,SC_MANAGER_ALL_ACCESS);
if (!sc)
{
AfxMessageBox(_T("You must have administrative priviledges to install device driver"),MB_OK);
return FALSE;
}
CString s=DriverFileName;
/*
GetCurrentDirectory(MAX_PATH,s.GetBuffer(MAX_PATH));
s.ReleaseBuffer();
if (s.Right(1)!=_T("\\"))
s+=_T("\\");
s+=_T("ComSpy.sys");
*/
SC_HANDLE hSrv;/*服务句柄*/
/*创建新的服务ComSpy*/
hSrv=CreateService(sc,_T("ComSpy"),_T("ComSpy"),SERVICE_ALL_ACCESS | GENERIC_EXECUTE | SERVICE_START | SERVICE_STOP,
SERVICE_KERNEL_DRIVER,SERVICE_DEMAND_START,SERVICE_ERROR_IGNORE,
s,
NULL,
NULL,
NULL,
NULL,
NULL);
CloseServiceHandle(sc);/*关闭SCM句柄*/
if (!hSrv)
{
AfxMessageBox(_T("Unexpected error. Cannot create service"),MB_OK);
return FALSE;
}
if (!StartService(hSrv,0,NULL))/*开启服务*/
{
qq: AfxMessageBox(_T("Cannot start device. Sys maybe not found"),MB_OK);
DeleteService(hSrv);/*删除服务*/
CloseServiceHandle(hSrv);/*关闭服务句柄*/
return FALSE;
}
if(OpenDevice()==FALSE)/*打开设备,如果失败*/
{
SERVICE_STATUS ss;
ControlService(hSrv,SERVICE_CONTROL_STOP,&ss);/*停止服务*/
goto qq;
}
CloseServiceHandle(hSrv);/*关闭服务句柄*/
AfxMessageBox(_T("ComSpy device driver successfully installed"),MB_OK);
return TRUE;
}
/*设备成功打开,开始运行view类的子线程,线程等待驱动事件的唤醒,唤醒后从共享内存读取要读取得数据大小*/
/*然后从m_hDevice读取nSize字节到lpBuffer,最后调用ProcessData(lpBuffer,dwRet);/*处理数据*/
最后ClearEvent();/*清除事件*/,延时10ms后重新下一轮等待。直到窗口关闭事件后才退出线程。
*/
/*测试线程*/
DWORD WINAPI CSerialSpyView::TestThread(LPVOID lpParam)
{
CSerialSpyView* pThis = (CSerialSpyView*) lpParam;/*获取父线程传递的参数,强制转换为view类指针*/
HANDLE hEvents[]={m_hCommEvent,pThis->hEvent};/*事件集合,一个是窗口关闭事件,一个是驱动事件*/
TRACE("Thread begin !!!\n");
while(TRUE)/*一直运行,除非break*/
{
DWORD Res=WaitForMultipleObjects(2,hEvents,FALSE,INFINITE);/*等待两个事件唤醒*/
TRACE("Get the event!!!");
if (Res==WAIT_OBJECT_0+1 )/*第二个事件,即窗口关闭事件,直接break*/
{
//
break;
}
/*否则是驱动事件*/
DWORD nSize=*((DWORD*)m_pShareMemory);/*从共享内存读取数据的大小*/
TRACE("ShareMemory %d!!!",nSize);
if(nSize>0)
{
char *lpBuffer=new char[nSize];
DWORD dwRet;
ReadFile(m_hDevice,lpBuffer,nSize,&dwRet,NULL);/*从m_hDevice读取nSize字节到lpBuffer*/
TRACE("Read Actual %d Bytes < Requested %d Bytes !!!", dwRet,nSize);
pThis->ProcessData(lpBuffer,dwRet);/*处理数据*/
delete lpBuffer;
}
ClearEvent();/*清除事件*/
Sleep(10);/*延时10ms*/
}
TRACE("Thread end !!!");
return TRUE;
}
/*线程获得的数据调用ProcessData处理数据,来源 lpBuffer,大小dwSize,ProcessData()把线性的lpBuffer分成一个一个的IO_REQ包*/
/*每一个IO_REQ包又调用ProcessIOReq(pReq)来处理*/
void CSerialSpyView::ProcessData(char* lpBuffer,int dwSize)
{
int nCount=dwSize;
char* p=lpBuffer;
TRACE(" ProcessData nCount = %d \n",nCount);
while(nCount>=sizeof(IO_REQ))/*dwsize(即ncount)可能包含多个IO_REQ包*/
{
PIO_REQ pReq=(PIO_REQ) p;/*强制类型转换为IO_REQ指针*/
TRACE(" SizeTotal = %d , SizeContent = %d , type = %d ,\n",pReq->SizeTotal,pReq->SizeCopied,pReq->type);
ProcessIOReq(pReq);/*调用ProcessIOReq()处理pReq*/
p+=pReq->SizeTotal;/*调整指针为一个包偏移,处理下一个包*/
nCount-=pReq->SizeTotal;/*已经处理完一个包*/
TRACE(" Process One Req size = %d nCount = %d \n",pReq->SizeTotal,nCount);
}
}
/*处理一个IO包的函数,先判断包类型,普通消息类如打开、关闭、设置波特率、线路控制的先合成cstring*/
/*然后调用AddMsgForNetDShow( NETD_SHOW_INFORMATION , strInf)添加到消息链表*/
/*串口发送接收的包要先获得(IO_REQ)的尾部,即pvoid pdata*/
/*然后调用AddRSDataForShow(NETD_SHOW_SEND,(char*)ptr,Size)添加到消息链表*/
void CSerialSpyView::ProcessIOReq(IO_REQ *p)
{
union
{
CHAR chr;
BYTE value;
} temp;
temp.chr=0;
switch(p->type)/*判断包类型*/
{
case REQ_OPEN:
case REQ_CLOSE: // 打开关闭类型的包these two requests will go in both windows
{
CString strInf;
CString strTime=::GetCurrStringTime();/*获取当前时间,格式已经由:GetCurrStringTime()格式化成cstring*/
if (p->type==REQ_OPEN)
strInf.Format(("时间:%s 消息:串口 打开成功 "),strTime);/*格式化消息*/
else
strInf.Format(("时间:%s 消息:串口 关闭成功 "),strTime);
AddMsgForNetDShow( NETD_SHOW_INFORMATION , strInf);/*添加到消息队列*/
break;
}
case REQ_READ:/*读类型的包*/
{
LPBYTE ptr=(LPBYTE) p+sizeof(IO_REQ);/*让ptr指向p(IO_REQ)的尾部,即pvoid pdata*/
DWORD Size=p->SizeCopied;/*数据的大小*/
AddRSDataForShow(NETD_SHOW_RECEIVE,(char*)ptr,Size);/*添加显示的数据*/
break;
}
case REQ_WRITE:/*写类型的包*/
{
LPBYTE ptr=(LPBYTE) p+sizeof(IO_REQ);/*让ptr指向p(IO_REQ)的尾部,即pvoid pdata*/
DWORD Size=p->SizeCopied;/*数据的大小*/
AddRSDataForShow(NETD_SHOW_SEND,(char*)ptr,Size);/*添加显示的数据*/
break;
}
case REQ_SETBAUDRATE:/*设置波特率的包*/
{
CString strInf;
DWORD dwBaud=*(ULONG *) ((LPBYTE) p+sizeof(IO_REQ));/*pvoid pdata强制转换为ulong*/
strInf.Format(("时间:%s 消息:串口 波特率设置成 %d "),::GetCurrStringTime(),dwBaud);/*格式化消息*/
AddMsgForNetDShow( NETD_SHOW_INFORMATION , strInf);/*添加到消息队列*/
break;
}
case REQ_SETLINECONTROL:/*线路控制的包*/
{
CString s;
LPCTSTR temp;
SERIAL_LINE_CONTROL *ptr=(SERIAL_LINE_CONTROL *) ((LPBYTE)p+sizeof(IO_REQ));/*pvoid pdata强制转换为SERIAL_LINE_CONTROL结构*/
switch(ptr->Parity)/*奇耦校验*/
{
case EVENPARITY:
temp=_T("偶");
break;
case MARKPARITY:
temp=_T("Mark");
break;
case NOPARITY:
temp=_T("No");
break;
case ODDPARITY:
temp=_T("奇");
break;
case SPACEPARITY:
temp=_T("SPACE");
break;
default:
temp=_T("未知");
break;
}
s.Format(("停止位: %s, 奇偶校验: %s 校验, 字长: %d"),
((ptr->StopBits==ONESTOPBIT)?_T("1 停止位")(ptr->StopBits==ONE5STOPBITS)?
_T("1.5 停止位"):_T("2 停止位"))),temp,ptr->WordLength);
CString strInf;
strInf.Format(("时间:%s 消息:串口 设置 %s"),::GetCurrStringTime(),s);
AddMsgForNetDShow( NETD_SHOW_INFORMATION , strInf);
break;
}
}
// delete [](LPBYTE) p;
}
/*ProcessIOReq要用到以下几个子函数,先了解重要的结构体*/
/*
typedef struct
{
CString strFrmNode;
int nType;
char* pShowMsg;
int nLen;
}tagNetDShowMsg;
*/
/*添加接收发送的数据到消息队列*/
void AddRSDataForShow(int nType, char* pDataBuf, WORD wLen)
{
if(pDataBuf == NULL || wLen <= 0)
return ;
////////////////////////////////////////////////
/*构建新的消息报文*/
tagNetDShowMsg* pMsg = new tagNetDShowMsg;
pMsg->nType = nType;/*消息类型*/
pMsg->nLen = wLen;/*消息长度*/
pMsg->pShowMsg = new char[wLen];/*消息缓冲区*/
memcpy(pMsg->pShowMsg, pDataBuf, wLen);/*拷贝消息到消息报文*/
AddMsgToNetDShowList(pMsg );/*添加到链表*/
}
/*添加消息送显示,输入的参数是cstring类型*/
void AddMsgForNetDShow(int nType, CString pMsgInf)
{
int nLen = pMsgInf.GetLength();/*获取字符串长度*/
if( nLen <= 0) return ;
tagNetDShowMsg* pMsg = new tagNetDShowMsg;/*构建新的消息报文*/
pMsg->nType = nType;/*消息类型*/
pMsg->nLen = nLen+1;/*消息长度*/
pMsg->pShowMsg = new char[pMsg->nLen];/*消息缓冲区*/
strcpy(pMsg->pShowMsg,(const char *) LPCTSTR(pMsgInf));/*拷贝消息到消息报文*/
AddMsgToNetDShowList( pMsg );/*添加到链表*/
}
/*添加到链表子函数*/
void AddMsgToNetDShowList(tagNetDShowMsg* pShowMsg)
{
g_mutexNetDShowMsg.Lock();/*获取互斥锁*/
while(g_plNetDShowMsg.GetCount() >= MAX_SHOWINFBAK) {/*链表的元素>MAX_SHOWINFBAK*/
tagNetDShowMsg* pMsg = (tagNetDShowMsg* )g_plNetDShowMsg.RemoveHead();/*取头部元素*/
if( pMsg->pShowMsg)/*元素消息不为空*/
delete[] pMsg->pShowMsg;/*删除消息*/
delete pMsg;/*删除元素*/
}
g_plNetDShowMsg.AddTail(pShowMsg);/*尾部把元素插入链表*/
g_mutexNetDShowMsg.Unlock();/*释放锁*/
}
/*清除链表*/
void ClearNetDShowMsgList()
{
g_mutexNetDShowMsg.Lock();/*获取互斥锁*/
for(POSITION pos = g_plNetDShowMsg.GetHeadPosition(); pos != NULL; ){
tagNetDShowMsg* pMsg = (tagNetDShowMsg* )g_plNetDShowMsg.GetNext(pos);/*获取下一个元素*/
if(pMsg->pShowMsg) delete[] pMsg->pShowMsg;/*删除消息*/
delete pMsg;/*删除元素*/
}
g_plNetDShowMsg.RemoveAll();/*删除所有*/
g_mutexNetDShowMsg.Unlock();/*释放锁*/
}
/*获取系统时间戳*/
CString GetCurrStringTime()
{
SYSTEMTIME sysTime;/*新建系统时间结构体*/
memset(&sysTime,0,sizeof(SYSTEMTIME));/*清空*/
::GetLocalTime(&sysTime);/*获取系统时间到systime*/
CString strTime;/*申明一个cstring结构strTime*/
strTime.Format(("%04d-%02d-%02d %02d:%02d:%02d:%04d"),sysTime.wYear,sysTime.wMonth,
sysTime.wDay,sysTime.wHour,sysTime.wMinute,sysTime.wSecond,sysTime.wMilliseconds);
return strTime;/*格式化后返回*/
}
/*上述过程只是准备好数据到链表,显示数据依靠的是一个定时器,定时检查链表有没有要显示的数据。*/
/*线程开始的时候设置定时器*/
void CSerialSpyView::OnInitialUpdate()
{
.....
SetTimer(ID_MONITORTIMERID, 200, NULL);/*设置定时器*/
.....
/*开始测试线程*/
pThread=AfxBeginThread((AFX_THREADPROC) TestThread,this,THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);
/*定时器时间到后调用回调函数,检查链表有没有数据,有的话调用ShowTraceData(pMsg);/*显示消息*/*/
void CSerialSpyView::OnTimer(UINT nIDEvent)/*定时器时间到回调函数*/
{
// TODO: Add your message handler code here and/or call default
if(nIDEvent == ID_MONITORTIMERID)
{
tagNetDShowMsg* pMsg = RemoveMsgFromNetDShowList();/*从链表取消息*/
while(pMsg)
{
ShowTraceData(pMsg);/*显示消息*/
if(pMsg->pShowMsg)/*释放消息内存*/
delete[] pMsg->pShowMsg;
delete pMsg;
pMsg = RemoveMsgFromNetDShowList();/*取下一条消息*/
}
}
CRichEditView::OnTimer(nIDEvent);
}
/*显示跟踪消息的函数稍复杂一点,主要需要考虑消息类型不同,颜色不一样,需要换行和退格*/
void CSerialSpyView::ShowTraceData(tagNetDShowMsg* pMsg)
{
char SndShow[256];
BYTE byType = NETD_TRACE_BLACK;/*默认颜色黑色*/
if(pMsg->nType == NETD_SHOW_ERROR)/*消息类型 NETD_SHOW_ERROR*/
{
byType = NETD_TRACE_DARK_RED;/*颜色为红色*/
sprintf(SndShow, "出错信息:%s\n", pMsg->pShowMsg);/*格式化消息到sndshow*/
Output(SndShow,COLORLIST[byType]);/*输出消息*/
}
else if(pMsg->nType == NETD_SHOW_INFORMATION)/*普通消息*/
{
if(nOldType!=pMsg->nType)/*是另外一种类型的消息,先换行*/
{
Output("\n",COLORLIST[byType]);
}
byType = NETD_TRACE_DARK_YELLOW;/*颜色为黄色*/
sprintf(SndShow, "运行信息:%s\n", pMsg->pShowMsg);/*格式化消息到sndshow*/
Output(SndShow,COLORLIST[byType]);/*输出消息*/
}
else
{
int nTab = 0;
if(nOldType!=pMsg->nType)/*开始输出新的类型的消息,先换行*/
{
Output("\n",COLORLIST[byType]);
if(pMsg->nType == NETD_SHOW_RECEIVE)/*消息类型为接收到的消息*/
{
byType = NETD_TRACE_GREEN;/*颜色绿色*/
sprintf(SndShow, "接收信息:");/*格式化表头*/
nTab = 10;
}
else if(pMsg->nType == NETD_SHOW_SEND)/*消息类型为发送的消息*/
{
byType = NETD_TRACE_BLUE;/*蓝色*/
sprintf(SndShow, "发送信息:");/*格式化表头*/
nTab = 10;
}
}
if(pMsg->nType == NETD_SHOW_RECEIVE)/*消息类型为接收到的消息*/
{
byType = NETD_TRACE_GREEN;/*颜色绿色*/
}
else if(pMsg->nType == NETD_SHOW_SEND)/*消息类型为发送的消息*/
{
byType = NETD_TRACE_BLUE;/*蓝色*/
}
char* pData = &SndShow[nTab];/*更新缓冲指针,偏移ntab*/
int nIndex = 0;
for(int i=0; i<pMsg->nLen; i++)/*消息包裹pMsg的消息pShowMsg长度pMsg->nLen*/
{
sprintf(pData, "%02x ", (BYTE )pMsg->pShowMsg);/*将消息按字节格式成16进制打印到pdata指针指向的SndShow缓冲区*/
pData += 3;/*两位十六进制数字加一个空格=3*/
nIndex++;/*处理完一个字节消息,索引++*/
if(nIndex>20)/*超过20个数据,先输出打印*/
{
pData[0] = 0;/*结尾+null方便打印*/
Output(SndShow,COLORLIST[byType]);/*先输出消息*/
pData = SndShow;/*回滚缓冲区首*/
for(int n=0; n<nTab-2; n++)/*退格ntab-2*/
{
sprintf(pData, " ");
pData += 1;
}
nIndex = 0;/*索引归零*/
}
}
if(nIndex != 0)
{
Output(SndShow,COLORLIST[byType]);
}
}
nOldType=pMsg->nType;/*更新消息类型纪录*/
}
/*另外定时器需要调用的函数*/
/*从链表获取消息报文包裹,返回所获取的报文包裹指针*/
tagNetDShowMsg* RemoveMsgFromNetDShowList()
{
tagNetDShowMsg* pMsg = NULL;/*新建一个报文*/
g_mutexNetDShowMsg.Lock();/*获取互斥锁*/
if(g_plNetDShowMsg.GetCount() >= 1)/*链表元素>1*/
pMsg= (tagNetDShowMsg* )g_plNetDShowMsg.RemoveHead();/*从头部取一个元素*/
g_mutexNetDShowMsg.Unlock();/*释放锁*/
return pMsg;/*返回元素的指针*/
}
/*ShowTraceData调用的输出绘制消息的函数*/
void CSerialSpyView::Output(CString str, COLORREF color)
{
if (m_IsPause)/*如果暂停,直接返回*/
return;
CRichEditCtrl &RichCtrl=GetRichEditCtrl();
/* long nLen = RichCtrl.GetTextLength();
if(nLen > 100000L)
{
RichCtrl.SetSel(0, nLen-100000L);
RichCtrl.ReplaceSel("");
RichCtrl.EmptyUndoBuffer();
}
*/
RichCtrl.SetSel(-1,-1);
CHARFORMAT cf;
RichCtrl.GetDefaultCharFormat(cf);
cf.dwMask |= CFM_COLOR;
cf.crTextColor=color;
cf.dwEffects &= ~CFE_AUTOCOLOR;
RichCtrl.SetSelectionCharFormat(cf);
RichCtrl.ReplaceSel(str);
}
源码包
用户1840457 2015-6-5 23:35
用户921427 2012-5-18 09:07
用户421525 2012-1-24 16:36
用户404687 2011-12-2 21:59
用户411023 2011-11-3 10:52