Функция DeviceIoControlEx
Jun 14, 2011 · CommentsПрограммированиеWin32Windows
Win32 API предоставляет «Ex» варианты функций ReadFile и WriteFile, в то время как «Ex» варианта функции DeviceIoControl не предлагается. Исправить этот недостаток очень просто, так как соответствующая функция Native API документирована в MSDN: NtDeviceIoControlFile (хотя и помечена как «Deprecated»). Прототип новой функции будет выглядеть вот так:
BOOL
WINAPI
DeviceIoControlEx(
__in HANDLE hDevice,
__in DWORD dwIoControlCode,
__in_opt LPVOID lpInBuffer,
__in DWORD nInBufferSize,
__out_opt LPVOID lpOutBuffer,
__in DWORD nOutBufferSize,
__inout LPOVERLAPPED lpOverlapped,
__in_opt LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);
Отличий от DeviceIoControl два: количество прочитанных байт возвращается в структуре OVERLAPPED и есть возможность передать указатель на completion callback (простите за мой французский).
NtDeviceIoControlFile будет вызываться вот так:
PIO_STATUS_BLOCK IoStatusBlock = (PIO_STATUS_BLOCK)&lpOverlapped->Internal;
IoStatusBlock->Status = STATUS_PENDING;
NTSTATUS Status =
NtDeviceIoControlFile(
hDevice,
NULL,
ApcRoutine,
lpCompletionRoutine,
IoStatusBlock,
dwIoControlCode,
lpInBuffer,
nInBufferSize,
lpOutBuffer,
nOutBufferSize);
if (!NT_SUCCESS(Status))
{
SetLastError(RtlNtStatusToDosError(Status));
return FALSE;
}
return TRUE;
Часть структуры OVERLAPPED используется как IO_STATUS_BLOCK. Точно также поступают ReadFileEx и WriteFileEx. NTSTATUS коды ошибок транслируются в Win32 аналоги функцией RtlNtStatusToDosError, которая также документирована в MSDN. Прототипы callback-ов Win32 и Native API отличаются, поэтому используется вспомогательная функция ApcRoutine:
VOID
WINAPI
ApcRoutine(
__in PVOID Context,
__in PIO_STATUS_BLOCK IoStatusBlock,
__reserved DWORD Reserved
)
{
DWORD BytesTransfered = 0;
if (NT_SUCCESS(IoStatusBlock->Status))
{
BytesTransfered = (DWORD)IoStatusBlock->Information;
}
((LPOVERLAPPED_COMPLETION_ROUTINE)Context)(
RtlNtStatusToDosError(IoStatusBlock->Status),
BytesTransfered,
CONTAINING_RECORD(IoStatusBlock, OVERLAPPED, Internal));
}
В результате функция DeviceIoControlEx обладает точно такой же семантикой вызова, как и ReadFileEx, и WriteFileEx.