📄 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 + -