编译第一个驱动程序笔记

(以下代码大部分摘抄自王艳平老师的《Windows程序设计》一书中的源代码,这里只是为了展示驱动的编译过程)

1:安装VC6
2:安装DDK(大概230M,最好完全安装)

3:写以下源代码(随便用一个编辑器来写):
CharConvert.h:

#define  CHAR_CONVERT    \
    CTL_CODE(FILE_DEVICE_UNKNOWN, 
0x830 , METHOD_BUFFERED, FILE_ANY_ACCESS)
CharConvert.cpp
extern   " C "
{
    #include 
< ntddk.h >
}

#include 
< devioctl.h >
#include 
" CharConvert.h "

//  自定义函数的声明
NTSTATUS DispatchCreateClose(PDEVICE_OBJECT pDevObj, PIRP pIrp);
void  DriverUnload(PDRIVER_OBJECT pDriverObj);
NTSTATUS DispatchIoctl(PDEVICE_OBJECT pDevObj, PIRP pIrp);

//  驱动内部名称和符号连接名称
#define  DEVICE_NAME L"\\Device\\devCharConvert"
#define  LINK_NAME L"\\DosDevices\\slCharConvert"

//  驱动程序加载时调用DriverEntry例程
extern   " C "  NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pRegistryString)
{
    NTSTATUS status 
=  STATUS_SUCCESS;

    
//  初始化各个派遣例程
    pDriverObj -> MajorFunction[IRP_MJ_CREATE]  =  DispatchCreateClose;
    pDriverObj
-> MajorFunction[IRP_MJ_CLOSE]  =  DispatchCreateClose;
    pDriverObj
-> MajorFunction[IRP_MJ_DEVICE_CONTROL]  =  DispatchIoctl;
    pDriverObj
-> DriverUnload  =  DriverUnload;

        
//  创建、初始化设备对象
    
//  设备名称
    UNICODE_STRING ustrDevName;
    RtlInitUnicodeString(
& ustrDevName, DEVICE_NAME);
    
//  创建设备对象
    PDEVICE_OBJECT pDevObj;
    status 
=  IoCreateDevice(pDriverObj, 
                
0 ,
                
& ustrDevName, 
                FILE_DEVICE_UNKNOWN,
                
0 ,
                FALSE,
                
& pDevObj);
    
if ( ! NT_SUCCESS(status))
    {
        
return  status;
    }

        
//  创建符号连接名称
    
//  符号连接名称
    UNICODE_STRING ustrLinkName;
    RtlInitUnicodeString(
& ustrLinkName, LINK_NAME);
    
//  创建关联
    status  =  IoCreateSymbolicLink( & ustrLinkName,  & ustrDevName);  
    
if ( ! NT_SUCCESS(status))
    {
        IoDeleteDevice(pDevObj);  
        
return  status;
    }
    
    
return  STATUS_SUCCESS;
}

void  DriverUnload(PDRIVER_OBJECT pDriverObj)
{    
    
//  删除符号连接名称
    UNICODE_STRING strLink;
    RtlInitUnicodeString(
& strLink, LINK_NAME);
    IoDeleteSymbolicLink(
& strLink);

    
//  删除设备对象
    IoDeleteDevice(pDriverObj -> DeviceObject);
}

//  处理IRP_MJ_CREATE、IRP_MJ_CLOSE功能代码
NTSTATUS DispatchCreateClose(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
    pIrp
-> IoStatus.Status  =  STATUS_SUCCESS;
    
//  完成此请求
    IoCompleteRequest(pIrp, IO_NO_INCREMENT);

    
return  STATUS_SUCCESS;
}

//  I/O控制派遣例程
NTSTATUS DispatchIoctl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
    
//  假设失败
    NTSTATUS status  =  STATUS_INVALID_DEVICE_REQUEST;

    
//  取得此IRP(pIrp)的I/O堆栈指针
    PIO_STACK_LOCATION pIrpStack  =  IoGetCurrentIrpStackLocation(pIrp);

    
