主要实现的功能是:
通过调用驱动,实现相应的功能,并把结果返回给调用者
(1)这里是通过应用程序出入两个参数a和b,
(2)然后调用驱动,在驱动里面实现这里个数的相加
(3)驱动把相加的结果作为参数通过缓冲区返回给应用程序
1.缓冲区内存模式IOCTL
/*************************************************************exe部分***************************************************/
/********************************ioctl_test.h*************************/
#ifndef CTL_CODE#pragma message("\n\n --------EXE模式 . Include winioctl.h ")
#include<winioctl.h> // <NTDDK.H> <WDM.H>包含CTL_CODE
#else
#pragma message("\n\n --------SYS模式 . Include winioctl.h ")
#endif
#define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,\
0x800, METHOD_BUFFERED,FILE_ANY_ACCESS)
#define sub_code CTL_CODE(FILE_DEVICE_UNKNOWN,\
0x801, METHOD_BUFFERED,FILE_ANY_ACCESS)
/********************************************************************/
/*****************************ioctl_test.cpp*************************/
#include "stdafx.h"#include <windows.h>
#include "ioctl_test.h"
int Add(HANDLE hDevice,int a,int b)
{
int inputBuffer[2];
int OutBuf;
DWORD dwWrite;
inputBuffer[0]=a;
inputBuffer[1]=b;
DeviceIoControl(
hDevice, // handle to device
add_code, // operation control code
&inputBuffer, // input data buffer
8, // size of input data buffer
&OutBuf, // output data buffer
4, // size of output data buffer
&dwWrite, // byte count
NULL); // overlapped information
return OutBuf; //return the result
}
int main(int argc, char* argv[])
{
HANDLE hDevice = CreateFile(
"\\\\.\\junHelloDDK", // file name
GENERIC_READ | GENERIC_WRITE, // access mode
0, // share mode
NULL, // SD
OPEN_EXISTING, // how to create
FILE_ATTRIBUTE_NORMAL, // file attributes
NULL); // handle to template file
printf("start\n");
if (hDevice == INVALID_HANDLE_VALUE)
{
printf("调用CreateFile失败 %s with Win32 error code: %d\n","MyDriver", GetLastError());
getchar(); //suspend
return -1;
}
int a = 55;
int b = 33;
int r =Add(hDevice,a,b);
printf("%d+%d=%d\n",a,b,r);
CloseHandle(hDevice);
getchar(); //suspend
return 0;
}
/********************************************************************/
/**********************************************************************************************************************/
/*************************************************************sys部分***************************************************/
只贴处理IRP_MJ_DEVICE_CONTROL部分:
NTSTATUS HelloDDKDispatchRoutine(IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp)
{
NTSTATUS status = STATUS_SUCCESS;
KdPrint(("进入派遣函数 ******\n"));
ULONG info = 0;
//得到当前堆栈
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
UCHAR mf = stack->MajorFunction; //区分IRP
switch(mf)
{
case IRP_MJ_DEVICE_CONTROL:
{
KdPrint(("Enter myDriver_DeviceIOControl\n"));
//得到输入缓冲区大小
ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength;
//得到输出缓冲区大小
ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength;
//得到IOCTL码
ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;
switch(code)
{
case add_code:
{
KdPrint(("add_code....\n"));
//缓冲区方式IOCTL
//显示输入缓冲区数据
int *InputBuffer = (int*) pIrp->AssociatedIrp.SystemBuffer;
int a,b,sum;
a = InputBuffer[0];
b = InputBuffer[1];
KdPrint(("a=%d,b=%d\n",a,b));
sum = a+b;
int *OutputBuffer = (int *)pIrp->AssociatedIrp.SystemBuffer;
*OutputBuffer = sum;
KdPrint(("a+b=%d\n",sum));
//设置实际操作输出缓冲区长度
info = cbout;
break;
}
case sub_code:
{
info = cbout;
break;
}
default:
status = STATUS_INVALID_VARIANT;
}
break;
}
case IRP_MJ_CREATE:
case IRP_MJ_CLOSE:
case IRP_MJ_WRITE:
case IRP_MJ_READ:
break;
}
// 完成IRP
pIrp->IoStatus.Status = status; // 设置IRP的状态为成功
pIrp->IoStatus.Information = info; // 设置操作的字节数为0
IoCompleteRequest( pIrp, IO_NO_INCREMENT ); // 指示完成此IRP
KdPrint(("离开派遣函数......\n")); // 打印调试信息
return status; // 返回成功
}
2.直接内存模式IOCTL
在1.缓冲区内存模式IOCTL的基础上需要改动的地方:
/************************************************************exe部分***************************************************/
/********************************ioctl_test.h*************************/
将 METHOD_BUFFERED 改为 METHOD_IN_DIRECT
/************************************************************sys部分***************************************************/
将
int *OutputBuffer = (int *)pIrp->AssociatedIrp.SystemBuffer;
改为
int *OutputBuffer = (int *)MmGetSystemAddressForMdlSafe(pIrp->MdlAddress,NormalPagePriority);
3.其他内存模式IOCTL
在1.缓冲区内存模式IOCTL的基础上需要改动的地方:
/************************************************************exe部分***************************************************/
/********************************ioctl_test.h*************************/
将 METHOD_BUFFERED 改为 METHOD_NEITHER
/************************************************************sys部分***************************************************/
NTSTATUS HelloDDKDispatchRoutine(IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp)
{
NTSTATUS status = STATUS_SUCCESS;
KdPrint(("进入派遣函数 ******\n"));
ULONG info = 0;
//得到当前堆栈
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
UCHAR mf = stack->MajorFunction; //区分IRP
switch(mf)
{
case IRP_MJ_DEVICE_CONTROL:
{
KdPrint(("Enter myDriver_DeviceIOControl\n"));
//得到输入缓冲区大小
ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength;
//得到输出缓冲区大小
ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength;
//得到IOCTL码
ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;
switch(code)
{
case add_code:
{
KdPrint(("add_code....\n"));
//缓冲区方式IOCTL
//显示输入缓冲区数据
int *UserInputBuffer = (int*) stack->Parameters.DeviceIoControl.Type3InputBuffer;
KdPrint(("UserInputBuffer:0x%0X \n",UserInputBuffer));
//得到用户模式地址
int *UserOutputBuffer = (int *)pIrp->UserBuffer;
KdPrint(("UserOutputBuffer:0x%0X \n",UserOutputBuffer));
__try
{
KdPrint(("Entry __try block \n"));
//判断指针是否可读
ProbeForRead(UserInputBuffer,cbin,4);
//显示缓冲区内容
int a,b,sum;
a = UserInputBuffer[0];
b = UserInputBuffer[1];
KdPrint(("a=%d,b=%d\n",a,b));
sum = a+b;
KdPrint(("a+b=%d\n",sum));
sum += 3;
//判断指针是否可写
ProbeForWrite(UserOutputBuffer,cbout,4);
//操作输出缓冲区
*UserOutputBuffer = sum;
info = cbout;
KdPrint(("Leave __try block \n"));
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
KdPrint(("发生异常 缓冲区不可读 或 写 \n"));
status = STATUS_UNSUCCESSFUL;
}
//设置实际操作输出缓冲区长度
info = cbout;
break;
}
case sub_code:
{
info = cbout;
break;
}
default:
status = STATUS_INVALID_VARIANT;
}
break;
}
case IRP_MJ_CREATE:
case IRP_MJ_CLOSE:
case IRP_MJ_WRITE:
case IRP_MJ_READ:
break;
}
// 完成IRP
pIrp->IoStatus.Status = status; // 设置IRP的状态为成功
pIrp->IoStatus.Information = info; // 设置操作的字节数为0
IoCompleteRequest( pIrp, IO_NO_INCREMENT ); // 指示完成此IRP
KdPrint(("离开派遣函数......\n")); // 打印调试信息
return status; // 返回成功
}