【问题标题】:What is the difference between CreateFile() and CreateFileA()?CreateFile() 和 CreateFileA() 有什么区别?
【发布时间】:2018-12-29 22:00:53
【问题描述】:

我正在按照教程here进行串口通信

打开然后关闭串口的主要代码如下:

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\n");
    printf("err = 0x%x\n", err);
}
else
    printf("opening serial port successful\n");

CloseHandle(hComm);//Closing the Serial Port

如果我使用CreateFile(),代码编译正常但串口没有打开(我收到Error in opening serial port 消息)

在玩了一会儿代码后,我发现CreateFileA() 成功打开了串口(我发现这是唯一的原因是因为当我搜索CreateFile() 函数时,我得到了 MSDN 定义页面CreateFileA() 作为第一个结果

我四处搜索,但找不到两者之间的区别。我找到了this,它说我应该总是CreateFile(),编译器应该做剩下的事情,但它在我的情况下不起作用,只有在我专门使用CreateFileA()时才起作用

CreateFile()CreateFileA() 有什么区别,我应该在我的程序中使用哪一个来进行基本的串行端口通信?

Windows 10
Visual Studio 2013 速成版

【问题讨论】:

  • CreateFile 是宏,在 ASCII 配置中定义为 CreateFileA,在 Unicode 配置中定义为 CreateFileW。
  • @Alex 我在我链接的那个旧论坛帖子中发现,我们只应该使用 CreateFile() 并且编译器会将其解析为正确的。它在我的情况下不起作用的原因可能是什么?
  • 没有。调用 GetLastError 了解原因。
  • 我猜你的程序是用Unicode编译的,所以对于CreateFile和CreateFileW,你需要使用L"COM8"参数。
  • 使用 `_T("COM8"),这应该适用于两种配置。阅读:codeproject.com/Articles/446/…

标签: c visual-studio serial-port


【解决方案1】:

这里需要对 windows API 做一些解释:微软很早就引入了 Unicode。那时,他们决定用 16 位表示一个 Unicode 字符。我想这在当时是一个有效的决定。因此,Microsoft 平台上的 wchar_t 是 16 位宽,(Unicode)文本存储在 wchar_ts 中——这具有每个字符具有相等宽度的优点。缺点是处理char 的现有API 不再兼容。

如今,使用 32 位 Unicode 代码点,这看起来很愚蠢——Microsoft 平台上的 Unicode 文本使用 UTF-16 编码,因此您有两个缺点:不兼容基于char 的简单字符串 多字符序列。在许多其他平台上,wchar_t 是 32 位宽,Unicode 要么存储在这些 wchar_ts 中,要么在“正常”chars 中编码为 UTF-8。

但回到 Microsoft API:为了解决问题,他们将所有处理字符串的 API 调用重命名为后缀为 A,并引入了第二组相同的调用,采用 wchar_t,后缀为 @ 987654332@ 用于 Unicode 变体。根据编译时开关UNICODE,预处理器将原始名称映射到带有后缀的真实名称。

您可能知道,C 中的字符串文字的类型为char *。要生成wchar_t * 类型的字符串文字,您需要在其前面加上L 前缀。为了在设置UNICODE 时自动执行此操作,提供了另一个宏:_T()。因此,您应该在代码中执行的操作是将任何字符串文字包装在 _T() 中,恰好在定义 UNICODE 时,它将以 L 为前缀。

因此,这一行:

hComm = CreateFileA((LPCSTR)"COM8"

应该改为:

hComm = CreateFile(_T("COM8")

关于LPCSTRLPWCSTR 的一句话:它们现在相当于char *wchar_t *。所以铸造是不必要的。这些名称的原因是向后兼容具有分段内存和“远指针”的古代系统。只要你的代码不需要为win16编译,就别管它们了。


最后一个个人意见:Windows 知道 Unicode 很长一段时间(IIRC 已经与 Win95 一起使用)并且它现在是标准的。您不太可能希望以不支持 unicode 的 Windows 系统为目标。您更有可能想要编写一些可移植的代码,然后问题是 Unicode 的不同处理方式(Windows 上的wchar_t,大多数其他系统上使用 UTF-8 的char,UTF-8 在 Internet 上也占主导地位) .

为了帮助解决这个问题,我更喜欢始终定义 UNICODE,对 Windows API 所需的任何常量字符串使用 wchar_t 字符串文字(如您的 CreateFile() 调用,因此只需在其前面加上 L)和使用 UTF-8 将所有字符串内部存储在 char 中,仅在需要将它们传递给 Windows API 时才转换它们。有两个函数可以进行转换:MultiByteToWideChar()WideCharToMultiByte()。这样,您可以轻松地为使用 UTF-8 的其他操作系统的 API 编写适配器。

【讨论】:

    猜你喜欢
    • 2010-10-02
    • 2011-12-12
    • 2010-09-16
    • 2012-03-14
    • 2012-02-06
    • 2011-02-25
    • 2011-11-22
    • 2015-03-26
    • 2013-08-19
    相关资源
    最近更新 更多