Конечная цель здесь — получить существующее приложение C ++ для связи через виртуальный последовательный COM-порт с существующим приложением C #, которое написал кто-то другой. Я не очень знаком с последовательными коммуникациями, я изучал их на прошлой неделе или около того, и это все еще далеко над моей головой, но это не делает задачу уйти, так что вот и я. Если вы можете помочь, пожалуйста, не забудьте ELI5.
В моей миссии по достижению этой цели моей последней идеей было написать приложение на C ++ с нуля, которое просто отправляло известное сообщение и получало ожидаемое сообщение взамен. Мне удалось написать приложение на C ++, которое создало дескриптор файла и успешно отправило сообщение через COM, используя CreateFile(...)
а также WriteFile(...)
, Я знаю, что приложение C # получило сообщение, потому что оно сообщает о полученных данных правильно. Тем не менее, данные, отправляемые обратно из приложения 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;
}
Отправитель сообщит, что отправляет сообщение, как и ожидалось. Слушатель просто бесконечно повторяет «в ожидании».
Так что ответ на любой вопрос будет полезен:
Ваша ошибка проверить возвращаемое значение ReadFile является ошибкой. Ваш цикл while (GetLastError () == ERROR_IO_PENDING) является ошибкой.
Цель перекрывающегося метода чтения — позволить вашему коду делать что-то еще, пока чтение завершается в драйвере. Если вам нечем заняться (например, читать другие COM-порты), не пытайтесь использовать перекрывающийся метод. Нет смысла использовать перекрывающееся чтение только потому, что писатель использует перекрывающиеся записи: два конца независимы.