?? apexcommctl.cpp
字號:
//////////////////////////////////////////////////////////
// 函數: OpenPort
//
// 目的: 在相應的端口啟動串口通訊
//
// 參數:
// hNewCommFile - 用于通訊的串口設備句柄
// 通過調用TAPI系統函數得到.
//
// 輸出:
// Successful: 啟動串口通訊.
// Failure: 產生異常事件.
//
// 注釋:
//
// OpenPort 函數確保相應串口沒有正在進行的通訊過程,
// 創建通訊用串口句柄, 創建讀寫線程. 同時為端口設置合適的參數.
//
// 不管何種原因導致OpenPort 實施失敗, 那么調用該函數的相應用戶程序要
// 對它進行響應的處理:關閉其它程序打開的端口或者其它操作.因為控件不能
// 隨便關閉其它程序打開的通訊過程.
///////////////////////////////////////////////////////////////////
void CApexCommCtrl::OpenPort()
{
HANDLE hNewCommFile;
//已經有通訊過程在執行嗎?
if (m_hCommFile != NULL)
throw "該端口已經打開!";
hNewCommFile = CreateFile( m_portID,
GENERIC_READ | GENERIC_WRITE,
0, //{! shared}
NULL, //{no security}
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL );//{template}
if (hNewCommFile == INVALID_HANDLE_VALUE) //得到非法值
throw "無法打開串口資源!";
// 這是一個合法的串口通訊句柄嗎?
{
CloseHandle( hNewCommFile );
throw "得到的文件句柄不為串口句柄!";
}
//設置輸入輸出緩沖區
if (! SetupComm( hNewCommFile, m_inputBufferSize, m_outputBufferSize ))
{
CloseHandle( hNewCommFile );
throw "無法設置輸入輸出緩沖區!";
}
// 成功創建串口通訊.
m_hCommFile = hNewCommFile;
//將相應的串口緩沖區(不管輸入還是輸出)清空;終止正在進行的輸入輸出操作
//并立即返回
PurgeComm( m_hCommFile, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR ) ;
m_bSendDataEmpty = true;//設緩沖區空標志
// 查詢并設置超時時間值
SetCommTimeState();
// 查詢并設置通訊狀態,包括波特率,字節數,停止位等.
SetPortState();
// 創建通知線程結束的消息.
m_hCloseEvent = CreateEvent( NULL, true, false, NULL );
//成功創建嗎
if (m_hCloseEvent == 0)
{
CloseHandle( m_hCommFile );
m_hCommFile = NULL;
throw "無法創建線程結束消息事件!";
}
// 創建讀線程.
try
{
ReadThread =new TReadThread;
if (ReadThread==NULL)
throw "無法生成新進程,程序將終止!";
if (!ReadThread->CreateThread(CREATE_SUSPENDED))
{
delete ReadThread;
throw "無法啟動新進程,程序將終止!";
}
}
catch(char * ErrorString)
{
ReadThread = NULL;
CloseHandle( m_hCloseEvent );
CloseHandle( m_hCommFile );
m_hCommFile = NULL;
throw ErrorString;
}
ReadThread->m_hCommFile = m_hCommFile;
ReadThread->m_hCloseEvent = m_hCloseEvent;
ReadThread->m_handlemsg=m_hWnd;
// 串口通訊具有最高優先級.
// 如果不這樣,那么串口通訊將丟失數據
ReadThread->SetThreadPriority(THREAD_PRIORITY_HIGHEST);
// 創建寫線程.
try
{
WriteThread = new TWriteThread;
if (WriteThread==NULL)
throw "無法生成新進程,程序將終止!";
if (!WriteThread->CreateThread(CREATE_SUSPENDED))
{
delete WriteThread;
throw "無法啟動新進程,程序將終止!";
}
}
catch(char * ErrorString)
{
CloseReadThread();
WriteThread = NULL;
CloseHandle( m_hCloseEvent );
CloseHandle( m_hCommFile );
m_hCommFile = NULL;
throw ErrorString;
}
WriteThread->m_hCommFile = m_hCommFile;
WriteThread->m_hCloseEvent = m_hCloseEvent;
WriteThread->m_handlemsg=m_hWnd;
WriteThread->m_pbSendDataEmpty = m_bSendDataEmpty;
WriteThread->SetThreadPriority(THREAD_PRIORITY_ABOVE_NORMAL);
//啟動線程
ReadThread->ResumeThread();
WriteThread->ResumeThread();
//至此串口通訊設置完畢,串口通訊準備就緒
}
//////////////////////////////////////////////////////
// 函數: ClosePort
//
// 目的: 停止串口通訊和讀寫線程
//
// 參數: 無
//
// 返回值: 無
//
// 注釋:
//
// 要通知所有的通訊線程結束通訊,如果不能結束
// 要用戶主動結束它
/////////////////////////////////////////////////////////
void CApexCommCtrl::ClosePort()
{
// 沒有通訊當然不用結束通訊過程
if (m_hCommFile == NULL )
return;
// 關閉線程.
CloseReadThread();
CloseWriteThread();
// 停止消息傳遞.
CloseHandle( m_hCloseEvent );
// 關閉通訊串口.
CloseHandle( m_hCommFile );
m_hCommFile = NULL;
}
////////////////////////////////////////////////////////
// 函數: WriteComX(PChar, Word)
//
// 目的: 向串口寫入字符串,該字符串等待寫線程的傳送.
//
// 參數:
// pszStringToWrite - 字符串.
// nSizeofStringToWrite - 字符串長度.
//
// 返回值:
// 如果消息成功發布,則返回true.
// 如果失敗或者寫線程不存在則返回false.
//
// 注釋:
//
// 這是一個封裝好的函數,用戶不必知道寫串口是通過向寫線程發布消息實現的
// 使用這種方法可以加速對 UI的反應 (very little delay to
// 'write' a string) 如果寫過程速度慢,那么還可以自動分配到緩沖區
// (ie: the messages just pile up in the message queue).
//
// Note that it is assumed that pszStringToWrite is allocated with
// LocalAlloc, and that if WriteComX succeeds, its the job of the
// Write thread to LocalFree it. If WriteComX fails, its
// the job of the calling function to free the string.
//////////////////////////////////////////////////////////////////////
BOOL CApexCommCtrl::WritePort(LPCTSTR pDataToWrite, long dwSizeofDataToWrite)
{
LPSTR Buffer;
if ((WriteThread != NULL) && (dwSizeofDataToWrite != 0))
{
Buffer = (LPSTR)(LocalAlloc( LPTR, dwSizeofDataToWrite+1 ));
strncpy(Buffer,(LPSTR)pDataToWrite,dwSizeofDataToWrite);
Buffer[dwSizeofDataToWrite] = '\0';
//AfxMessageBox(Buffer);
if (PostThreadMessage( WriteThread->m_nThreadID, USER_WRITEPORT,WPARAM(dwSizeofDataToWrite), LPARAM(Buffer)))
{
m_bSendDataEmpty = false;
return true;
}
else
{
LocalFree(HLOCAL(Buffer));
}
}
return false;
}
void CApexCommCtrl::SetPortState()
{
DCB dcb;//保存通訊設置參數的結構體
COMMPROP commprop;//保存通訊設置參數狀態的結構體
DWORD fdwEvtMask;
// Configure the comm settings.
// !E: Most Comm settings can be set through TAPI, but this means that
// the CommFile will have to be passed to this component.
if (!GetCommState(m_hCommFile, &dcb))
throw "無法取到串口配置";
GetCommProperties(m_hCommFile, &commprop );
GetCommMask(m_hCommFile, &fdwEvtMask );
// fAbortOnError is the only DCB dependancy in TapiComm.
// Can't guarentee that the SP will set this to what we expect.
//{dcb.fAbortOnError = false; NOT VALID}
dcb.BaudRate = m_baudRate;
dcb.fBinary = 1; // Enable fBinary
dcb.fParity = m_enableParity; // Enable parity check
dcb.fOutxCtsFlow =m_outxCtsFlow; // setup hardware flow control
dcb.fOutxDsrFlow = m_outxDsrFlow;
switch(m_dtrControl)
{
case 0:
dcb.fDtrControl=DTR_CONTROL_ENABLE;
break;
case 1:
dcb.fDtrControl=DTR_CONTROL_DISABLE;
break;
case 2:
dcb.fDtrControl=DTR_CONTROL_HANDSHAKE;
break;
}
dcb.fDsrSensitivity = m_dsrSensitivity;
dcb.fTXContinueOnXoff = m_txContinueOnXoff;
dcb.fOutX = m_outxXonXoffFlow;
dcb.fInX = m_inxXonXoffFlow;
dcb.fErrorChar = m_replaceWhenParityError;
dcb.fNull = m_ignoreNullChar;
switch(m_rtsControl)
{
case 0:
dcb.fRtsControl=RTS_CONTROL_ENABLE;
break;
case 1:
dcb.fRtsControl=RTS_CONTROL_DISABLE;
break;
case 2:
dcb.fRtsControl=RTS_CONTROL_HANDSHAKE;
break;
case 3:
dcb.fRtsControl=RTS_CONTROL_TOGGLE;
break;
}
dcb.XonLim = m_xonLimit;
dcb.XoffLim = m_xoffLimit;
dcb.ByteSize = (unsigned char)(m_byteSize + 5);
dcb.Parity = (unsigned char) m_parity;
dcb.StopBits = (unsigned char) m_stopBits;
dcb.XonChar = char(m_xonChar);
dcb.XoffChar = char(m_xoffChar);
dcb.ErrorChar = char(m_replaceChar);
if (!SetCommState( m_hCommFile, &dcb))
throw "無法配置串口!";
}
void CApexCommCtrl::SetCommTimeState()
{
COMMTIMEOUTS commtimeouts;
if (!GetCommTimeouts(m_hCommFile, &commtimeouts))
throw "無法得到串口時間配置!";
// The CommTimeout numbers will very likely change if you are
// coding to meet some kind of specification where
// you need to reply within a certain amount of time after
// recieving the last byte. However, If 1/4th of a second
// goes by between recieving two characters, its a good
// indication that the transmitting end has finished, even
// assuming a 1200 baud modem.
commtimeouts.ReadIntervalTimeout = m_readIntervalTimeout;
commtimeouts.ReadTotalTimeoutMultiplier = m_readTotalTimeoutMultiplier;
commtimeouts.ReadTotalTimeoutConstant = m_readTotalTimeoutConstant;
commtimeouts.WriteTotalTimeoutMultiplier = m_writeTotalTimeoutMultiplier;
commtimeouts.WriteTotalTimeoutConstant = m_writeTotalTimeoutConstant;
if (!SetCommTimeouts(m_hCommFile, &commtimeouts))
throw "無法配置串口時間!";
}
////////////////////////////////////////////////////////
// 函數: CloseReadThread
//
// 目的: Close the Read Thread.
//
// 參數:
// none
//
// 返回值:
// none
//
// 注釋:
//
// Closes the Read thread by signaling the CloseEvent.
// Purges any outstanding reads on the comm port.
//
// Note that terminating a thread leaks memory.
// Besides the normal leak incurred, there is an event object
// that doesn't get closed. This isn't worth worrying about
// since it shouldn't happen anyway.
//
//
void CApexCommCtrl::CloseReadThread()
{
// If it exists...
if (ReadThread != NULL )
{
// Signal the event to close the worker threads.
SetEvent( m_hCloseEvent );
// Purge all outstanding reads
PurgeComm( m_hCommFile, PURGE_RXABORT + PURGE_RXCLEAR );
// Wait 10 seconds for it to return. Shouldn't happen.
//如果通過消息傳遞來關閉線程不能實現則主動刪除
if (WaitForSingleObject(ReadThread->m_hThread, 10000) == WAIT_TIMEOUT)
TerminateThread(ReadThread->m_hThread,0);
ReadThread = NULL;
}
}
/////////////////////////////////////////////////////////
// 函數: CloseWriteThread
//
// 目的: 關閉寫線程.
//
// 參數:
// none
//
// 返回值:
// none
/////////////////////////////////////////////////////////////////
void CApexCommCtrl::CloseWriteThread()
{
// If it exists...
if (WriteThread != NULL )
{
// Signal the event to close the worker threads.
SetEvent(m_hCloseEvent);
// Purge all outstanding writes.
PurgeComm(m_hCommFile, PURGE_TXABORT + PURGE_TXCLEAR);
m_bSendDataEmpty = true;
// Wait 10 seconds for it to return. Shouldn't happen.
if (WaitForSingleObject( WriteThread->m_hThread, 10000 ) == WAIT_TIMEOUT )
TerminateThread(WriteThread->m_hThread,0);
WriteThread = NULL;
};
}
////////////////////////////////////////////////////////////////////
//函數名:ReceiveData
//功能: 處理用戶自定義消息:接收到數據
//參數: wParam數據長度,lParam字符串
//返回值:標準自定義消息返回值
//注釋: 下面的函數形式相同
////////////////////////////////////////////////////////////////////
LRESULT CApexCommCtrl::ReceiveData(WPARAM wParam, LPARAM lParam )
{
LPCTSTR strdata;
WORD temp;
strdata=(LPCTSTR)lParam;
temp=wParam;
FireOnReceiveData(strdata,temp);
LocalFree((void*)lParam );
return 0;
}
LRESULT CApexCommCtrl::CommHangup(WPARAM wParam, LPARAM lParam )
{
WORD read_or_write;
read_or_write=HIWORD(lParam);
FireOnCommHangup(((read_or_write==0) ? 0:1));
return 0;
}
LRESULT CApexCommCtrl::ReceiveDataError(WPARAM wParam, LPARAM lParam )
{
long eventmask;
eventmask=(long)lParam;
FireReceiveDataError(eventmask);
return 0;
}
LRESULT CApexCommCtrl::DataSendFinished(WPARAM wParam, LPARAM lParam )
{
FireDataSendFinished();
return 0;
}
//只有這樣才能讓窗口接收消息,同時又不顯示
BOOL CApexCommCtrl::PreCreateWindow(CREATESTRUCT& cs)
{
LPCTSTR tt;
tt=AfxRegisterWndClass (CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS,AfxGetApp()->LoadCursor(IDC_NOTHING),0,0);
cs.lpszClass=tt;
if (AmbientUserMode())
cs.style = WS_CHILD | WS_CLIPSIBLINGS | WS_MAXIMIZEBOX ;
else
cs.style = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_MAXIMIZEBOX;
cs.dwExStyle &=~WS_EX_NOPARENTNOTIFY;
return COleControl::PreCreateWindow(cs);
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -