Windows 驱动开发笔记(四)

Windows 驱动开发笔记(四)
一个设备驱动通常是要能接受用户控制的。为了能够完成用户的调用,就需编写各种响应例程。这就是驱动中的I/O处理例程(Dispatch例程)。响应什么"事件"就注册对应的例程。如:响应CreateFile Windows API 就要编写一个响应[IRP_MJ_CREATE]的例程。当用户发出CreateFile调用时就会生成一个IRP这个IRP的MajorFunction的值就是[IRP_MJ_CREATE]。写驱动其中的一项任务就是编写各种Dispatch例程。
一个Dispatch例程通过系统传递进来的两个指针(DeviceObject和pIrp)来了解调用信息。也通过操作这两个对象中的某些域来向系统报告完成情况或要求系统执行什么操作。理解IRP中的域也是编写驱动的必要条件。下面我们简单的说明一下IRP。
IRP的域比较多,但是需要我们操作的不是很多。简单的有:
 :
IO_STATUS_BLOCK IoStatus         ;包含I/O请求的状态
PVOID AssociatedIrp.SystemBuffer ;如果执行缓冲区I/O,这个指针指向系统缓冲区
PMDL MdlAddress        ;如果直接I/O,这个指针指向用户缓冲区的存储器描述符表
PVOID UserBuffer        ;I/O缓冲区的用户空间地址
 :

任何内核模式程序在创建一个IRP时,同时还创建了一个与之关联的IO_STACK_LOCATION结构数组:数组中的每个堆栈单元都对应一个将处理该IRP的驱动程序,另外还有一个堆栈单元供IRP的创建者使用。需要了解IRP堆栈的域有:
IRP堆栈:
 :
UCHAR MajorFunction   ;指示IRP_MJ_XXX派遣例程
UCHAR MinorFunction   ;指示次要的IRP_MJ_XXX派遣例程,一般文件系统和SCSI驱动程序使用它
 :
用要使用一个设备,那么就要能找到代表这个设备的对象。也要知道这个设备使用那些驱动程序。这就是“驱动程序对象”和“设备对象”。简单的解释一下。驱动程序对象,就是记录着驱动程序入口和属性数据的变量。设备对象就是记录设备的特性、设备队列地址(存放生成的IRP)、设备缓冲区等数据的变量。用户要操作设备就要定位到对应的设备对象。怎么样找到需要操作的设备对象呢?这个就要给这个设备对象起一个名字。通过这个名字找到这个对象(设备对象的名字管理很复杂,暂时先不讨论)设备对象由驱动程序创建。下面我们给出一个例子:
hello.c文件

#ifndef __HELLOWORLD_C__
#define __HELLOWORLD_C__

#define DEBUGMSG

#include "Hello.h"