//  取得I/O控制代码
    ULONG uIoControlCode  =  pIrpStack -> Parameters.DeviceIoControl.IoControlCode;
    
//  取得I/O缓冲区指针和它的长度
    PVOID pIoBuffer  =  pIrp -> AssociatedIrp.SystemBuffer;
    ULONG uInSize 
=  pIrpStack -> Parameters.DeviceIoControl.InputBufferLength;
    ULONG uOutSize 
=  pIrpStack -> Parameters.DeviceIoControl.OutputBufferLength;

    
switch (uIoControlCode)
    {
    
case  CHAR_CONVERT:
        {
            
char  str[]  =   " 零一二三四五六七八九 " ;
            
if (uInSize  >=   1   &&  uOutSize  >= 2 )
            {
                
char  c  =  (( char * )pIoBuffer)[ 0 ];
                
if (c  >=   ' 0 '   &&  c  <=   ' 9 ' )
                {
                    
//  进行转换
                    c  -=   ' 0 ' ;
                    RtlCopyMemory(pIoBuffer, 
& str[c * 2 ],  2 );
                    status 
=  STATUS_SUCCESS;
                }
            }
        }
        
break ;
    }

    
if (status  ==  STATUS_SUCCESS)
        pIrp
-> IoStatus.Information  =  uOutSize;
    
else
        pIrp
-> IoStatus.Information  =   0 ;

    
//  完成请求
    pIrp -> IoStatus.Status  =  status;
    IoCompleteRequest(pIrp, IO_NO_INCREMENT);

    
return  status;
}
注意:当你的驱动源代码文件为.cpp时,驱动的入口点函数名 DriverEntry前需要添加 extern "C"修饰符。
makefile:
#
# DO NOT EDIT THIS FILE
!!!   Edit .\sources.  if  you want to add a  new  source
# file to 
this  component.  This file merely indirects to the real make file
# that 
is  shared by all the driver components of the Windows NT DDK
#

! IF DEFINED(_NT_TARGET_VERSION)
!    IF $(_NT_TARGET_VERSION) >= 0x501
!        IFNDEF AMD64
!            INCLUDE $(NTMAKEENV)\makefile.def
!        ELSE
!            message BUILDMSG: Warning : Perm2 sample  is  not supported on AMD64.
!        ENDIF
!    ELSE
!        message BUILDMSG: Warning : The sample  " $(MAKEDIR) "   is  not valid  for  the current OS target.
!    ENDIF
! ELSE
!    INCLUDE $(NTMAKEENV)\makefile.def
! ENDIF

注意:每个驱动的makefile文件都是一样的,可以直接COPY。
sources
:

TARGETNAME = CharConvert
TARGETPATH
= obj
TARGETTYPE
= DRIVER

SOURCES
= CharConvert.cpp
注意:TARGETNAME是驱动编译后的驱动文件名,TARGETTYPE是驱动类型,SOURCES是源代码文件名。

4:开始-程序-Development Kits-Windows DDK 3790.1830-Windows XP-Windows XP Checked Build Environment

从而打开了一个命令行窗口。

cd E:                     //进入源代码目录(我的是E:\CharConvert文件夹)
cd CharConvert (回车)
build                     //运行build命令

BUILD:Adding /Y to COPYCMD so xcopy ops won't hang.
BUILD:Object root set to: ==> objchk_wxp_x86
BUILD:Compile and Link for i386
BUILD:Loading D:\WINDDK\3790~1.183\build.dat...
BUILD:Computing Include file dependencies:
BUILD:Examining e:\CharConvert directory for files to compile.
    e:\CharConvert - 1 source files <138 lines>
BUILD:Compiling <NoSync> e:\CharConvert directory
Compiling - CharConvert.cpp for i386
BUILD:Linking e:\CharConvert directory
Linking Executable - objchk_wxp_x86\i386\CharConvert.sys for i386
BUILD:Done

    2 files compiled
    1 executable built

在E:\CharConvert\objchk_wxp_x86\i386目录下就生成了CharConvert.sys驱动程序文件。至此驱动编译成功!

你可能感兴趣的:(笔记)