?? vcthread.cpp
字號:
}
// Its possible that multiple errors occured and were handled
// in the last ClearCommError. Because all errors were signaled
// individually, but cleared all at once, pending comm events
// can yield EV_ERR while dwErrors equals 0. Ignore this event.
if (! ReceiveError( dwErrors )) return false;
return true;
}
else
{
PostHangupCall();
return false;
}
}// {TReadThread.HandleCommEvent}
bool TReadThread::HandleReadEvent( OVERLAPPED* lpOverlappedRead,LPSTR lpszInputBuffer,DWORD dwSizeofBuffer,DWORD & lpnNumberOfBytesRead)
{
DWORD dwLastError;
//Result = false;
if (GetOverlappedResult( m_hCommFile,lpOverlappedRead, &lpnNumberOfBytesRead, false ) )
{
return( HandleReadData( lpszInputBuffer, lpnNumberOfBytesRead ));
}
// Error in GetOverlappedResult; handle it.
dwLastError = GetLastError();
// Its possible for this error to occur if the
// service provider has closed the port. Time to end.
if (dwLastError == ERROR_INVALID_HANDLE )
return false;
// Unexpected error come here. No idea what could cause this to happen.
PostHangupCall();
return false;
}// {TReadThread.HandleReadEvent}
//////////////////////////////////////////////////////////
// 函數: HandleReadData(LPCSTR, DWORD)
//
// 目的: Deals with data after its been read from the comm file.
//
// 參數:
// lpszInputBuffer - Buffer to place incoming bytes.
// dwSizeofBuffer - size of lpszInputBuffer.
//
// 返回值:
// TRUE if able to successfully handle the data.
// FALSE if unable to allocate memory or handle the data.
//
// 注釋:
//
// This function is yet another helper function for the Read Thread.
// It LocalAlloc()s a buffer, copies the new data to this buffer and
// calls PostWriteToDisplayCtl to let the EditCtls module deal with
// the data. Its assumed that PostWriteToDisplayCtl posts the message
// rather than dealing with it right away so that the Read Thread
// is free to get right back to waiting for data. Its also assumed
// that the EditCtls module is responsible for LocalFree()ing the
// pointer that is passed on.
//
bool TReadThread::HandleReadData(LPCSTR lpszInputBuffer, DWORD dwSizeofBuffer)
{
LPSTR lpszPostedBytes;
//Result = false;
// If we got data and didn't just time out empty...
if (dwSizeofBuffer != 0 )
{
// Do something with the bytes read.
lpszPostedBytes = (LPSTR)( LocalAlloc( LPTR, dwSizeofBuffer+1 ) );
if (lpszPostedBytes == NULL )
{
// Out of memory
PostHangupCall();
return false;
}
strncpy( lpszPostedBytes,lpszInputBuffer,dwSizeofBuffer);
lpszPostedBytes[dwSizeofBuffer] = '\0';
return (ReceiveData( lpszPostedBytes, dwSizeofBuffer ));
}
return false;
}//{TReadThread.HandleReadData}
bool TReadThread::ReceiveData(LPSTR lpNewString,DWORD dwSizeofNewString)
{
if (! PostMessage(m_handlemsg,USER_RECEIVEDATA,WPARAM(dwSizeofNewString), LPARAM(lpNewString)))
{
PostHangupCall();
return false;
}
return true;
}
bool TReadThread::ReceiveError(DWORD EvtMask)
{
if (! PostMessage(m_handlemsg,USER_RECEIVEDATAERROR, 0, LPARAM(EvtMask) ) )
{
PostHangupCall ();
return false;
}
return true;
}
void TReadThread::PostHangupCall()
//當讀線程掛起時,觸發掛起線程事件,讓用戶處理它
{ //接收窗體 讀數據時事件掛起標識
int i=1;
PostMessage(m_handlemsg,USER_ONCOMMHANGUP, 0, LPARAM(i));
}
IMPLEMENT_DYNAMIC(TWriteThread, CWinThread)
////////////////////////////////////////////////////////
// 過程: TWriteThread::TWriteThread
//
// 目的: 寫線程的起始點
//
// 參數: 無
//
// 返回值: 無
//
// 注釋:
//
// 寫線程使用消息循環等待要寫入的字符串,當得到后便寫入到串口中。
// 如果收到關閉消息,則關閉退出
// 使用消息的方法使得向串口中寫數據與用戶的操作是不同步的。
/////////////////////////////////////////////////////////////////////////////
TWriteThread::TWriteThread()
{
}
//////////////////////////////////////////////////////////////////
//線程處理實體,當返回FALSE時,表示線程結束
//////////////////////////////////////////////////////////////////
BOOL TWriteThread::InitInstance()
{
MSG msg;
DWORD dwHandleSignaled;
OVERLAPPED overlappedWrite;
BOOL CompleteOneWriteRequire;
BOOL contiflag;
// overlapped 方式的輸入輸出需要下面處理過的結構體.
memset( &overlappedWrite,0, sizeof(overlappedWrite));
overlappedWrite.hEvent = CreateEvent( NULL, true, false, NULL );
//沒有創建適合的事件
if (overlappedWrite.hEvent == 0 )
{
PostHangupCall();
goto EndWriteThread;
}
CompleteOneWriteRequire = false;
//主循環,直到結束它.
while (true)
{
contiflag=false;
if (! PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
{
// 如果沒有消息則等待消息產生或者操作被停止
m_pbSendDataEmpty = true;//此時當然沒有要傳輸的數據
if (CompleteOneWriteRequire) //一次傳輸完畢告訴用戶
{
if (!PostMessage(m_handlemsg,USER_DATASENDFINISHED, 0, 0 ) )
{
PostHangupCall();
goto EndWriteThread;
}
}
CompleteOneWriteRequire = false;
dwHandleSignaled = MsgWaitForMultipleObjects(1, &m_hCloseEvent, false,
INFINITE, QS_ALLINPUT);
switch (dwHandleSignaled)
{
case WAIT_OBJECT_0: // 關閉消息!
// 退出.
goto EndWriteThread;
break;
case WAIT_OBJECT_0 + 1: // 得到新的消息.
// 重新循環來處理它.
contiflag =true;
break;
case WAIT_FAILED: // 超時,不可能出現.
PostHangupCall();
goto EndWriteThread;
break;
default: // 不可能出現.
PostHangupCall();
goto EndWriteThread;
}
if (contiflag) continue;
}
else
{
// 確認在接收數據時是否有關閉消息產生
if (WAIT_TIMEOUT != WaitForSingleObject(m_hCloseEvent,0) )
goto EndWriteThread;
// 處理該條消息,如果此時有對話框出現則下面語句可做范例.
//本控件用不到
if (msg.hwnd != NULL )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
continue;
}
// 處理得到的消息.
switch ( msg.message )
{
case USER_WRITEPORT: // 向串口中寫入字符串.
// 向串口中寫入字符串. HandleWriteData
// 直到寫完數據后才返回,
// 除非出現錯誤或者端口被關閉.
if (! HandleWriteData( &overlappedWrite,
(char*)(msg.lParam), DWORD(msg.wParam) ) )
{
// 將得到的消息結構體釋放
LocalFree( HLOCAL(msg.lParam) );
goto EndWriteThread;
}
CompleteOneWriteRequire = true;//成功完成一次寫操作
// 將寫入到消息結構體中的數據空間清空.
LocalFree( HLOCAL(msg.lParam) );
}
}
} //{main loop}
//結束寫線程.
EndWriteThread:
PurgeComm(m_hCommFile, PURGE_TXABORT + PURGE_TXCLEAR);
m_pbSendDataEmpty = true;
CloseHandle(overlappedWrite.hEvent);
return false;
}//{TWriteThread.Execute}
////////////////////////////////////////////////////////
// 函數: HandleWriteData(LPOVERLAPPED, LPCSTR, DWORD)
//
// 目的: 向串口文件寫入字符串.
//
// 參數:
// lpOverlappedWrite - WriteFile函數中使用的LPOVERLAPPED結構體
// pDataToWrite - 需要寫入的字符串.
// dwNumberOfBytesToWrite - 字符串的長度.
//
// 返回值:
// 當所有字節都寫完時返回真值(非零). 否則返回假值(零)
//
// 注釋:
//
// 該函數是寫線程的輔助函數,它實際向串口寫數據.
// 注意該調用將阻塞直到寫線程結束寫操作,或者收到結束線程的消息.
// 返回假值時可能的原因是串口被服務提供者關閉
//
bool TWriteThread::HandleWriteData(OVERLAPPED* lpOverlappedWrite,LPSTR pDataToWrite, DWORD dwNumberOfBytesToWrite)
{
DWORD dwLastError;
DWORD dwNumberOfBytesWritten,dwWhereToStartWriting,dwHandleSignaled;
HANDLE HandlesToWaitFor[2];
//Result = false;//缺省返回值
dwNumberOfBytesWritten = 0;//已經寫的字符為零
dwWhereToStartWriting = 0; // 從字符串的開始位置寫字符串.
//記錄兩個事件
HandlesToWaitFor[0] = m_hCloseEvent;//關閉事件句柄
HandlesToWaitFor[1] = lpOverlappedWrite->hEvent;
// 循環,直到將字符寫完.
do
{
// 開始進行輸入/輸出.
if (! WriteFile( m_hCommFile,//串口文件句柄
&(pDataToWrite[ dwWhereToStartWriting ]),//每次接著傳輸剩下的字符串
dwNumberOfBytesToWrite, &dwNumberOfBytesWritten,
lpOverlappedWrite ) )
{
//如果寫操作失敗,則下面要得到錯誤句柄.
dwLastError = GetLastError();
// 如果服務提供者關閉了串口或者超時,則將出現下面的錯誤
if (dwLastError == ERROR_INVALID_HANDLE) return false;
//不可知的錯誤.
if (dwLastError != ERROR_IO_PENDING )
{
PostHangupCall();//調用用戶的相應事件處理程序
return false;
};
// 下面是可以處理的情況.有時沒有等待寫完數據便返回FALSE
// 等待寫過程結束或者收到了停止信號。
dwHandleSignaled = WaitForMultipleObjects(2, HandlesToWaitFor,
false, INFINITE);
switch ( dwHandleSignaled )
{
case WAIT_OBJECT_0: // 收到了關閉消息!
// 退出.
return false;
case WAIT_OBJECT_0 + 1: // 寫操作完畢.
// 得到寫操作的結果
if (! GetOverlappedResult(m_hCommFile,
lpOverlappedWrite,
&dwNumberOfBytesWritten, true) )
{
dwLastError = GetLastError();
// 當服務提供者關閉端口時將出現下面的錯誤
if (dwLastError == ERROR_INVALID_HANDLE) return false;
// 其它情況不再做特殊處理,直接退出.
PostHangupCall();
return false;
}
break;
case WAIT_FAILED: // 等待超時,由于參數為真值,所以不可能出現.
PostHangupCall();
return false;
default: // 所以不可能出現.
PostHangupCall();
return false;
}
}
//{處理了寫操作失敗的情況}
// 記錄寫過的數據數和剩下的字節數.
dwNumberOfBytesToWrite -= dwNumberOfBytesWritten; //減
dwWhereToStartWriting+=dwNumberOfBytesWritten ;//加
} while (dwNumberOfBytesToWrite > 0); // 直到寫完為止!
// 寫完畢后返回真.
return true;
}//{TWriteThread.HandleWriteData}
void TWriteThread::PostHangupCall()
//當寫線程掛起時,觸發掛起線程事件,讓用戶處理它
{ //接收窗體 寫數據時事件掛起標識
int i=0;
PostMessage(m_handlemsg,USER_ONCOMMHANGUP, 0, LPARAM(i));
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -