简体   繁体   中英

Configuring serial port with Windows API: CreateFile failed with error 2 (ERROR_FILE_NOT_FOUND)

I'm trying to create a C++ program to communicate with a serial port device using Windows API in Visual Studio Community 2017 on Windows 7. Running this example from MSDN with one change - using this:

const wchar_t *pcCommPort = TEXT("\\.\COM16"); //  Most systems have a COM1 port

instead of this (otherwise it wouldn't compile):

TCHAR *pcCommPort = TEXT("COM1"); //  Most systems have a COM1 port

I get a CreateFile error 2 (ERROR_FILE_NOT_FOUND). I'm quite clueless what's going wrong here.

Here's the code:

#include "stdafx.h"

void PrintCommState(DCB dcb)
{
    //  Print some of the DCB structure values
    _tprintf(TEXT("\nBaudRate = %d, ByteSize = %d, Parity = %d, StopBits = %d\n"),
        dcb.BaudRate,
        dcb.ByteSize,
        dcb.Parity,
        dcb.StopBits);
}


int _tmain(int argc, TCHAR *argv[])
{
    DCB dcb;
    HANDLE hCom;
    BOOL fSuccess;
    const wchar_t *pcCommPort = TEXT("\\.\COM16"); //  Most systems have a COM1 port

                                      //  Open a handle to the specified com port.
    hCom = CreateFile(pcCommPort,
        GENERIC_READ | GENERIC_WRITE,
        0,      //  must be opened with exclusive-access
        NULL,   //  default security attributes
        OPEN_EXISTING, //  must use OPEN_EXISTING
        0,      //  not overlapped I/O
        NULL); //  hTemplate must be NULL for comm devices

    if (hCom == INVALID_HANDLE_VALUE)
    {
        //  Handle the error.
        printf("CreateFile failed with error %d.\n", GetLastError());
        system("PAUSE");
        return (1);
    }

    //  Initialize the DCB structure.
    SecureZeroMemory(&dcb, sizeof(DCB));
    dcb.DCBlength = sizeof(DCB);

    //  Build on the current configuration by first retrieving all current
    //  settings.
    fSuccess = GetCommState(hCom, &dcb);

    if (!fSuccess)
    {
        //  Handle the error.
        printf("GetCommState failed with error %d.\n", GetLastError());
        return (2);
    }

    PrintCommState(dcb);       //  Output to console

                               //  Fill in some DCB values and set the com state: 
                               //  57,600 bps, 8 data bits, no parity, and 1 stop bit.
    dcb.BaudRate = CBR_9600;     //  baud rate
    dcb.ByteSize = 8;             //  data size, xmit and rcv
    dcb.Parity = NOPARITY;      //  parity bit
    dcb.StopBits = ONESTOPBIT;    //  stop bit

    fSuccess = SetCommState(hCom, &dcb);

    if (!fSuccess)
    {
        //  Handle the error.
        printf("SetCommState failed with error %d.\n", GetLastError());
        return (3);
    }

    //  Get the comm config again.
    fSuccess = GetCommState(hCom, &dcb);

    if (!fSuccess)
    {
        //  Handle the error.
        printf("GetCommState failed with error %d.\n", GetLastError());
        return (2);
    }

    PrintCommState(dcb);       //  Output to console

    _tprintf(TEXT("Serial port %s successfully reconfigured.\n"), pcCommPort);
    return (0);
}

There are two different defines that control the ANSI/Unicode character stuff:

#define UNICODE controls the Windows SDK API ( LPTSTR and TEXT )

#define _UNICODE controls the C Run Time ( TCHAR , _TEXT and _T )

You normally define none or both and if you don't you have to use the correct combinations:

const TCHAR* cstr = _T("Hello");
LPCTSTR winstr = TEXT("World");

The other issue with your code is that you are using TCHAR* and not const TCHAR* . Depending on your compiler version and switches, literal strings might be located in the read-only data section of the binary so make sure the type is a pointer to a constant string.

If you are still unsure of the sizes you can do this:

LPCTSTR x;
printf("TEXT=%d LPCTSTR=%d _T=%d TCHAR=%d\n", sizeof(TEXT("")), sizeof(*x), sizeof(_T("")), sizeof(TCHAR));

I just tested on a virtual machine with a COM port and the plain name works just fine:

LPCTSTR pcCommPort = TEXT("COM1"); 
HANDLE hCom = CreateFile(pcCommPort,
        GENERIC_READ | GENERIC_WRITE,
        0,      //  must be opened with exclusive-access
        NULL,   //  default security attributes
        OPEN_EXISTING, //  must use OPEN_EXISTING
        0,      //  not overlapped I/O
        NULL); //  hTemplate must be NULL for comm devices

If you want to use a COM port above 9 you have to use the Win32 device path syntax:

LPCTSTR pcCommPortWin32DevicePath = TEXT("\\\\.\\COM16"); 
HANDLE hCom = CreateFile(pcCommPortWin32DevicePath, ...);

(MSDN describes the string as it should look in memory, not in your code. Your clue to this is the single slash in the example string. This means you must double all backslashes to get a correct C literal string.)

您需要转义字符串文字中的反斜杠,例如

const TCHAR *pcCommPort = TEXT("\\\\.\\COM16");

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM