在笔者上一篇文章《驱动开发:应用DeviceIoContro开发模板》
简单为大家介绍了如何使用DeviceIoContro
模板快速创建一个驱动开发通信案例,但是该案例过于简单也无法独立加载运行,本章将继续延申这个知识点,通过封装一套标准通用模板来实现驱动通信中的常用传递方式,这其中包括了如何传递字符串,传递整数,传递数组,传递结构体等方法。可以说如果你能掌握本章模板精讲的内容基本上市面上的功能都可以使用本方法进行通信。
首先定义驱动功能号和名字,提供接口给应用程序调用。
#define IOCTL_IO_Msg CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_IO_TEST CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_IO_Array CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_IO_STRUCT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x803, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_IO_String CTL_CODE(FILE_DEVICE_UNKNOWN, 0x804, METHOD_BUFFERED, FILE_ANY_ACCESS)
IOCTL_IO_TEST 传递整数: 派遣例程用于传递整数类型,首先客户端通过DriveControl.IoControl
将数据通过变量input
传入到内核中,并等待返回,如果返回了结果则outpot
里存储的就是返回结果,ref_len
则是返回长度。
看看客户端如何接收这个数据的传递。
// 传入x参数,返回到y中,返回长度为z
DWORD input = 100, output = 0, ref_len = 0;
DriveControl.IoControl(IOCTL_IO_TEST, &input, sizeof(input), &output, sizeof(output), &ref_len);
std::cout << "传入参数: " << input << std::endl;
std::cout << "输出参数: " << output << std::endl;
std::cout << "参数长度: " << ref_len << std::endl;
对于驱动中我们不需要做任何操作只需要通过memcpy(&dw, pIoBuffer, sizeof(DWORD))
得到缓冲区内的数据,对该数据dw++
递增,最后通过memcpy(pIoBuffer, &dw, sizeof(DWORD))
再将数据写回到应用层。
case IOCTL_IO_TEST:
{
DWORD dw = 0;
// 得到输入参数
memcpy(&dw, pIoBuffer, sizeof(DWORD));
// 对输入参数进行处理
dw++;
// 设置输出参数
memcpy(pIoBuffer, &dw, sizeof(DWORD));
// 返回通信状态
status = STATUS_SUCCESS;
break;
}
IOCTL_IO_Array 传递数组: 派遣例程用于传递数组类型,首先定义数组MyArray
将数组首地址
以及数组长度
传递到内核中,内核收到首地址以及长度后通过uInSize / sizeof(int)
得到每一个元素的长度,最后循环输出元素即可。
// --------------------------------------------------------------------------
// 应用层
// --------------------------------------------------------------------------
// 传入数组
int MyArray[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
int array_count = 10 * sizeof(int);
DriveControl.IoControl(IOCTL_IO_Array, &MyArray, array_count, 0, 0, 0);
// --------------------------------------------------------------------------
// 内核层
// --------------------------------------------------------------------------
// 输出一个数组
case IOCTL_IO_Array:
{
int *ArrayPtr = (int *)pIoBuffer;
int count = uInSize / sizeof(int);
for (int x = 0; x < count; x++)
{
DbgPrint("计数器: %d \n", ArrayPtr[x]);
}
status = STATUS_SUCCESS;
break;
}
IOCTL_IO_STRUCT 传递结构: 结构体的传输与数组类似,仅仅只是在接收到数据后对其进行一定的转换即可,应用层只需要DriveControl.IoControl
发送send_ptr
指针并等待回传recv_ptr即可,最后将得到的结果直接输出,而内核层收到数据后仅仅也只需要
(MyData *)pIoBuffer将数据转为一个指针即可操作这片区域,当操作完成时以同样的方式
memcpy(pIoBuffer, &send_data, sizeof(MyData))`返回一个结构体给应用层。
// --------------------------------------------------------------------------
// 应用层
// --------------------------------------------------------------------------
// 传入一个结构体,返回结构体
MyData send_ptr, recv_ptr;
DWORD dwSize = 0;
memset(send_ptr.szUname, 0, 1024);
memset(recv_ptr.szUname, 0, 1024);
send_ptr.uuid = 1001;
strcpy(send_ptr.szUname, "lyshark");
// 派遣命令
DriveControl.IoControl(IOCTL_IO_STRUCT, &send_ptr, sizeof(send_ptr), &