zoukankan      html  css  js  c++  java
  • 串口.Qt532测试(同步)

    环境:Win7x64、Qt5.3.2 MSVC OpenGL(x86)、vs2010(x86)

    ZC:这里的例子是 同步的函数操作,貌似 如果子线程在等待 WaitCommEvent(...)或ReadFile(...) 返回的话(即 串口句柄正在被使用中),界面主线程执行 CloseHandle(...) 或 SetCommMask(...) 的话,就会卡在那里...    于是 考虑改用 异步方式

      ZC:想到 一个方式,使用同步方式的时候 可以使用 强制关闭线程的方式“TerminateThread(线程句柄, ExitCode);” 来关闭子线程,这样就不会再占用 串口句柄了,CloseHandle(..)也可以顺利执行。问题:TerminateThread(...) 会有一些 动态申请的资源释放,获取的锁释放 等的问题(具体看MSDN的说明,里面还提到了"heap lock",于是在 申请内存的过程中 如果强制结束线程的话 堆锁未释放 别的线程再申请内存的时候就卡在那里了...),还有 在 XP以及之前的Windws版本OS中 强制结束线程 OS不会释放 它的初始栈,造成内存泄漏(我看了一下 XP的资源管理器,确实是这样的现象)。

    1、ZC:

     1.1、开始时,遇到的问题:在接收信息的线程中,ReadFile(...) 每次都是 立即返回的  但是获取的数据都是0字节的长度,现象就好像是 用了 异步的方式 没等到事件 就立即返回了...

      找到问题:(1)、查看了 CreateFile(...)的参数,发现使用的就是 同步的方式(没有指定 参数 FILE_FLAG_OVERLAPPED)

           (2)、后来 发现是 COMMTIMEOUTS 设置的不正确的缘故

      测试下来,有2种方式 设置COMMTIMEOUTS,来 解决上面的问题:

        ①、类似如下的参数设置:

             COMMTIMEOUTS TimeOuts;
             //设定读超时
             TimeOuts.ReadIntervalTimeout = 100;
             TimeOuts.ReadTotalTimeoutMultiplier = 5000;
             TimeOuts.ReadTotalTimeoutConstant = 5000;
             //设定写超时
             TimeOuts.WriteTotalTimeoutMultiplier = 500;
             TimeOuts.WriteTotalTimeoutConstant = 2000;

        ②、这样设置:

             COMMTIMEOUTS CommTimeOuts;
             GetCommTimeouts(hCom1, &CommTimeOuts);
             CommTimeOuts.ReadIntervalTimeout  = MAXDWORD;
             CommTimeOuts.ReadTotalTimeoutMultiplier  = 0;
             CommTimeOuts.ReadTotalTimeoutConstant  = 0;
             CommTimeOuts.WriteTotalTimeoutMultiplier  = 10;
             CommTimeOuts.WriteTotalTimeoutConstant  = 1000;

          ZC:光是这样设置的话,就会出现上面的问题,ReadFile(...) 立即返回 0字节数据。接收线程 就会 连续不断的去ReadFile(...) ...

          ZC:这样设置的话,需要 使用 “SetCommMask(hCom1, EV_RXCHAR);” 和 “DWORD dwMask = EV_RXFLAG; WaitCommEvent(g_hCom, &dwMask, NULL);”,使用 它们 就是 声明和等待EV_RXCHAR事件(该事件 意思是 只要输入缓冲区接收到数据就会触发)

          

    2、测试代码:

      2,1、main.cpp

    #include "MainWindow.h"
    #include <QApplication>
    
    extern MainWindow* g_pMainWindow;
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        MainWindow w;
        w.show();
    
        g_pMainWindow = &w;
        a.installNativeEventFilter(&w);// 注意,不是“a.installEventFilter(w);”,少了 "Native"
    
        return a.exec();
    }

      2.2、MainWindow.h

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    #include <QAbstractNativeEventFilter>
    
    namespace Ui {
    class MainWindow;
    }
    
    class MainWindow : public QMainWindow, public QAbstractNativeEventFilter
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();
    
    public:
        virtual bool nativeEventFilter(const QByteArray &eventType, void *message, long *);
    
    private slots:
        void on_pbtnConn_clicked();
        void on_pbtnRecvMsgClear_clicked();
        void on_pbtnSendMsgClear_clicked();
        void on_pbrnSend_clicked();
    
    public:
        Ui::MainWindow *ui;
    };
    
    #endif // MAINWINDOW_H

      2.3、MainWindow.cpp

    #include "MainWindow.h"
    #include "ui_MainWindow.h"
    
    
    
    MainWindow* g_pMainWindow = NULL;
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        // https://blog.csdn.net/horizons_kong/article/details/54412339
        // https://blog.csdn.net/zmdsjtu/article/details/78539681
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    #include <QDebug>
    #include <windows.h>
    #include <stdio.h>
    #include <process.h>
    
    #include "thread_z.h"
    #include "PassInfo_z.h"
    #include "SeriesPort_z.h"
    
    QString TimeNowZ()
    {
        SYSTEMTIME sys;
        GetLocalTime( &sys );
    
        char buf[128] = {0};
        sprintf_s( buf, sizeof(buf), "%02d:%02d:%02d.%03d ", sys.wHour, sys.wMinute, sys.wSecond, sys.wMilliseconds );
    
        return QString::fromLocal8Bit(buf);
    }
    
    void ShowMsgZ(const QString& _str)
    {
        if (g_pMainWindow != NULL)
            g_pMainWindow->ui->teRecv->append(_str);
    }
    
    bool MainWindow::nativeEventFilter(const QByteArray &eventType, void *message, long *)
    {
        MSG* pMsg = reinterpret_cast<MSG*>(message);
        if(pMsg->message == WM_PASSINFO)
        {
            int iLen = pMsg->wParam;
            QString strInfo = Info_Recv(ShowMsgZ, iLen, (char*)pMsg->lParam);
            if (! strInfo.isNull())
                //ui->teRecv->append(TimeNowZ() + strInfo);
                ui->teRecv->append(strInfo);
            else
                ui->teRecv->append("
    ");
    
            return true;
        }
    
        return false;
    }
    
    void MainWindow::on_pbtnConn_clicked()
    {
        QString strChuanKouHao = ui->cbChuanKouHao->currentText();
        QString strBoTeLv = ui->cbBoTeLv->currentText();
        BYTE Parity = (BYTE)ui->cbJiaoYanWei->currentIndex();
        BYTE ShuJuWei = (BYTE)(ui->cbShuJuWei->currentIndex() + 4);
        BYTE TingZhiWei = ((BYTE)ui->cbTingZhiWei->currentIndex() + 2) * 0.5;
        bool bRtn = SPort_Init(ShowMsgZ, strChuanKouHao.toLocal8Bit().data(),
                               strBoTeLv.toULong(), Parity, ShuJuWei, TingZhiWei);
        if (! bRtn)
        {
            ui->pbtnConn->setChecked(false);
            return;
        }
    
        ShowMsgZ("After SPort_Init(...)");
        _beginthread(Thread_RECV, 0, (void*)this->winId());
        ShowMsgZ("After _beginthread(...)");
    }
    
    
    void MainWindow::on_pbtnRecvMsgClear_clicked()
    {
        ui->teRecv->clear();
        //_beginthread(Thread_RECV, 0, (void*)this->winId());
    }
    
    
    void MainWindow::on_pbtnSendMsgClear_clicked()
    {
        ui->teSend->clear();
    }
    
    void MainWindow::on_pbrnSend_clicked()
    {
    //    char pc[] = {128,129};
    //    if (IsDBCSLeadByte(pc[0]))
    //        qDebug() << "T";
    //    else
    //        qDebug() << "F";
    
        ui->teRecv->append("
    ");
    }

      2.4、PassInfo_z.h

    #ifndef PASSINFO_Z_H
    #define PASSINFO_Z_H
    
    #include <QString>
    
    #include <Windows.h>
    #define WM_PASSINFO     WM_USER+0x1000
    
    typedef void (__cdecl *TshowMsg)(const QString& _str);
    
    void Info_Send(HWND _hWnd, int _iLen, char* _pc);
    void Info_Send_pc(HWND _hWnd, char* _pc);
    QString Info_Recv(TshowMsg _funcShowMsg, int _iLen, char* _pc);
    
    #endif // PASSINFO_Z_H

      2.5、PassInfo_z.cpp

    #include "PassInfo_z.h"
    
    
    void Info_Send(HWND _hWnd, int _iLen, char* _pc)
    {
        if (_hWnd == 0)
            return;
    
        if (_iLen > 0)
        {
            char* pc = new char[_iLen];
            memcpy(&pc[0], _pc, _iLen);
    
            PostMessage( _hWnd, WM_PASSINFO, WPARAM(_iLen), LPARAM(pc) );
        }
        else
            PostMessage( _hWnd, WM_PASSINFO, WPARAM(_iLen), 0 );
    }
    
    void Info_Send_pc(HWND _hWnd, char* _pc)
    {
        Info_Send(_hWnd, strlen(_pc), _pc);
    }
    
    QString Info_Recv(TshowMsg _funcShowMsg, int _iLen, char* _pc)
    {
        // ZC: 进入到这个函数,前提是 "_iLen > 0"
        if (_iLen <= 0)
            return QString::null;
        return QString::fromLocal8Bit(_pc, _iLen);
    }
    
    
    // ZC: IsDBCSLeadByte( char ):BOOL; // ZC: 判断是否是 中文/韩文等字符的第1个字节
    //char g_infoRecv[1024 * 4] = {0};
    //int g_iInfoRecvCnt = 0;
    
    //QString Info_Recv(TshowMsg _funcShowMsg, int _iLen, char* _pc)
    //{
    //    // ZC: 进入到这个函数,前提是 "_iLen > 0"
    
    //    _funcShowMsg(QString::number(g_iInfoRecvCnt));
    
    //    if (g_iInfoRecvCnt > 0)
    //    {
    //        memcpy(&g_infoRecv[g_iInfoRecvCnt], _pc, _iLen);
    //        g_iInfoRecvCnt += _iLen;
    
    //        if (! IsDBCSLeadByte(_pc[_iLen - 1]) )// ZC: 判断是否是 中文/韩文等字符的第1个字节
    //        {
    //            QString str = QString::fromLocal8Bit(g_infoRecv, g_iInfoRecvCnt);
    //            g_iInfoRecvCnt = 0;
    //            return str;
    //        }
    //    }
    //    else
    //    {
    //        if ( IsDBCSLeadByte(_pc[_iLen - 1]) )
    //        {
    //            memcpy(&g_infoRecv[g_iInfoRecvCnt], _pc, _iLen);
    //            g_iInfoRecvCnt += _iLen;
    //        }
    //        else
    //            return QString::fromLocal8Bit(_pc, _iLen);
    //    }
    //    return QString::null;
    //}

      2.6、SeriesPort_z.h

    #ifndef SERIESPORT_Z_H
    #define SERIESPORT_Z_H
    
    #include <Windows.h>
    #include <QString>
    
    extern HANDLE g_hCom;
    
    #define SERIES_PORT__IN_QUEUE_SIZE  1024 * 16
    #define SERIES_PORT__OUT_QUEUE_SIZE 1024 * 16
    
    typedef void (__cdecl *TshowMsg)(const QString& _str);
    
    bool SPort_Init(TshowMsg _funcShowMsg,
                    char* _pcSeriesPortName, DWORD _BaudRate, BYTE _Parity, BYTE _ByteSize, BYTE _StopBits);
    
    #endif // SERIESPORT_Z_H

      2.7、SeriesPort_z.cpp

    #include "SeriesPort_z.h"
    
    #include <QDebug>
    #include <QTextCodec>
    
    #include "PassInfo_z.h"
    
    //HWND g_hWnd = 0;
    HANDLE g_hCom = 0;
    
    bool SPort_Init(TshowMsg _funcShowMsg,
                    char* _pcSeriesPortName,
                    DWORD _BaudRate, BYTE _Parity, BYTE _ByteSize, BYTE _StopBits)
    {
        g_hCom = 0;
    
        WCHAR wszSeriesPortName[8] = {0};
        MultiByteToWideChar(CP_ACP, 0, _pcSeriesPortName, strlen(_pcSeriesPortName) + 1,
                            wszSeriesPortName, sizeof(wszSeriesPortName) / sizeof(wszSeriesPortName[0]));
        HANDLE hCom1 = CreateFile(wszSeriesPortName,//COM1口
                                  GENERIC_READ | GENERIC_WRITE, //允许读和写
                                  0, //独占方式
                                  NULL,
                                  OPEN_EXISTING, //打开而不是创建
                                  0, //同步方式
                                  NULL);
        if (hCom1 == INVALID_HANDLE_VALUE)
        {
            QTextCodec *pCodec = QTextCodec::codecForName("GBK");
            QString strPrint = pCodec->toUnicode("打开COM失败 !");
            _funcShowMsg(strPrint);
            return false;
        }
        else
        {
            QTextCodec *pCodec = QTextCodec::codecForName("GBK");
            QString strPrint = pCodec->toUnicode("COM打开成功 !");
            _funcShowMsg(strPrint);
        }
    
                            //    SetupComm(hCom1, SERIES_PORT__IN_QUEUE_SIZE, SERIES_PORT__OUT_QUEUE_SIZE); //输入缓冲区和输出缓冲区的大小都是1024
    
                            //    COMMTIMEOUTS TimeOuts;
                            //    //设定读超时
                            //    TimeOuts.ReadIntervalTimeout = 100;
                            //    TimeOuts.ReadTotalTimeoutMultiplier = 5000;
                            //    TimeOuts.ReadTotalTimeoutConstant = 5000;
                            //    //设定写超时
                            //    TimeOuts.WriteTotalTimeoutMultiplier = 500;
                            //    TimeOuts.WriteTotalTimeoutConstant = 2000;
                            //    if (! SetCommTimeouts(hCom1, &TimeOuts)) //设置超时
                            //    {
                            //        int iErr = ::GetLastError();
                            //        QTextCodec *pCodec = QTextCodec::codecForName("GBK");
                            //        QString strPrint = pCodec->toUnicode("设置串口读写超时时间失败");
                            //        strPrint += ", last error code is "+QString::number(iErr);
                            //        _funcShowMsg(strPrint);
                            //        return false;
                            //    }
    
                            //    DCB dcb;
                            //    GetCommState(hCom1, &dcb);
                            //    dcb.BaudRate = _BaudRate;//9600; //波特率为9600
                            //    dcb.ByteSize = _ByteSize;//8; //每个字节有8位
                            //    dcb.Parity = _Parity;//NOPARITY; //无奇偶校验位
                            //    dcb.StopBits = _StopBits;//ONESTOPBIT; //1个停止位
                            //    if (! SetCommState(hCom1, &dcb))
                            //    {
                            //        int iErr = ::GetLastError();
                            //        QTextCodec *pCodec = QTextCodec::codecForName("GBK");
                            //        QString strPrint = pCodec->toUnicode("设置串口参数失败");
                            //        strPrint += ", last error code is "+QString::number(iErr);
                            //        _funcShowMsg(strPrint);
                            //        return false;
                            //    }
    
        _funcShowMsg( QString::number(_BaudRate)+","+QString::number(_ByteSize)
                      +","+QString::number(_Parity)+","+QString::number(_StopBits) );
    
        DCB dcb;
        if (! GetCommState(hCom1, &dcb))
        {
            int iErr = ::GetLastError();
            QTextCodec *pCodec = QTextCodec::codecForName("GBK");
            QString strPrint = pCodec->toUnicode("获取串口当前属性参数失败");
            strPrint += ", last error code is "+QString::number(iErr);
            _funcShowMsg(strPrint);
            return false;
        }
        //配置串口参数
        dcb.BaudRate  = _BaudRate;    //波特率
        dcb.fBinary  = TRUE;    //二进制模式。必须为TRUE
        dcb.ByteSize  = _ByteSize;    //数据位。范围4-8
        dcb.StopBits  = _StopBits;    //停止位
        if (_Parity  == NOPARITY)
        {
            dcb.fParity  = FALSE;    //奇偶校验。无奇偶校验
            dcb.Parity  = _Parity;    //校验模式。无奇偶校验
        }
        else
        {
            dcb.fParity  = TRUE;        //奇偶校验。
            dcb.Parity  = _Parity;    //校验模式。无奇偶校验
        }
        dcb.fOutxCtsFlow  = FALSE;    //CTS线上的硬件握手
        dcb.fOutxDsrFlow  = FALSE;    //DST线上的硬件握手
        dcb.fDtrControl  = DTR_CONTROL_ENABLE;//DTR控制
        dcb.fDsrSensitivity  = FALSE;
        dcb.fTXContinueOnXoff  = FALSE;//
        dcb.fOutX  = FALSE;            //是否使用XON/XOFF协议
        dcb.fInX  = FALSE;            //是否使用XON/XOFF协议
        dcb.fErrorChar  = FALSE;        //是否使用发送错误协议
        dcb.fNull  = FALSE;            //停用null stripping
        dcb.fRtsControl  = RTS_CONTROL_ENABLE;//
        dcb.fAbortOnError  = FALSE;    //串口发送错误,并不终止串口读写
        //设置串口参数
        if (! SetCommState(hCom1, &dcb))
        {
            int iErr = ::GetLastError();
            QTextCodec *pCodec = QTextCodec::codecForName("GBK");
            QString strPrint = pCodec->toUnicode("设置串口参数失败");
            strPrint += ", last error code is "+QString::number(iErr);
            _funcShowMsg(strPrint);
            return false;
        }
    
        //设置串口事件
        SetCommMask(hCom1, EV_RXCHAR);//在缓存中有字符时产生事件
    
        SetupComm(hCom1, SERIES_PORT__IN_QUEUE_SIZE, SERIES_PORT__OUT_QUEUE_SIZE);
    
        //设置串口读写时间
        COMMTIMEOUTS CommTimeOuts;
        GetCommTimeouts(hCom1, &CommTimeOuts);
        CommTimeOuts.ReadIntervalTimeout  = MAXDWORD;
        CommTimeOuts.ReadTotalTimeoutMultiplier  = 0;
        CommTimeOuts.ReadTotalTimeoutConstant  = 0;
        CommTimeOuts.WriteTotalTimeoutMultiplier  = 10;
        CommTimeOuts.WriteTotalTimeoutConstant  = 1000;
        if (!SetCommTimeouts(hCom1, &CommTimeOuts))
        {
            int iErr = ::GetLastError();
            QTextCodec *pCodec = QTextCodec::codecForName("GBK");
            QString strPrint = pCodec->toUnicode("设置串口读写超时时间失败");
            strPrint += ", last error code is "+QString::number(iErr);
            _funcShowMsg(strPrint);
            return false;
        }
    
        g_hCom = hCom1;
        return true;
    }
    
    bool SendData(TshowMsg _funcShowMsg, HANDLE _hComm, char* data, int len)
    {
        if (_hComm == INVALID_HANDLE_VALUE)
        {
            QTextCodec *pCodec = QTextCodec::codecForName("GBK");
            QString strPrint = pCodec->toUnicode("串口未打开");
            _funcShowMsg(strPrint);
            return false;
        }
        //清空串口
        PurgeComm(_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR);
        //写串口
        DWORD dwWrite  = 0;
        DWORD dwRet  = WriteFile(_hComm, data, len, &dwWrite, NULL);
        int iErr = 0;
        if (! dwRet) { iErr = ::GetLastError(); }
        //清空串口
        PurgeComm(_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR);
        if (! dwRet)
        {
            QTextCodec *pCodec = QTextCodec::codecForName("GBK");
            QString strPrint = pCodec->toUnicode("发送数据失败");
            strPrint += ", last error code is "+QString::number(iErr);
            _funcShowMsg(strPrint);
            return false;
        }
        return true;
    }

      2.8、thread_z.h

    #ifndef THREAD_Z_H
    #define THREAD_Z_H
    
    void Thread_RECV(void *_ArgList);
    
    #endif // THREAD_Z_H

      2.9、thread_z.cpp

    #include "thread_z.h"
    
    #include <QDebug>
    
    #include <Windows.h>
    #include <process.h>
    
    #include "PassInfo_z.h"
    #include "SeriesPort_z.h"
    
    int g_iIdx = 0;
    bool MsgHandler01(HWND _hWnd, DWORD _dwRecv, char* _pc);
    
    void Thread_RECV(void *_ArgList)
    {
    //    ::MessageBoxA(0, "Thread_RECV(...) in ", "", 0);
    
        HWND hWnd = (HWND)_ArgList;
        if (hWnd == 0)
        {
            qDebug() << "Thread_RECV(...) - hWnd is NULL .";
            _endthread();
            return;
        }
        if (g_hCom == 0)
        {
            Info_Send_pc(hWnd, "Thread_RECV(...) - g_hCom is 0 .");
            _endthread();
            return;
        }
    
        Info_Send_pc(hWnd, "Thread_RECV(...) in");
        qDebug() << "Thread_RECV(...) in";
    
        //清空串口
        PurgeComm(g_hCom, PURGE_RXCLEAR | PURGE_TXCLEAR);
    
        char buf[SERIES_PORT__OUT_QUEUE_SIZE] = {0};
        char bufErr[256] = {0};
        while (true)
        {
    //        g_iIdx ++;
    //        if (g_iIdx > 10)
    //            break;
    
            BOOL bRtn = false;
    
            DWORD dwMask = EV_RXFLAG;//EV_RXCHAR;
            bRtn = WaitCommEvent(g_hCom, &dwMask, NULL);
            if (! bRtn)
            {
                int iErr = ::GetLastError();
                sprintf_s(bufErr, sizeof(bufErr), "WaitCommEvent(...) return false, last error code is %d .", iErr);
                Info_Send_pc(hWnd, bufErr);
                break;
            }
    
            DWORD dwRead;
            bRtn = ReadFile(g_hCom, &buf[0], SERIES_PORT__OUT_QUEUE_SIZE, &dwRead, NULL);
    //                {
    //                    char msg[128] = {0};
    //                    sprintf_s(msg, sizeof(msg), "%d - %d", g_iIdx, dwRead);
    //                    Info_Send_pc(hWnd, msg);
    //                }
            if (! bRtn)
            {
                int iErr = ::GetLastError();
                sprintf_s(bufErr, sizeof(bufErr), "ReadFile(...) return false, last error code is %d .", iErr);
                Info_Send_pc(hWnd, bufErr);
                break;
            }
    
            if (dwRead > 0)
                if (! MsgHandler01(hWnd, dwRead, buf))
                    break;
        }
    
        Info_Send_pc(hWnd, "Thread_RECV(...) out");
        qDebug() << "Thread_RECV(...) out";
    
        /* _endthread given to terminate */
        _endthread();
    }
    
    // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
    
    char g_infoRecv[1024 * 4] = {0};
    DWORD g_dwInfoRecvCnt = 0;
    
    bool MsgHandler01(HWND _hWnd, DWORD _dwRecv, char* _pc)
    {
        //char buf1[64] = {0};
    
    
        memcpy(&g_infoRecv[g_dwInfoRecvCnt], _pc, _dwRecv);
        g_dwInfoRecvCnt += _dwRecv;
    
        //Info_Send_pc(_hWnd, "11");
        void* p = memchr(&g_infoRecv[0], '
    ', g_dwInfoRecvCnt);
        if (p != NULL)
        {
            //Info_Send_pc(_hWnd, "12");
            DWORD dwBegin = (DWORD)( &g_infoRecv[0] );
            DWORD dwPos = (DWORD)p;
            int iLen = dwPos - dwBegin - 1;// 
     为占2个字节位置,需要将它们占的位置去掉
            //Info_Send_pc(_hWnd, "13");
            if (iLen < 0)
            {
                char bufErr[64] = {0};
                sprintf_s(bufErr, sizeof(bufErr), "MsgHandler01(...) - (dwLen < 0) : %d", iLen);
                Info_Send_pc(_hWnd, bufErr);
                return false;
            }
    
            //sprintf_s(buf1, sizeof(buf1), "14 : %d, %d, %d, %d", iLen, g_dwInfoRecvCnt, dwBegin, dwPos);
            //Info_Send_pc(_hWnd, buf1);
            Info_Send(_hWnd, iLen, &g_infoRecv[0]);
            //Info_Send_pc(_hWnd, "15");
            memcpy( &g_infoRecv[0], &g_infoRecv[iLen + 2], g_dwInfoRecvCnt - (iLen+2) );
            //Info_Send_pc(_hWnd, "16");
            g_dwInfoRecvCnt -= (iLen+2);
            //Info_Send_pc(_hWnd, "17");
        }
        return true;
    }

    3、

    4、

    5、

  • 相关阅读:
    WCF 第四章 绑定 在多个绑定上暴露一个服务契约
    WCF 第五章 行为 事务跨操作事务流
    WCF 第五章 导出并发布元数据(服务行为)
    WCF 第五章 行为 通过配置文件暴露一个服务行为
    WCF 第五章 不支持会话的绑定的默认并发和实例
    WCF 第五章 并发和实例(服务行为)
    WCF 第五章 行为 总结
    WCF 第四章 绑定 绑定元素
    WCF 第五章 行为 事务之选择一个事务协议OleTx 或者WSAT
    WCF 第四章 绑定 比较各种绑定的性能和可扩展性
  • 原文地址:https://www.cnblogs.com/cppskill/p/9723688.html
Copyright © 2011-2022 走看看