虽然目前,没有具体的项目,但是Direct3D学习还是会继续。其实很多东西,虽然看起来现在没多大用处,说不定将来有很大的用处。这个无法衡量,多学点,总是有好处的。后面,断断续续,会把另外的几个方向,WDDM 驱动,数据结构算法,也开始捡起来继续。现在需要的是,将知识变成体系。所以,需要大量的总结。
我们今天看一下Windows驱动中的IOCTL,IOCTL顾名思义,就是IO控制码。也就是输入输出控制码。Window驱动中大量充斥着这样的控制码。前面的文章,我们知道,所有在驱动中的流都是以IRP的形式进行的。而用来标识IRP的就是这些IOCTL码。回忆一下MSDN中的IRP的结构。
typedef struct _IRP {
.
.
PMDL MdlAddress;
ULONG Flags;
union {
struct _IRP *MasterIrp;
.
.
PVOID SystemBuffer;
} AssociatedIrp;
.
.
IO_STATUS_BLOCK IoStatus;
KPROCESSOR_MODE RequestorMode;
BOOLEAN PendingReturned;
.
.
BOOLEAN Cancel;
KIRQL CancelIrql;
.
.
PDRIVER_CANCEL CancelRoutine;
PVOID UserBuffer;
union {
struct {
.
.
union {
KDEVICE_QUEUE_ENTRY DeviceQueueEntry;
struct {
PVOID DriverContext[4];
};
};
.
.
PETHREAD Thread;
.
.
LIST_ENTRY ListEntry;
.
.
} Overlay;
.
.
} Tail;
} IRP, *PIRP;
我们知道IRP的一些信息都是存储在IO的堆栈中的:
typedef struct _IO_STACK_LOCATION {
UCHAR MajorFunction;
UCHAR MinorFunction;
UCHAR Flags;
UCHAR Control;
union {
//
// Parameters for IRP_MJ_CREATE
//
struct {
PIO_SECURITY_CONTEXT SecurityContext;
ULONG Options;
USHORT POINTER_ALIGNMENT FileAttributes;
USHORT ShareAccess;
ULONG POINTER_ALIGNMENT EaLength;
} Create;
//
// Parameters for IRP_MJ_READ
//
struct {
ULONG Length;
ULONG POINTER_ALIGNMENT Key;
LARGE_INTEGER ByteOffset;
} Read;
//
// Parameters for IRP_MJ_WRITE
//
struct {
ULONG Length;
ULONG POINTER_ALIGNMENT Key;
LARGE_INTEGER ByteOffset;
} Write;
//
// Parameters for IRP_MJ_QUERY_INFORMATION
//
struct {
ULONG Length;
FILE_INFORMATION_CLASS POINTER_ALIGNMENT
FileInformationClass;
} QueryFile;
//
// Parameters for IRP_MJ_SET_INFORMATION
//
struct {
ULONG Length;
FILE_INFORMATION_CLASS POINTER_ALIGNMENT
FileInformationClass;
PFILE_OBJECT FileObject;
union {
struct {
BOOLEAN ReplaceIfExists;
BOOLEAN AdvanceOnly;
};
ULONG ClusterCount;
HANDLE DeleteHandle;
};
} SetFile;
//
// Parameters for IRP_MJ_QUERY_VOLUME_INFORMATION
//
struct {
ULONG Length;
FS_INFORMATION_CLASS POINTER_ALIGNMENT
FsInformationClass;
} QueryVolume;
//
// Parameters for IRP_MJ_DEVICE_CONTROL and
IRP_MJ_INTERNAL_DEVICE_CONTROL
//
struct {
ULONG OutputBufferLength;
ULONG POINTER_ALIGNMENT InputBufferLength;
ULONG POINTER_ALIGNMENT IoControlCode;
PVOID Type3InputBuffer;
} DeviceIoControl;
//
// Nonsystem service parameters.
//
// Parameters for IRP_MN_MOUNT_VOLUME
//
struct {
PVOID DoNotUse1;
PDEVICE_OBJECT DeviceObject;
} MountVolume;
//
// Parameters for IRP_MN_VERIFY_VOLUME
//
struct {
PVOID DoNotUse1;
PDEVICE_OBJECT DeviceObject;
} VerifyVolume;
//
// Parameters for Scsi using IRP_MJ_INTERNAL_DEVICE_CONTROL
//
struct {
struct _SCSI_REQUEST_BLOCK *Srb;
} Scsi;
//
// Parameters for IRP_MN_QUERY_DEVICE_RELATIONS
//
struct {
DEVICE_RELATION_TYPE Type;
} QueryDeviceRelations;
//
// Parameters for IRP_MN_QUERY_INTERFACE
//
struct {
CONST GUID *InterfaceType;
USHORT Size;
USHORT Version;
PINTERFACE Interface;
PVOID InterfaceSpecificData;
} QueryInterface;
//
// Parameters for IRP_MN_QUERY_CAPABILITIES
//
struct {
PDEVICE_CAPABILITIES Capabilities;
} DeviceCapabilities;
//
// Parameters for IRP_MN_FILTER_RESOURCE_REQUIREMENTS
//
struct {
PIO_RESOURCE_REQUIREMENTS_LIST
IoResourceRequirementList;
} FilterResourceRequirements;
//
// Parameters for IRP_MN_READ_CONFIG and IRP_MN_WRITE_CONFIG
//
struct {
ULONG WhichSpace;
PVOID Buffer;
ULONG Offset;
ULONG POINTER_ALIGNMENT Length;
} ReadWriteConfig;
//
// Parameters for IRP_MN_SET_LOCK
//
struct {
BOOLEAN Lock;
} SetLock;
//
// Parameters for IRP_MN_QUERY_ID
//
struct {
BUS_QUERY_ID_TYPE IdType;
} QueryId;
//
// Parameters for IRP_MN_QUERY_DEVICE_TEXT
//
struct {
DEVICE_TEXT_TYPE DeviceTextType;
LCID POINTER_ALIGNMENT LocaleId;
} QueryDeviceText;
//
// Parameters for IRP_MN_DEVICE_USAGE_NOTIFICATION
//
struct {
BOOLEAN InPath;
BOOLEAN Reserved[3];
DEVICE_USAGE_NOTIFICATION_TYPE POINTER_ALIGNMENT
Type;
} UsageNotification;
//
// Parameters for IRP_MN_WAIT_WAKE
//
struct {
SYSTEM_POWER_STATE PowerState;
} WaitWake;
//
// Parameter for IRP_MN_POWER_SEQUENCE
//
struct {
PPOWER_SEQUENCE PowerSequence;
} PowerSequence;
//
// Parameters for IRP_MN_SET_POWER and IRP_MN_QUERY_POWER
//
struct {
ULONG SystemContext;
POWER_STATE_TYPE POINTER_ALIGNMENT Type;
POWER_STATE POINTER_ALIGNMENT State;
POWER_ACTION POINTER_ALIGNMENT ShutdownType;
} Power;
//
// Parameters for IRP_MN_START_DEVICE
//
struct {
PCM_RESOURCE_LIST AllocatedResources;
PCM_RESOURCE_LIST AllocatedResourcesTranslated;
} StartDevice;
//
// Parameters for WMI Minor IRPs
//
struct {
ULONG_PTR ProviderId;
PVOID DataPath;
ULONG BufferSize;
PVOID Buffer;
} WMI;
//
// Others - driver-specific
//
struct {
PVOID Argument1;
PVOID Argument2;
PVOID Argument3;
PVOID Argument4;
} Others;
} Parameters;
PDEVICE_OBJECT DeviceObject;
PFILE_OBJECT FileObject;
.
.
} IO_STACK_LOCATION, *PIO_STACK_LOCATION;
在IO堆栈中,我们看到了大量的IOCTL。这个是在WDM中的,在WDF对其进行了封装。我们在WDF中,一般使用如下的3个函数向其他模块发送这些IRP.我认为REQUEST是WDM中的IRP和IO_STATION_LOCATION的封装。
看一下异步函数:
WdfIoTargetFormatRequestForInternalIoctl
,WdfIoTargetFormatRequestForInternalIoctlOthers
,WdfIoTargetFormatRequestForIoctl
,WdfIoTargetFormatRequestForRead
,WdfIoTargetFormatRequestForWrite
,这是是异步的,后面需要设置完成例程,和真正发送请求。
再看一下同步的:
WdfIoTargetSendInternalIoctlOthersSynchronously
,WdfIoTargetSendInternalIoctlSynchronously
,WdfIoTargetSendIoctlSynchronously
,WdfIoTargetSendReadSynchronously
,WdfIoTargetSendWriteSynchronously
,同步需要等待,所以可以直接发。
先看一下异步的例子:
NTSTATUS
NICSendOidRequestToTargetAsync(
IN WDFIOTARGET IoTarget,
IN WDFREQUEST Request,
IN PFILE_OBJECT FileObject,
IN ULONG IoctlControlCode,
IN OUT PVOID InputBuffer,
IN ULONG InputBufferLength,
IN OUT PVOID OutputBuffer,
IN ULONG OutputBufferLength,
OUT PULONG BytesReadOrWritten
)
{
NTSTATUS status;
PREQUEST_CONTEXT reqContext;
WDF_REQUEST_REUSE_PARAMS params;
WDFMEMORY inputMem, outputMem;
WDF_REQUEST_REUSE_PARAMS_INIT(
¶ms,
WDF_REQUEST_REUSE_NO_FLAGS,
STATUS_SUCCESS
);
status = WdfRequestReuse(Request, ¶ms);
if (!NT_SUCCESS(status)){
return status;
}
reqContext = GetRequestContext(Request);
inputMem = outputMem = NULL;
if (InputBuffer != NULL) {
status = WdfMemoryAssignBuffer(
reqContext->InputMemory,
InputBuffer,
InputBufferLength
);
if (!NT_SUCCESS(status)) {
return status;
}
inputMem = reqContext->InputMemory;
}
if (OutputBuffer != NULL) {
status = WdfMemoryAssignBuffer(
reqContext->OutputMemory,
OutputBuffer,
OutputBufferLength
);
if (!NT_SUCCESS(status)) {
return status;
}
outputMem = reqContext->OutputMemory;
}
status = WdfIoTargetFormatRequestForIoctl(
IoTarget,
Request,
IoctlControlCode,
inputMem,
NULL,
outputMem,
NULL
);
if (!NT_SUCCESS(status)) {
return status;
}
WdfRequestSetCompletionRoutine(
Request,
NICSendOidRequestToTargetAsyncCompletionRoutine,
BytesReadOrWritten
);
if (WdfRequestSend(
Request,
IoTarget,
WDF_NO_SEND_OPTIONS
) == FALSE) {
status = WdfRequestGetStatus(Request);
}
return status;
}
再看一下同步的:
WDF_MEMORY_DESCRIPTOR outputDescriptor;
NTSTATUS status;
HID_COLLECTION_INFORMATION collectionInformation;
WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(
&outputDescriptor,
(PVOID) &collectionInformation,
sizeof(HID_COLLECTION_INFORMATION)
);
status = WdfIoTargetSendIoctlSynchronously(
hidTarget,
NULL,
IOCTL_HID_GET_COLLECTION_INFORMATION,
NULL,
&outputDescriptor,
NULL,
NULL
)
上面是发送,我们在驱动中如何进行处理这些IOCTL了,有些IOCTL,已经被WDF封装了,直接成为了驱动对象的一些域了,比如
IRP_MN_START_DEVICE
,IRP_MN_FILTER_RESOURCE_REQUIREMENTS
等。有些我们自己定义的流给应用程序的接口,我们需要在请求对象中获取。调用函数
WdfRequestGetParameters(
IN WDFREQUEST Request,
OUT PWDF_REQUEST_PARAMETERS Parameters
);
请求对象会在队列处理函数中,以参数的形式传给你,所以,你可以得到请求的参数,以确定IOCTL,而做不同的操作。
回忆一下请求参数:
typedef struct _WDF_REQUEST_PARAMETERS {
USHORT Size;
UCHAR MinorFunction;
WDF_REQUEST_TYPE Type;
union {
//
// Parameters for IRP_MJ_CREATE
//
struct {
PIO_SECURITY_CONTEXT SecurityContext;
ULONG Options;
USHORT POINTER_ALIGNMENT FileAttributes;
USHORT ShareAccess;
ULONG POINTER_ALIGNMENT EaLength;
} Create;
//
// Parameters for IRP_MJ_READ
//
struct {
size_t Length;
ULONG POINTER_ALIGNMENT Key;
LONGLONG DeviceOffset;
} Read;
//
// Parameters for IRP_MJ_WRITE
//
struct {
size_t Length;
ULONG POINTER_ALIGNMENT Key;
LONGLONG DeviceOffset;
} Write;
//
// Parameters for IRP_MJ_DEVICE_CONTROL and IRP_MJ_INTERNAL_DEVICE_CONTROL
//
struct {
size_t OutputBufferLength;
size_t POINTER_ALIGNMENT InputBufferLength;
ULONG POINTER_ALIGNMENT IoControlCode;
PVOID Type3InputBuffer;
} DeviceIoControl;
struct {
PVOID Arg1;
PVOID Arg2;
ULONG POINTER_ALIGNMENT IoControlCode;
PVOID Arg4;
} Others;
} Parameters;
} WDF_REQUEST_PARAMETERS, *PWDF_REQUEST_PARAMETERS;
这里,我们就可以很方便的得到控制码进行操作了。
http://blog.youkuaiyun.com/z18_28_19/article/details/8892552
转载自其博客,因为排版较乱,所以重新编辑后发到自己博客记录。