www.gusucode.com > Visual C++_Turbo C串口通信编程实践(第2版)配套光盘 > Visual C++_Turbo C串口通信编程实践(第2版)配套光盘/Visual C++_TurboC串口通信编程实践(第2版)光盘/第12章/SerialPortVxD/SerialPortVxDDlg.cpp

    // SerialPortVxDDlg.cpp : implementation file
//

#include "stdafx.h"
#include "SerialPortVxD.h"
#include "SerialPortVxDDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// Dialog Data
	//{{AFX_DATA(CAboutDlg)
	enum { IDD = IDD_ABOUTBOX };
	//}}AFX_DATA

	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CAboutDlg)
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
	//}}AFX_VIRTUAL

// Implementation
protected:
	//{{AFX_MSG(CAboutDlg)
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
	//{{AFX_DATA_INIT(CAboutDlg)
	//}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CAboutDlg)
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
	//{{AFX_MSG_MAP(CAboutDlg)
		// No message handlers
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CSerialPortVxDDlg dialog

CSerialPortVxDDlg::CSerialPortVxDDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CSerialPortVxDDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CSerialPortVxDDlg)
	m_strPortName = _T("");
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

	//变量的初始化
	m_bRunning = false;
	m_cpTargetPortName = NULL;
	m_hVxD = NULL;

	CFont font;
	font.CreatePointFont( 100, _T( "Courier New" ) );
	font.GetLogFont( &m_logfontTrace );
	m_fontTrace.CreateFontIndirect( &m_logfontTrace );

	m_pCurRec = NULL;

}

void CSerialPortVxDDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CSerialPortVxDDlg)
	DDX_Control(pDX, IDC_LIST_DISPDATA, m_ctrlListDispData);
	DDX_Text(pDX, IDC_EDIT_PORT, m_strPortName);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CSerialPortVxDDlg, CDialog)
	//{{AFX_MSG_MAP(CSerialPortVxDDlg)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BUTTON_STARTSTOP, OnButtonStartstop)
	ON_WM_TIMER()
	ON_BN_CLICKED(IDC_BUTTON_STATRESET, OnButtonStatreset)
	ON_BN_CLICKED(IDC_BUTTON_CLEARDISP, OnButtonCleardisp)
	ON_BN_CLICKED(IDC_BUTTON_SAVEDATA, OnButtonSavedata)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CSerialPortVxDDlg message handlers

BOOL CSerialPortVxDDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;
		strAboutMenu.LoadString(IDS_ABOUTBOX);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	
	// TODO: Add extra initialization here
	
	// 事件传送
	HINSTANCE hKernel32 = LoadLibrary("KERNEL32");
	DWORD (*fpOVH)(HANDLE) =
		(DWORD (*)(HANDLE)) GetProcAddress(hKernel32, "OpenVxDHandle" );

	FreeLibrary(hKernel32);

	CRect rect;
	m_ctrlListDispData.GetClientRect( &rect );
	m_ctrlListDispData.InsertColumn( 0, NULL, LVCFMT_LEFT, rect.right-GetSystemMetrics(SM_CXVSCROLL) );

	//列表中的 WM_MEASUREITEM映射
	m_ctrlListDispData.GetWindowRect( &rect );
	WINDOWPOS wp;
	wp.hwnd = m_ctrlListDispData.m_hWnd;
	wp.cx = rect.Width();
	wp.cy = rect.Height();
	wp.flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER;
	m_ctrlListDispData.SendMessage( WM_WINDOWPOSCHANGED, 0, (LPARAM)&wp );

	// 准备好第一个记录
	m_pCurRec = new CListRecord;
	int item = m_ctrlListDispData.InsertItem( 0, NULL );
	m_ctrlListDispData.SetItemData( item, (DWORD)m_pCurRec );

	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CSerialPortVxDDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CSerialPortVxDDlg::OnPaint() 
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CSerialPortVxDDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}

void CSerialPortVxDDlg::OnButtonStartstop() 
{
	// TODO: Add your control notification handler code here
	m_bRunning = !m_bRunning;
	if ( m_bRunning )
	{
		UpdateData( TRUE );
		if ( m_strPortName.IsEmpty() )
			m_strPortName = "NONE";
		delete[] m_cpTargetPortName;
		m_cpTargetPortName = new char[ m_strPortName.GetLength() + 1 ];
		strcpy( m_cpTargetPortName, m_strPortName );

		// 以下的设置是把串口设备驱动文件CommHook.vxd放在系统文件夹中
		// WINSYSDIR一般在C:\Windows\System
		//CreateFile函数中用"\\\\.\\CommHook.vxd"
		m_hVxD = CreateFile( "\\\\.\\CommHook.vxd",
							0, 0, NULL, 0,
							FILE_FLAG_DELETE_ON_CLOSE, NULL );
		if ( m_hVxD == INVALID_HANDLE_VALUE )
		{
			AfxMessageBox( "无法打开虚拟设备驱动文件commhook.VxD -\n\n(请检查是否放在系统文件夹:WINSYSDIR)", MB_OK );
			m_bRunning = false;
			m_hVxD = NULL;
			return;
		}
		GetDlgItem( IDC_BUTTON_STARTSTOP )->SetWindowText( "停止截获串口数据" );

		DWORD result;

		DeviceIoControl(m_hVxD,
						_CommHook_DIOC_SetTargetPort,
						m_cpTargetPortName,
						strlen(m_cpTargetPortName),
						NULL,
						0,
						&result,
						NULL );
		//如果打开设备驱动文件成功,就启动定时器每200ms查询一次数据
		SetTimer( 1000, 200, NULL );
	}
	else
	{
		KillTimer( 1000 );  //停止定时
		GetDlgItem( IDC_BUTTON_STARTSTOP )->SetWindowText( "开始截获串口数据" );
		CloseHandle( m_hVxD );  //关闭虚拟设备句柄
		m_hVxD = NULL;
	}
}

