How to call DeviceIOControl code asynchronously?
Asked Answered
K

2

7

I am trying to call DeviceIO functions asynchronously by using the OVERLAPPED structure as described on MSDN. I am using the FSCTL_ENUM_USN_DATA control code to enumerate the MFT of NTFS drives but i am not able to run it asynchronously. The file handle is created with FILE_FLAG_OVERLAPPED but there is no difference whether I use the overlapped structure with FILE_FLAG_OVERLAPPED or not. The function does not return immediately. Is seems to be synchronous in both cases. The example below shows the enumeration of the first 100.000 MFT entries on the C:\ drive. Since I am not so familiar with the usage of overlapped structures maybe I did something wrong. My question: How can I execute DeviceIoControl(hDevice, FSCTL_ENUM_USN_DATA,...) asynchronously? Thanks for any help.

#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);
        }
    }
}
Kutaisi answered 8/7, 2014 at 14:4 Comment(3)
If driver doesn't support asynchronous I/O generally or for some request, it handles I/O request synchronously, ignoring OVERLAPPED parameter. I don't know whether this driver supports this specific request in async I/O mode, though.Leatherette
Thanks for the reply. According to Microsoft FSCTL_ENUM_USN_DATA can be called async: msdn.microsoft.com/en-us/library/windows/desktop/…Kutaisi
Well, looking again at your code, I don't see that you fill the hEvent member of lOverlapped variable. This may be a good reason to execute this request synchronously.Leatherette
N
2

TL:DR - you only get async behavior if the driver that received your request pended it.

When you call DeviceIoControl and pass an overlapped structure, it does not guarantee that the operation will be asynchronous. It means that it can be asynchronous. That depends on the way that the driver that will receive your request is implemented. When you run DeviceIoControl, it creates a irp and sends it to the driver. DeviceIoControl will promote your thread to kernel mode to create and dispatch the irp. The driver's callback will be called on that thread to handle the request. If the driver decides to handle (and complete) the request immediately, then the request is completed synchronously. In this flow, there is no difference between opening the driver with FILE_FLAG_OVERLAPPED or not. If the driver decides to pend the request then you will see real async behavior. DeviceIoControl will return FALSE and GetLastError will return ERROR_IO_PENDING. That means that the irp is pending completion and the event you supplied in the OVERLAPPED struct will be signaled when the irp is completed.

Natie answered 28/1, 2020 at 11:50 Comment(0)
L
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
Leatherette answered 8/7, 2014 at 14:50 Comment(1)
Thank you. But still doesn't work. No async. The overlapped structure and the device handle should be correct: If I call e.g. the 'readfile' function with the same overlapped structure and the same hdevice handle, it returns immediately with GetalstError() = 997 (ERROR_IO_PENDING: Overlapped I/O operation is in progress), which indicates that 'readfile' is called asynchronously. But it is not working for deviceio.Kutaisi

© 2022 - 2024 — McMap. All rights reserved.