Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
579 views
in Technique[技术] by (71.8m points)

c - What is the difference between CreateFile() and CreateFileA()?

I am following the tutorial here to communicate with the serial port

The main code to open and then close the serial port is as follows:

HANDLE hComm;

hComm = CreateFileA((LPCSTR)"COM8",                //port name
    GENERIC_READ | GENERIC_WRITE, //Read/Write
    0,                            // No Sharing
    NULL,                         // No Security
    OPEN_EXISTING,// Open existing port only
    0,               // Non Overlapped I/O              // FILE_FLAG_NO_BUFFERING,            // copied from the MFC version
    NULL);        // Null for Comm Devices

if (hComm == INVALID_HANDLE_VALUE){
    DWORD err = GetLastError();
    printf("Error in opening serial port
");
    printf("err = 0x%x
", err);
}
else
    printf("opening serial port successful
");

CloseHandle(hComm);//Closing the Serial Port

If I use CreateFile() the code compiles fine but the serial port is not opened (I get the Error in opening serial port message)

After playing around with the code for a while, I found that CreateFileA() opens the serial port successfully (and the only reason I even found this was because when I googled for CreateFile() function I was given the MSDN definition page for CreateFileA() as the first result

I googled around but I couldn't find what the difference between the two is. I found this, which says I should always CreateFile() and the compiler should do the rest, but it didn't work in my case and only works when I specifically use CreateFileA()

What is the difference between CreateFile() and CreateFileA(), and which one should I be using in my program for a basic serial port communication?

Windows 10
Visual Studio 2013 express

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Some explanation on the windows API is needed here: Microsoft was very early introducing Unicode. Back then, they decided to represent a Unicode character in 16 bits. I guess this was a valid decision at that time. A wchar_t on a Microsoft platform therefore is 16 bits wide, (Unicode) text is stored in wchar_ts -- this had the advantage that every character had equal width. The drawback is that existing APIs, dealing with char, weren't compatible any more.

Nowadays, with 32bit Unicode codepoints, this looks silly -- Unicode text on Microsoft platforms is encoded using UTF-16, so you have both drawbacks: not being compatible with simple char-based strings and multi-character sequences. On many other platforms, wchar_t is 32 bits wide and Unicode is either stored in these wchar_ts or encoded as UTF-8 in "normal" chars.

But back to the Microsoft API: In order to solve the problem, they renamed all API calls dealing with strings to have an A suffixed and introduced a second set of the same calls, taking wchar_t, suffixed with W for the Unicode variant. Depending on a compile-time switch UNICODE, the original names are mapped to the real names with either suffix by the preprocessor.

As you probably know, string literals in C have the type char *. To make a string literal of type wchar_t *, you need to prefix it with an L. In order to automatically do this when UNICODE is set, another macro is provided: _T(). So what you are expected to do in your code is to wrap any string literal in _T(), it will become prefixed with L exactly when UNICODE is defined.

Therefore, this line:

hComm = CreateFileA((LPCSTR)"COM8"

should instead read:

hComm = CreateFile(_T("COM8")

A word on LPCSTR and LPWCSTR: They are nowadays equivalent to just char * and wchar_t *. So casting is unnecessary. The reason for these names is backwards compatibility to ancient systems with segmented memory and "far pointers". As long as you don't need your code to compile for win16, just forget about them.


Finally a personal opinion: Windows knows Unicode for quite a long time (IIRC already with Win95) and it's standard nowadays. It's unlikely you ever want to target a windows system that doesn't support unicode. It's much more likely you want to write some portable code and then the problem is the different handling of Unicode (wchar_t on Windows, char with UTF-8 on most other systems, UTF-8 is also predominant on the Internet).

To help with that, I prefer to always define UNICODE, use wchar_t string literals for any constant string needed by the windows API (like your CreateFile() call, so just prefix it with L) and store all strings internally in char using UTF-8, only converting them when you need to pass them to the Windows API. There are two functions for doing the conversion: MultiByteToWideChar() and WideCharToMultiByte(). That way, you can easily write adapters for the APIs of other OS's that use UTF-8.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...