如何异步调用DeviceIOControl代码?

6
我正在尝试使用OVERLAPPED结构异步调用DeviceIO函数,如MSDN所述。 我正在使用FSCTL_ENUM_USN_DATA控制代码枚举NTFS驱动器的MFT,但我无法以异步方式运行它。文件句柄是使用FILE_FLAG_OVERLAPPED创建的,但是无论我是否使用带有FILE_FLAG_OVERLAPPED的重叠结构都没有区别。该函数不会立即返回。在两种情况下,它似乎都是同步的。 以下示例显示了在C:\驱动器上枚举前100,000个MFT条目。 由于我对重叠结构的使用不太熟悉,也许我做错了什么。我的问题是:如何异步执行DeviceIoControl(hDevice,FSCTL_ENUM_USN_DATA,...)?感谢您的任何帮助。
#include "stdafx.h"
#include <Windows.h>

typedef struct {
  DWORDLONG  nextusn;
  USN_RECORD FirstUsnRecord;
  BYTE Buffer[500];
}TDeviceIoControlOutputBuffer, *PTDeviceIoControlOutputBuffer;

int _tmain(int argc, _TCHAR* argv[])
{
    MFT_ENUM_DATA lInputMftData;
    lInputMftData.StartFileReferenceNumber = 0;
    lInputMftData.MinMajorVersion = 2;
    lInputMftData.MaxMajorVersion = 3;
    lInputMftData.LowUsn = 0;
    lInputMftData.HighUsn = 0;

    TDeviceIoControlOutputBuffer lOutputMftData;
    DWORD lOutBytesReturned = 0;
    HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    OVERLAPPED  lOverlapped = { 0 };
    lOverlapped.hEvent = hEvent;
    LPCWSTR path = L"\\\\.\\C:";
    HANDLE hDevice = CreateFile(path, GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
    if (hDevice != INVALID_HANDLE_VALUE) {
        lOutputMftData.nextusn = 0;
        while (lOutputMftData.nextusn < 100000) {
            lInputMftData.StartFileReferenceNumber = lOutputMftData.nextusn;
            BOOL result = DeviceIoControl(hDevice, FSCTL_ENUM_USN_DATA, &lInputMftData, sizeof(lInputMftData), &lOutputMftData, sizeof(lOutputMftData), &lOutBytesReturned, &lOverlapped);
        }
    }
}

如果驱动程序通常不支持异步I/O或某些请求,则它会同步处理I/O请求,忽略OVERLAPPED参数。虽然我不知道这个驱动程序是否支持在异步I/O模式下处理此特定请求。 - Alex F
感谢您的回复。根据微软的文档,FSCTL_ENUM_USN_DATA可以异步调用:http://msdn.microsoft.com/en-us/library/windows/desktop/aa364563%28v=vs.85%29.aspx - jampeter
好的,再看一下你的代码,我没有看到你填充lOverlapped变量的hEvent成员。这可能是同步执行此请求的一个很好的理由。 - Alex F
2个回答

2
TL:DR - 只有在接收请求的驱动程序挂起它时,您才能获得异步行为。
当您调用DeviceIoControl并传递一个重叠结构时,并不保证该操作将是异步的。这意味着它可以是异步的。这取决于将接收您的请求的驱动程序实现的方式。 当您运行DeviceIoControl时,它会创建一个irp并将其发送到驱动程序。DeviceIoControl将提升您的线程到内核模式以创建和分派irp。驱动程序的回调将在该线程上被调用以处理请求。如果驱动程序决定立即处理(并完成)请求,则请求将同步完成。在此流程中,使用FILE_FLAG_OVERLAPPED打开驱动程序与否没有区别。 如果驱动程序决定挂起请求,则您将看到真正的异步行为。 DeviceIoControl将返回FALSE,并且GetLastError将返回ERROR_IO_PENDING。这意味着irp正在等待完成,并且在irp完成时将信号传递给您在OVERLAPPED结构中提供的事件。

0
HEVENT hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
OVERLAPPED  lOverlapped = { 0 };
lOverlapped.hEvent = hEvent;

...

BOOL result = DeviceIoControl(hDevice, FSCTL_ENUM_USN_DATA, &lInputMftData, sizeof(lInputMftData), &lOutputMftData, sizeof(lOutputMftData), &lOutBytesReturned, &lOverlapped);

// If operation is asynchronous, wait for hEvent here or somewhere else

谢谢。但仍然不起作用。没有异步。重叠结构和设备句柄应该是正确的:如果我使用相同的重叠结构和相同的hdevice句柄调用“readfile”函数,它会立即返回GetalstError()= 997(ERROR_IO_PENDING:正在进行重叠I / O操作),这表明“readfile”被异步调用。但对于deviceio而言,它并不起作用。 - jampeter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接