原创 监听串口的comspy源码分析_应用程序部分

2010-7-30 22:04 4047 13 18 分类: 软件与OS

监听串口的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);
}


 


源码包

文章评论5条评论)

登录后参与讨论

用户1840457 2015-6-5 23:35

源码能直接编译运行吗?

用户921427 2012-5-18 09:07

good thicks

用户421525 2012-1-24 16:36

有用,正在学习中。

用户404687 2011-12-2 21:59

很好,我是做java的,最近想通过串口监视来控制其他通信流程,看了这个VC的基于驱动的实现,多谢详解。

用户411023 2011-11-3 10:52

下载学习一下。可不可以监控usb转的串口呢?
相关推荐阅读
用户1620250 2013-06-14 21:21
CIMCOEdit5自动生成轮廓的G代码
做了台全自动的NC数控玻璃切割机,感觉就是一台CNC的雏形了。     不管是哪一类的机床,只要是 NC 加工,零件的加工步骤如下: 1. 分析研究零件图; 2. 选择最合适...
用户1620250 2012-12-30 22:38
STM32 FSMC与FPGA 存储器接口 读写
  STM32 FSMC与FPGA 存储器接口 读写  panasonic.lin@163.com FPG...
用户1620250 2012-01-12 21:33
DSP/BIOS:Cannot create/delete a Clock from Hwi or Swi thread
DSP/BIOS:Cannot create/delete a Clock from Hwi or Swi thread 上篇文章提到Task_sleep睡死的问题解决后,添加了系统心跳cloc...
用户1620250 2012-01-12 21:28
DSP/BIOS:Task_sleep睡死的问题
程序其中的一个任务调用了Task_sleep(100),结果睡死在里面,用ROV查看任务的状态,Blocked阻塞,但是阻塞点是Unknown. 这是因为没有添加clock模块到系统...
用户1620250 2011-12-23 00:55
TI DSP 28335 CCSV4 外置SRAM调试(二)
11.为再次确保万无一失,往外置SRAM读写校验一下   12由于板子设置了从FLASH boot,FLASH内还有程序,debug 在LOAD了程序后自动复位然后运行了flash的...
用户1620250 2011-12-23 00:38
TI DSP 28335 CCSV4 外置SRAM调试(一)
DSP28335有内置256K X 16的FLASH,34K X 16的RAM,但是如果运行一个大一点的系统,如SYS/BIOS,这么小的RAM很难容纳的下,如果在FLASH中调试的话,每次都烧写...
我要评论
5
13
关闭 站长推荐上一条 /2 下一条