当我尝试运行对串行端口进行一些基本写入的c文件时,出现错误。我尝试异步运行它,因为写入有时需要很长时间才能传输。我的原始版本使它与WriteFile()命令同步运行,效果很好。我是使用OVERLAPPED的新手,希望能对此有所感激和投入。

我得到的错误是:

Debug Assertion Failed!
<path to dbgheap.c>
Line: 1317
Expression: _CrtIsValidHeapPointer(pUserData)

当第二个写函数被调用时。

在主要方面:
    {
        //initialized port (with overlapped), DBC, and timeouts

        result = write_port(outPortHandle, 128);
        result = write_port(outPortHandle, 131);
    }




static void CALLBACK write_compl(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped) {
        //write completed. check for errors? if so throw an exception maybe?
        printf("write completed--and made it to callback function\n");
    }


int write_port(HANDLE hComm,BYTE* lpBuf) {

   OVERLAPPED osWrite = {0};

   // Create this write operation's OVERLAPPED structure's hEvent.
   osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
   if (osWrite.hEvent == NULL)
      // error creating overlapped event handle
      return 0;

   // Issue write.
   if (!WriteFileEx(hComm, &lpBuf, 1, &osWrite, &write_compl )) {
      if (GetLastError() != ERROR_IO_PENDING) {
         // WriteFile failed, but isn't delayed. Report error and abort.
          printf("last error: %ld",GetLastError());
          return 0; //failed, return false;
      }
      else {
         // Write is pending.
         WaitForSingleObjectEx(osWrite.hEvent, 50, TRUE);   //50 ms timeout

        return -1; //pending
      }
   }
   else {
        return 1; //finished
   }
}

抱歉,那不是完整的代码。我也使用了BYTE数组,而不是常量。但是system(“pause”)导致我的调试断言失败错误,并且仔细查看我的代码后,当WriteFileEx()成功时,它从未在重叠结构中为事件设置警报/超时,因此回调函数将永远不会被调用。我解决了这些问题。

我只需要帮助处理/访问在调用ReadFileEx()函数时分配的结构中的单个BYTE(用于存储读取的BYTE,以便可以对其进行处理)。我需要知道如何使用偏移量访问BYTE存储并使重叠的结构为null。将重叠结构设为null就像将其中的句柄设置为INVALID_HANDLE_VALUE一样简单吗?

最佳答案

我认为您有几个问题:

您正在传递一个整数作为指针(您的编译器应对此发出警告,或者最好拒绝编译代码):



将此与write_port的定义进行比较:



上面的陈述不符。稍后,您通过获取BYTE *->“&lpBuf”的地址,将指向lpBuf的指针传递给WriteFileEx函数。这不会导致您认为的结果。

即使已解决此问题,只要写入成功排队但仍无法在50毫秒的超时时间内完成,您仍然会遇到潜在的生命周期问题。

使用重叠的I/O时,需要确保读/写缓冲区和重叠的结构保持有效,直到I/O完成,取消或关联的设备关闭为止。在上面的代码中,您使用指向OVERLAPPED结构的指针,该结构位于对WriteFileEx的调用中的堆栈中。如果WriteFileEx在50毫秒内未完成,则挂起的I/O将引用不存在的OVERLAPPED结构,并且(希望)发生访问冲突(或更糟糕的是,在应用程序中的某个位置静默损坏了堆栈数据)。

处理这些生命周期问题(如果性能不是大问题)的规范方法是使用自定义结构,该结构包括OVERLAPPED结构和一些用于读取/写入数据的存储。发布写操作时分配结构,并从I/O完成例程中取消分配结构。将包含的OVERLAPPED结构的地址传递给WriteFileEx,并使用例如offsetof以从完成例程中的OVERLAPPED地址获取自定义结构的地址。

还要注意,WriteFileEx实际上并不使用hEvent成员IIRC。

编辑:添加了代码示例,请注意:

  • 我实际上尚未尝试编译代码,代码可能存在拼写错误或其他问题。
  • 这不是发送数据的最有效方法(为发送的每个字节分配/取消分配内存块)。不过,它应该易于改进。

  • #include
    #include
    #include

    //...
    typedef结构体_MYOVERLAPPED
    {
    重叠ol;
    BYTE缓冲区;
    } MYOVERLAPPED,* LPMYOVERLAPPED;
    //...

    静态void回调write_compl(DWORD dwErrorCode,DWORD dwNumberOfBytesTransfered,LPOVERLAPPED lpOverlapped)
    {
    如果(NULL == lpOverlapped)
    {
    断言(!“永远不会发生”);
    返回;
    }

    LPBYTE pOlAsBytes =(LPBYTE)lpOverlapped;
    LPBYTE pMyOlAsBytes = pOlAsBytes-offsetof(MYOVERLAPPED,ol);
    LPMYOVERLAPPED pMyOl =(LPMYOVERLAPPED)pOlAsBytes;

    如果((ERROR_SUCCESS == dwErrorCode)&&
    (sizeof(BYTE)== dwNumberOfBytesTransfered))
    {
    printf(“write%uc\n”,pMyOl-> buffer);
    }
    别的
    {
    //处理错误
    }

    免费(pMyOl);
    }

    int write_port(HANDLE hComm,BYTE字节){

    LPMYOVERLAPPED pMyOl =(LPMYOVERLAPPED)malloc(sizeof(MYOVERLAPPED));

    ZeroMemory(pMyOl,sizeof(MYOVERLAPPED));
    pMyOl-> buffer =字节;

    //发布写入。
    如果(!WriteFileEx(hComm,&pMyOl-> buffer,sizeof(BYTE),pMyOl,&write_compl)){
    如果(GetLastError()!= ERROR_IO_PENDING){
    //WriteFile失败,但没有延迟。报告错误并中止。
    免费(pMyOl);
    printf(“上一个错误:%ld”,GetLastError());
    返回0;//失败,返回false;
    }
    别的 {
    返回-1;//待办的
    }
    }
    别的 {
    免费(pMyOl);
    返回1;//完成的
    }
    }

    09-07 05:23