⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 comm.cpp

📁 用bcb6.0修改了原来用delphi编的spcomm
💻 CPP
📖 第 1 页 / 共 4 页
字号:
  Internal,InternalHigh 是保留给系统使用的,用户不需要设置。 

  Offset,OffsetHigh  是读写串口的偏移量,一般设置OffsetHigh为NULL, 
                        可以支持2GB数据。 

  hEvent  读写事件,因为串口是异步通讯,操作可能被其他进程堵塞, 
            程序可以通过检查该时间来得知是否读写完毕。事件将在读写完成后, 
            自动设置为有效。 

****************************************************************************/ 
/***************************************************************************/ 
//  READ THREAD 
/***************************************************************************/ 
// 
//  PROCEDURE: TReadThread.Execute 
// 
//  PURPOSE: This is the starting point for the Read Thread. 
// 
//  PARAMETERS: 
//    None. 
// 
//  RETURN VALUE: 
//    None. 
// 
//  COMMENTS: 
// 
//    The Read Thread uses overlapped ReadFile and sends any data 
//    read from the comm port to the Comm32Window.  This is 
//    eventually done through a PostMessage so that the Read Thread 
//    is never away from the comm port very long.  This also provides 
//    natural desynchronization between the Read thread and the UI. 
// 
//    If the CloseEvent object is signaled, the Read Thread exits. 
// 
//        Separating the Read and Write threads is natural for a application 
//    where there is no need for synchronization between 
//    reading and writing.  However, if there is such a need (for example, 
//    most file transfer algorithms synchronize the reading and writing), 
//    then it would make a lot more sense to have a single thread to handle 
//    both reading and writing. 
// 
// 
void __fastcall TReadThread::Execute(void) 
{ 
    char         szInputBuffer[INPUTBUFFERSIZE]; 
    DWORD        nNumberOfBytesRead; 
    HANDLE       HandlesToWaitFor[3]; 
    UINT         dwHandleSignaled; 
    DWORD        fdwEvtMask; 

    // Needed for overlapped I/O (ReadFile) 
    TOverlapped  overlappedRead; 

    // Needed for overlapped Comm Event handling. 
    TOverlapped  overlappedCommEvent; 

    memset( &overlappedRead , 0 , sizeof(overlappedRead) ); 
    memset( &overlappedCommEvent, 0, sizeof(overlappedCommEvent) ); 

    // Lets put an event in the Read overlapped structure. 
    overlappedRead.hEvent = CreateEvent( NULL, true, true, NULL ); 
    if (overlappedRead.hEvent == NULL) 
    { 
        PostHangupCall(); 
        goto EndReadThread; 
    } 

    // And an event for the CommEvent overlapped structure. 
    overlappedCommEvent.hEvent = CreateEvent( NULL, true, true, NULL ); 
    if (overlappedCommEvent.hEvent  == NULL) 
    { 
          PostHangupCall(); 
          goto EndReadThread; 
    } 

    // We will be waiting on these objects. 
    HandlesToWaitFor[0] = hCloseEvent; 
    HandlesToWaitFor[1] = overlappedCommEvent.hEvent; 
    HandlesToWaitFor[2] = overlappedRead.hEvent; 

    // Setup CommEvent handling. 

    // Set the comm mask so we receive error signals. 
    // EV_ERR or EV_RLSD or EV_RING //??????????????????? 
    if (! SetCommMask(hCommFile, EV_ERR  | EV_RLSD  | EV_RING ) ) 
    { 
          PostHangupCall(); 
          goto EndReadThread; 
    } 

     // Start waiting for CommEvents (Errors) 
     if (! SetupCommEvent( &overlappedCommEvent,  fdwEvtMask )) 
        goto EndReadThread; 

     // Start waiting for Read events. 
     if (! SetupReadEvent( &overlappedRead, 
                            szInputBuffer, INPUTBUFFERSIZE, 
                            nNumberOfBytesRead ) ) 
        goto EndReadThread; 

     // Keep looping until we break out. 
     while (true) 
     { 
        // WaitForMultipleObjects是Windows中的一个功能非常强大的函数, 
        // 几乎可以等待Windows中的所有的内核对象.但同时该函数在用法上 
        // 却需要一定的技巧。 
        // 原型:DWORD WaitForMultipleObjects( 
        //                  DWORD nCount, 
        //                  const HANDLE* lpHandles, 
        //                  BOOL  bWaitAll, 
        //                  DWORD dwMilliseconds); 
        // 当WaitForMultipleObjects等到多个内核对象的时候,如果它的bWaitAll 
        // 参数设置为false。其返回值减去WAIT_OBJECT_0 就是参数lpHandles数组 
        // 的序号。如果同时有多个内核对象被出发,这个函数返回的只是其中序号 
        // 最小的那个。 

        // Wait until some event occurs (data to read; error; stopping). 
        dwHandleSignaled = WaitForMultipleObjects(3, HandlesToWaitFor, 
                              false, INFINITE); 

        switch ( dwHandleSignaled ) 
        { 
            case  WAIT_OBJECT_0:     // Signal to end the thread. 
            { 
                // Time to exit. 
                goto EndReadThread; 
            } 

            case  WAIT_OBJECT_0 + 1: // CommEvent signaled. 
            { 
                // Handle the CommEvent. 
                if (! HandleCommEvent( &overlappedCommEvent, fdwEvtMask, TRUE )) 
                       goto EndReadThread; 

                // Start waiting for the next CommEvent. 
                if (! SetupCommEvent( &overlappedCommEvent, fdwEvtMask )) 
                       goto EndReadThread; 

                break; 
            } 

            case WAIT_OBJECT_0 + 2: // Read Event signaled. 
            { 
                // Get the new data! 
                if (! HandleReadEvent( &overlappedRead, 
                                       szInputBuffer, 
                                       INPUTBUFFERSIZE, 
                                       nNumberOfBytesRead )) 
                       goto EndReadThread; 

                // Wait for more new data. 
                if (! SetupReadEvent( &overlappedRead, 
                                      szInputBuffer, 
                                      INPUTBUFFERSIZE, 
                                      nNumberOfBytesRead )) 
                       goto EndReadThread; 
                break; 
            } 

            case  WAIT_FAILED:       // Wait failed.  Shouldn't happen. 
            { 
                PostHangupCall(); 
                goto EndReadThread; 
            } 

            default:                // This case should never occur. 
            { 
                PostHangupCall(); 
                goto EndReadThread; 
            } 
        } // switch 
    }// while( true ) 

    // Time to clean up Read Thread. 
    EndReadThread: 

    // 清空串口缓冲区,退出所有相关操作 
    PurgeComm( hCommFile, PURGE_RXABORT  | PURGE_RXCLEAR ); 
    CloseHandle( overlappedRead.hEvent ); 
    CloseHandle( overlappedCommEvent.hEvent ); 
}
//--------------------------------------------------------------------------- 
// 
//  FUNCTION: SetupReadEvent(LPOVERLAPPED, LPSTR, DWORD, LPDWORD) 
// 
//  PURPOSE: Sets up an overlapped ReadFile 
// 
//  PARAMETERS: 
//    lpOverlappedRead      - address of overlapped structure to use. 
//    lpszInputBuffer       - Buffer to place incoming bytes. 
//    dwSizeofBuffer        - size of lpszInputBuffer. 
//    lpnNumberOfBytesRead  - address of DWORD to place the number of read bytes. 
// 
//  RETURN VALUE: 
//    TRUE if able to successfully setup the ReadFile.  FALSE if there 
//    was a failure setting up or if the CloseEvent object was signaled. 
// 
//  COMMENTS: 
// 
//    This function is a helper function for the Read Thread.  This 
//    function sets up the overlapped ReadFile so that it can later 
//    be waited on (or more appropriatly, so the event in the overlapped 
//    structure can be waited upon).  If there is data waiting, it is 
//    handled and the next ReadFile is initiated. 
//    Another possible reason for returning FALSE is if the comm port 
//    is closed by the service provider. 
// 
// 
// 
bool __fastcall TReadThread::SetupReadEvent( 
Windows::POverlapped lpOverlappedRead, 
char *   lpszInputBuffer, 
                    DWORD   dwSizeofBuffer, 
                    DWORD   &lpnNumberOfBytesRead) 
{ 
    DWORD dwLastError; 

    StartSetupReadEvent: 

    // Make sure the CloseEvent hasn't been signaled yet. 
    // Check is needed because this function is potentially recursive. 
    if (WAIT_TIMEOUT != WaitForSingleObject(hCloseEvent, 0)) 
        return false; 

    // Start the overlapped ReadFile. 
    if (ReadFile( hCommFile, lpszInputBuffer, dwSizeofBuffer, 
                  &lpnNumberOfBytesRead, lpOverlappedRead )) 
    { 
        // This would only happen if there was data waiting to be read. 

        // Handle the data. 
        if (! HandleReadData( lpszInputBuffer, lpnNumberOfBytesRead ) ) 
            return false; 

        // Start waiting for more data. 
        goto StartSetupReadEvent; 
    } 

    // ReadFile failed.  Expected because of overlapped I/O. 
    dwLastError = GetLastError(); 

    // LastError was ERROR_IO_PENDING, as expected. 
    if (dwLastError == ERROR_IO_PENDING) 
        return true; 

    // 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; 
} 
//--------------------------------------------------------------------------- 
// 
//  FUNCTION: HandleReadData(LPCSTR, DWORD) 
// 
//  PURPOSE: Deals with data after its been read from the comm file. 
// 
//  PARAMETERS: 
//    lpszInputBuffer  - Buffer to place incoming bytes. 
//    dwSizeofBuffer   - size of lpszInputBuffer. 
// 
//  RETURN VALUE: 
//    TRUE if able to successfully handle the data. 
//    FALSE if unable to allocate memory or handle the data. 
// 
//  COMMENTS: 
// 
//    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 __fastcall TReadThread::HandleReadData(char * 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 = (char*)( LocalAlloc( LPTR, dwSizeofBuffer+1 ) ); 

        // Out of memory - 内存不足 
        if (lpszPostedBytes == NULL) 
        { 
            PostHangupCall(); 
            return false; 
        } 

        Move( lpszInputBuffer, lpszPostedBytes, dwSizeofBuffer ); 
        lpszPostedBytes[dwSizeofBuffer] = '\0'; 

        return ReceiveData( lpszPostedBytes, dwSizeofBuffer ); 
    } 

    return false; 
} 
//--------------------------------------------------------------------------- 
// 
//  FUNCTION: HandleReadEvent(LPOVERLAPPED, LPSTR, DWORD, LPDWORD) 
// 
//  PURPOSE: Retrieves and handles data when there is data ready. 
// 
//  PARAMETERS: 
//    lpOverlappedRead      - address of overlapped structure to use. 
//    lpszInputBuffer       - Buffer to place incoming bytes. 
//    dwSizeofBuffer        - size of lpszInputBuffer. 
//    lpnNumberOfBytesRead  - address of DWORD to place the number of read bytes. 
// 
//  RETURN VALUE: 
//    TRUE if able to successfully retrieve and handle the available data. 
//    FALSE if unable to retrieve or handle the data. 
// 
//  COMMENTS: 
// 
//    This function is another helper function for the Read Thread.  This 
//    is the function that is called when there is data available after 
//    an overlapped ReadFile has been setup.  It retrieves the data and 
//    handles it. 
// 
// 
bool __fastcall TReadThread::HandleReadEvent( 
                    Windows::POverlapped lpOverlappedRead, 
                    char * lpszInputBuffer, 
                    DWORD dwSizeofBuffer, 
                    DWORD &lpnNumberOfBytesRead) 
{ 
    DWORD dwLastError; 
      
    if (GetOverlappedResult( 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; 
}
//--------------------------------------------------------------------------- 
// 
//  FUNCTION: SetupCommEvent(LPOVERLAPPED, LPDWORD) 
// 
//  PURPOSE: Sets up the overlapped WaitCommEvent call. 
// 
//  PARAMETERS: 
//    lpOverlappedCommEvent - Pointer to the overlapped structure to use. 
//    lpfdwEvtMask          - Pointer to DWORD to received Event data. 
// 
//  RETURN VALUE: 
//    TRUE if able to successfully setup the WaitCommEvent. 
//    FALSE if unable to setup WaitCommEvent, unable to handle 
//    an existing outstanding event or if the CloseEvent has been signaled. 
// 
//  COMMENTS: 
// 
//    This function is a helper function for the Read Thread that sets up 
//    the WaitCommEvent so we can deal with comm events (like Comm errors) 
//    if they occur. 
// 
// 
bool __fastcall TReadThread::SetupCommEvent( 
            Windows::POverlapped lpOverlappedCommEvent, 
            DWORD &lpfdwEvtMask) 
{ 
    DWORD dwLastError; 
StartSetupCommEvent: 

    // Make sure the CloseEvent hasn't been signaled yet. 
    // Check is needed because this function is potentially recursive. 
    if (WAIT_TIMEOUT != WaitForSingleObject( hCloseEvent, 0 )) 
        return false; 

    // Start waiting for Comm Errors. 
    if (WaitCommEvent( hCommFile, &lpfdwEvtMask, lpOverlappedCommEvent )) 
    { 
        // This could happen if there was an error waiting on the 
        // comm port.  Lets try and handle it. 

        if (! HandleCommEvent( NULL, lpfdwEvtMask, false ) ) 
        { 
               //??? GetOverlappedResult does not handle "NIL" as defined by Borland 
               return false; 
        } 

        // What could cause infinite recursion at this point? 
        goto StartSetupCommEvent; 
    } 

    // We expect ERROR_IO_PENDING returned from WaitCommEvent 
    // because we are waiting with an overlapped structure. 

    dwLastError = GetLastError(); 

    // LastError was ERROR_IO_PENDING, as expected. 
    if (dwLastError == ERROR_IO_PENDING) 
        return true;//  Result := True; 

    // 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. No idea what could cause this to happen. 
    PostHangupCall(); 
    return false; 
} 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -