めいくりぷとのブログ

技術的なことをまったりと。

DeviceIoControl Emulate

DeviceIoControl
https://msdn.microsoft.com/ja-jp/library/windows/desktop/aa363216(v=vs.85).aspx

BOOL
WINAPI
DeviceIoControl(
	_In_        HANDLE       hDevice,
	_In_        DWORD        dwIoControlCode,
	_In_opt_    LPVOID       lpInBuffer,
	_In_        DWORD        nInBufferSize,
	_Out_opt_   LPVOID       lpOutBuffer,
	_In_        DWORD        nOutBufferSize,
	_Out_opt_   LPDWORD      lpBytesReturned,
	_Inout_opt_ LPOVERLAPPED lpOverlapped
	)
{
	IO_STATUS_BLOCK IoStatusBlock;
	NTSTATUS ntStatus;
	
	if (!lpOverlapped)
	{
		if ((dwIoControlCode >> 16) == 0x9)
		{
			ntStatus = NtFsControlFile(hDevice, NULL, NULL, NULL, 
				&IoStatusBlock, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize);
		}
		else
		{
			ntStatus = NtDeviceIoControlFile(hDevice, NULL, NULL, NULL, 
				&IoStatusBlock, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize);
		}

		if (ntStatus == STATUS_PENDING)
		{
			ntStatus = NtWaitForSingleObject(hDevice, 0, NULL);
			if (NT_SUCCESS(ntStatus))
			{
				ntStatus = IoStatusBlock.Status;
				if (NT_SUCCESS(ntStatus))
				{
					if (lpBytesReturned)
						*lpBytesReturned = IoStatusBlock.Information;

					return TRUE;
				}
			}

			if ((ntStatus & 0xC0000000) != 0xC0000000 && lpBytesReturned)
				*lpBytesReturned = IoStatusBlock.Information;

			BaseSetLastNTError(ntStatus);
			return FALSE;
		}

		if (NT_SUCCESS(ntStatus))
		{
			if (lpBytesReturned)
				*lpBytesReturned = IoStatusBlock.Information;
			return TRUE;
		}

		BaseSetLastNTError(ntStatus);
		return FALSE;
	}

	lpOverlapped->Internal = STATUS_PENDING;
	if ((dwIoControlCode >> 16) == 0x9) 
	{
		ntStatus = NtFsControlFile(hDevice, lpOverlapped->hEvent, NULL, 
			reinterpret_cast<PVOID>(((DWORD)lpOverlapped->hEvent & 1) == NULL ? (DWORD)lpOverlapped : NULL),
			reinterpret_cast<PIO_STATUS_BLOCK>(lpOverlapped), 
			dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize);
	}
	else 
	{
		ntStatus = NtDeviceIoControlFile(hDevice, lpOverlapped->hEvent, NULL,
			reinterpret_cast<PVOID>(((DWORD)lpOverlapped->hEvent & 1) == NULL ? (DWORD)lpOverlapped : NULL),
			reinterpret_cast<PIO_STATUS_BLOCK>(lpOverlapped),
			dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize);
	}

	IoStatusBlock.Information = ntStatus;
	if ((ntStatus & 0xC0000000) != 0xC0000000 && lpBytesReturned)
		*lpBytesReturned = lpOverlapped->InternalHigh;

	if (IoStatusBlock.Information != STATUS_PENDING && (IoStatusBlock.Information & 0x80000000) == STATUS_SUCCESS)
		return TRUE;

	BaseSetLastNTError(IoStatusBlock.Information);
	return FALSE;
}