-2

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

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

我的下一步是设置我的 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;
}

发件人将报告它按预期发送了消息。听者只是无限地重复'io pending'。

因此,任何一个问题的答案都会有所帮助:

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

1 回答 1

1

您没有检查 ReadFile 的返回值是一个错误。您的 while (GetLastError() == ERROR_IO_PENDING) 循环是一个错误。

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

于 2015-02-20T02:05:24.967 回答