操作系统在初始化驱动程序的时候会调用DriverEntry,通常会用这个函数来填充dispatch例程的指针,这就象注册回调函数一样。有的设备要创建设备的对象,或者还要创建一个设备名字,以及其他的初始化操作。它的原型:
NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) { }
IN,OUT,INOUT是一个空的宏,只是用来说明这个参数是用于输入参数,还是输出的参数。NTSTATUS实际是个长整型可以在DDK头文件NTSTATUS.H中找到NTSTATUS的代码列表。函数的第一个参数DriverObject是刚被初始化的驱动对象,就是操作系统为这个驱动分配的空间的指针。函数的第二个参数RegistryPath是驱动在注册表中的键值。如果驱动程序需要访问设备的服务键需要保存这个键值以备后用。
本章使用的例子驱动是DDK自带的ioctrl代码。代码位于src\general\ioctl\sys。
NTSTATUS DriverEntry( IN OUT PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) /*++ Routine Description: This routine is called by the Operating System to initialize the driver. It creates the device object, fills in the dispatch entry points and completes the initialization. Arguments: DriverObject - a pointer to the object that represents this device driver. RegistryPath - a pointer to our Services key in the registry. Return Value: STATUS_SUCCESS if initialized; an error otherwise. --*/ { NTSTATUS ntStatus; UNICODE_STRING ntUnicodeString; // NT Device Name "\Device\SIOCTL" UNICODE_STRING ntWin32NameString; // Win32 Name "\DosDevices\IoctlTest" PDEVICE_OBJECT deviceObject = NULL ; // ptr to device object RtlInitUnicodeString( & ntUnicodeString, NT_DEVICE_NAME ) ; ntStatus = IoCreateDevice( DriverObject, // Our Driver Object 0, // We don't use a device extension & ntUnicodeString, // Device name "\Device\SIOCTL" FILE_DEVICE_UNKNOWN, // Device type FILE_DEVICE_SECURE_OPEN, // Device characteristics FALSE , // Not an exclusive device & deviceObject ) ; // Returned ptr to Device Object if ( ! NT_SUCCESS( ntStatus ) ) { SIOCTL_KDPRINT( ( "Couldn't create the device object\n" ) ) ; return ntStatus; } // // Initialize the driver object with this driver's entry points. // DriverObject- > MajorFunction[ IRP_MJ_CREATE] = SioctlCreateClose; DriverObject- > MajorFunction[ IRP_MJ_CLOSE] = SioctlCreateClose; DriverObject- > MajorFunction[ IRP_MJ_DEVICE_CONTROL] = SioctlDeviceControl; DriverObject- > DriverUnload = SioctlUnloadDriver; // // Initialize a Unicode String containing the Win32 name // for our device. // RtlInitUnicodeString( & ntWin32NameString, DOS_DEVICE_NAME ) ; // // Create a symbolic link between our device name and the Win32 name // ntStatus = IoCreateSymbolicLink( & ntWin32NameString, & ntUnicodeString ) ; if ( ! NT_SUCCESS( ntStatus ) ) { // // Delete everything that this routine has allocated. // SIOCTL_KDPRINT( ( "Couldn't create symbolic link\n" ) ) ; IoDeleteDevice( deviceObject ) ; } return ntStatus; }
这是一个非常规范的例子,函数首先构造了设备对象,这里并没有把设备对象扩展来存储驱动特需的东西。NT设备名字是"\Device\SIOCTL"。然后填充了派发函数的指针。然后创建了一个设备名字的符号链接。这样这个设备就是命名了的设备,上层应用可以通过打开这个符号链接,从而获得设备handle来访问这个驱动。这里的符号链接是"\DosDevice\IoctlTest",上层应用要想访问这个设备只需要调用CreateFile就可得到这个设备的句柄。如下代码所示:
// // open the device // if ( ( hDevice = CreateFile( "\\\\.\\IoctlTest" , GENERIC_READ | GENERIC_WRITE, 0, NULL , CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ) ) = = INVALID_HANDLE_VALUE) { //error to open device } else { //good get it,:) }