我想问一下,怎么监视一个被占用的串口的传输数据???包括接收的和发送的!!!写程序实现.....我暂时没有思路...

解决方案 »

  1.   

    一个办法是参考http://www.codeguru.com/network/commspy.shtml,这是一个监视串口的例子,不过它需要一些硬件的调整。 
        另一个办法是编写设备驱动,因为在保护模式下可以虚拟化端口。在杨强、李堂秋编著的《Win9X 虚拟设备驱动程序编程指南》(清华大学出版社1999年出版,ISBN7-302-03324-2)有一个监视并口的例子,你可以参考。 
      

  2.   

    中转数据就可以了。但需要多开2个串口。
    举例:原来程序使用串口Com1连接终端。中转的时候你需要将COM1连接到COM2上,然后COM3连接到终端上。这样当COM1发送数据时,就被COM2接收到,这个时候因为COM2、COM3是你写的程序打开的,所以不管COM1中发过来什么数据,你的程序都可以记录下来,在COM2接收到数据以后直接将数据通过COM3发给终端,避免通讯超时。数据发出去以后可以将备份数据存入缓存,然后开一个线程慢慢处理。
      

  3.   

    头文件
    #ifndef _MOONZWU_SUPER_SERIAL_PORT
    #define _MOONZWU_SUPER_SERIAL_PORT#include <vector>
    using namespace std;typedef struct WIN_ARG
    {
    UINT  winId;
    CWnd* pWin;
    DWORD msg;
    }WINARG, *pWINARG;
    typedef vector<WIN_ARG>   vWINLIST; // 窗口列表// 传输数据包
    typedef struct tagPackage
    {
    enum emMaxSize
    { emMAX_SIZE = 1024 };

    UINT iLen;
    UINT iType;
    BYTE pData[emMAX_SIZE]; tagPackage()
    {
    Clear();
    } void Clear()
    {
    iLen  = 0;
    iType = 0;
    ZeroMemory(pData, sizeof(*pData));
    }

    }PACKAGE, * pPACKAGE;class CSuperSerialPort : public CObject
    {
    public:
    CSuperSerialPort();
    virtual ~CSuperSerialPort(); // 
    BOOL Open(TCHAR* com,
          UINT rate,
      UINT parity,
      BYTE dataBits,
      float stopBits); // 
    BOOL     IsOpen() { return m_bIsOpen; }

    //
    void Close(); //
    UINT Attach(CWnd* pwin, DWORD msg);
    void Detach(UINT winId);
    //
    BOOL SendData(pPACKAGE pPack); // 发送数据
    BOOL StartReceive(LPVOID arg); // 启动接收, 参数为串口指针 //
    COMSTAT* GetComState(); // 获取串口状态
    HANDLE   GetComHandle();// 获取串口句柄 //
    ULONG    GetWritedBytes() const;
    ULONG    GetReadedBytes() const;

    // 设置输入输出缓存区
    void     SetInOutBuffer(DWORD inBuf, DWORD outBuf); // 获取错误信息
    DWORD    GetErrorCode();
    const TCHAR*   FormatErrorCodeToString(DWORD code);
    static void SafeRelease(pPACKAGE pPack); // 释放包 typedef struct COM_ARG
    {
    TCHAR  com[10];
    HANDLE comHandle;
    UINT   comRate;
    UINT   comParity;
    BYTE   dataBits;
    UINT   stopBits; COM_ARG()
    {
    sprintf(com, _T("COM1"));
    comHandle = INVALID_HANDLE_VALUE;
    comRate   = 9600;
    comParity = 0;
    dataBits  = 8;
    stopBits  = 1;
    }

    }COMARG, *pCOMARG;
    // 错误类型枚举
    enum emErrorType
    {
    emET_SUCCEDED = 0,
    emET_NO_OPEN,
    emET_NO_HANDLE,
    emET_OPENED,
    emET_COM_UNNAMED,
    emET_UNKNOW = 99
    };

    // 数据类型
    enum emDataType
    {
    emDATA_TYPE_TEXT=0, emDATA_TYPE_BINARY
    }; // 线程事件数量
    enum emThreadEvent

    emTHREAD_EXIT = 0,
    emTHREAD_RUN = 1,
    emMAX_EVENT_NUMBER = 2 
    };

    protected:
        
    // 接收线程
        friend UINT WINAPI ReceiveThread(LPVOID pVoid);
    friend void PostPackage(CSuperSerialPort* pCom, pPACKAGE pPack); BOOL WriteComm(pPACKAGE pPack);private:

    COMARG   m_com;
    COMSTAT  m_comState;
    DWORD    m_errorCode;
    TCHAR    m_errorInfo[128];
    BOOL     m_bIsOpen;
         vWINLIST m_winList; /*------------------------------*/
    OVERLAPPED    m_ovReader;                          // Overlapped structure for ReadFile
        OVERLAPPED    m_ovWriter;                          // Overlapped structure for WriteFile
        OVERLAPPED    m_ovWaitEvent;                       // Overlapped structure for WaitCommEvent
    HANDLE        m_hWait;
    HANDLE        m_hReader;
    HANDLE        m_hWriter;


    UINT     m_nextWinId; // 返回附加的窗体Id ULONG    m_WriteCount; // 已发送字节数
    ULONG    m_ReadCount;  // 已接收字节数 HANDLE   m_hEvent[emMAX_EVENT_NUMBER];    // 线程控制事件句柄
    UINT     m_threadId;
    };
    #endif
      

  4.   

    实现文件, 可以直接用
    #include "stdafx.h"
    #include "superSP.h"
    #include <process.h>//////////////////////////////////////////////////////////////////////////
    // 静态成员void CSuperSerialPort::SafeRelease(pPACKAGE pPack)
    {
    if (NULL != pPack)
    {
    delete pPack;
    pPack = NULL;
    }
    }
    // 这两个函数被设计成友元目的是可以访问类的私有变量
    UINT WINAPI ReceiveThread(LPVOID pVoid)
    {
    long threadStatus;
    DWORD dwMask, dwTrans;
    DWORD dwErrFlag;
    BOOL bExit = false;
    CSuperSerialPort* pCom = (CSuperSerialPort *)pVoid;//
    //
    while (!bExit)
    {
    threadStatus = 
    WaitForMultipleObjects(CSuperSerialPort::emMAX_EVENT_NUMBER,
    pCom->m_hEvent,
    FALSE,
    INFINITE);
    threadStatus -= WAIT_OBJECT_0; if (threadStatus < 0 ||
    threadStatus >= CSuperSerialPort::emMAX_EVENT_NUMBER)
    {
    bExit = true;
    break;
    }
    //
    // // 进行事件处理
    switch (threadStatus)
    {
    case CSuperSerialPort::emTHREAD_EXIT:
    bExit = true;
    break;
    //
    case CSuperSerialPort::emTHREAD_RUN:
    ClearCommError(pCom->GetComHandle(),
    &dwErrFlag,
    &pCom->m_comState); // 缓存队列中有数据
    if (pCom->m_comState.cbInQue)
    {
    pPACKAGE pPack = new PACKAGE;
    DWORD rdLen = pCom->m_comState.cbInQue;
    pPack->iLen   = rdLen;

    // 根据长度读取指定字节到包中
    if (ReadFile(pCom->GetComHandle(), 
    pPack->pData,
    pPack->iLen,
    &rdLen,
    &pCom->m_ovReader))
    {
    // 发送包到win消息队列
    pPack->iLen = rdLen;
    pCom->m_ReadCount += pPack->iLen;
    PostPackage(pCom, pPack);
    continue;
    }
    } dwMask = 0;

    if (!WaitCommEvent(pCom->GetComHandle(),
    &dwMask,
    &pCom->m_ovWaitEvent))
    {
    // GetLastError查找错误
    DWORD errorCode = GetLastError();
    if (errorCode == ERROR_IO_PENDING)
    {
    GetOverlappedResult(pCom->GetComHandle(),
    &pCom->m_ovWaitEvent,
    &dwTrans,
    TRUE);
    }
    else // 非交叠操作,输出错误信息并退出
    {
    LPVOID lpMsg;

    FormatMessage(
    FORMAT_MESSAGE_ALLOCATE_BUFFER | 
    FORMAT_MESSAGE_FROM_SYSTEM | 
    FORMAT_MESSAGE_IGNORE_INSERTS,
    NULL,
    errorCode,
    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
    (LPTSTR)&lpMsg,
    0,
    NULL);

    TRACE((LPCTSTR)lpMsg);
    LocalFree(lpMsg);
    bExit = true;
    }
    }

                break;
    default:
    break;
    }
    }

    return 0;
    }void PostPackage(CSuperSerialPort* pCom,  pPACKAGE pPack)
    {
    if (NULL != pCom)
    {
    vWINLIST::iterator it;
    for (it = pCom->m_winList.begin();
         it != pCom->m_winList.end();
         it++)
    {
    it->pWin->PostMessage(it->msg, (WPARAM)pPack);
    }
    }
    }
    //////////////////////////////////////////////////////////////////////////
    // 构造/析构CSuperSerialPort::CSuperSerialPort()
    : m_nextWinId(1),
      m_WriteCount(0),
      m_ReadCount(0),
      m_bIsOpen(false)
    {
    }CSuperSerialPort::~CSuperSerialPort()
    { CloseHandle(m_com.comHandle);
    }//////////////////////////////////////////////////////////////////////////
    // 操作控制//
    // Open 函数
    //
    // 参数: TCHAR* com    串口名
    //       UINT rate     波特率
    //       UINT parity   校验位
    //       BYTE dataBits 数据位
    //       UINT stopBits 停止位
    //
    // 返回值: true 成功, false 失败
    //
    // 注意: 如果返回失败,请调用GetErrorCode来查找原因
    //BOOL CSuperSerialPort::Open(TCHAR* com,
    UINT rate,
    UINT parity,
    BYTE dataBits,
    float stopBits)
    {
    m_errorCode = emET_SUCCEDED;
    COMMTIMEOUTS cto = { 0, 0, 0, 0, 0}; if (NULL == com)
    {
    m_errorCode = emET_COM_UNNAMED;
    return false;
    } strcpy(m_com.com, com);
    m_com.comRate   = rate;
    m_com.comParity = parity;
    m_com.dataBits  = dataBits;

    if (stopBits == 1) {
    stopBits = 0;
    } else if (stopBits == 1.5){
            stopBits = 1;
    } else {
    stopBits = 2;
    } m_com.stopBits  = stopBits;
    // 串口已经打开
    if (m_com.comHandle != INVALID_HANDLE_VALUE)
    {
    m_errorCode = emET_OPENED;
    return FALSE;
    } DCB  dcb;
    memset(&dcb, 0, sizeof(dcb));
    dcb.DCBlength = sizeof(dcb);
    dcb.BaudRate  = m_com.comRate;
    dcb.Parity    = m_com.comParity;
    dcb.fParity   = m_com.comParity & 0; // 0&0 = 0, 1,2 & 0 = 1
    dcb.StopBits  = m_com.stopBits; // 0, 1, 2 = 1, 1.5, 2
    dcb.ByteSize  = m_com.dataBits; dcb.fOutxCtsFlow    = 0;
    dcb.fOutxDsrFlow    = 0;
    dcb.fDtrControl     = DTR_CONTROL_DISABLE;
    dcb.fDsrSensitivity = 0;
    dcb.fRtsControl     = RTS_CONTROL_DISABLE;
    dcb.fOutX           = 0;
    dcb.fInX            = 0;

    /* ----------------- misc parameters ----- */
    dcb.fErrorChar      = 0;
    dcb.fBinary         = 1;
    dcb.fNull           = 0;
    dcb.fAbortOnError   = 0;
    dcb.wReserved       = 0;
    dcb.XonLim          = 2;
    dcb.XoffLim         = 4;
    dcb.XonChar         = 0x13;
    dcb.XoffChar        = 0x19;
    dcb.EvtChar         = 0;

    // 
    m_com.comHandle = CreateFile(m_com.com,
    GENERIC_READ | GENERIC_WRITE,
    0,
    NULL,
    OPEN_EXISTING,
    FILE_FLAG_OVERLAPPED,
    NULL); if (m_com.comHandle == INVALID_HANDLE_VALUE)
    {
    m_errorCode = emET_NO_OPEN;
    return false;
    } if (SetCommMask(m_com.comHandle, EV_RXCHAR |  EV_BREAK) &&
    SetCommTimeouts(m_com.comHandle, &cto) &&
    SetCommState(m_com.comHandle, &dcb) &&
    SetupComm(m_com.comHandle, 1024, 1024)) // 默认输入输出缓存大小
    {
    m_bIsOpen = true;
    return true;
    }
    else

    m_errorCode = emET_UNKNOW;
    return false;
    }

    }
      

  5.   


    //
    // Close 函数
    //void CSuperSerialPort::Close()
    {
    CloseHandle(m_com.comHandle);
    SetEvent(m_hEvent[emTHREAD_EXIT]);
    ResetEvent(m_hEvent[emTHREAD_RUN]);
    m_bIsOpen = false;
    }
    //
    // Attach 函数
    //
    // 参数: CWnd* pwin  窗口指针
    //       DWORD msg   窗口消息
    //
    // 返回值: 返回一个附加到串口窗口列表的位置
    //
    // 注意: 窗口的附加Id(2^32)会用完,会导致程序崩溃
    //
    UINT CSuperSerialPort::Attach(CWnd* pwin, DWORD msg)
    {
    if (NULL == pwin)
    {
    return 0;
    } WIN_ARG wa;
    wa.winId = m_nextWinId++;
    wa.msg   = msg;
    wa.pWin  = pwin;
    m_winList.push_back(wa); return wa.winId;
    }
    //
    // Detach 函数
    // 
    // 参数: UINT winId  窗口附加时的Id
    //void CSuperSerialPort::Detach(UINT winId)
    {
    if (winId == 0 || winId >= m_nextWinId)
    {
    return;
    } vWINLIST::iterator it;
    for(it = m_winList.begin();
        it != m_winList.end();
    it++)
    {
    if (it->winId == winId)
    {
    m_winList.erase(it);
    break;
    }
    }
    }//
    // SendData 函数
    // 
    // 参数: pPACKAGE pPack 要发送的数据包
    //
    // 返回值: true 发送成, false 发送失败
    //BOOL CSuperSerialPort::SendData(pPACKAGE pPack)
    {
    DWORD dwErrFlag;
    COMSTAT comStat;
    m_errorCode = emET_SUCCEDED; if (m_com.comHandle == INVALID_HANDLE_VALUE)
    {
    m_errorCode = emET_NO_HANDLE;
    return false;
    } ClearCommError(m_com.comHandle, 
    &dwErrFlag,
    &comStat);    BOOL bl;
    UINT nums = 0;
    UINT reserve = 0;

    // 数据过大
        if (pPack->iLen > pPack->emMAX_SIZE)
    {
    nums = pPack->iLen/pPack->emMAX_SIZE;
    reserve = pPack->iLen%pPack->emMAX_SIZE;
        

    // 分解传输
    for (int i= 0; i<nums; i++)
    {
    PACKAGE pk;
    pk.iLen = pk.emMAX_SIZE;
    memcpy(pk.pData, 
    pPack->pData+i*pPack->emMAX_SIZE,
    pPack->emMAX_SIZE*sizeof(BYTE)); bl = WriteComm(&pk);
    } // 如果还有剩余的数据
    if (reserve != 0)
    {
    PACKAGE pk;
    pk.iLen = reserve;
    memcpy(pk.pData,
    pPack->pData+nums*pPack->emMAX_SIZE,
    pPack->emMAX_SIZE*sizeof(BYTE));
    bl = WriteComm(&pk);
    }
    }
    else
    {
    bl = WriteComm(pPack);
    }


    return bl;
    } BOOL CSuperSerialPort::WriteComm(pPACKAGE pPack)
    {
    DWORD wV;
        BOOL bl; bl = WriteFile(m_com.comHandle,
    pPack->pData,
    pPack->iLen,
    &wV, 
    &m_ovWriter);

    if (!bl)
    {
    if (GetLastError() == ERROR_IO_PENDING)
    {
    bl = GetOverlappedResult(m_com.comHandle,
    &m_ovWriter,
    &wV,
    TRUE);
    }
    }

    m_WriteCount += pPack->iLen; // 统计
    return bl;
    }//
    // StartReceive 函数
    //
    // 参数: LPVOID arg 传入对象,主要包含串口对象
    //
    // 返回值:  true 启动成功, false 启动失败
    //
    // 注意: 传入的参数必须包含串口对象, 否则不能接收数据
    //BOOL CSuperSerialPort::StartReceive(LPVOID arg)
    {
    m_errorCode = emET_SUCCEDED; if (NULL == arg)
    {
    m_errorCode = emET_NO_HANDLE;
    return false;
    } // 创建事件
    m_hEvent[emTHREAD_EXIT] = CreateEvent(NULL, TRUE, FALSE, NULL);
    m_hEvent[emTHREAD_RUN]  = CreateEvent(NULL, TRUE, TRUE, NULL);

    m_hReader               = CreateEvent(NULL, TRUE, FALSE, NULL);
    ZeroMemory(&m_ovReader, sizeof(m_ovReader));
    m_ovReader.hEvent       = m_hReader; m_hWriter               = CreateEvent(NULL, TRUE, FALSE, NULL);
    ZeroMemory(&m_ovWriter, sizeof(m_ovWriter));
    m_ovWriter.hEvent       = m_hWriter;

    m_hWait                 = CreateEvent(NULL, TRUE, FALSE, NULL);
    ZeroMemory(&m_ovWaitEvent, sizeof(m_ovWaitEvent));
    m_ovWaitEvent.hEvent    = m_hWait;


    int success = _beginthreadex(NULL,
                     0,
                     ReceiveThread,
                     arg,
                     0,
                     &m_threadId);
    if (success != 0)
    {
        return true;
    }
    else
    {
    return false;
    }
    }
    //////////////////////////////////////////////////////////////////////////
    // 类属性COMSTAT* CSuperSerialPort::GetComState()
    {
    return &m_comState;
    }HANDLE CSuperSerialPort::GetComHandle()
    {
    return m_com.comHandle; 
    }void CSuperSerialPort::SetInOutBuffer(DWORD inBuf, DWORD outBuf)
    {
    SetupComm(m_com.comHandle, inBuf, outBuf);
    }DWORD CSuperSerialPort::GetErrorCode()
    {
    return m_errorCode;
    }ULONG CSuperSerialPort::GetWritedBytes() const
    {
    return m_WriteCount;
    }ULONG CSuperSerialPort::GetReadedBytes() const
    {
    return m_ReadCount;
    }
    // 注意该函数
    const TCHAR* CSuperSerialPort::FormatErrorCodeToString(DWORD code)
    {
    switch(code)
    {
    case emET_SUCCEDED:
    sprintf(m_errorInfo, _T("操作成功!"));
    break; case emET_NO_OPEN:
    sprintf(m_errorInfo, _T("串口没打开"));
    break; case emET_NO_HANDLE:
    sprintf(m_errorInfo, _T("串口没有句柄"));
    break; case emET_OPENED:
    sprintf(m_errorInfo, _T("串口已经打开过"));
    break; case emET_COM_UNNAMED:
    sprintf(m_errorInfo, _T("串口没命名"));
    break;

    default:
    sprintf(m_errorInfo,
    _T("未定义的错误,请调用系统的GetLastError来查找"));
    break;
    } return m_errorInfo;
    }
      

  6.   

    参考一下SUDT SerialTrace吧,自己写应该要写驱动吧.我没做过,帮你顶!