源文件Driver.h和Driver.cpp清单如下,以下程序根据我自己的理解进行了适当注释,有不对之处请谅解:
/************************************************************************
* 文件名称:Driver.h
* 作 者:张帆
* 完成日期:2007-11-1
*************************************************************************/
//只要在头文件的最开始加入这条指令就能够保证头文件被编译一次
#pragma once
/*
__cplusplus是cpp中的自定义宏,为了在C++代码中调用用C写成的库文件,就需要用extern "C"来告诉编译器:
这是一个用C写成的库文件,请用C的方式来编译、链接它们。
*/
#ifdef __cplusplus
extern "C"
{
#endif
#include <NTDDK.h>
#ifdef __cplusplus
}
#endif
//代码以分页方式分配存储空间
#define PAGEDCODE code_seg("PAGE")
//恢复编译开始时的分配方式
#define LOCKEDCODE code_seg()
//代码加载时需要载入内存,当加载成功后此代码从内存中卸载掉
#define INITCODE code_seg("INIT")
//以下针对数据变量的,与上面针对代码的相似。
#define PAGEDDATA data_seg("PAGE")
#define LOCKEDDATA data_seg()
#define INITDATA data_seg("INIT")
#define arraysize(p) (sizeof(p)/sizeof((p)[0]))
//设备扩展结构体,用户自定义其中的字段,根据实际要求字段个数不一样。
typedef struct _DEVICE_EXTENSION {
PDEVICE_OBJECT pDevice;
UNICODE_STRING ustrDeviceName; //设备名称
UNICODE_STRING ustrSymLinkName; //符号链接名
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
// 函数声明
NTSTATUS CreateDevice (IN PDRIVER_OBJECT pDriverObject);
VOID HelloDDKUnload (IN PDRIVER_OBJECT pDriverObject);
NTSTATUS HelloDDKDispatchRoutine(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp);
-------------------------------------------------------------------------------------------------------------------
/************************************************************************
* 文件名称:Driver.cpp
* 作 者:张帆
* 完成日期:2007-11-1
*************************************************************************/
#include "Driver.h"
/************************************************************************
* 函数名称:DriverEntry
* 功能描述:初始化驱动程序,定位和申请硬件资源,创建内核对象
* 参数列表:
pDriverObject:从I/O管理器中传进来的驱动对象
pRegistryPath:驱动程序在注册表的中的路径
* 返回 值:返回初始化驱动状态
*************************************************************************/
#pragma INITCODE
extern "C" NTSTATUS DriverEntry ( //以C方式而不是C++方式编译此函数
IN PDRIVER_OBJECT pDriverObject,
IN PUNICODE_STRING pRegistryPath )
{
NTSTATUS status;
//用于打印调试信息。在Checked版本中,编译器将用DbgPrint代替它,在Free版中,则不执行任何操作。
KdPrint(("Enter DriverEntry\n"));
//向I/O管理器注册回调函数(或称派遣例程)。
/*
回调函数是程序员定义的,由操作系统调用而不是由驱动程序调用。程序员需要把这些函数的地址在DriverEntry函数中告诉操作系统即注册到操作系统。
操作系统将在适当的时候调用相应的回调函数。
*/
pDriverObject->DriverUnload = HelloDDKUnload;
pDriverObject->MajorFunction[IRP_MJ_CREATE] = HelloDDKDispatchRoutine;
pDriverObject->MajorFunction[IRP_MJ_CLOSE] = HelloDDKDispatchRoutine;
pDriverObject->MajorFunction[IRP_MJ_WRITE] = HelloDDKDispatchRoutine;
pDriverObject->MajorFunction[IRP_MJ_READ] = HelloDDKDispatchRoutine;
//创建驱动设备对象
status = CreateDevice(pDriverObject);
KdPrint(("DriverEntry end\n"));
return status;
}
/************************************************************************
* 函数名称:CreateDevice
* 功能描述:初始化设备对象
* 参数列表:
pDriverObject:从I/O管理器中传进来的驱动程序对象
* 返回 值:返回初始化状态
*************************************************************************/
#pragma INITCODE
NTSTATUS CreateDevice (
IN PDRIVER_OBJECT pDriverObject)
{
NTSTATUS status;
PDEVICE_OBJECT pDevObj;
PDEVICE_EXTENSION pDevExt;
//创建设备名称,这是一个Unicode字符串
UNICODE_STRING devName;
RtlInitUnicodeString(&devName,L"\\Device\\MyDDKDevice");
//创建设备对象
status = IoCreateDevice( pDriverObject,
sizeof(DEVICE_EXTENSION),
&(UNICODE_STRING)devName, //设备名称
FILE_DEVICE_UNKNOWN, //设备类型
0, //设备特性:可安全地打开(0)、可读、可写等
TRUE, //独占设备
&pDevObj );//设备对象保存在pDevObj中
//判断上面创建设备对象的工作是否成功。
if (!NT_SUCCESS(status))
return status;
//读写设备数据的方式:缓冲区方式
pDevObj->Flags |= DO_BUFFERED_IO;
//填写设备扩展结构体
pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;
pDevExt->pDevice = pDevObj;
pDevExt->ustrDeviceName = devName;
//创建符号链接。应用程序中看不到设备名称,驱动程序暴露一个符号链接给应用程序,而符号链接指向设备名称。
UNICODE_STRING symLinkName;
RtlInitUnicodeString(&symLinkName,L"\\??\\HelloDDK");
pDevExt->ustrSymLinkName = symLinkName;
status = IoCreateSymbolicLink( &symLinkName,&devName );
//如果创建符号链接失败,则需要把设备对象删除。
if (!NT_SUCCESS(status))
{
IoDeleteDevice( pDevObj );
return status;
}
//返回设备创建成功的标志。
return STATUS_SUCCESS;
}
/************************************************************************
* 函数名称:HelloDDKUnload
* 功能描述:负责驱动程序的卸载操作
* 参数列表:
pDriverObject:驱动对象
* 返回 值:返回状态
*************************************************************************/
#pragma PAGEDCODE
VOID HelloDDKUnload (IN PDRIVER_OBJECT pDriverObject)
{
PDEVICE_OBJECT pNextObj;
KdPrint(("Enter DriverUnload\n"));
//遍历系统中这个驱动程序对应所有的的设备,然后删除设备对象及符号链接
pNextObj = pDriverObject->DeviceObject;
while (pNextObj != NULL)
{
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
pNextObj->DeviceExtension;
//删除符号链接
UNICODE_STRING pLinkName = pDevExt->ustrSymLinkName;
IoDeleteSymbolicLink(&pLinkName);
//删除设备
pNextObj = pNextObj->NextDevice;
IoDeleteDevice( pDevExt->pDevice );
}
}
/************************************************************************
* 函数名称:HelloDDKDispatchRoutine
* 功能描述:对读IRP进行处理
* 参数列表:
pDevObj:功能设备对象
pIrp:从IO请求包
* 返回 值:返回状态
*************************************************************************/
#pragma PAGEDCODE
NTSTATUS HelloDDKDispatchRoutine(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp)
{
KdPrint(("Enter HelloDDKDispatchRoutine\n"));
NTSTATUS status = STATUS_SUCCESS; //成功
// 完成IRP
pIrp->IoStatus.Status = status;
pIrp->IoStatus.Information = 0; // 读写的字节数据,这里无实际意义。
IoCompleteRequest( pIrp, IO_NO_INCREMENT ); //完成此IRP
KdPrint(("Leave HelloDDKDispatchRoutine\n"));
return status;
}
如下这篇文章也是有关VC环境下的DDK编译,值得参考。http://blog.youkuaiyun.com/linuxpgy/archive/2008/05/11/2434572.aspx