-2

ここでの最終的な目標は、既存の C++ アプリケーションが仮想シリアル COM ポートを介して既存の C# アプリケーションと通信できるようにすることです。どちらも他の誰かが作成したものです。私はシリアル通信にあまり詳しくありません。先週かそこらで勉強してきましたが、まだ頭を悩ませていますが、それでも仕事がなくなるわけではないので、ここにいます。ご協力いただける場合は、ELI5 までご連絡ください。

これを達成するという私の使命の中で、私の最近のアイデアは、単に既知のメッセージを送信し、期待されるメッセージを受信するだけの C++ アプリケーションをゼロから作成することでした。ファイル ハンドルを作成する C++ アプリケーションを作成し、 と を使用して COM 経由でメッセージを正常に送信することができましCreateFile(...)WriteFile(...)。C# アプリケーションがメッセージを受信したことはわかっています。これは、受信したデータが正しく報告されているためです。ただし、C# アプリケーションから送り返されたデータが my によって受信されることはありませんReadFile(...)

次のステップは、メッセージを送信してリッスンするように C++ ミニアプリケーションをセットアップすることでした。これが機能することを発見したので、私の小さなアプリは COM 経由でメッセージを送受信できることがわかりました。しかし、C# アプリケーションは、どのバージョンの C++ アプリケーションにも届いたメッセージを送信できません。

C# アプリは FILE_FLAG_OVERLAPPED を使用しているのに対し、C++ アプリはすべて FILE_ATTRIBUTE_NORMAL を使用していると誰かが指摘しました。そこで、C++ アプリと C# アプリの一貫性を保つために、C++ アプリを微調整して FILE_FLAG_OVERLAPPED を使用するようにしました。ただし、これにより 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 をどのように使用しますか?
  • -また-
  • 1 つのアプリが重複して送信/受信していて、もう 1 つのアプリが重複していないことは問題ですか?
  • 実際に 3 番目の質問です。COM 通信が一方の方向では成功するのに、他方の方向では失敗する理由が他にありませんか?
4

1 に答える 1

1

ReadFile の戻り値をチェックしないのは間違いです。while (GetLastError() == ERROR_IO_PENDING) ループは間違いです。

オーバーラップされた読み取り方法の目的は、読み取りがドライバーで完了している間に、コードで何か他のことを実行できるようにすることです。他にやること (他の COM ポートの読み取りなど) がない場合は、重複した方法を使用する必要はありません。ライターがオーバーラップ書き込みを使用しているからといって、オーバーラップ読み取りを使用する理由はありません。両端は独立しています。

于 2015-02-20T02:05:24.967 に答える