1.DriverEntry例程,用于驱动对象的创建,第一次添加设备对象的时候调用
#include "private.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, DriverEntry)
#endif
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
WDF_DRIVER_CONFIG config;
NTSTATUS status;
WDF_DRIVER_CONFIG_INIT(&config, CharSample_EvtDeviceAdd);//设置Add例程
status = WdfDriverCreate(//创建驱动对象
DriverObject,
RegistryPath,
WDF_NO_OBJECT_ATTRIBUTES,
&config,
WDF_NO_HANDLE
);
return status;
}
2.
EvtDriverDeviceAdd例程,用于创建设备,创建IO队列,创建GUID接口。
#include "private.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, CharSample_EvtDeviceAdd)
#endif
NTSTATUS
CharSample_EvtDeviceAdd(
IN WDFDRIVER Driver,
IN PWDFDEVICE_INIT DeviceInit
)
{
NTSTATUS status;
WDFDEVICE device;
WDF_IO_QUEUE_CONFIG ioQueueConfig;
//例程的首句PAGED_CODE,表示该例程的代码占用分页内存。
//只能在PASSIVE_LEVEL中断级别调用该例程,否则会蓝屏。
//如不说明,则占用系统的非分页内存,要珍惜使用。
PAGED_CODE();
//创建设备,没有对象属性和设备对象环境变量结构
status = WdfDeviceCreate(&DeviceInit, WDF_NO_OBJECT_ATTRIBUTES, &device);
if (!NT_SUCCESS(status)) {
return status;
}
//初始化缺省队列配置,设置I/O请求分发处理方式为串行。
//对这个实例而言,选择串行或并行都可以,但不能选手工。
WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig, WdfIoQueueDispatchSequential);
//设置EvtIoDeviceControl例程,处理应用程序的DeviceIoControl()函数调用
ioQueueConfig.EvtIoDeviceControl = CharSample_EvtIoDeviceControl;
//创建队列
status = WdfIoQueueCreate(device, &ioQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, NULL);
if (!NT_SUCCESS(status)) {
return status;
}
//创建设备GUID接口
status = WdfDeviceCreateDeviceInterface(device, (LPGUID) &CharSample_DEVINTERFACE_GUID, NULL);
if (!NT_SUCCESS(status)) {
}
return status;
}
3.完成DeviceControl例程,用于应用层与驱动层的通信。
#include "private.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, CharSample_EvtIoDeviceControl)
#endif
VOID
CharSample_EvtIoDeviceControl(
IN WDFQUEUE Queue,
IN WDFREQUEST Request,
IN size_t OutputBufferLength,
IN size_t InputBufferLength,
IN ULONG IoControlCode
)
{
NTSTATUS status;
PVOID buffer;
CHAR n,c[]="零一二三四五六七八九";
PAGED_CODE();
switch(IoControlCode) {
case CharSample_IOCTL_800:
if (InputBufferLength == 0 || OutputBufferLength < 2)
{ //检查输入、输出参数有效性
WdfRequestComplete(Request, STATUS_INVALID_PARAMETER);
}
else
{
//输入缓冲区地址可通过调用WdfRequestRetrieveInputBuffer函数获得
//输出缓冲区地址可通过调用WdfRequestRetrieveOutputBuffer函数获得
//获取输入缓冲区地址buffer
//要求1字节空间
status = WdfRequestRetrieveInputBuffer(Request, 1, &buffer, NULL);
if (!NT_SUCCESS(status)) {
WdfRequestComplete(Request, STATUS_UNSUCCESSFUL);
break;
}
//这里buffer表示输入缓冲区地址
//输入n=应用程序传给驱动程序的数字ASCII码
n = *(CHAR *)buffer;
if ((n>='0') && (n<='9'))
{ //若为数字,则处理
n-='0'; //n=数字(0-9)
//获取输出缓冲区地址buffer
status = WdfRequestRetrieveOutputBuffer(Request, 2, &buffer, NULL);
if (!NT_SUCCESS(status)) {
WdfRequestComplete(Request, STATUS_UNSUCCESSFUL);
break;
}
//这里buffer表示输出缓冲区地址
//输出:从中文数组c[]中取出对应的数字的中文码,拷贝到输出缓冲区
strncpy((PCHAR)buffer,&c[n*2],2);
//完成I/O请求,驱动程序传给应用程序的数据长度为2字节(一个中文)
WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, 2);
}
else //否则返回无效参数
WdfRequestComplete(Request, STATUS_INVALID_PARAMETER);
}
break;
default :
status = STATUS_INVALID_DEVICE_REQUEST;
WdfRequestCompleteWithInformation(Request, status, 0);
break;
}
return;
}
4.完成应用层程序的编写。
// Test_CharSample.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include
#include
#include
#include
#include
#include
#include "public.h"
PCHAR
GetDevicePath(
IN LPGUID InterfaceGuid
);
int main(int argc, char* argv[])
{
PCHAR DevicePath;
HANDLE hDevice = INVALID_HANDLE_VALUE;
printf("Application Test_CharSample starting...\n");
DevicePath = GetDevicePath((LPGUID)&CharSample_DEVINTERFACE_GUID);
hDevice = CreateFile(DevicePath,
GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL );
if (hDevice == INVALID_HANDLE_VALUE) {
printf("ERROR opening device: (%0x) returned from CreateFile\n", GetLastError());
return 0;
}
printf("OK.\n");
CHAR bufInput[1]; // Input to device
CHAR bufOutput[2]; // Output from device
ULONG nOutput; // Count written to bufOutput
printf("请输入数字(0-9)\n");
l0: bufInput[0] = _getch();
if ((bufInput[0]<'0') || (bufInput[0]>'9')) goto l0;
_putch(bufInput[0]);
// Call device IO Control interface (CharSample_IOCTL_800) in driver
if (!DeviceIoControl(hDevice,
CharSample_IOCTL_800,
bufInput,
1,
bufOutput,
2,
&nOutput,
NULL)
)
{
printf("ERROR: DeviceIoControl returns %0x.", GetLastError());
goto exit;
}
printf(":");
_putch(bufOutput[0]);
_putch(bufOutput[1]);
printf("\n");
exit:
if (hDevice != INVALID_HANDLE_VALUE) {
CloseHandle(hDevice);
}
return 0;
}
//获取设备符号链接路径
PCHAR
GetDevicePath(
IN LPGUID InterfaceGuid
)
{
HDEVINFO HardwareDeviceInfo;
SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData = NULL;
ULONG Length, RequiredLength = 0;
BOOL bResult;
HardwareDeviceInfo = SetupDiGetClassDevs(
InterfaceGuid,
NULL,
NULL,
(DIGCF_PRESENT | DIGCF_DEVICEINTERFACE));
if (HardwareDeviceInfo == INVALID_HANDLE_VALUE) {
printf("SetupDiGetClassDevs failed!\n");
exit(1);
}
DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
bResult = SetupDiEnumDeviceInterfaces(HardwareDeviceInfo,
0,
InterfaceGuid,
0,
&DeviceInterfaceData);
if (bResult == FALSE) {
printf("SetupDiEnumDeviceInterfaces failed.\n");
SetupDiDestroyDeviceInfoList(HardwareDeviceInfo);
exit(1);
}
SetupDiGetDeviceInterfaceDetail(
HardwareDeviceInfo,
&DeviceInterfaceData,
NULL,
0,
&RequiredLength,
NULL
);
DeviceInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA) LocalAlloc(LMEM_FIXED, RequiredLength);
if (DeviceInterfaceDetailData == NULL) {
SetupDiDestroyDeviceInfoList(HardwareDeviceInfo);
printf("Failed to allocate memory.\n");
exit(1);
}
DeviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
Length = RequiredLength;
bResult = SetupDiGetDeviceInterfaceDetail(
HardwareDeviceInfo,
&DeviceInterfaceData,
DeviceInterfaceDetailData,
Length,
&RequiredLength,
NULL);
if (bResult == FALSE) {
printf("Error in SetupDiGetDeviceInterfaceDetail\n");
SetupDiDestroyDeviceInfoList(HardwareDeviceInfo);
LocalFree(DeviceInterfaceDetailData);
exit(1);
}
return DeviceInterfaceDetailData->DevicePath;
}