驱动和应用层的三种通信方式Word格式文档下载.docx
《驱动和应用层的三种通信方式Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《驱动和应用层的三种通信方式Word格式文档下载.docx(6页珍藏版)》请在冰豆网上搜索。
输入缓冲区大小
lpOutBuffer,
输出缓冲区地址
nOutBufferSize,
输出缓冲区大小
LPDWORD
lpBytesReturned,
存放返回字节数的指针
LPOVERLAPPED
lpOverlapped
用于异步操作的Overlapped结构体指针
);
dwIoControlCode
要进行操作的控制码。
驱动程序可以通过CTL_CODE宏来组合定义一个控制码,并在IRP_MJ_DEVICE_CONTROL的实现中进行控制码的操作。
在驱动层,irpStack->
Parameters.DeviceIoControl.IoControlCode表示了这个控制码。
IOCTL请求有四种缓冲策略,下面一一介绍。
1、
输入输出缓冲I/O(METHOD_BUFFERED)
2、
直接输入缓冲输出I/O(METHOD_IN_DIRECT)
3、
缓冲输入直接输出I/O(METHOD_OUT_DIRECT)
4、
上面三种方法都不是(METHOD_NEITHER)
为了对这些类型更详细的描述,请看msdn上的解释,我抄录如下:
"
缓冲"
方法(METHOD_BUFFERED)
备注:
在下面的讨论中,"
输入"
表示数据从用户模式的应用程序到驱动程序,"
输出"
表示数据从驱动程序到应用程序。
对于读取请求,I/O
管理器分配一个与用户模式的缓冲区大小相同的系统缓冲区。
IRP
中的
SystemBuffer
字段包含系统地址。
UserBuffer
字段包含初始的用户缓冲区地址。
当完成请求时,I/O
管理器将驱动程序已经提供的数据从系统缓冲区复制到用户缓冲区。
对于写入请求,会分配一个系统缓冲区并将
设置为地址。
用户缓冲区的内容会被复制到系统缓冲区,但是不设置
UserBuffer。
对于
IOCTL
请求,会分配一个容量大小足以包含输入缓冲区或输出缓冲区的系统缓冲区,并将
设置为分配的缓冲区地址。
输入缓冲区中的数据复制到系统缓冲区。
字段设置为用户模式输出缓冲区地址。
内核模式驱动程序应当只使用系统缓冲区,且不应使用
中存储的地址。
IOCTL,驱动程序应当从系统缓冲区获取输入并将输出写入到系统缓冲区。
系统将输出数据从系统缓冲区复制到用户缓冲区。
直接"
方法(METHOD_IN/OUT_DIRECT)
对于读取和写入请求,用户模式缓冲区会被锁定,并且会创建一个内存描述符列表
(MDL)。
MDL
地址会存储在
的
MdlAddress
字段中。
和
均没有任何含义。
但是,驱动程序不应当更改这些字段的值。
请求,如果在
METHOD_IN_DIRECT
METHOD_OUT_DIRECT
中同时有一个输出缓冲区,则分配一个系统缓冲区(SystemBuffer
又有了地址)并将输入数据复制到其中。
如果有一个输出缓冲区,且它被锁定,则会创建
并设置
MdlAddress。
字段没有任何含义。
两者都不"
方法(METHOD_NEITHER)
对于读取和写入请求,UserBuffer
字段被设置为指向初始的用户缓冲区。
不执行任何其他操作。
SystemAddress
没有任何含义。
请求,I/O
管理器将
设置为初始的用户输出缓冲区,而且,它将当前
I/O
栈位置的
Parameters.DeviceIoControl.Type3InputBuffer
设置为用户输入缓冲区。
利用该
方法,由驱动程序来确定如何处理缓冲区:
分配系统缓冲区或创建
MDL。
通常,驱动程序在访问用户数据时不应当将
字段用作地址,即使当用户缓冲区被锁定时也是如此。
这是由于在调用驱动程序时,在系统中可能看不到调用用户的地址空间。
(对于该规则的一个例外是,在最高层驱动程序将
向下传递到较低层的驱动程序之前,它可能需要使用
来复制数据。
)如果使用"
或"
方法,在创建
之后,驱动程序可以使用
MmGetSystemAddressForMdl
函数来获取有效的系统地址以访问用户缓冲区。
在驱动层,依传输类型的不同,输入缓冲区的位置亦不同,见下表。
传输类型
位置
irp->
AssociatedIrp.SystemBuffer
METHOD_BUFFERED
METHOD_NEITHER
irpStack->
Parameters.DeviceIoControl.Type3InputBuffer
在驱动层,依传输类型的不同,输出缓冲区的位置亦不同,见下表。
MdlAddress
UserBuffer
所以只要确定了传输方式后,就可以根据各自的位置来读取和写入数据,从而实现应用层和驱动的通信。
下面看驱动层对ioctl控制码的处理代码:
代码:
//METHOD_OUT_DIREC方式
NTSTATUS
COMM_DirectOutIo(PIRP
Irp,
PIO_STACK_LOCATION
pIoStackIrp,
UINT
*sizeofWrite)
{
status
=
STATUS_UNSUCCESSFUL;
PVOID
pInputBuffer,
pOutputBuffer;
ULONG
outputLength,
inputLength;
DbgPrint("
COMM_DirectOutIo\r\n"
outputLength
pIoStackIrp->
Parameters.DeviceIoControl.OutputBufferLength;
inputLength
Parameters.DeviceIoControl.InputBufferLength;
pInputBuffer
Irp->
AssociatedIrp.SystemBuffer;
pOutputBuffer
NULL;
if(Irp->
MdlAddress)
MmGetSystemAddressForMdlSafe(Irp->
MdlAddress,
NormalPagePriority);
if(pInputBuffer
&
pOutputBuffer)
{
COMM_DirectOutIo
UserModeMessage
'
%s'
pInputBuffer);
RtlCopyMemory(pOutputBuffer,
outputLength);
*sizeofWrite
outputLength;
STATUS_SUCCESS;
}
return
status;
METHOD_IN_DIRECT
COMM_DirectInIo(PIRP
COMM_DirectInIo\r\n"
COMM_DirectInIo
METHOD_BUFFERED
COMM_BufferedIo(PIRP
COMM_BufferedIo\r\n"
COMM_BufferedIo
METHOD_NEITHER
COMM_NeitherIo(PIRP
COMM_NeitherIo\r\n"
Parameters.DeviceIoControl.Type3InputBuffer;
UserBuffer;
COMM_NeitherIo
代码比较简单,都是取得输入的数据,然后把数据直接拷贝到输出,传输给应用层。
应用层的代码:
procedure
TfrmMain.Send_Recv_Data(AInData:
String;
var
AOutData:
IoctlCode:
DWORD);
var
dwReturn:
DWORD;
inData:
array[0..1023]
of
char;
outData:
begin
StrPCopy(inData,
AInData);
if
m_hCommDevice
<
>
0
then
DeviceIoControl(m_hCommDevice,
IoctlCode,
@inData,
Length(inData),
@outData,
Length(outData),
dwReturn,
nil);
AOutData
:
StrPas(@outData);
end;
上面是进行发送和接受的过程。
需要通信,只要如下做:
TfrmMain.
btnDirect_IN_IOClick
(Sender:
TObject);
Send_Recv_Data(Trim(edtDirect_in_in.Text),
outData,
IOCTL_COMM_DIRECT_IN_IO);
edtDirect_in_out.Text
outData;