void CSerialPortVxDDlg::OnTimer(UINT nIDEvent) 
{
	// TODO: Add your message handler code here and/or call default
	BOOL status;
	DWORD nBytes;

	status = DeviceIoControl(	m_hVxD,
								_CommHook_DIOC_AccessStats,
								NULL,
								0,
								&m_sAccessData,
								sizeof(m_sAccessData),
								&nBytes,
								NULL );

	// 得到串口设备中的数据量的大小(字节数).
	status = DeviceIoControl(	m_hVxD,
								_CommHook_DIOC_ReadTraceData,
								NULL,
								0,
								NULL,
								0,
								&nBytes,
								NULL );
	if ( nBytes )
	{
		ASSERT( nBytes < 10000 );
		DWORD request = nBytes;
		// 这里每个字节占一个字的容量,高字节为Tx/Rx(发送/接收)标志 
		unsigned short int *pData = new unsigned short int[ request ];
		status = DeviceIoControl(	m_hVxD,
									_CommHook_DIOC_ReadTraceData,
									NULL,
									0,
									pData,
									request,
									&nBytes,
									NULL );
		ASSERT( request == nBytes );

		for ( int i=0; i<(int)nBytes; i++ )
		{
			m_pCurRec->m_pwData[m_pCurRec->m_dwLength++] = pData[i];

			if ( m_pCurRec->m_dwLength == 32 )
			{
				int n = m_ctrlListDispData.GetItemCount();
				m_ctrlListDispData.RedrawItems( n-1, n-1 );

				m_pCurRec = new CListRecord;
				m_ctrlListDispData.InsertItem( n, NULL );
				m_ctrlListDispData.SetItemData( n, (DWORD)m_pCurRec );
			}
		}
		int n = m_ctrlListDispData.GetItemCount();
		m_ctrlListDispData.RedrawItems( n-1, n-1 );

		for ( i=m_ctrlListDispData.GetItemCount(); i>1000; i-- )
			m_ctrlListDispData.DeleteItem(0);
		m_ctrlListDispData.EnsureVisible( m_ctrlListDispData.GetItemCount()-1, FALSE );

		delete[] pData;
	}

	if ( status )
	{
		CString str;
		str.Format( "%ld", m_sAccessData.dwReadCount );
		GetDlgItem( IDC_EDIT_READS )->SetWindowText( str );
		str.Format( "%ld", m_sAccessData.dwWriteCount );
		GetDlgItem( IDC_EDIT_WRITES )->SetWindowText( str );
		str.Format( "%ld", m_sAccessData.dwReadBytes );
		GetDlgItem( IDC_EDIT_READBYTES)->SetWindowText( str );
		str.Format( "%ld", m_sAccessData.dwWriteBytes );
		GetDlgItem( IDC_EDIT_WRITEBYTES )->SetWindowText( str );
	}

	CDialog::OnTimer(nIDEvent);
}

void CSerialPortVxDDlg::OnButtonStatreset() 
{
	// TODO: Add your control notification handler code here
	if ( m_hVxD != NULL )
	{
		DWORD result;
		DeviceIoControl(m_hVxD,
						_CommHook_DIOC_ClearStats,
						NULL,
						0,
						NULL,
						0,
						&result,
						NULL);
	}

	GetDlgItem( IDC_EDIT_READS )->SetWindowText( "0" );
	GetDlgItem( IDC_EDIT_WRITES )->SetWindowText( "0" );
	GetDlgItem( IDC_EDIT_READBYTES )->SetWindowText( "0" );
	GetDlgItem( IDC_EDIT_WRITEBYTES )->SetWindowText( "0" );
}

void CSerialPortVxDDlg::OnButtonCleardisp() 
{
	// TODO: Add your control notification handler code here
	m_ctrlListDispData.DeleteAllItems();
	m_pCurRec = new CListRecord;
	int item = m_ctrlListDispData.InsertItem( 0, NULL );
	m_ctrlListDispData.SetItemData( item, (DWORD)m_pCurRec );
}


void CSerialPortVxDDlg::OnButtonSavedata() 
{
	// TODO: Add your control notification handler code here
	FILE *fp = fopen( "CHT.log", "wb" );
	int count = m_ctrlListDispData.GetItemCount();
	WORD status = 10;
	int cols = 0;
	bool getLen = true;
	WORD len=0;

	for ( int i=0; i<count; i++ )
	{
		CListRecord *pRec = (CListRecord *)m_ctrlListDispData.GetItemData( i );

		for ( int j=0; j<(int)pRec->m_dwLength; j++ )
		{
			WORD w = pRec->m_pwData[j];

			WORD type = w >> 8;

			if ( type != status || !len)
			{
				fprintf( fp, "\x0D\x0A" );
				status = type;
				if ( status == 0 )	// receive
					fprintf( fp, "Rx:" );
				else
					fprintf( fp, "Tx:" );
				cols = 0;
				getLen = true;
			}

			++cols;
			fprintf( fp, " %2.2X", w & 0xFF );
			len --;

			if ( getLen && cols == 9 )
			{
				len = (w & 0xFF) + 1;
				getLen = false;
			}
		}
	}

	fclose( fp );
}