//驱动入口
NTSTATUS DriverEntry (IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)
{
    NTSTATUS ntStatus=STATUS_SUCCESS;
    PDEVICE_OBJECT lpDeviceObject=NULL;   //指向设备对象的指针
    UNICODE_STRING DeviceNameString;      //设备名称
    UNICODE_STRING DeviceLinkString;      //符号连接

    //调试信息
    #ifdef DEBUGMSG
           DbgPrint("Starting DriverEntry()/n");
    #endif

    RtlInitUnicodeString(&DeviceNameString,NT_DEVICE_NAME);  //初始化Unicode字符串

    //创建设备
    ntStatus=IoCreateDevice(DriverObject,0,&DeviceNameString,FILE_DEVICE_UNKNOWN,
                            0,FALSE,&lpDeviceObject);

    //使用NT_SUCCESS宏检测函数调用是否成功
    if (!NT_SUCCESS(ntStatus))
    {
        #ifdef DEBUGMSG
               DbgPrint("Error IoCreateDevice()/n");
        #endif
        goto Error;
    }

    RtlInitUnicodeString(&DeviceLinkString,DOS_DEVICE_NAME);

    //创建符号连接
    ntStatus=IoCreateSymbolicLink(&DeviceLinkString,&DeviceNameString);

    if (!NT_SUCCESS(ntStatus))
    {
        #ifdef DEBUGMSG
               DbgPrint("Error IoCreateSymbolicLink()/n");
        #endif
        goto Error;
    }

    //设置IRP派遣例程和卸载例程
    DriverObject->MajorFunction[IRP_MJ_CREATE]=HelloCreateDispatch;
    DriverObject->MajorFunction[IRP_MJ_CLOSE]=HelloCloseDispatch;
    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]=HelloControlDispatch;
    DriverObject->DriverUnload=HelloWorldUnLoad;

    return ntStatus;

    Error:
          #ifdef DEBUGMSG
                 DbgPrint("Error DriverEntry()/n");
          #endif

          return ntStatus;
}
//打开设备例程
NTSTATUS HelloCreateDispatch (IN PDEVICE_OBJECT DeviceObject,IN PIRP pIrp)
{
    NTSTATUS ntStatus=STATUS_SUCCESS;
    ULONG IoControlCodes=0;             //I/O控制代码
    PIO_STACK_LOCATION IrpStack=NULL;   //IRP堆栈

    //设置IRP状态
    pIrp->IoStatus.Status=STATUS_SUCCESS;
    pIrp->IoStatus.Information=0;

    #ifdef DEBUGMSG
           DbgPrint("Starting HelloCreateDispatch()/n");
    #endif

    IrpStack=IoGetCurrentIrpStackLocation(pIrp);    //得到当前调用者的IRP
    #ifdef DEBUGMSG
           DbgPrint("IRP_MJ_CREATE/n");
    #endif
 ntStatus=pIrp->IoStatus.Status;

    IoCompleteRequest(pIrp,IO_NO_INCREMENT);

    return ntStatus;
}
//关闭例程
NTSTATUS HelloCloseDispatch (IN PDEVICE_OBJECT DeviceObject,IN PIRP pIrp)
{
    NTSTATUS ntStatus=STATUS_SUCCESS;
    ULONG IoControlCodes=0;             //I/O控制代码
    PIO_STACK_LOCATION IrpStack=NULL;   //IRP堆栈

    //设置IRP状态
    pIrp->IoStatus.Status=STATUS_SUCCESS;
    pIrp->IoStatus.Information=0;

    #ifdef DEBUGMSG
           DbgPrint("Starting HelloCloseDispatch()/n");
    #endif

    IrpStack=IoGetCurrentIrpStackLocation(pIrp); //得到当前调用者的IRP

    #ifdef DEBUGMSG
           DbgPrint("IRP_MJ_CLOSE/n");
    #endif

 ntStatus=pIrp->IoStatus.Status;

    IoCompleteRequest(pIrp,IO_NO_INCREMENT);

    return ntStatus;
}
//控制例程
NTSTATUS HelloControlDispatch (IN PDEVICE_OBJECT DeviceObject,IN PIRP pIrp)
{
    NTSTATUS ntStatus=STATUS_SUCCESS;
    ULONG IoControlCodes=0;             //I/O控制代码
    PIO_STACK_LOCATION IrpStack=NULL;   //IRP堆栈

    //设置IRP状态
    pIrp->IoStatus.Status=STATUS_SUCCESS;
    pIrp->IoStatus.Information=0;

    #ifdef DEBUGMSG
           DbgPrint("Starting HelloControlDispatch()/n");
    #endif

    IrpStack=IoGetCurrentIrpStackLocation(pIrp);    //得到当前调用者的IRP
  
 //取得I/O控制代码
    IoControlCodes=IrpStack->Parameters.DeviceIoControl.IoControlCode;

 switch (IoControlCodes)
 {
    //启动
       case START_HELLPWORLD:
            DbgPrint("Starting /"Hello World/"/n");
            break;
       //停止
       case STOP_HELLPWORLD:
            DbgPrint("Stoping /"Hello World/"/n");
            break;
    default:
       DbgPrint("Invalid Parameter /"Hello World/"/n");
            pIrp->IoStatus.Status=STATUS_INVALID_PARAMETER;
            break;
    }

 ntStatus=pIrp->IoStatus.Status;

    IoCompleteRequest(pIrp,IO_NO_INCREMENT);

    return ntStatus;
}

VOID HelloWorldUnLoad (IN PDRIVER_OBJECT DriverObject)
{
     UNICODE_STRING DeviceLinkString;
     PDEVICE_OBJECT DeviceObjectTemp1=NULL;
     PDEVICE_OBJECT DeviceObjectTemp2=NULL;

     #ifdef DEBUGMSG
            DbgPrint("Starting HelloWorldUnLoad()/n");
     #endif

     RtlInitUnicodeString(&DeviceLinkString,DOS_DEVICE_NAME);
     IoDeleteSymbolicLink(&DeviceLinkString);  //删除符号连接

     if (DriverObject)
     {
         DeviceObjectTemp1=DriverObject->DeviceObject;

         //删除设备
         while (DeviceObjectTemp1)
         {
                DeviceObjectTemp2=DeviceObjectTemp1;
                DeviceObjectTemp1=DeviceObjectTemp1->NextDevice;
                IoDeleteDevice(DeviceObjectTemp2);
         }
     }
}

#endif

-----------------------------------------------------------------------------------------
hello.h文件


#ifndef __HELLOWORLD_H__
#define __HELLOWORLD_H__

