Delphi驱动开发研究第三篇--一个完整的驱动程序示例

本文档介绍了如何使用Delphi编写一个完整的驱动程序,讲解了驱动程序与用户模式程序的交互机制,包括I/O管理器的作用、设备对象的创建以及如何通过CreateFile函数和DeviceIoControl函数进行通讯。文中详细阐述了驱动程序的创建过程、设备对象、符号连接以及IRP处理,展示了如何实现虚拟设备的创建与控制。
 (注:本篇的原理部分均摘自罗云彬大侠翻译的驱动开发教程)
     在前面的两篇教程中我们写了三个玩具驱动程序,为什么说是玩具驱动呢?因为它们确确实实是驱动程序,而且也能完成一些有趣的功能,但是它们都不完整,没有同用户交流的功能,这一篇就让我们来完成一个简单的全功能驱动程序。
   在写程序之前,我们有必要了解一些基础知识。
   在用户模式下,我们可以通过访问某个地址来直接调用dll中的函数,但是在内核模式下,从系统的稳定性考虑,这样做是非常危险的。所以,系统提供了和内核模式通讯的媒介--I/O管理器,它是I/O子系统的部件之一。I/O管理器将应用程序、系统部件和设备连接起来,并定义了一个架构来支持设备驱动程序。下图是I/O管理器如何在用户模式程序和驱动程序之间进行沟通的简单图解。
screen.width-333)this.width=screen.width-333" dypop="按此在新窗口浏览图片">
    一般来说,用户模式的操作都被转换成了对具体硬件设备的I/O操作,仅对于某些设备,设备由驱动程序来创建和控制,这些设备就是虚拟设备。当然,创建这些设备并不意味着你创造了什么硬件,而仅仅是在内存中创建了一个新的对象而已。每个对象和一个物理设备或者逻辑设备对应,用于描述它们的特征。
   创建设备后,驱动程序告诉I/O管理器:“这里有个我控制的设备,如果你收到了操作这个设备的I/O请求的话,直接发给我好了,剩下的由我来搞定!”。驱动程序知道如何对自己管理的设备进行I/O操作,I/O管理器唯一的职责在于创建I/O请求并把它发送给适当的设备驱动程序。用户模式的代码不知道(也不必知道)其中的细节,也不用知道究竟是哪个驱动程序在管理哪个设备。
下面先让我们来看一下用户模式下的控制程序:
program VirToPhys;

{$APPTYPE CONSOLE}

uses
  SysUtils, Windows, WinSvc, Dialogs, nt_status;

const
  NUM_DATA_ENTRY =4;
  DATA_SIZE = sizeof(DWORD) * NUM_DATA_ENTRY;
  _DELETE = $10000;

var
  hSCManager:THANDLE;
  hService:THANDLE;
  acModulePath: array [0..MAX_PATH] of char;
  _ss:SERVICE_STATUS;
  hDevice:THANDLE;

  adwInBuffer: array [0..NUM_DATA_ENTRY] of DWORD;
  adwOutBuffer: array [0..NUM_DATA_ENTRY] of DWORD;
  dwBytesReturned:DWORD;
  IOCTL_GET_PHYS_ADDRESS: DWORD;
  lpTemp: PChar;
  iRetValue: boolean;

{生成控制码}  
function CTL_CODE(DeviceType, Func, Method, Access: DWORD): DWORD;
begin
  result := (((DeviceType) SHL 16) OR ((Access) SHL 14) OR ((Func) SHL 2) OR (Method));
end;

begin
  IOCTL_GET_PHYS_ADDRESS := CTL_CODE(FILE_DEVICE_UNKNOWN,
                            $800, METHOD_BUFFERED,
                            FILE_READ_ACCESS + FILE_WRITE_ACCESS);
  hSCManager := OpenSCManager(nil, nil, SC_MANAGER_ALL_ACCESS);
  if hSCManager <> 0 then
  begin
    GetFullPathName(PChar('VirtToPhys.sys'), sizeof(acModulePath), acModulePath, lpTemp);
    hService := CreateService(hSCManager, 'VirtToPhys', 'Virtual To Physical Address Converter',
                              SERVICE_START + SERVICE_STOP + _DELETE, SERVICE_KERNEL_DRIVER,
                              SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE, acModulePath,
                              nil, nil, nil, nil, nil);
    if hService <> 0 then
    begin
      {驱动程序的DriverEntry过程将被调用}
      if StartService(hService, 0, lpTemp) = true then
      begin
        {驱动程序将接收IRP_MJ_CREATE I/O请求包(IRP)}
        hDevice := CreateFile('\\.\slVirtToPhys', GENERIC_READ+GENERIC_WRITE,
                              0, nil, OPEN_EXISTING, 0, 0);
        if hDevice <> INVALID_HANDLE_VALUE  then
        begin
          {准备送往驱动程序的数据包}
          adwInBuffer[0] := GetModuleHandle(nil);
          adwInBuffer[1] := GetModuleHandle('kernel32.dll');
          adwInBuffer[2] := GetModuleHandle('user32.dll');
          adwInBuffer[3] := GetModuleHandle('comctl32.dll');
          {驱动程序将接收IRP_MJ_DEVICE_CONTROL I/O请求包}
          iRetValue := DeviceIoControl(hDevice, IOCTL_GET_PHYS_ADDRESS,
                                       @adwInBuffer, sizeof(adwInBuffer),
                                       @adwOutBuffer, sizeof(adwOutBuffer),
                                       dwBytesReturned, nil);
          if (iRetValue = true) and (dwBytesReturned <> 0) then
          begin
            {取程序名}
            GetModuleFileName(adwInBuffer[0], acModulePath, sizeof(acModule
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值