【问题标题】:What does it mean for ReadFile to be "completing asynchronously", and why is it an error?ReadFile “异步完成”是什么意思,为什么会出错?
【发布时间】:2014-12-06 21:02:28
【问题描述】:

我正在(同步)使用ReadFile() 读取 Windows 中的串行输入,但不是等待串行端口输入然后返回我认为应该的,ReadFile() 而是立即返回值 @ 987654324@ 和 0 的 GetLastError()。(是的,我确定我有正确的错误代码并且没有在两者之间进行系统调用)。

ReadFile() documentation 表示当函数“异步完成时,返回值为零 (FALSE)”。同步读取如何异步完成?为什么这会是一个错误?值得注意的是,读取的数据是垃圾数据,正如人们所预料的那样。

更一般地说,我如何强制 ReadFile() 表现得像一个简单的串行端口同步读取,或者至少表现得像 UNIX read()

编辑:这是一些源代码:

HANDLE my_connect(char *port_name)
{
    DCB dcb;
    COMMTIMEOUTS timeouts;
    HANDLE hdl = CreateFile(port_name,
            GENERIC_READ | GENERIC_WRITE,
            0,
            NULL,
            OPEN_EXISTING,
            FILE_ATTRIBUTE_NORMAL,
            0);

    GetCommState(port_name, &dcb);
    dcb.BaudRate = 115200;
    dcb.ByteSize = 8;
    dcb.StopBits = ONESTOPBIT;
    dcb.Parity = NOPARITY;
    if(SetCommState(hdl, &dcb) == 0)
    {
        fprintf(stderr, "SetCommState failed with error code %d.\n",
                GetLastError());
        return (HANDLE) -1;
    }

    /* TODO: Set a variable timeout. */
    timeouts.ReadIntervalTimeout = 0;
    timeouts.ReadTotalTimeoutMultiplier = 0;
    timeouts.ReadTotalTimeoutConstant = 5000; /* wait 5s for input */
    timeouts.WriteTotalTimeoutMultiplier = 0;
    timeouts.WriteTotalTimeoutConstant = 5000;
    if(SetCommTimeouts(hdl, &timeouts) == 0)
    {
        fprintf(stderr, "SetCommTimeouts failed with error code %d.\n",
                GetLastError());
        return (HANDLE) -1;
    }

    return hdl;
}

int my_disconnect(HANDLE hdl)
{
    return CloseHandle(hdl);
}

int my_send(HANDLE hdl, char *cmd)
{
    DWORD nb = 0;
    if(WriteFile(hdl, cmd, strlen(cmd), &nb, NULL) == 0)
    {
        fprintf(stderr, "WriteFile failed with error code %d.\n",
                GetLastError());
        return -1;
    }
    return (int) nb;
}

int my_receive(HANDLE hdl, char *dst, int dstlen)
{
    int i;
    DWORD r;
    BOOL err;
    char c = '\0';

    for (i = 0; i < dstlen; err = ReadFile(hdl, &c, 1, &r, NULL))
    {
        if (err == 0)
        {
            fprintf(stderr, "ReadFile failed with error code %d.\n",
                    GetLastError());
            return -1;
        }
        if (r > 0)
        {
            dst[i++] = c;
            if (c == '\n') break;
        }
    }

    if (i == dstlen)
    {
        fprintf(stderr, "Error: read destination buffer not large enough.\
                Recommended size: 256B. Your size: %dB.\n", dstlen);
        return -1;
    }
    else
    {
        dst[i] = '\0'; /* null-terminate the string. */
    }

    return i;
}

还有我的测试代码:

HANDLE hdl = my_connect("COM4");
char *cmd = "/home\n"; /* basic command */
char reply[256];

my_send(hdl, cmd);
my_receive(hdl, reply, 256);
puts(reply);

【问题讨论】:

  • 您能否显示代码以便我们了解您是如何打开串行端口并从中读取数据的?
  • 正如本所说,这不应该发生。它可能是由设备驱动程序中的错误引起的,但更有可能是您的代码中的错误。没有看到代码,我们无能为力。
  • 感谢您的意见;如果您仍然想看一下,我添加了我的代码。 :)
  • 这不是你的真实代码。编译器不会接受GetCommState(port_name, &amp;dcb);,如果你接受GetCommState(hdl, &amp;dcb);,它就会失败。如果您需要帮助,请至少使用您向我们展示的代码进行一次测试。
  • 很抱歉没有回答您关于 STRICT 的问题。它是一个宏,它会导致 Windows 头文件为所有不同类型的句柄创建虚拟结构类型:HANDLE、HWND、HBRUSH、HBITMAP 等,以便它们成为不同且不兼容的指针类型,防止传递错误类型的句柄 (或另一个指针,比如你的port_name)没有 STRICT 是有效的,它只是typedef void* HANDLE 这是任何指针的隐式转换,就像听起来一样危险。

标签: c windows winapi asynchronous serial-port


【解决方案1】:

它不是异步完成的。如果是,GetLastError 将返回 ERROR_IO_PENDING

要进行同步 I/O,请打开不带 FILE_FLAG_OVERLAPPED 的文件。

如果没有有效的GetLastError 代码,ReadFile 应该不可能失败。 ReadFile 仅在驱动设置非成功状态码时返回 false。

【讨论】:

  • 感谢您的回答;如果您愿意看,我添加了一些源代码。我宁愿不做同步 I/O,这对我的目的来说是不必要的。
  • @EricDand:不要使用GetCommState。而是说DCB dcb = { sizeof dcb }; 将所有内容归零并设置您需要的值。对于任何晦涩的字段,我从来没有发现“从以前的应用程序中留下的一些值”比零更好的设置。
猜你喜欢
  • 2011-03-24
  • 1970-01-01
  • 1970-01-01
  • 2010-11-08
  • 2013-11-26
  • 2012-08-08
相关资源
最近更新 更多