#include <ntddk.h>

#define DEVICE_HELLO_INDEX 0x860

#define START_HELLPWORLD CTL_CODE(FILE_DEVICE_UNKNOWN,DEVICE_HELLO_INDEX,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define STOP_HELLPWORLD CTL_CODE(FILE_DEVICE_UNKNOWN,DEVICE_HELLO_INDEX+1,METHOD_BUFFERED,FILE_ANY_ACCESS)

#define NT_DEVICE_NAME L"//Device//hello"        //设备名称
#define DOS_DEVICE_NAME L"//DosDevices//hello"   //符号连接

NTSTATUS HelloCreateDispatch (IN PDEVICE_OBJECT DeviceObject,IN PIRP pIrp);
NTSTATUS HelloCloseDispatch (IN PDEVICE_OBJECT DeviceObject,IN PIRP pIrp);
NTSTATUS HelloControlDispatch (IN PDEVICE_OBJECT DeviceObject,IN PIRP pIrp);

VOID HelloWorldUnLoad (IN PDRIVER_OBJECT DriverObject);

#endif
------------------------------------------------------------------------------------------
helloctl.c 文件

#define DEBUGMSG

#include <windows.h>
#include <winioctl.h>
#include <stdio.h>

#define DEVICE_HELLO_INDEX 0x860

#define START_HELLPWORLD CTL_CODE(FILE_DEVICE_UNKNOWN,DEVICE_HELLO_INDEX,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define STOP_HELLPWORLD CTL_CODE(FILE_DEVICE_UNKNOWN,DEVICE_HELLO_INDEX+1,METHOD_BUFFERED,FILE_ANY_ACCESS)

#define erron GetLastError()

#define MY_DEVICE_NAME ".//hello"

#define MY_DEVICE_START "-start"
#define MY_DEVICE_STOP "-stop"

BOOL DriverControl (TCHAR *Maik);

void Usage (TCHAR *Paramerter);

int main (int argc,TCHAR *argv[])
{
    if (argc!=2)
    {
        Usage(argv[0]);
        return 0;
    }

    if (strcmpi(argv[1],MY_DEVICE_START)==0 || strcmpi(argv[1],MY_DEVICE_STOP)==0)
        DriverControl(argv[1]);
    else
    {
        Usage(argv[0]);
        return 0;
    }

    return 0;
}

BOOL DriverControl (TCHAR *Maik)
{
     HANDLE hDevice=NULL;  //设备句柄
     DWORD RetBytes=0;

     //获得设备句柄
     hDevice=CreateFile(MY_DEVICE_NAME,GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);

     if (hDevice==INVALID_HANDLE_VALUE)
     {
         #ifdef DEBUGMSG
                printf("CreateFile() GetLastError reports %d/n",erron);
         #endif
         return FALSE;
     }

     //启动
     if (strcmpi(Maik,MY_DEVICE_START)==0)
     {
         //传递启动的I/O控制代码
         if (!(DeviceIoControl(hDevice,START_HELLPWORLD,NULL,0,NULL,0,&RetBytes,NULL)))
         {
             #ifdef DEBUGMSG
                    printf("DeviceIoControl() GetLastError reports %d/n",erron);
             #endif
             CloseHandle(hDevice);
             return FALSE;
         }
     }

     //停止
     if (strcmpi(Maik,MY_DEVICE_STOP)==0)
     {
         //传递停止的I/O控制代码
         if (!(DeviceIoControl(hDevice,STOP_HELLPWORLD,NULL,0,NULL,0,&RetBytes,NULL)))
         {
             #ifdef DEBUGMSG
                    printf("DeviceIoControl() GetLastError reports %d/n",erron);
             #endif
             CloseHandle(hDevice);
             return FALSE;
         }
     }

     if (hDevice)
         CloseHandle(hDevice);  //关闭句柄

     return TRUE;
}

void Usage (TCHAR *Paramerter)
{
     fprintf(stderr,"============================================================================/n"
             "      Hello驱动控制例程/n"
             "%s -start/t启动/n"
             "%s -stop /t停止/n/n"
             "本程序只是用做代码交流,如有错误,还请多多包含!/n"
             "============================================================================/n"
             ,Paramerter,Paramerter);
}

----------------------------------------------------------------------------------------------------
hello.reg安装注册文件。

REGEDIT4
[HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/hello]

"ErrorControl"=dword:00000001

#
# When to start the driver:
# At boot: Start=1
# Manually: Start=3
#
"Start"=dword:00000003

"Type"=dword:00000001
-------------------------------------------------------------------------
安装方法参考前面的笔记。
安装后,打开debugview察看结果

>net start hello

>helloctl -start

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值