Which ReadFile parameter in this code is incorrect

2019-09-10 11:37发布

问题:

(Edit: I didn't exclude any code except the headers and the main() function's brackets. Nothing is written between lines of code listed here.)

.

I used the ReadFile function to read this COM3 port (which returned no INVALID_HANDLE_VALUE or ERROR_FILE_NOT_FOUND):

LPCTSTR portName = "COM3" ;

HANDLE hSerial;
hSerial = CreateFile(portName,
                     GENERIC_READ | GENERIC_WRITE,
                     0,    // exclusive access
                     NULL, // default security attributes
                     OPEN_EXISTING,
                     FILE_FLAG_OVERLAPPED,
                     NULL);

And the ReadFile function in question uses following parameters:

DWORD n = 512 ;
char szBuff[n] = {0};
DWORD dwBytesRead = 0;

if(!ReadFile(hSerial, szBuff, n, &dwBytesRead, NULL))
{
    cout << "ReadFile error. Error code: " << GetLastError() << endl ;
    cin.get() ;
    return 0 ;
}

What changes should I introduce to cause the read to succeed?

(I searched through the function's documentation and other StackOverflow questions, tested lots of things, but couldn't find an answer.)

回答1:

In ReadFile documentation you can read:

lpOverlapped [in, out, optional] A pointer to an OVERLAPPED structure is required if the hFile parameter was opened with FILE_FLAG_OVERLAPPED, otherwise it can be NULL.

so since you specified FILE_FLAG_OVERLAPPED in CreateFile you should provide OVERLAPPED in ReadFile.

In CreateFile you can read on parameters for Communications Resources:

... and the handle can be opened for overlapped I/O.

so you can skip FILE_FLAG_OVERLAPPED in CreateFile



回答2:

Marcin Jędrzejewski's answer is correct about the mismatch between the overlapped IO Flag and the ReadFile function, but I will leave this up just to be helpful.
You are missing a lot of initialisation which may be helpful to you when operating a COM port.

This code is used to open, configure, and read from a COM port on windows using C++.

FOR REFERENCE

READ_BUFFER_SIZE = 1024;
WRITE_BUFFER_SIZE = 1024;
COM_READ_BUFFER_SIZE = 1024;
COM_WRITE_BUFFER_SIZE = 1024;
READ_TIMEOUT = 50;
WRITE_TIMEOUT = 100;

port = "\\.\COM6"
portFormat = "9600,N,8,1" /* for information on this, google the MODE command for windows. */

HANDLE hComPort;
DCB dcbComConfig;

OPENING COM PORT

DWORD dwStoredFlags = EV_BREAK | EV_ERR | EV_RXCHAR;
COMMTIMEOUTS timeouts;

FillMemory(&dcbComConfig, sizeof(dcbComConfig), 0);
dcbComConfig.DCBlength = sizeof(dcbComConfig);

/* assign a COM format to the COM Port. */
if(!BuildCommDCB(portFormat, &dcbComConfig))
{
    printf("Failed to build comm format data %s\n", portFormat);
}

/* Open the COM port with overlapped IO. */
hComPort = CreateFile(port, GENERIC_READ | GENERIC_WRITE, 0, 0, 
                OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);

if (hComPort == INVALID_HANDLE_VALUE)
{
    printf("Error opening port %s\n", port);
}

/* Set the COM Ports internal Read and Write buffer sizes. */
if(!SetupComm(hComPort, COM_READ_BUFFER_SIZE, COM_WRITE_BUFFER_SIZE))
{
    printf("Could not set COM buffers\n");
}

/* assign the previously created COM Format to the COM Port. */
if(!SetCommState(hComPort, &dcbComConfig))
{
    printf("Error setting com to format data.\n");
}

/* Mask what events you want to look for in the COM Port. */
if (!SetCommMask(hComPort, dwStoredFlags))
{
    printf("Error setting communications mask\n");
}

/*-- Read Timeouts set like this so we can use the event based reading. --*/
timeouts.ReadIntervalTimeout = MAXDWORD; 
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.ReadTotalTimeoutConstant = 0;
timeouts.WriteTotalTimeoutMultiplier = 10;
timeouts.WriteTotalTimeoutConstant = 100;

if (!SetCommTimeouts(hComPort, &timeouts))
{
    printf("Error setting time-outs.\n");
}

READING COM PORT

DWORD dwRead = 0;
DWORD dwComEvent = EV_RXCHAR;
DWORD lpErrors = 0;
char readBuffer[READ_BUFFER_SIZE];

/* Create the Overlapped IO Read Event. */
OVERLAPPED osRead = {0};
osRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

/* Used to monitor the COM Port State. */
COMSTAT ComStatus;

/* Loop at 20Hz to read the COM Port until a Kill event has been set. */
while(WaitForSingleObject(hKillEvent, 50) == WAIT_TIMEOUT)
{
    /* Wait for a COM Event to occur ( Read Event in this Case ). */
    if (WaitCommEvent(hComPort, &dwComEvent , NULL))
    {
        /* If the COM Port had an error Clear it. */
        ClearCommError(hComPort, &lpErrors, &ComStatus);
        /*-- Reset read operation's OVERLAPPED structure's hEvent --*/
        ResetEvent(osRead.hEvent);

        if (ReadFile(hComPort, readBuffer, ComStatus.cbInQue, &dwRead, &osRead))
        {
            /*-- bytes have been read; process it --*/
            USE_DATA(readBuffer, dwRead);
        }
        else
        {
            /*-- An error occurred in the ReadFile call --*/
            printf("ReadFile encountered an error.\n");
            break;
        }
    }
    else 
    {
        /*-- Error in WaitCommEvent --*/
        printf("WaitCommEvent encountered an error.\n");
        break;
    }
}

/* Close the Overlapped IO Read Event. */
CloseHandle(osRead.hEvent);


回答3:

The top answer is correct. In this case, opening with FILE_FLAG_OVERLAPPED, ReadFile expects an OVERLAPPED structure as last argument.

Would like to add that you can also get 'parameter is incorrect' error if you do supply an OVERLAPPED struct, but forget to ZeroMemory it.

From the documentation:

Any unused members of this structure should always be initialized to zero before the structure is used in a function call. Otherwise, the function may fail and return ERROR_INVALID_PARAMETER.

So don't forget to:

OVERLAPPED ovl;
ZeroMemory(&ovl, sizeof(ovl));
...
ReadFile(hSerial, szBuff, n, &dwBytesRead, &ovl);