ここでの最終的な目標は、既存の 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 通信が一方の方向では成功するのに、他方の方向では失敗する理由が他にありませんか?