COM端口通信永远与Win32上的FILE_FLAG_OVERLAPPED挂起

时间:2015-02-20 00:40:57

标签: c# c++ serial-port serial-communication overlapped-io

这里的最终目标是让现有的C ++应用程序通过虚拟串行COM端口与现有的C#应用​​程序进行通信,这两个应用程序都是其他人编写的。我对串行通信不是很熟悉,我在上周左右一直在研究它并且它仍然在我脑海中,但这并没有使任务消失,所以我在这里。如果您能提供帮助,请记得ELI5。

在完成此任务的任务中,我最近的想法是从头开始编写一个C ++应用程序,它只是发送一条已知消息并收到一条预期的消息作为回报。我能够编写一个创建文件句柄的C ++应用程序,并使用CreateFile(...)WriteFile(...)通过COM成功发送了一条消息。我知道C#应用程序收到了消息,因为它报告了正确接收的数据。但是,我的ReadFile(...)永远不会收到从C#应用程序发回的数据。

我的下一步是设置我的C ++迷你应用程序来发送和收听消息。我发现这很有效,所以我知道我的小应用程序可以通过COM发送和接收消息。但是C#应用程序无法发送到任何版本的C ++应用程序的消息。

其他人向我指出C#应用程序使用FILE_FLAG_OVERLAPPED,而C ++应用程序都使用FILE_ATTRIBUTE_NORMAL。所以我开始尝试调整我的C ++应用程序以使用FILE_FLAG_OVERLAPPED,以便C ++和C#应用程序保持一致。但是,这导致我的C ++应用程序失败,我无法弄清楚原因。被困在它上足够长的时间来寻求帮助。这是我的代码失败,错误997:ERROR_IO_PENDING,似乎永远不会收到消息(重叠)。

// ComTest.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <cstdlib>
#include <iostream>
#include <Windows.h>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    cout << "hello, world" << endl;

    HANDLE SerialHandle;

    bool listener;
    if (argc > 1) listener = true;
    else listener = false;

    if(listener) {
        SerialHandle = CreateFile(L"COM7", GENERIC_READ | GENERIC_WRITE, 
            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0,
            OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, 0);
    } else {
        SerialHandle = CreateFile(L"COM6", GENERIC_READ | GENERIC_WRITE, 
            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0,
            OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, 0);
    }
    OVERLAPPED overlapped_structure;
    memset(&overlapped_structure, 0, sizeof(overlapped_structure));
    overlapped_structure.Offset = 0;
    overlapped_structure.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);

    if( SerialHandle == INVALID_HANDLE_VALUE ) {
        if( GetLastError() == ERROR_FILE_NOT_FOUND ) {
            cout << "Serial Port 1 does not exist." << endl;
            return 1;
        }
        cout << "Invalid Handle Value due to error: " << GetLastError() << endl;
        return 2;
    }
    else {
        cout << "Successfully opened the file handle." << endl;
    }

    DCB dcbSerialParams = {0};

    dcbSerialParams.DCBlength = sizeof(dcbSerialParams);

    if (!GetCommState(SerialHandle, &dcbSerialParams)) {
        cout << "Error retrieving comm state." << endl;
        return 3;
    }
    else {
        cout << "Retrieved comm state." << endl;
    }

    dcbSerialParams.BaudRate = CBR_19200;
    dcbSerialParams.ByteSize = 8;
    dcbSerialParams.StopBits = ONESTOPBIT;
    dcbSerialParams.Parity = NOPARITY;

    if (!SetCommState(SerialHandle, &dcbSerialParams)) {
        cout << "Error setting comm state." << endl;
        return 4;
    }
    else {
        cout << "Comm state set." << endl;
    }

    cout << "Setting up timeouts . . . " << endl;

    COMMTIMEOUTS timeouts = {0};

    timeouts.ReadIntervalTimeout = 1000;
    timeouts.ReadTotalTimeoutConstant = 1000;
    timeouts.ReadTotalTimeoutMultiplier = 10;
    timeouts.WriteTotalTimeoutConstant = 1000;
    timeouts.WriteTotalTimeoutMultiplier = 10;

    if (!SetCommTimeouts(SerialHandle, &timeouts)) {
        cout << "Error setting up comm timeouts." << endl;
        return 5;
    }
    else {
        cout << "Comm timeouts set up." << endl;
    }

    typedef unsigned char UInt8;
    UInt8 InputBuffer[2000] = {0};
    UInt8 val = 130;
    UInt8 * intBuffer = &val;
    DWORD BytesRead = 0;

    if (listener) {
        cout << "Trying to read in listen mode" << endl;
        ReadFile(SerialHandle, InputBuffer, 2000, &BytesRead, &overlapped_structure);
        while (GetLastError() == ERROR_IO_PENDING){
            cout << "error: io still pending" << endl;
        }
    }
    else {  // if sender
        if (!WriteFile(SerialHandle, intBuffer, 9, NULL, &overlapped_structure)) {
            cout << "Error writing content." << endl;
        }
        else {
            cout << "Wrote content: " << (int)(*intBuffer) << endl;
        }
    }

    CloseHandle(SerialHandle);

    return 0;
}

发件人将按预期报告其发送邮件。听众只是重复“等待”。无限永远。

所以对这两个问题的回答都会有所帮助:

  • 为什么我的代码失败了?你如何使用FILE_FLAG_OVERLAPPED?
  • -OR -
  • 是否一个应用程序发送/接收重叠,另一个不是?
  • 实际上是第三个问题,为什么COM通信在一个方向上会成功但在另一个方向上失败的任何其他想法?

1 个答案:

答案 0 :(得分:1)

您未能检查ReadFile的返回值是错误的。你的while(GetLastError()== ERROR_IO_PENDING)循环是错误的。

重叠读取方法的目的是让您的代码在驱动程序中完成读取时执行其他操作。如果您没有其他事情要做(例如读取其他COM端口),则不要费心使用重叠方法。没有理由因为编写器使用重叠写入而使用重叠读取:两端是独立的。