如何检查WriteFile函数是否完成

时间:2012-08-17 21:04:25

标签: c++ winapi uart

我想检查WriteFile函数是否写入UART,以便我可以在同一个ComDev上调用ReadFile而不会导致异常。

WriteFile function似乎可以在写完之前返回。

BOOL WriteCommBlock(HANDLE * pComDev, char *pBuffer , int BytesToWrite)
{
while(fComPortInUse){}

fComPortInUse = 1; 

BOOL       bWriteStat   = 0;
DWORD      BytesWritten = 0;
COMSTAT    ComStat      = {0};
OVERLAPPED osWrite      = {0,0,0};

if(WriteFile(*pComDev,pBuffer,BytesToWrite,&BytesWritten,&osWrite) == FALSE)
{
    short Errorcode = GetLastError();
    if( Errorcode != ERROR_IO_PENDING )
        short breakpoint = 5; // Error

    Sleep(1000); // complete write operation TBD

    fComPortInUse = 0; 
    return (FALSE);
}


fComPortInUse = 0; 
return (TRUE);
}

我使用Sleep(1000)作为解决方法,但我该如何等待适当的时间?

5 个答案:

答案 0 :(得分:1)

您可以创建一个事件,将其存储在重叠结构中并等待它发出信号。像这样(未经测试):

BOOL WriteCommBlock(HANDLE * pComDev, char *pBuffer , int BytesToWrite)
{
while(fComPortInUse){}

fComPortInUse = 1; 

BOOL       bWriteStat   = 0;
DWORD      BytesWritten = 0;
COMSTAT    ComStat      = {0};
OVERLAPPED osWrite      = {0,0,0};
HANDLE     hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

if (hEvent != NULL)
{
    osWrite.hEvent = hEvent;
    if(WriteFile(*pComDev,pBuffer,BytesToWrite,&BytesWritten,&osWrite) == FALSE)
    {
        short Errorcode = GetLastError();
        if( Errorcode != ERROR_IO_PENDING )
            short breakpoint = 5; // Error

        WaitForSingleObject(hEvent, INFINITE);

        fComPortInUse = 0; 
        return (FALSE);
    }
    CloseHandle(hEvent);
}


fComPortInUse = 0; 
return (TRUE);
}

请注意,根据您尝试做的其他操作,只需调用WaitForSingleObject()可能不是最佳选择。并且INFINITE也不会超时。

答案 1 :(得分:1)

您的问题是错误使用重叠的I / O,无论是UART还是其他任何底层设备。

修复代码最简单(但不一定是最优化)的方法是使用事件来处理I / O完成。

// ...
OVERLAPPED osWrite      = {0,0,0};

osWrite.hEvent = CreateEvent(FALSE, NULL, NULL, FALSE);

if(WriteFile(*pComDev,pBuffer,BytesToWrite,&BytesWritten,&osWrite) == FALSE)
{
    DWORD Errorcode = GetLastError();
    // ensure it's ERROR_IO_PENDING

    WaitForSingleObject(osWrite.hEvent, INFINITE);

}

CloseHandle(osWrite.hEvent);

但请注意,整个I / O是同步的。操作系统以异步方式处理它,但是代码在完成之前不会继续运行。如果是这样,为什么还要使用重叠的I / O?

应该使用它来同时处理同一线程中的多个I / O(和其他任务)。要正确执行此操作 - 您应该在堆上分配OVERLAPPED结构并使用其中一个可用的完成机制:事件,APC,完成端口等。您的程序流逻辑也应该更改。

答案 2 :(得分:0)

你的Sleep(1000);没有用,它只会在writefile完成其操作后执行。你必须等到WriteFile结束。

if(WriteFile(*pComDev,pBuffer,BytesToWrite,&BytesWritten,&osWrite) == FALSE)
{}

你必须知道条件语句中的任何内容只有在结果为真时才会执行。 在这里,结果在WriteFile例程完成后(无论是完整的还是有错误的)发送到程序。

答案 3 :(得分:0)

由于您没有说您需要异步I / O,因此您应该尝试同步。这更容易。我想如果你只是为OVERLAPPED arg传递一个空指针,你会得到同步,阻塞,I / O.请参阅本文档“Windows C”部分中编写的示例代码:

http://www.pololu.com/docs/0J40/

答案 4 :(得分:0)

好的,我错过了读/写代码中重叠的I / O OVL参数,所以我也只是昨天作为评论回复,否则我会用downvotes敲打:(

处理重叠I / O的经典方法是将_OVL结构作为在重叠读/写调用中发出的缓冲类的数据成员。这使得同时加载读取和写入调用变得容易(或者实际上,具有单独缓冲区实例的多个读取/写入调用)。

对于COM posrts,我通常使用APC完成例程,其地址在readFileEx / writeFileEx API中传递。这使得_OVL的hEvent字段可以自由地用来保存缓冲区的实例指针,因此很容易将它强制转换回完成例程,这意味着每个缓冲区类实例都包含一个_OVL memebr,它包含一个指向hEvent字段的指针到缓冲类实例 - 听起来很奇怪,但工作正常。)