Kernel Mode Driver Tutorial: Part I: “The Skeleton KMD”

by Clandestiny

                    

 

 

 

I. Introduction

 

Greetings!  Here is the first of hopefully several KMD (kernel mode driver) tutorials.  KMD’s are the accepted driver format for the Windows NT/2000/XP operating systems, but by and large they are still a mystery.  There are hundreds of obscure structures and obtuse functions documented in the mess that calls itself the MSDN.  There are a handful of books on the subject which are useful references if we ignore the fact that most of them exceed 500 pages and require a PhD in computer science to get past the first couple pages of the “introduction”.  There are even a few snippets of example KMD code lying around the internet if you know where to look.  Of course, they too assume an advanced background and are hardly suited to serve as examples to the programmer taking his/her first baby steps into kernel mode programming.  When I first became interested in writing a driver, I was using Windows 98 and I started by learning about VxD’s from Iczelion’s fantastic win32 asm series tutorials.  Eventually, when I migrated to Windows 2000, I was forced to abandon my VxD knowledge and embark on a new search for the KMD equivalent to Iczelion’s famous tutorials.  I’m sorry to report that I never found it.  After much searching, I cobbled up enough information to understand and create a successful skeleton KMD. What you are about to read is the result of that effort.  It is my hope that this tutorial serves as a simple introduction to those programmers, like me, who are taking their first baby steps into KMD development.  I am by no means an expert on the subject and readily welcome corrections or suggestions for improvement from those more knowlegable in the field. You can contact me at clandestiny(at)despammed.com.  If this tutorial generates some positive feedback, ultimately I hope to write KMD tutorials on other low-level programming tasks like interrupt hooking and memory access / management.

 

 

 

IIa. Getting Started

 

For the skeleton KMD you will need at least the following include files / libraries... I used the include files / libraries kindly provided by Four-F in his KMD kit.

 

§    ntoskrnl.lib

§    ntddk.inc

§    ntoskrnl.inc

§    ntstatus.inc

§    Strings.mac – not strictly required but very helpful nonetheless

 

NOTE: The code presented in this tutorial was written and assembled using MASM version 7.

 

I would also like to add that DriverStudio by Numega contains a very handy utility called DriverMonitor that can be used to start, stop, load, and unload drivers while testing and debugging.  I recommend obtaining it both for DriverMonitor and for SoftICE (IMO, the BEST ring 0 debugger). There is also some KMD example code included with DriverStudio if you know C++.

 

IIb. Driver Structure

 

Unlike the VxDs of Win9x which followed the LE (linear executable) format, KMDs structurally follow the standard PE (portable executable format) of .exe’s and .dll’s and compile to a .sys file extension. 

 

On the programmatic level, the skeleton kernel mode driver can be broken down into 3 basic functions, DriverEntry, DriverDispatcher, and DriverUnload.  The purpose of Driver Entry is to perform initialization tasks.  Unless your driver is intended to be loaded upon bootup, it’s driver entry function will be called from within a ring 3 loader that you write.  The second primary function of your KMD will be the DriverDispatcher routine.  As its name implies, the DriverDispatcher routine handles messages dispatched to the driver by either the OS or another ring 3 application via the DeviceIoControl interface.  As such, it can act as a communication conduit between ring 0 and ring 3 where the ring 0 driver provides privaleged “services” to a ring 3 program for tasks it would be unable to accomplish under ring 3 restrictions (ie. like accessing the IDT,GDT, and LDT system descriptors or low level hooking and spying on I/O functions).  Used in this manner, a KMD functions much like a ring 0 dll. Finally, like the DriverEntry function, DriverUnload will be called from a ring 3 application.  It performs standard deinitialization and cleanup (freeing memory, closing handles, removing hooks, ect).

 

    

 

Ø                           The Driver Entry Routine

 

This is the one function common to all KMD drivers and as its name implies, serves as the driver entry point. The first function of the DriverEntry is to create a "device object" using the IoCreateDevice call.  Assuming this is successful, it will secondarily set up a "symbolic link" using the IoCreateSymbolicLink function.  The symbolic link is optional for the functioning of the driver, BUT is required if you need a ring 3 application to be able to communicate with your driver.  Indeed, the symbolic link basically creates a name for your driver which will be used to access it in ring 3 using the CreateFile call.  The CreateFile call takes this name as its path parameter.  Lastly, DriverEntry must set up pointers to functions for any requests that it will handle (these requests are of the form IRP_MJ_XXX).  The minimum standard requests that must be handled for the driver to work are IRP_MJ_CREATE, IRP_MJ_CLOSE, AND IRP_MJ_CLEANUP.  The IRP_MJ_DEVICE_CONTROL request must be handled if the driver is to be able to communicate with ring 3 apps via the DeviceIoControl interface. The driver object maintains an array of pointers to the dispatch procedures that will be called when these requests are recieved.  It is the responsiblity of DriverEntry to set the function pointers in this array.  A successful DriverEntry function returns the value STATUS_SUCCESS (0X00).  I should also mention that KMDs typically only use strings in the UNICODE format. Four-f provides some convienient macros for dealing with them in Strings.mac found in his KMD Kit.

 

We can summarize the DriverEntry routine’s responsiblites as follows…

 

1. Create the device using IoCreateDevice

2. Set up a SymbolicLink using IoCreateSymbolicLink if your driver needs to be able to communicate with ring 3 applications

3. Set up the entry points for the IRP_MJ requests your driver services

4. Set the DriverUnload entry point

 

 

 

DriverEntry     PROC    pDriverObject:PDRIVER_OBJECT, pRegistryPath:PUNICODE_STRING   

LOCAL status:DWORD     

pushad

mov esi, pDriverObject

ASSUME esi:PTR DRIVER_OBJECT

mov edi, OFFSET gDeviceObject

ASSUME edi:PTR DEVICE_OBJECT

 

;------------------------------------

;Create the device & Set up the symbolic

;link so ring 3 apps can communicate w/

;our ring 0 driver

;------------------------------------

invoke IoCreateDevice,esi,0,$CCOUNTED_UNICODE_STRING("\\Device\\skeleton", uDeviceName, 4),FILE_DEVICE_UNKNOWN,0,FALSE,edi

.IF eax == STATUS_SUCCESS

        invoke IoCreateSymbolicLink,$CCOUNTED_UNICODE_STRING("\\DosDevices\\skeleton", uSymbolicLinkName, 4),OFFSET uDeviceName

        .IF eax == STATUS_SUCCESS

                ;------------------------------------

                ;Set up dispatch routine entry points

                ;for IRP_MJ_Xxx requests

                ;------------------------------------

                mov [esi].MajorFunction[IRP_MJ_DEVICE_CONTROL*(sizeof PVOID)],OFFSET DriverDispatcher

                mov [esi].MajorFunction[IRP_MJ_CREATE*(sizeof PVOID)],OFFSET DriverDispatcher

                mov [esi].MajorFunction[IRP_MJ_CLOSE*(sizeof PVOID)],OFFSET DriverDispatcher

                mov [esi].MajorFunction[IRP_MJ_CLEANUP*(sizeof PVOID)],OFFSET DriverDispatcher

               

                ;----------------------------------

                ;Set DriverUnload entry point

                ;----------------------------------

                mov [esi].DriverUnload, OFFSET DriverUnload

        .ENDIF 

.ENDIF

mov status,eax

popad

mov eax,status

ret

DriverEntry     endp

 

 

 

 

Ø                              The Driver Dispatcher Routine

 

The DriverDispatcher routine functions more or less as the WndProc does to a standard win32 application.  It processes messages / requests.  A request is defined by an IRP also known I/O request packet. Every driver is assigned a unique location in the IRP stack which contains information about its requests.  When the driver recieves a request, it looks up the request in the IRP stack using IoGetCurrentStackLocation.  These requests can fall into 3 categories:

 

1. Standard Requests necessary for the driver to function like  IRP_MJ_CREATE, IRP_MJ_CLOSE, and IRP_MJ_CLEANUP.  The programmer's responsiblity at a bare minimum is to return STATUS_SUCCESS in response to these requests.

 

 

2. Programmer Defined Requests which fall under IRP_MJ_DEVICE_CONTROL are those custom services provided to ring 3 applications via the DeviceIoControl interface. As in the VxD, you will look up the IOCTL code and branch off to the procedure that needs to be handled.  In order for the DeviceIoControl  interface to work with a KMD, it is necessary to write an IOCTL header file.  The IOCTL header file defines the device type, service control code value, buffer transfer type, and access type for both the driver and the requestor of its services.  All together these parameters define an IOCTL value.  IOCTL values are obtained by calling the macro CTL_CODE in your IOCTL header file.  The header file will be included both in the driver build and the ring 3 application which desires to communicate with the driver. The IOCTL parameters are as follows:

 

CTL_CODE( DeviceType, ControlCode, TransferType, RequiredAccess)

 

 

       Parameter                                                                 Description            

DeviceType

File_Device_XXX values supplied to IoCreateDevice

§         00h to 7FFh – reserved for Microsoft

§         8000h to FFFh – customer defined

 

Control Code

 

Driver defined IOCTL code

§         000h to 7FFh – reserved for Microsoft

§         800h to FFFh – customer defined

Transfer Type

Buffer passing mechanism for this control code

§         METHOD_INDIRECT

§         METHOD_BUFFERED

§         METHOD_OUT_DIRECT

§         METHOD_NEITHER

Required Access

 

Requestor access requirement

§         FILE_ANY_ACCESS

§         FILE_READ_DATA

§         FILE_WRITE_DATA

§         FILE_READ_DATA | FILE_WRITE_DATA

 

 

In the skeleton driver I have defined 1 IOCTL value to serve as an example for how the DeviceIoControl Interface operates.  I declared it in ctrl_codes.inc using the CTL_CODE macro as follows:

            

SERVICE_SAY_HELLO equ CTL_CODE (FILE_DEVICE_UNKNOWN,801H,METHOD_NEITHER,FILE_ANY_ACCESS)

 

For the device type I delcared , FILE_DEVICE_UNKNOWN, the same device type as I declared when I created it using IoCreateDevice. I set the control code at 801, but it could have been any number within the customer defined range of 800h to FFFh.  The important point when choosing control codes is that all of the control codes for your device are unique values within that range. I set the transfer type as METHOD_NEITHER for this service.  Basically this means that the I/O manager directly passes you the address to the input or output buffer sent by the DeviceIoControl call.  In other words, there is no error checking done on this address by the I/O manager and consequently, it is the least safe method of passing your data to and from the driver.  The METHOD_BUFFERED, METHOD_INDIRECT, and METHOD_OUT_DIRECT all have checks performed on them by the I/O Manager and are therefore safer to use.

 

Passing data via the DeviceIoControl interface differs depending on the transfer type you’ve specified…

 

For METHOD_BUFFERED, the I/O manager allocates a single buffer which is accessed through pIRP.AssoicatedIrp.SystemBuffer.  Because this buffer is used for both input and output, the driver must be careful to extract all input information before writing output back to the buffer.

 

For METHOD_IN_DIRECT, the I/O manager checks the input buffer and builds an MDL for it.  It then stores a pointer to the MDL in pIRP.MdlAddress. The output buffer is accessed through pIRP.AssociatedIrp.SystemBuffer.

 

For METHOD_OUT_DIRECT, the I/O manager checks the output buffer and builds an MDL for it.  It then stores a pointer to the MDL in pIRP.MdlAddress. The input buffer is accessed through pIRP.AssociatedIrp.SystemBuffer.

 

For METHOD_NEITHER, the addresses specified by the user in the DeviceIoControl call are provided directly to the driver with no error checking or verification. The input buffer can be accessed though pIRP.Parameters.DeviceIoControl.Type3InputBuffer and the output buffer can be accessed though pIrp.UserBuffer.

 

As I mentioned previously, I handled 1 programmer defined request in the skeleton driver.  It’s function was simply return a string from ring 0 to ring 3 which is printed out by the ring 3 applciation in a messagebox.  When handling a user defined request, the first step is to verify that it is an IRP_MJ_DEVICE_CONTROL request.  If it is, then you will go on to check the CTRL code to determine what service is being requested.  There could be several which you would have to check, but in this case the only request is defined as SERVICE_SAY_HELLO. The function of SERVICE_SAY_HELLO is to copy a string into the output buffer and return STATUS_SUCCESS.  Remember, I am using METHOD_NEITHER for the data transfer so the data will be copied into the location addressed by pIrp.UserBuffer.

 

.ELSEIF [eax].MajorFunction == IRP_MJ_DEVICE_CONTROL      ;check for DeviceIoControl request from user

.IF [eax].Parameters.DeviceIoControl.IoControlCode == SERVICE_SAY_HELLO  ;determine what service is being requested

         invoke CopyString,[edi].UserBuffer,OFFSET msgHello,[eax].Parameters.DeviceIoControl.OutputBufferLength ;copy string into output buffer

         mov[edi].IoStatus.Status,STATUS_SUCCESS 

.ELSE

         mov[edi].IoStatus.Status,STATUS_NOT_IMPLEMENTED

.ENDIF

 

 

3. Undefined Requests, or requests which are not handled directly by the given driver. For these, it is the programmers responsiblity to return the  STATUS_NOT_IMPLEMENTED value.

 

 

DriverDispatcher         PROC    pDeviceObject:PDEVICE_OBJECT, pIrp:PIRP

LOCAL status:DWORD

pushad

mov esi, pDeviceObject

ASSUME esi: PTR DEVICE_OBJECT

mov edi, pIrp

ASSUME edi:PTR _IRP

 

;----------------------------------

;Determine what driver service is

;being requested

;----------------------------------

IoGetCurrentIrpStackLocation edi

assume eax:PTR IO_STACK_LOCATION

 

;---------------------------------

;Standard Requests

;---------------------------------

.IF [eax].MajorFunction == IRP_MJ_CREATE || [eax].MajorFunction == IRP_MJ_CLOSE || [eax].MajorFunction == IRP_MJ_CLEANUP

mov [edi].IoStatus.Status, STATUS_SUCCESS

 

;--------------------------------

;Programmer Defined Requests

;--------------------------------

.ELSEIF [eax].MajorFunction == IRP_MJ_DEVICE_CONTROL

.IF [eax].Parameters.DeviceIoControl.IoControlCode == SERVICE_SAY_HELLO

         invoke CopyString,[edi].UserBuffer,OFFSET msgHello,[eax].Parameters.DeviceIoControl.OutputBufferLength

         mov[edi].IoStatus.Status,STATUS_SUCCESS

.ELSE

         mov[edi].IoStatus.Status,STATUS_NOT_IMPLEMENTED

.ENDIF

 

;--------------------------------

;Undefined Requests

;--------------------------------

.ELSE

         mov[edi].IoStatus.Status,STATUS_NOT_IMPLEMENTED

.ENDIF

 

push [edi].IoStatus.Status

pop status

mov[edi].IoStatus.Information,0

invoke IoCompleteRequest,edi,IO_NO_INCREMENT

popad

mov eax,status

ret

DriverDispatcher endp

 

 

 

Ø                              The Driver Unload Routine

 

The DriverUnload routine is pretty self explanatory.  It will be called when the loader invokes the ControlService API with a SERVICE_CONTROL_STOP message. DriverUnload basically unwinds the actions taken by the DriverEntry function.  It will perform any driver specific cleanup and is at a minimum required to delete the device object (IoDeleteDevice) and the symbolic link (IoDeleteSymbolicLink).  Failure to perform either of these actions will corrupt the internal service database entry for the driver preventing it from being loaded again (until you reboot L).

 

 

DriverUnload             PROC    pDriverObject:PDRIVER_OBJECT

pushad

mov esi, pDriverObject

ASSUME esi: PTR DRIVER_OBJECT

invoke   IoDeleteSymbolicLink, OFFSET uSymbolicLinkName

invoke IoDeleteDevice,[esi].DeviceObject                         

popad

ret

DriverUnload     endp

 

 

 

 

IIc. The Loader

 

If you have Driver Studio, you can use the handy little utitlity “Driver Monitor” to load, start, stop, and unload drivers for testing purposes. However, if your driver must provide services to a ring 3 application will, the ring 3 application will will manually have to install the driver as a service in order to be able to communicate with it.  The procedure for loading a driver is as follows:

 

1. Obtain a handle to the service manager using OpenSCManager.

 

2. Define the driver using CreateService. This creates an entry in the service database for the driver.  Note, that this information is kept in the registry under...HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\"My Driver's Name".  Realize, that CreateService does not *load* the driver.  It simply creates an entry in the service database so that it can be recognized.

 

3. Open the driver using OpenService.  This call loads the driver, but realize that this call does not *start* the driver.

 

4. Finally start the driver using the StartService function.  Note that this function is what finally calls the DriverEntry routine.  If there are errors in your DriverEntry routine, expect StartService to fail.

 

5. Now you can open a handle to the driver in a ring 3 application using CreateFile and send requests via the DeviceIoControl.

 

6. Stop the driver by sending a SERVICE_CONTROL_STOP via ControlService.  Note that this function calls the DriverUnload routine.  If there are errors in your DriverUnload routine, expect this function to fail and expect to be unable to load the driver again unless you reboot.  This is because if this call fails, or the driver crashes before executing this call, the service database entry for the driver will be corrupted until you reboot.

 

7. Finally delete the service using DeleteService and release the handle to the service control database using CloseServiceHandle.  DeleteService is the function responsible for deleting the actual entry in the service database and the corresponding key in the registry.

 

;THE LOADER

 

.code

start:

TestDriver PROC

;--------------------------------------------------

;Obtain a handle to the service control manager

;--------------------------------------------------

invoke OpenSCManager, 0, 0, SC_MANAGER_ALL_ACCESS

mov hScManager,eax

;-------------------------------------------------

;Add the service to the system

;-------------------------------------------------

invoke GetFullPathName,ADDR DriverName,256,ADDR FilePath,ADDR pFilePart

;------------------------------------------------

;Register the service w/ the system

;------------------------------------------------

invoke CreateService,hScManager,ADDR ServiceName,ADDR ServiceName,SERVICE_ALL_ACCESS,SERVICE_KERNEL_DRIVER, \

SERVICE_DEMAND_START,SERVICE_ERROR_NORMAL,ADDR FilePath,0,0,0,0,0

xchg eax,ebx

invoke GetLastError

.IF (ebx != 0) || (eax == ERROR_SERVICE_EXISTS) ;service database entry already exists for driver

         mov hService,eax

        

         ;---------------------------------------------------------------

         ;Load the service /driver

         ;---------------------------------------------------------------

         invoke OpenService,hScManager,ADDR ServiceName,SERVICE_ALL_ACCESS

         .IF eax != 0

                 mov hService,eax

 

                 ;--------------------------------------------------

                 ;Start the service to set the service to the running

                 ;state. StartService will call the DriverEntry procedure

                 ;--------------------------------------------------

                 invoke StartService,hService,0,0

                 .IF eax != 0

 

                         ;---------------------------------------------------

                         ;Obtain a handle to the loaded driver for DeviceIoControl

                         ;interface communcation

                         ;---------------------------------------------------

                         invoke CreateFile,ADDR DriverPath ,GENERIC_READ or GENERIC_WRITE,0,0,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,0

                        .IF eax != INVALID_HANDLE_VALUE

                              mov       hDriver, eax

                         .ELSE

                               invoke  MessageBoxA,NULL,ADDR lpMsgFileErrorText,ADDR lpMsgErrorTitle,MB_OK

                               jmp file_error             ;CreateFile error

                         .ENDIF

                         ;--------------------------------------------------

                         ;Send service request SERVICE_SAY_HELLO

                         ;--------------------------------------------------

                         invoke DeviceIoControl,hDriver,SERVICE_SAY_HELLO,0,0,ADDR lpOutBuffer,256,ADDR BytesReturned,0

                         mov edi,dword ptr lpOutBuffer

                         .IF edi == 0

                                 invoke  MessageBoxA,NULL,ADDR lpMsgTransferErrorText,ADDR lpMsgErrorTitle,MB_OK ;transfer error

                                 jmp stop_service

                         .ENDIF

                         invoke  MessageBoxA,NULL,ADDR lpOutBuffer,ADDR lpMsgTitle,MB_OK

stop_service:                    invoke  CloseHandle,hDriver      ;Close the handle

file_error:                              invoke ControlService,hService,SERVICE_CONTROL_STOP,ADDR ServiceStatus

                         invoke DeleteService,hService

                         jmp exit

                 .ELSE

                         jmp stop_service ;StartService error

                 .ENDIF

         .ELSE

                 jmp error ;OpenService error

         .ENDIF

         invoke CloseServiceHandle,hScManager

.ELSE

         jmp error ;CreateService error

.ENDIF

 

;--------------------------------------------------

;Close the service to release manager and service

;handles

;--------------------------------------------------

error:   invoke CloseServiceHandle,hScManager

invoke  MessageBoxA,NULL,ADDR lpMsgErrorText,ADDR lpMsgErrorTitle,MB_OK

 

exit:

ret 

TestDriver endp

end start

 

 

 

 

III. Credits

      

A special credit and thanks to Four-F for making his handy KMD kit available to MASM programmers and to RAMA for his example KMD which aided me in figuring out how to write a kernel mode driver.

 

Last but not least, a personal thanks to my friend Kayaker for his past, present, and future help and encouragement J.

 

Additional references include the MSDN and Undocumented Windows Secrets: A Programmer’s cookbook (I got the undocumented secrets book from amazon.com for $10 used and would highly recommend it to anyone interested in ring 0 programming).

 

 

IV. Appendix

 

NOTE: Yes, I shamelessly copied these function & structure definitions from the MSDN documentation ;-)  I figured it would be easier for you to follow if I conveniently referenced them here rather than forcing you to search for them on the MSDN site J

 

DRIVER_OBJECT

Each driver object represents the image of a loaded kernel-mode driver. A pointer to the driver object is an input parameter to a driver’s DriverEntry, AddDevice, and optional Reinitialize routines and to its Unload routine, if any.

A driver object is partially opaque. Driver writers must know about certain members of a driver object to initialize a driver and to unload it if the driver is unloadable. The following members of the driver object are accessible to drivers.

Accessible Members

PDEVICE_OBJECT DeviceObject

Pointer to the device objects created by the driver. This member is automatically updated when the driver calls IoCreateDevice successfully. A driver can use this member and the NextDevice member of DEVICE_OBJECT to step through a list of all the device objects that the driver created.

PDRIVER_EXTENSION DriverExtension

Pointer to the driver extension. The only accessible member of the driver extension is DriverExtension->AddDevice, into which a driver's DriverEntry routine stores the driver's AddDevice routine.

PUNICODE_STRING HardwareDatabase

Pointer to the \Registry\Machine\Hardware path to the hardware configuration information in the registry.

PFAST_IO_DISPATCH FastIoDispatch

Pointer to a structure defining the driver’s fast I/O entry points. This member is used only by FSDs and network transport drivers.

PDRIVER_INITIALIZE DriverInit

The entry point for the DriverEntry routine, which is set up by the I/O Manager.

PDRIVER_STARTIO DriverStartIo

The entry point for the driver’s StartIo routine, if any, which is set by the DriverEntry routine when the driver initializes. If a driver has no StartIo routine, this member is NULL.

PDRIVER_UNLOAD DriverUnload

The entry point for the driver’s Unload routine, if any, which is set by the DriverEntry routine when the driver initializes. If a driver has no Unload routine, this member is NULL.

PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION+1]

A dispatch table consisting of an array of entry points for the driver’s DispatchXxx routines. The array's index values are the IRP_MJ_Xxx values representing each IRP major function code. Each driver must set entry points in this array for the IRP_MJ_Xxx requests that the driver handles. For more information, see Writing Dispatch Routines. Each DispatchXxx routine is declared as follows:

NTSTATUS

(*PDRIVER_DISPATCH) (

    IN PDEVICE_OBJECT DeviceObject,

    IN PIRP Irp

    );

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

Each kernel-mode driver’s initialization routine should be named DriverEntry so the system will load the driver automatically. If this routine’s name is something else, the driver writer must define the name of the initialization routine for the linker; otherwise, the OS loader or I/O Manager cannot find the driver’s transfer address. The names of other standard driver routines can be chosen at the discretion of the driver writer.

A driver must set its DispatchXxx entry points in the driver object that is passed in to the DriverEntry routine when the driver is loaded. A device driver must set one or more DispatchXxx entry points for the IRP_MJ_XXX that any driver of the same type of device is required to handle. A higher-level driver must set one or more DispatchXxx entry points for all the IRP_MJ_XXX that it must pass on to the underlying device driver. Otherwise, a driver is not sent IRPs for any IRP_MJ_XXX for which it does not set up a DispatchXxx routine in the driver object. For more information about the set of IRP_MJ_XXX that drivers for different types of underlying devices are required to handle, see IRP Major Function Codes.

The DriverEntry routine also sets the driver’s AddDevice, StartIo and/or Unload entry points, if any, in the driver object.

The HardwareDatabase string can be used by device drivers to get hardware configuration information from the registry when the driver is loaded. A driver is given read-only access to this string.

The RegistryPath input to the DriverEntry routine points to the \Registry\Machine\System\CurrentControlSet\Services\DriverName key, where the value entry of DriverName identifies the driver. As for the HardwareDatabase in the input driver object, a driver is given read-only access to this string.

Undocumented members within a driver object should be considered inaccessible. Drivers with dependencies on object member locations or on access to undocumented members might not remain portable and interoperable with other drivers over time.

See Also

DriverEntry, IoCreateDevice, IoDeleteDevice, StartIo, Unload

 

DEVICE_OBJECT

A device object represents a logical, virtual, or physical device for which a driver handles I/O requests.

Accessible Members

PDRIVER_OBJECT DriverObject

Pointer to the driver object, representing the driver’s loaded image, that was input to the DriverEntry and AddDevice routines.

PDEVICE_OBJECT NextDevice

Pointer to the next device object, if any, created by the same driver. The I/O Manager updates this list at each successful call to IoCreateDevice or IoCreateDeviceSecure. A driver that is being unloaded must walk the list of its device objects and delete them. A driver that recreates its device objects dynamically also uses this field.

PIRP CurrentIrp

Pointer to the current IRP if the driver has a StartIo routine whose entry point was set in the driver object and if the driver is currently processing IRP(s). Otherwise, this field is NULL.

ULONG Flags

Device drivers OR this field in their newly created device objects with one or more of the following system-defined values:

DO_BUFFERED_IO or DO_DIRECT_IO

Higher-level drivers OR the field with the same value as the next-lower driver, except possibly for highest-level drivers.

DO_BUS_ENUMERATED_DEVICE

The system sets this flag in each PDO. Drivers must not modify this flag.

DO_DEVICE_INITIALIZING

The I/O Manager sets this flag when it creates the device object.

A device function or filter driver clears the flag in its AddDevice routine, after attaching the device object to the device stack, establishing the device power state, and ORing the field with one of the power flags (if necessary). The PnP Manager checks that the flag is clear after return from AddDevice.

DO_POWER_INRUSH

Drivers of devices that require inrush current when powering on must set this flag. A driver cannot set both this flag and DO_POWER_PAGABLE.

DO_POWER_PAGABLE

Windows® 2000 and later drivers that are pageable, are not part of the paging path, and do not require inrush current must set this flag. The system calls such drivers at IRQL PASSIVE_LEVEL. Drivers cannot set both this flag and DO_POWER_INRUSH.

All WDM, Windows 98, and Windows Me drivers must set DO_POWER_PAGABLE.

DO_VERIFY_VOLUME

Removable-media drivers set this flag while processing transfer requests. Such drivers should also check for this flag in the target for a transfer request before transferring any data. See the Supporting Removable Media for details.

For more information about setting the Flags field, see Initializing a Device Object.

ULONG Characteristics

Specifies one or more system-defined constants, ORed together, that provide additional information about the driver's device. The constants include:

FILE_AUTOGENERATED_DEVICE_NAME

Directs the I/O Manager to generate a name for the device, instead of the caller specifying a DeviceName when calling this routine. The I/O Manager ensures that the name is unique. This characteristic is typically specified by a PnP bus driver to generate a name for a physical device object (PDO) for a child device on its bus. This characteristic is new for Windows 2000 and Windows 98.

FILE_CHARACTERISTIC_PNP_DEVICE

Indicates that the device object is part of a Plug and Play stack. This flag is required if a bus driver (or bus filter driver) registers WMI support for a device object that has not yet received the IRP_MN_START_DEVICE request. It is also required if a function or filter driver registers for WMI before attaching to its device stack.

FILE_DEVICE_IS_MOUNTED

Indicates that a file system is mounted on the device. Drivers should not set this characteristic.

FILE_DEVICE_SECURE_OPEN

(Windows NT® 4.0 SP5 and later)

Directs the I/O Manager to apply the security descriptor of the device object to relative opens and trailing file name opens on the device. For more information, see Controlling Device Namespace Access.

FILE_FLOPPY_DISKETTE

Indicates that the device is a floppy disk device.

FILE_READ_ONLY_DEVICE

Indicates that the device cannot be written to.

FILE_REMOTE_DEVICE

Indicates that the device is remote.

FILE_REMOVABLE_MEDIA

Indicates that the storage device supports removable media.

Note that this characteristic indicates removable media, not a removable device. For example, drivers for JAZ drive devices should specify this characteristic, but drivers for PCMCIA flash disks should not.

FILE_VIRTUAL_VOLUME

Indicates that the volume is virtual. Drivers should not set this characteristic.

FILE_WRITE_ONCE_MEDIA

Indicates that the device supports write-once media.

Drivers do not set this member directly. For more information about setting device characteristics, see Specifying Device Characteristics.

PVOID DeviceExtension

Pointer to the device extension. The structure and contents of the device extension are driver-defined. The size is driver-determined, specified in the driver’s call to IoCreateDevice or IoCreateDeviceSecure. For more information about device extensions, see Device Extensions.

DEVICE_TYPE DeviceType

Set by IoCreateDevice, using the value specified for that routine's DeviceType parameter. For more information, see Specifying Device Types.

CCHAR StackSize

Specifies the minimum number of stack locations in IRPs to be sent to this driver. IoCreateDevice and IoCreateDeviceSecure sets this field to one in newly created device objects; lowest-level drivers can therefore ignore this field. The I/O manager automatically sets the StackSize field in a higher-level driver’s device object to the appropriate value if the driver calls IoAttachDevice or IoAttachDeviceToDeviceStack. Only a higher-level driver that chains itself over another driver with IoGetDeviceObjectPointer must explicitly set the value of StackSize in its own device object(s) to (1 + the StackSize value of the next-lower driver’s device object).

ULONG AlignmentRequirement

Specifies the device's address alignment requirement for data transfers. The value must be one of the FILE_XXX_ALIGNMENT values defined in wdm.h and ntddk.h. For more information, see Initializing a Device Object. Also see GetDmaAlignment and ZwQueryInformationFile.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

The operating system represents devices by device objects. For more information, see Device Objects and Device Stacks.

Drivers create device objects by using the IoCreateDevice and IoCreateDeviceSecure routines. For more information on creating device objects, see Creating a Device Object.

A device object is partially opaque. Drivers do not set members of the device object directly, unless otherwise documented. For information on the members that drivers can modify directly, see Initializing a Device Object. For other device object properties, see Properties of Device Objects.

Undocumented members within a device object must be considered inaccessible. Drivers with dependencies on object member locations or access to undocumented members might not remain portable and interoperable with other drivers over time.

The system-supplied video port driver sets up the fields of the device objects it creates on behalf of video miniport drivers.

The system-supplied SCSI port driver sets up the fields of the device objects it creates on behalf of SCSI miniport drivers.

The system-supplied NDIS library sets up the fields of the device objects it creates on behalf of NDIS miniport drivers.

See Also

DRIVER_OBJECT, IoAttachDevice, IoAttachDeviceToDeviceStack, IoCreateDevice, IoDeleteDevice, IoGetDeviceObjectPointer

 

IoCreateDevice

The IoCreateDevice routine creates a device object for use by a driver.

NTSTATUS

  IoCreateDevice(

    IN PDRIVER_OBJECT  DriverObject,

    IN ULONG  DeviceExtensionSize,

    IN PUNICODE_STRING  DeviceName  OPTIONAL,

    IN DEVICE_TYPE  DeviceType,

    IN ULONG  DeviceCharacteristics,

    IN BOOLEAN  Exclusive,

    OUT PDEVICE_OBJECT  *DeviceObject

    );

Parameters

DriverObject

Pointer to the driver object for the caller. Each driver receives a pointer to its driver object in a parameter to its DriverEntry routine. WDM function and filter drivers also receive a driver object pointer in their AddDevice routines.

DeviceExtensionSize

Specifies the driver-determined number of bytes to be allocated for the device extension of the device object. The internal structure of the device extension is driver-defined. For more information about device extensions, see Device Extensions.

DeviceName

Optionally points to a buffer containing a zero-terminated Unicode string that names the device object. The string must be a full path name. WDM filter and function drivers do not name their device objects. For more information, see Named Device Objects.

DeviceType

Specifies one of the system-defined FILE_DEVICE_XXX constants that indicate the type of device (such as FILE_DEVICE_DISK, FILE_DEVICE_KEYBOARD, etc.) or a vendor-defined value for a new type of device. For more information, see Specifying Device Types.

DeviceCharacteristics

Specifies one or more system-defined constants, ORed together, that provide additional information about the driver's device. For a list of possible device characteristics, see DEVICE_OBJECT. For more information on how to specify device characteristics, see Specifying Device Characteristics. Most drivers specify FILE_DEVICE_SECURE_OPEN for this parameter.

Exclusive

Reserved for system use. Drivers set this parameter to FALSE.

DeviceObject

Pointer to a variable that receives a pointer to the newly created DEVICE_OBJECT structure. The DEVICE_OBJECT structure is allocated from nonpaged pool.

Return Value

IoCreateDevice returns STATUS_SUCCESS on success, or the appropriate NTSTATUS error code on failure. A partial list of the failure codes returned by this function include:

STATUS_INSUFFICIENT_RESOURCES
STATUS_OBJECT_NAME_EXISTS
STATUS_OBJECT_NAME_COLLISION

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

IoCreateDevice creates a device object and returns a pointer to the object. The caller is responsible for deleting the object when it is no longer needed by calling IoDeleteDevice.

IoCreateDevice can only be used to create an unnamed device object, or a named device object for which a security descriptor is set by an INF file. Otherwise, drivers must use IoCreateDeviceSecure to create named device objects. For more information, see Creating a Device Object. The caller is responsible for setting certain members of the returned device object. For more information, see Initializing a Device Object and the device-type-specific documentation for your device.

Be careful to specify the DeviceType and DeviceCharacteristics values in the correct parameters. Both parameters use system-defined FILE_XXX constants and some driver writers specify the values in the wrong parameters by mistake.

Device objects for disks, tapes, CD-ROMs, and RAM disks are given a Volume Parameter Block (VPB) that is initialized to indicate that the volume has never been mounted on the device.

If a driver's call to IoCreateDevice returns an error, the driver should release any resources that it allocated for that device.

Callers of IoCreateDevice must be running at IRQL < DISPATCH_LEVEL.

See Also

DEVICE_OBJECT, IoAttachDevice, IoAttachDeviceToDeviceStack, IoCreateDeviceSecure, IoCreateSymbolicLink, IoDeleteDevice

 

IoCreateSymbolicLink

The IoCreateSymbolicLink routine sets up a symbolic link between a device object name and a user-visible name for the device.

NTSTATUS

  IoCreateSymbolicLink(

    IN PUNICODE_STRING  SymbolicLinkName,

    IN PUNICODE_STRING  DeviceName

    );

Parameters

SymbolicLinkName

Pointer to a buffered Unicode string that is the user-visible name.

DeviceName

Pointer to a buffered Unicode string that is the name of the driver-created device object.

Return Value

IoCreateSymbolicLink returns STATUS_SUCCESS if the symbolic link object was created.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

WDM drivers do not name device objects and therefore should not use this routine. Instead, a WDM driver should call IoRegisterDeviceInterface to set up a symbolic link.

For more information on when to use IoCreateSymbolicLink, see Named Device Objects.

Callers of IoCreateSymbolicLink must be running at IRQL = PASSIVE_LEVEL.

See Also

IoRegisterDeviceInterface, IoAssignArcName, IoCreateUnprotectedSymbolicLink, IoDeleteSymbolicLink

 

IRP Major Function Codes

Each driver-specific I/O stack location (IO_STACK_LOCATION) for every IRP contains a major function code (IRP_MJ_XXX), which tells the driver what operation it or the underlying device driver should carry out to satisfy the I/O request. Each kernel-mode driver must provide dispatch routines for the major function codes that it must support.

The specific operations a driver carries out for a given IRP_MJ_XXX code depend somewhat on the underlying device, particularly for IRP_MJ_DEVICE_CONTROL and IRP_MJ_INTERNAL_DEVICE_CONTROL requests. For example, the requests sent to a keyboard driver are necessarily somewhat different from those sent to a disk driver. However, the I/O Manager defines the parameters and I/O stack location contents for each system-defined major function code.

Every higher-level driver must set up the appropriate I/O stack location in IRPs for the next-lower-level driver and call IoCallDriver, either with each input IRP, or with a driver-created IRP (if the higher-level driver holds on to the input IRP). Consequently, every intermediate driver must supply a dispatch routine for each major function code that the underlying device driver handles. Otherwise, a new intermediate driver will “break the chain” whenever an application or still higher-level driver attempts to send an I/O request down to the underlying device driver.

File system drivers also handle a required subset of system-defined IRP_MJ_XXX function codes, some with subordinate IRP_MN_XXX function codes.

Drivers handle IRPs set with some or all of the following major function codes:

IRP_MJ_CREATE

IRP_MJ_PNP

IRP_MJ_POWER

IRP_MJ_READ

IRP_MJ_WRITE

IRP_MJ_FLUSH_BUFFERS

IRP_MJ_QUERY_INFORMATION

IRP_MJ_SET_INFORMATION

IRP_MJ_DEVICE_CONTROL

IRP_MJ_INTERNAL_DEVICE_CONTROL

IRP_MJ_SYSTEM_CONTROL

IRP_MJ_CLEANUP

IRP_MJ_CLOSE

IRP_MJ_SHUTDOWN

The input and output parameters described in this section are the function-specific parameters in the IRP.

For more information about IRPs, see Handling IRPs.

 

IoDeleteSymbolicLink

The IoDeleteSymbolicLink routine removes a symbolic link from the system.

NTSTATUS

  IoDeleteSymbolicLink(

    IN PUNICODE_STRING  SymbolicLinkName

    );

Parameters

SymbolicLinkName

Pointer to a buffered Unicode string that is the user-visible name for the symbolic link.

Return Value

IoDeleteSymbolicLink returns STATUS_SUCCESS if the symbolic link object is deleted.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

Callers of IoDeleteSymbolicLink must be running at IRQL = PASSIVE_LEVEL.

See Also

IoCreateSymbolicLink, IoCreateUnprotectedSymbolicLink, IoDeassignArcName

 

IoDeleteDevice

The IoDeleteDevice routine removes a device object from the system, for example, when the underlying device is removed from the system.

VOID

  IoDeleteDevice(

    IN PDEVICE_OBJECT  DeviceObject

    );

Parameters

DeviceObject

Pointer to the device object to be deleted.

Return Value

None

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

When handling a PnP IRP_MN_REMOVE_DEVICE request, a PnP driver calls IoDeleteDevice to delete any associated device objects. See Handling an IRP_MN_REMOVE_DEVICE Request for details.

A legacy driver should call this routine when it is being unloaded or when its DriverEntry routine encounters a fatal initialization error, such as being unable to properly initialize a physical device. This routine also is called when a driver reconfigures its devices dynamically. For example, a disk driver called to repartition a disk would call IoDeleteDevice to tear down the device objects representing partitions to be replaced.

A driver must release certain resources for which the driver supplied storage in its device extension before it calls IoDeleteDevice. For example, if the driver stores the pointer to its interrupt object(s) in the device extension, it must call IoDisconnectInterrupt before calling IoDeleteDevice.

A driver can call IoDeleteDevice only once for a given device object.

When a driver calls IoDeleteDevice, the I/O Manager deletes the target device object if there are no outstanding references to it. However, if any outstanding references remain, the I/O Manager marks the device object as "delete pending" and deletes the device object when the references are released.

Callers of IoDeleteDevice must be running at IRQL < DISPATCH_LEVEL.

See Also

IoCreateDevice, IoDisconnectInterrupt

 

IoCompleteRequest

The IoCompleteRequest routine indicates that the caller has completed all processing for a given I/O request and is returning the given IRP to the I/O Manager.

VOID

  IoCompleteRequest(

    IN PIRP  Irp,

    IN CCHAR  PriorityBoost

    );

Parameters

Irp

Pointer to the IRP to be completed.

PriorityBoost

Specifies a system-defined constant by which to increment the runtime priority of the original thread that requested the operation. This value is IO_NO_INCREMENT if the original thread requested an operation the driver could complete quickly (so the requesting thread is not compensated for its assumed wait on I/O) or if the IRP is completed with an error. Otherwise, the set of PriorityBoost constants are device-type-specific. See ntddk.h or wdm.h for these constants.

Return Value

None

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

When a driver has finished all processing for a given IRP, it calls IoCompleteRequest. The I/O Manager checks the IRP to determine whether any higher-level drivers have set up an IoCompletion routine for the IRP. If so, each IoCompletion routine is called, in turn, until every layered driver in the chain has completed the IRP.

When all drivers have completed a given IRP, the I/O Manager returns status to the original requester of the operation. Note that a higher-level driver that sets up a driver-created IRP must supply an IoCompletion routine to release the IRP it created.

Never call IoCompleteRequest while holding a spin lock. Attempting to complete an IRP while holding a spin lock can cause deadlocks.

Callers of IoCompleteRequest must be running at IRQL <= DISPATCH_LEVEL.

See Also

IoSetCompletionRoutine

 

IoGetCurrentIrpStackLocation

The IoGetCurrentIrpStackLocation routine returns a pointer to the caller’s stack location in the given IRP.

PIO_STACK_LOCATION

  IoGetCurrentIrpStackLocation(

    IN PIRP  Irp

    );

Parameters

Irp

Pointer to the IRP.

Return Value

The routine returns a pointer to the I/O stack location for the driver.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

Every driver must call IoGetCurrentIrpStackLocation with each IRP it is sent in order to get any parameters for the current request. Unless a driver supplies a dispatch routine for each IRP_MJ_XXX code that the driver handles, the driver also must check its I/O stack location in the IRP to determine what operation is being requested.

If a driver is passing the same parameters that it received to the next-lower driver, it should call IoCopyCurrentIrpStackLocationToNext or IoSkipCurrentIrpStackLocation instead of getting a pointer to the next-lower stack location and copying the parameters manually.

See Also

IO_STACK_LOCATION, IoCallDriver, IoGetNextIrpStackLocation, IoSetNextIrpStackLocation

 

IO_STACK_LOCATION

The IO_STACK_LOCATION structure defines an I/O stack location, which is an entry in the I/O stack that is associated with each IRP. Each I/O stack location in an IRP has some common members and some request-type-specific members.

typedef struct _IO_STACK_LOCATION {

  UCHAR  MajorFunction;

  UCHAR  MinorFunction;

  UCHAR  Flags;

  UCHAR  Control;

  union {

        //

        // Parameters for IRP_MJ_CREATE

        //

        struct {

            PIO_SECURITY_CONTEXT SecurityContext;

            ULONG Options;

            USHORT POINTER_ALIGNMENT FileAttributes;

            USHORT ShareAccess;

            ULONG POINTER_ALIGNMENT EaLength;

        } Create;

        //

        // Parameters for IRP_MJ_READ

        //

        struct {

            ULONG Length;

            ULONG POINTER_ALIGNMENT Key;

            LARGE_INTEGER ByteOffset;

        } Read;

        //

        // Parameters for IRP_MJ_WRITE

        //

        struct {

            ULONG Length;

            ULONG POINTER_ALIGNMENT Key;

            LARGE_INTEGER ByteOffset;

        } Write;

        //

        // Parameters for IRP_MJ_QUERY_INFORMATION

        //

        struct {

            ULONG Length;

            FILE_INFORMATION_CLASS POINTER_ALIGNMENT FileInformationClass;

        } QueryFile;

        //

        // Parameters for IRP_MJ_SET_INFORMATION

        //

        struct {

            ULONG Length;

            FILE_INFORMATION_CLASS POINTER_ALIGNMENT FileInformationClass;

            PFILE_OBJECT FileObject;

            union {

                struct {

                    BOOLEAN ReplaceIfExists;

                    BOOLEAN AdvanceOnly;

                };

                ULONG ClusterCount;

                HANDLE DeleteHandle;

            };

        } SetFile;

        //

        // Parameters for IRP_MJ_QUERY_VOLUME_INFORMATION

        //

        struct {

            ULONG Length;

            FS_INFORMATION_CLASS POINTER_ALIGNMENT FsInformationClass;

        } QueryVolume;

        //

        // Parameters for IRP_MJ_DEVICE_CONTROL and IRP_MJ_INTERNAL_DEVICE_CONTROL

        //

        struct {

            ULONG OutputBufferLength;

            ULONG POINTER_ALIGNMENT InputBufferLength;

            ULONG POINTER_ALIGNMENT IoControlCode;

            PVOID Type3InputBuffer;

        } DeviceIoControl;

        //

        // Nonsystem service parameters.

        //

        // Parameters for IRP_MN_MOUNT_VOLUME

        //

        struct {

            PVOID DoNotUse1;

            PDEVICE_OBJECT DeviceObject;

        } MountVolume;

        //

        // Parameters for IRP_MN_VERIFY_VOLUME

        //

        struct {

            PVOID DoNotUse1;

            PDEVICE_OBJECT DeviceObject;

        } VerifyVolume;

        //

        // Parameters for Scsi using IRP_MJ_INTERNAL_DEVICE_CONTROL

        //

        struct {

            struct _SCSI_REQUEST_BLOCK *Srb;

        } Scsi;

        //

        // Parameters for IRP_MN_QUERY_DEVICE_RELATIONS

        //

        struct {

            DEVICE_RELATION_TYPE Type;

        } QueryDeviceRelations;

        //

        // Parameters for IRP_MN_QUERY_INTERFACE

        //

        struct {

            CONST GUID *InterfaceType;

            USHORT Size;

            USHORT Version;

            PINTERFACE Interface;

            PVOID InterfaceSpecificData;

        } QueryInterface;

        //

        // Parameters for IRP_MN_QUERY_CAPABILITIES

        //

        struct {

            PDEVICE_CAPABILITIES Capabilities;

        } DeviceCapabilities;

        //

        // Parameters for IRP_MN_FILTER_RESOURCE_REQUIREMENTS

        //

        struct {

            PIO_RESOURCE_REQUIREMENTS_LIST IoResourceRequirementList;

        } FilterResourceRequirements;

        //

        // Parameters for IRP_MN_READ_CONFIG and IRP_MN_WRITE_CONFIG

        //

        struct {

            ULONG WhichSpace;

            PVOID Buffer;

            ULONG Offset;

            ULONG POINTER_ALIGNMENT Length;

        } ReadWriteConfig;

        //

        // Parameters for IRP_MN_SET_LOCK

        //

        struct {

            BOOLEAN Lock;

        } SetLock;

        //

        // Parameters for IRP_MN_QUERY_ID

        //

        struct {

            BUS_QUERY_ID_TYPE IdType;

        } QueryId;

        //

        // Parameters for IRP_MN_QUERY_DEVICE_TEXT

        //

        struct {

            DEVICE_TEXT_TYPE DeviceTextType;

            LCID POINTER_ALIGNMENT LocaleId;

        } QueryDeviceText;

        //

        // Parameters for IRP_MN_DEVICE_USAGE_NOTIFICATION

        //

        struct {

            BOOLEAN InPath;

            BOOLEAN Reserved[3];

            DEVICE_USAGE_NOTIFICATION_TYPE POINTER_ALIGNMENT Type;

        } UsageNotification;

        //

        // Parameters for IRP_MN_WAIT_WAKE

        //

        struct {

            SYSTEM_POWER_STATE PowerState;

        } WaitWake;

        //

        // Parameter for IRP_MN_POWER_SEQUENCE

        //

        struct {

            PPOWER_SEQUENCE PowerSequence;

        } PowerSequence;

        //

        // Parameters for IRP_MN_SET_POWER and IRP_MN_QUERY_POWER

        //

        struct {

            ULONG SystemContext;

            POWER_STATE_TYPE POINTER_ALIGNMENT Type;

            POWER_STATE POINTER_ALIGNMENT State;

            POWER_ACTION POINTER_ALIGNMENT ShutdownType;

        } Power;

        //

        // Parameters for IRP_MN_START_DEVICE

        //

        struct {

            PCM_RESOURCE_LIST AllocatedResources;

            PCM_RESOURCE_LIST AllocatedResourcesTranslated;

        } StartDevice;

        //

        // Parameters for WMI Minor IRPs

        //

        struct {

            ULONG_PTR ProviderId;

            PVOID DataPath;

            ULONG BufferSize;

            PVOID Buffer;

        } WMI;

        //

        // Others - driver-specific

        //

        struct {

            PVOID Argument1;

            PVOID Argument2;

            PVOID Argument3;

            PVOID Argument4;

        } Others;

    } Parameters;

  PDEVICE_OBJECT  DeviceObject;

  PFILE_OBJECT  FileObject;

  .

  .

} IO_STACK_LOCATION, *PIO_STACK_LOCATION;

Members

MajorFunction

The IRP major function code indicating the type of I/O operation to be performed.

MinorFunction

A subfunction code for MajorFunction. The PnP Manager, the Power Manager, file system drivers, and SCSI class drivers set this member for some requests.

Flags

Request-type-specific values used almost exclusively by file system drivers. Removable-media device drivers check whether this member is set with SL_OVERRIDE_VERIFY_VOLUME for read requests to determine whether to continue the read operation even if the device object’s Flags is set with DO_VERIFY_VOLUME. Intermediate drivers layered over a removable-media device driver must copy this member into the I/O stack location of the next-lower driver in all incoming IRP_MJ_READ requests.

Control

Drivers can check this member to determine whether it is set with SL_PENDING_RETURNED. Drivers have read-only access to this member.

Parameters

A union that depends on the major and minor IRP function code values contained in MajorFunction and MinorFunction. For more information, see IRP Major Function Codes.

DeviceObject

A pointer to the driver-created DEVICE_OBJECT structure representing the target physical, logical, or virtual device for which this driver is to handle the IRP.

FileObject

A pointer to a FILE_OBJECT structure that represents the file object, if any, that is associated with DeviceObject pointer.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

For each IRP, there is one IO_STACK_LOCATION structure for each driver in a driver stack. Each IRP's set of I/O stack locations is appended to the IRP, following the IRP structure.

Every higher-level driver is responsible for setting up the I/O stack location for the next-lower driver in each IRP. A driver must call IoGetCurrentIrpStackLocation to get a pointer to its own stack location for each IRP. Higher-level drivers can call IoGetNextIrpStackLocation to get a pointer to the next-lower driver’s stack location.

The higher-level driver must set up the stack location contents before calling IoCallDriver to pass an IRP to the lower-level driver. If the driver will pass the input IRP on to the next lower-level driver, the dispatch routine should call IoSkipCurrentIrpStackLocation or IoCopyCurrentIrpStackLocationToNext to set up the I/O stack location of the next-lower driver.

A higher-level driver’s call to IoCallDriver sets the DeviceObject member to the next-lower-level driver’s target device object, in the I/O stack location of the lower driver. The I/O Manager passes each higher-level driver’s IoCompletion routine a pointer to its own device object when the IoCompletion routine is called on completion of the IRP.

If a higher-level driver allocates IRPs to make requests of its own, its IoCompletion routine is passed a NULL DeviceObject pointer if that driver neither allocates a stack location for itself nor sets up the DeviceObject pointer in its own stack location of the newly allocated IRP.

In some cases, a higher-level driver layered over a mass-storage device driver is responsible for splitting up large transfer requests for the underlying device driver. In particular, SCSI class drivers must check the Parameters.Read.Length and Parameters.Write.Length, determine whether the size of the requested transfer exceeds the underlying HBA’s transfer capabilities, and, if so, split the Length of the original request into a sequence of partial transfers to satisfy the original IRP.

See Also

IoCallDriver,
IoCopyCurrentIrpStackLocationToNext,
IoGetCurrentIrpStackLocation,
IoGetNextIrpStackLocation,
IoSetCompletionRoutine,
IoSkipCurrentIrpStackLocation,
IoSetNextIrpStackLocation,
IO_STATUS_BLOCK,
IRP

 

IRP

The IRP structure represents an I/O request packet. Drivers can use the following members of the IRP structure.

typedef struct _IRP {

  .

  .

  PMDL  MdlAddress;

  ULONG  Flags;

  union {

    struct _IRP  *MasterIrp;

    .

    .

    PVOID  SystemBuffer;

  } AssociatedIrp;

  .

  .

  IO_STATUS_BLOCK  IoStatus;

  KPROCESSOR_MODE  RequestorMode;

  BOOLEAN PendingReturned;

  .

  .

  BOOLEAN  Cancel;

  KIRQL  CancelIrql;

  .

  .

  PDRIVER_CANCEL  CancelRoutine;

  PVOID UserBuffer;

  union {

    struct {

    .

    .

    union {

      KDEVICE_QUEUE_ENTRY DeviceQueueEntry;

      struct {

        PVOID  DriverContext[4];

      };

    };

    .

    .

    PETHREAD  Thread;

    .

    .

    LIST_ENTRY  ListEntry;

    .

    .

    } Overlay;

  .

  .

  } Tail;

} IRP, *PIRP;

Members

MdlAddress

Pointer to an MDL describing a user buffer, if the driver is using direct I/O, and the IRP major function code is one of the following:

IRP_MJ_READ

The MDL describes an empty buffer that the device or driver fills in.

IRP_MJ_WRITE

The MDL describes a buffer that contains data for the device or driver.

IRP_MJ_DEVICE_CONTROL or IRP_MJ_INTERNAL_DEVICE_CONTROL

If the IOCTL code specifies the METHOD_IN_DIRECT transfer type, the MDL describes a buffer that contains data for the device or driver.

If the IOCTL code specifies the METHOD_OUT_DIRECT transfer type, the MDL describes an empty buffer that the device or driver fills in.

For more information about the buffers that are associated with METHOD_IN_DIRECT and METHOD_OUT_DIRECT transfer types in IOCTL codes, see Buffer Descriptions for I/O Control Codes.

If the driver is not using direct I/O, this pointer is NULL.

Flags

File system drivers use this field, which is read-only for all drivers. Network and, possibly, highest-level device drivers also might read this field, which can be set with one or more of the following system-defined masks:

IRP_NOCACHE
IRP_PAGING_IO
IRP_MOUNT_COMPLETION
IRP_SYNCHRONOUS_API
IRP_ASSOCIATED_IRP
IRP_BUFFERED_IO
IRP_DEALLOCATE_BUFFER
IRP_INPUT_OPERATION
IRP_SYNCHRONOUS_PAGING_IO
IRP_CREATE_OPERATION
IRP_READ_OPERATION
IRP_WRITE_OPERATION
IRP_CLOSE_OPERATION
IRP_DEFER_IO_COMPLETION

AssociatedIrp.MasterIrp

Pointer to the master IRP in an IRP that was created by a highest-level driver’s call to IoMakeAssociatedIrp.

AssociatedIrp.SystemBuffer

Pointer to a system-space buffer.

If the driver is using buffered I/O, the buffer's purpose is determined by the IRP major function code, as follows:

IRP_MJ_READ

The buffer receives data from the device or driver. The buffer's length is specified by Parameters.Read.Length in the driver's IO_STACK_LOCATION structure.

IRP_MJ_WRITE

The buffer supplies data for the device or driver. The buffer's length is specified by Parameters.Write.Length in the driver's IO_STACK_LOCATION structure.

IRP_MJ_DEVICE_CONTROL or IRP_MJ_INTERNAL_DEVICE_CONTROL

The buffer represents both the input and output buffers that are supplied to DeviceIoControl and IoBuildDeviceIoControlRequest. Output data overwrites input data.

For input, the buffer's length is specified by Parameters.DeviceIoControl.InputBufferLength in the driver's IO_STACK_LOCATION structure.

For output, the buffer's length is specified by Parameters.DeviceIoControl.OutputBufferLength in the driver's IO_STACK_LOCATION structure.

For more information, see Buffer Descriptions for I/O Control Codes.

If the driver is using direct I/O, the buffer's purpose is determined by the IRP major function code, as follows:

IRP_MJ_READ

NULL.

IRP_MJ_WRITE

NULL.

IRP_MJ_DEVICE_CONTROL or IRP_MJ_INTERNAL_DEVICE_CONTROL

The buffer represents the input buffer that is supplied to DeviceIoControl and IoBuildDeviceIoControlRequest.

The buffer's length is specified by Parameters.DeviceIoControl.InputBufferLength in the driver's IO_STACK_LOCATION structure.

For more information, see Buffer Descriptions for I/O Control Codes.

IoStatus

Contains the IO_STATUS_BLOCK structure in which a driver stores status and information before calling IoCompleteRequest.

RequestorMode

Indicates the execution mode of the original requester of the operation, one of UserMode or KernelMode. PendingReturned

If set to TRUE, a driver has marked the IRP pending. Each IoCompletion routine should check the value of this flag. If the flag is TRUE, and if the IoCompletion routine will not return STATUS_MORE_PROCESSING_REQUIRED, the routine should call IoMarkIrpPending to propagate the pending status to drivers above it in the device stack.

Cancel

If set to TRUE, the IRP either is or should be canceled.

CancelIrql

Contains the IRQL at which a driver is running when IoAcquireCancelSpinLock is called.

CancelRoutine

Contains the entry point for a driver-supplied Cancel routine to be called if the IRP is canceled. NULL indicates that the IRP is not currently cancelable.

UserBuffer

Contains the address of an output buffer if the major function code in the I/O stack location is IRP_MJ_DEVICE_CONTROL or IRP_MJ_INTERNAL_DEVICE_CONTROL and the I/O control code was defined with METHOD_NEITHER.

Tail.Overlay.DeviceQueueEntry

If IRPs are queued in the device queue associated with the driver’s device object, this field links IRPs in the device queue. These links can be used only while the driver is processing the IRP.

Tail.Overlay.DriverContext

If IRPs are not queued in the device queue associated with the driver’s device object, this field can be used by the driver to store up to four pointers. This field can be used only while the driver owns the IRP.

Tail.Overlay.Thread

Is a pointer to the caller’s thread control block. Higher-level drivers that allocate IRPs for lower-level removable-media drivers must set this field in the IRPs they allocate. Otherwise, the FSD cannot determine which thread to notify if the underlying device driver indicates that the media requires verification.

Tail.Overlay.ListEntry

If a driver manages its own internal queues of IRPs, it uses this field to link one IRP to the next. These links can be used only while the driver is holding the IRP in its queue or is processing the IRP.

Headers

Defined in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

Undocumented members of the IRP structure are reserved, used only by the I/O Manager or, in some cases, by FSDs.

An IRP is the basic I/O Manager structure used to communicate with drivers and to allow drivers to communicate with each other. A packet consists of two different parts:

·                       Header, or fixed part of the packet – This is used by the I/O Manager to store information about the original request, such as the caller’s device-independent parameters, the address of the device object upon which a file is open, and so on. It is also used by drivers to store information such as the final status of the request.

·                       I/O stack locations – Following the header is a set of I/O stack locations, one per driver in the chain of layered drivers for which the request is bound. Each stack location contains the parameters, function codes, and context used by the corresponding driver to determine what it is supposed to be doing. For more information, see the IO_STACK_LOCATION structure.

While a higher-level driver might check the value of the Cancel Boolean in an IRP, that driver cannot assume the IRP will be completed with STATUS_CANCELLED by a lower-level driver even if the value is TRUE.

See Also

IoCreateDevice, IoGetCurrentIrpStackLocation, IoGetNextIrpStackLocation, IoSetCancelRoutine, IoSetNextIrpStackLocation, IO_STACK_LOCATION, IO_STATUS_BLOCK \

 

OpenSCManager

The OpenSCManager function establishes a connection to the service control manager on the specified computer and opens the specified service control manager database.

SC_HANDLE OpenSCManager(

  LPCTSTR lpMachineName,

  LPCTSTR lpDatabaseName,

  DWORD dwDesiredAccess

);

Parameters

lpMachineName

[in] Pointer to a null-terminated string that specifies the name of the target computer. If the pointer is NULL or points to an empty string, the function connects to the service control manager on the local computer.

lpDatabaseName

[in] Pointer to a null-terminated string that specifies the name of the service control manager database to open. This parameter should be set to SERVICES_ACTIVE_DATABASE. If it is NULL, the SERVICES_ACTIVE_DATABASE database is opened by default.

dwDesiredAccess

[in] Access to the service control manager. For a list of access rights, see Service Security and Access Rights.

Before granting the requested access rights, the system checks the access token of the calling process against the discretionary access-control list of the security descriptor associated with the service control manager.

The SC_MANAGER_CONNECT access right is implicitly specified by calling this function.

Return Values

If the function succeeds, the return value is a handle to the specified service control manager database.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

The following error codes can be set by the SCM. Other error codes can be set by the registry functions that are called by the SCM.

Return Code

Description

ERROR_ACCESS_DENIED

The requested access was denied.

ERROR_DATABASE_DOES_NOT_EXIST

The specified database does not exist.

ERROR_INVALID_PARAMETER

A specified parameter is invalid.

Remarks

When a process uses the OpenSCManager function to open a handle to a service control manager database, the system performs a security check before granting the requested access.

Only authenticated users are granted the SC_MANAGER_CONNECT, SC_MANAGER_ENUMERATE_SERVICE, and SC_MANAGER_QUERY_LOCK_STATUS access rights.

Windows 2000/NT:  All processes are granted the SC_MANAGER_CONNECT, SC_MANAGER_ENUMERATE_SERVICE, and SC_MANAGER_QUERY_LOCK_STATUS access rights. This enables any process to open a service control manager database handle that it can use in the OpenService, EnumServicesStatus, and QueryServiceLockStatus functions.

Only processes with Administrator privileges are able to open a database handle that can be used by the CreateService and LockServiceDatabase functions.

The returned handle is only valid for the process that called the OpenSCManager function. It can be closed by calling the CloseServiceHandle function.

Example Code

For an example, see Opening an SCManager Database.

Requirements

Client: Included in Windows XP, Windows 2000 Professional, and Windows NT Workstation.
Server: Included in Windows Server 2003, Windows 2000 Server, and Windows NT Server.
Unicode: Implemented as Unicode and ANSI versions.
Header: Declared in Winsvc.h; include Windows.h.
Library: Use Advapi32.lib.

See Also

CloseServiceHandle, CreateService, EnumServicesStatus, LockServiceDatabase, OpenService, QueryServiceLockStatus, Service Functions, Services Overview

 

CreateService

The CreateService function creates a service object and adds it to the specified service control manager database.

SC_HANDLE CreateService(

  SC_HANDLE hSCManager,

  LPCTSTR lpServiceName,

  LPCTSTR lpDisplayName,

  DWORD dwDesiredAccess,

  DWORD dwServiceType,

  DWORD dwStartType,

  DWORD dwErrorControl,

  LPCTSTR lpBinaryPathName,

  LPCTSTR lpLoadOrderGroup,

  LPDWORD lpdwTagId,

  LPCTSTR lpDependencies,

  LPCTSTR lpServiceStartName,

  LPCTSTR lpPassword

);

Parameters

hSCManager

[in] Handle to the service control manager database. This handle is returned by the OpenSCManager function and must have the SC_MANAGER_CREATE_SERVICE access right. For more information, see Service Security and Access Rights.

lpServiceName

[in] Pointer to a null-terminated string that specifies the name of the service to install. The maximum string length is 256 characters. The service control manager database preserves the case of the characters, but service name comparisons are always case insensitive. Forward-slash (/) and back-slash (\) are invalid service name characters.

lpDisplayName

[in] Pointer to a null-terminated string that contains the display name to be used by user interface programs to identify the service. This string has a maximum length of 256 characters. The name is case-preserved in the service control manager. Display name comparisons are always case-insensitive.

dwDesiredAccess

[in] Access to the service. Before granting the requested access, the system checks the access token of the calling process. For a list of values, see Service Security and Access Rights.

dwServiceType

[in] Service types. This parameter can be one of the following values.

Type

Meaning

SERVICE_FILE_SYSTEM_DRIVER

File system driver service.

SERVICE_KERNEL_DRIVER

Driver service.

SERVICE_WIN32_OWN_PROCESS

Service that runs in its own process.

SERVICE_WIN32_SHARE_PROCESS

Service that shares a process with other services.

 

If you specify either SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS, and the service is running in the context of the LocalSystem account, you can also specify the following type.

Type

Meaning

SERVICE_INTERACTIVE_PROCESS

The service can interact with the desktop.

For more information, see Interactive Services.

dwStartType

[in] Service start options. This parameter can be one of the following values.

Type

Meaning

SERVICE_AUTO_START

A service started automatically by the service control manager during system startup.

SERVICE_BOOT_START

A device driver started by the system loader. This value is valid only for driver services.

SERVICE_DEMAND_START

A service started by the service control manager when a process calls the StartService function.

SERVICE_DISABLED

A service that cannot be started. Attempts to start the service result in the error code ERROR_SERVICE_DISABLED.

SERVICE_SYSTEM_START

A device driver started by the IoInitSystem function. This value is valid only for driver services.

dwErrorControl

[in] Severity of the error, and action taken, if this service fails to start. This parameter can be one of the following values.

Value

Meaning

SERVICE_ERROR_IGNORE

The startup program logs the error but continues the startup operation.

SERVICE_ERROR_NORMAL

The startup program logs the error and puts up a message box pop-up but continues the startup operation.

SERVICE_ERROR_SEVERE

The startup program logs the error. If the last-known-good configuration is being started, the startup operation continues. Otherwise, the system is restarted with the last-known-good configuration.

SERVICE_ERROR_CRITICAL

The startup program logs the error, if possible. If the last-known-good configuration is being started, the startup operation fails. Otherwise, the system is restarted with the last-known good configuration.

lpBinaryPathName

[in] Pointer to a null-terminated string that contains the fully qualified path to the service binary file. If the path contains a space, it must be quoted so that it is correctly interpreted. For example, "d:\\my share\\myservice.exe" should be specified as "\"d:\\my share\\myservice.exe\"".

The path can also include arguments for an auto-start service. For example, "d:\\myshare\\myservice.exe arg1 arg2". These arguments are passed to the service entry point (typically the main function).

lpLoadOrderGroup

[in] Pointer to a null-terminated string that names the load ordering group of which this service is a member. Specify NULL or an empty string if the service does not belong to a group.

The startup program uses load ordering groups to load groups of services in a specified order with respect to the other groups. The list of load ordering groups is contained in the ServiceGroupOrder value of the following registry key:

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control

lpdwTagId

[out] Pointer to a variable that receives a tag value that is unique in the group specified in the lpLoadOrderGroup parameter. Specify NULL if you are not changing the existing tag.

You can use a tag for ordering service startup within a load ordering group by specifying a tag order vector in the GroupOrderList value of the following registry key:

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control

Tags are only evaluated for driver services that have SERVICE_BOOT_START or SERVICE_SYSTEM_START start types.

lpDependencies

[in] Pointer to a double null-terminated array of null-separated names of services or load ordering groups that the system must start before this service. Specify NULL or an empty string if the service has no dependencies. Dependency on a group means that this service can run if at least one member of the group is running after an attempt to start all members of the group.

You must prefix group names with SC_GROUP_IDENTIFIER so that they can be distinguished from a service name, because services and service groups share the same name space.

lpServiceStartName

[in] Pointer to a null-terminated string that specifies the name of the account under which the service should run. If the service type is SERVICE_WIN32_OWN_PROCESS, use an account name in the form DomainName\UserName. The service process will be logged on as this user. If the account belongs to the built-in domain, you can specify .\UserName.

If this parameter is NULL, CreateService uses the LocalSystem account. If the service type specifies SERVICE_INTERACTIVE_PROCESS, the service must run in the LocalSystem account.

If this parameter is NT AUTHORITY\LocalService, CreateService uses the LocalService account. If the parameter is NT AUTHORITY\NetworkService, CreateService uses the NetworkService account.

Windows NT:  If the service type is SERVICE_WIN32_SHARE_PROCESS, you must specify the LocalSystem account. On later versions of Windows, a shared process can run as any user.

If the service type is SERVICE_KERNEL_DRIVER or SERVICE_FILE_SYSTEM_DRIVER, the name is the driver object name that the system uses to load the device driver. Specify NULL if the driver is to use a default object name created by the I/O system.

lpPassword

[in] Pointer to a null-terminated string that contains the password to the account name specified by the lpServiceStartName parameter. Specify an empty string if the account has no password or if the service runs in the LocalService, NetworkService, or LocalSystem account. For more information, see Service Record List.

Passwords are ignored for driver services.

Return Values

If the function succeeds, the return value is a handle to the service.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

The following error codes can be set by the service control manager. Other error codes can be set by the registry functions that are called by the service control manager.

Return Code

Description

ERROR_ACCESS_DENIED

The handle to the SCM database does not have the SC_MANAGER_CREATE_SERVICE access right.

ERROR_CIRCULAR_DEPENDENCY

A circular service dependency was specified.

ERROR_DUPLICATE_SERVICE_NAME

The display name already exists in the service control manager database either as a service name or as another display name.

ERROR_INVALID_HANDLE

The handle to the specified service control manager database is invalid.

ERROR_INVALID_NAME

The specified service name is invalid.

ERROR_INVALID_PARAMETER

A parameter that was specified is invalid.

ERROR_INVALID_SERVICE_ACCOUNT

The user account name specified in the lpServiceStartName parameter does not exist.

ERROR_SERVICE_EXISTS

The specified service already exists in this database.

Remarks

The CreateService function creates a service object and installs it in the service control manager database by creating a key with the same name as the service under the following registry key:

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services

Information specified by CreateService, ChangeServiceConfig, and ChangeServiceConfig2 is saved as values under this key. The following are examples of values stored for a service.

Value

Description

DependOnGroup

Load-ordering groups on which this service depends, as specified by lpDependencies.

DependOnService

Services on which this service depends, as specified by lpDependencies.

Description

Description specified by ChangeServiceConfig2 .

DisplayName

Display name specified by lpDisplayName.

ErrorControl

Error control specified by dwErrorControl.

FailureActions

Failure actions specified by ChangeServiceConfig2 .

Group

Load ordering group specified by lpLoadOrderGroup.

ImagePath

Name of binary file, as specified by lpBinaryPathName.

ObjectName

Account name specified by lpServiceStartName.

Start

When to start service, as specified by dwStartType.

Tag

Tag identifier specified by lpdwTagId.

Type

Service type specified by dwServiceType.

 

Setup programs and the service itself can create additional subkeys for service-specific information.

The returned handle is only valid for the process that called CreateService. It can be closed by calling the CloseServiceHandle function.

If you are creating services that share a process, avoid calling functions with process-wide effects, such as ExitProcess. In addition, do not unload your service DLL.

Example Code

For an example, see Installing a Service.

Requirements

Client: Included in Windows XP, Windows 2000 Professional, and Windows NT Workstation.
Server: Included in Windows Server 2003, Windows 2000 Server, and Windows NT Server.
Unicode: Implemented as Unicode and ANSI versions.
Header: Declared in Winsvc.h; include Windows.h.
Library: Use Advapi32.lib.

See Also

Services Overview, Service Functions, ChangeServiceConfig, ChangeServiceConfig2, CloseServiceHandle, ControlService, DeleteService, EnumDependentServices, OpenSCManager, QueryServiceConfig, QueryServiceObjectSecurity, QueryServiceStatus, SetServiceObjectSecurity, StartService

 

OpenService

The OpenService function opens an existing service.

SC_HANDLE OpenService(

  SC_HANDLE hSCManager,

  LPCTSTR lpServiceName,

  DWORD dwDesiredAccess

);

Parameters

hSCManager

[in] Handle to the service control manager database. The OpenSCManager function returns this handle.

lpServiceName

[in] Pointer to a null-terminated string that specifies the name of the service to open. The maximum string length is 256 characters. The service control manager database preserves the case of the characters, but service name comparisons are always case insensitive. Forward-slash (/) and backslash (\) are invalid service name characters.

dwDesiredAccess

[in] Access to the service. For a list of access rights, see Service Security and Access Rights.

Before granting the requested access, the system checks the access token of the calling process against the discretionary access-control list of the security descriptor associated with the service object.

Return Values

If the function succeeds, the return value is a handle to the service.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

The following error codes can be set by the service control manager. Others can be set by the registry functions that are called by the service control manager.

Return Code

Description

ERROR_ACCESS_DENIED

The handle does not have access to the service.

ERROR_INVALID_HANDLE

The specified handle is invalid.

ERROR_INVALID_NAME

The specified service name is invalid.

ERROR_SERVICE_DOES_NOT_EXIST

The specified service does not exist.

Remarks

The returned handle is only valid for the process that called OpenService. It can be closed by calling the CloseServiceHandle function.

Example Code

For an example, see Starting a Service.

Requirements

Client: Included in Windows XP, Windows 2000 Professional, and Windows NT Workstation.
Server: Included in Windows Server 2003, Windows 2000 Server, and Windows NT Server.
Unicode: Implemented as Unicode and ANSI versions.
Header: Declared in Winsvc.h; include Windows.h.
Library: Use Advapi32.lib.

See Also

ChangeServiceConfig, CloseServiceHandle, ControlService, CreateService, DeleteService, EnumDependentServices, OpenSCManager, QueryServiceConfig, QueryServiceObjectSecurity, QueryServiceStatus, Service Functions, Services Overview, SetServiceObjectSecurity, StartService

 

StartService

The StartService function starts a service.

BOOL StartService(

  SC_HANDLE hService,

  DWORD dwNumServiceArgs,

  LPCTSTR* lpServiceArgVectors

);

Parameters

hService

[in] Handle to the service. This handle is returned by the OpenService or CreateService function, and it must have the SERVICE_START access right. For more information, see Service Security and Access Rights.

dwNumServiceArgs

[in] Number of strings in the lpServiceArgVectors array. If lpServiceArgVectors is NULL, this parameter can be zero.

lpServiceArgVectors

[in] Pointer to an array of pointers to null-terminated strings to be passed to a service as arguments. Driver services do not receive these arguments. If no arguments are passed to the service, this parameter can be NULL. The service accesses these arguments through its ServiceMain function. The first argument (argv[0]) is the name of the service by default, followed by the arguments, if any, in the lpServiceArgVectors array.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

The following error codes can be set by the service control manager. Others can be set by the registry functions that are called by the service control manager.

Return Code

Description

ERROR_ACCESS_DENIED

The handle does not have the SERVICE_START access right.

ERROR_INVALID_HANDLE

The handle is invalid.

ERROR_PATH_NOT_FOUND

The service binary file could not be found.

ERROR_SERVICE_ALREADY_RUNNING

An instance of the service is already running.

ERROR_SERVICE_DATABASE_LOCKED

The database is locked.

ERROR_SERVICE_DEPENDENCY_DELETED

The service depends on a service that does not exist or has been marked for deletion.

ERROR_SERVICE_DEPENDENCY_FAIL

The service depends on another service that has failed to start.

ERROR_SERVICE_DISABLED

The service has been disabled.

ERROR_SERVICE_LOGON_FAILED

The service could not be logged on. This error occurs if the service was started from an account that does not have the "Log on as a service" right.

ERROR_SERVICE_MARKED_FOR_DELETE

The service has been marked for deletion.

ERROR_SERVICE_NO_THREAD

A thread could not be created for the service.

ERROR_SERVICE_REQUEST_TIMEOUT

The process for the service was started, but it did not call StartServiceCtrlDispatcher, or the thread that called StartServiceCtrlDispatcher may be blocked in a control handler function.

Remarks

When a driver service is started, the StartService function does not return until the device driver has finished initializing.

When a service is started, the service control manager spawns the service process, if necessary. If the specified service shares a process with other services, the required process may already exist. The StartService function does not wait for the first status update from the new service, because it can take a while. Instead, it returns when the service control manager receives notification from the service control dispatcher that the ServiceMain thread for this service was created successfully.

The service control manager sets the following default status values before returning from StartService:

·                       Current state of the service is set to SERVICE_START_PENDING.

·                       Controls accepted is set to none (zero).

·                       The CheckPoint value is set to zero.

·                       The WaitHint time is set to 2 seconds.

The calling process can determine if the new service has finished its initialization by calling the QueryServiceStatus function periodically to query the service's status.

A service cannot call StartService during initialization. The reason is that the service control manager locks the service control database during initialization, so a call to StartService will block. Once the service reports to the service control manager that it has successfully started, it can call StartService.

Example Code

For an example, see Starting a Service.

Requirements

Client: Included in Windows XP, Windows 2000 Professional, and Windows NT Workstation.
Server: Included in Windows Server 2003, Windows 2000 Server, and Windows NT Server.
Unicode: Implemented as Unicode and ANSI versions.
Header: Declared in Winsvc.h; include Windows.h.
Library: Use Advapi32.lib.

See Also

ControlService, CreateService, OpenService, QueryServiceStatus, Service Functions, Services Overview, ServiceMain

 

CreateFile

The CreateFile function creates or opens a file, directory, physical disk, volume, console buffer, tape drive, communications resource, mailslot, or pipe. The function returns a handle that can be used to access the object.

Windows Me/98/95:  You cannot open a directory, physical disk, or volume using CreateFile.

HANDLE CreateFile(

  LPCTSTR lpFileName,

  DWORD dwDesiredAccess,

  DWORD dwShareMode,

  LPSECURITY_ATTRIBUTES lpSecurityAttributes,

  DWORD dwCreationDisposition,

  DWORD dwFlagsAndAttributes,

  HANDLE hTemplateFile

);

Parameters

lpFileName

[in] Pointer to a null-terminated string that specifies the name of the object to create or open.

In the ANSI version of this function, the name is limited to MAX_PATH characters. To extend this limit to 32,767 wide characters, call the Unicode version of the function and prepend "\\?\" to the path. For more information, see Naming a File.

Windows Me/98/95:  This string must not exceed MAX_PATH characters.

dwDesiredAccess

[in] Access to the object. For a list of values, see File Security and Access Rights. You cannot request an access mode that conflicts with the sharing mode specified in a previous open request whose handle is still open.

If this parameter is zero, the application can query file and device attributes without accessing the device. This is useful if an application wants to determine the size of a floppy disk drive and the formats it supports without requiring a floppy in the drive. It can also be used to test for the file's or directory's existence without opening it for read or write access.

dwShareMode

[in] Sharing mode of the object. You cannot request a sharing mode that conflicts with the access mode specified in a previous open request whose handle is still open.

If this parameter is zero and CreateFile succeeds, the object cannot be shared and cannot be opened again until the handle is closed. For more information about sharing violations, see the Remarks section.

To enable other processes to share the object while your process has it open, use a combination of one or more of the following values to specify the type of access they can request when they open the object. These sharing options remain in effect until you close the handle to the object.

Value

Meaning

FILE_SHARE_DELETE

Enables subsequent open operations on the object to request delete access. Otherwise, other processes cannot open the object if they request delete access.

If the object has already been opened with delete access, the sharing mode must include this flag.

Windows Me/98/95:  This flag is not supported.

FILE_SHARE_READ

Enables subsequent open operations on the object to request read access. Otherwise, other processes cannot open the object if they request read access.

If the object has already been opened with read access, the sharing mode must include this flag.

FILE_SHARE_WRITE

Enables subsequent open operations on the object to request write access. Otherwise, other processes cannot open the object if they request write access.

If the object has already been opened with write access, the sharing mode must include this flag.

lpSecurityAttributes

[in] Pointer to a SECURITY_ATTRIBUTES structure that determines whether the returned handle can be inherited by child processes. If lpSecurityAttributes is NULL, the handle cannot be inherited.

The lpSecurityDescriptor member of the structure specifies a security descriptor for the object. If lpSecurityAttributes is NULL, the object gets a default security descriptor. The ACLs in the default security descriptor for a file or directory are inherited from its parent directory. Note that the target file system must support security on files and directories for this parameter to have an effect on them. (This is indicated when GetVolumeInformation returns FS_PERSISTENT_ACLS.) CreateFile ignores lpSecurityDescriptor when opening an existing file, but continues to use the other structure members.

dwCreationDisposition

[in] Action to take on files that exist, and which action to take when files do not exist. For more information about this parameter, see the Remarks section. This parameter must be one of the following values.

Value

Meaning

CREATE_ALWAYS

Creates a new file. If the file exists, the function overwrites the file, clears the existing attributes, combines the specified file attributes and flags with FILE_ATTRIBUTE_ARCHIVE, but does not set the security descriptor specified by the SECURITY_ATTRIBUTES structure.

CREATE_NEW

Creates a new file. The function fails if the specified file already exists.

OPEN_ALWAYS

Opens the file, if it exists. If the file does not exist, the function creates the file as if dwCreationDisposition were CREATE_NEW.

OPEN_EXISTING

Opens the file. The function fails if the file does not exist.

For a discussion of why you should use OPEN_EXISTING for devices, see Remarks.

TRUNCATE_EXISTING

Opens the file and truncates it so that its size is zero bytes. The calling process must open the file with the GENERIC_WRITE access right. The function fails if the file does not exist.

dwFlagsAndAttributes

[in] File attributes and flags.

The following file attributes and flags are used only for file objects, not other types of objects created by CreateFile.

When CreateFile opens an existing file, it combines the file flags with existing file attributes, and ignores any supplied file attributes.

This parameter can include any combination of the file attributes (noting that all other file attributes override FILE_ATTRIBUTE_NORMAL).

Attribute

Meaning

FILE_ATTRIBUTE_ARCHIVE

The file should be archived. Applications use this attribute to mark files for backup or removal.

FILE_ATTRIBUTE_ENCRYPTED

The file or directory is encrypted. For a file, this means that all data in the file is encrypted. For a directory, this means that encryption is the default for newly created files and subdirectories. For more information, see File Encryption.

This flag has no effect if FILE_ATTRIBUTE_SYSTEM is also specified.

FILE_ATTRIBUTE_HIDDEN

The file is hidden. It is not to be included in an ordinary directory listing.

FILE_ATTRIBUTE_NORMAL

The file has no other attributes set. This attribute is valid only if used alone.

FILE_ATTRIBUTE_NOT_CONTENT_INDEXED

The file will not be indexed by the content indexing service.

FILE_ATTRIBUTE_OFFLINE

The data of the file is not immediately available. This attribute indicates that the file data has been physically moved to offline storage. This attribute is used by Remote Storage, the hierarchical storage management software. Applications should not arbitrarily change this attribute.

FILE_ATTRIBUTE_READONLY

The file is read only. Applications can read the file but cannot write to it or delete it.

FILE_ATTRIBUTE_SYSTEM

The file is part of or is used exclusively by the operating system.

FILE_ATTRIBUTE_TEMPORARY

The file is being used for temporary storage. File systems avoid writing data back to mass storage if sufficient cache memory is available, because often the application deletes the temporary file shortly after the handle is closed. In that case, the system can entirely avoid writing the data. Otherwise, the data will be written after the handle is closed.

This parameter can also include any combination of the following flags.

Flag

Meaning

FILE_FLAG_BACKUP_SEMANTICS

Indicates that the file is being opened or created for a backup or restore operation. The system ensures that the calling process overrides file security checks, provided it has the SE_BACKUP_NAME and SE_RESTORE_NAME privileges. For more information, see Changing Privileges in a Token.

You can also set this flag to obtain a handle to a directory. Where indicated, a directory handle can be passed to some functions in place of a file handle.

Windows Me/98/95:  This flag is not supported.

FILE_FLAG_DELETE_ON_CLOSE

Indicates that the operating system is to delete the file immediately after all of its handles have been closed, not just the handle for which you specified FILE_FLAG_DELETE_ON_CLOSE.

If there are existing open handles to the file, the call fails unless they were all opened with the FILE_SHARE_DELETE share mode.

Subsequent open requests for the file will fail, unless they specify the FILE_SHARE_DELETE share mode.

FILE_FLAG_NO_BUFFERING

Instructs the system to open the file with no system caching. This flag has no effect on hard disk caching. When combined with FILE_FLAG_OVERLAPPED, the flag gives maximum asynchronous performance, because the I/O does not rely on the synchronous operations of the memory manager. However, some I/O operations will take longer, because data is not being held in the cache. Also, the file metadata may still be cached. To flush the metadata to disk, use the FlushFileBuffers function.

An application must meet certain requirements when working with files opened with FILE_FLAG_NO_BUFFERING:

·                       File access must begin at byte offsets within the file that are integer multiples of the volume's sector size.

·                       File access must be for numbers of bytes that are integer multiples of the volume's sector size. For example, if the sector size is 512 bytes, an application can request reads and writes of 512, 1024, or 2048 bytes, but not of 335, 981, or 7171 bytes.

·                       Buffer addresses for read and write operations should be sector aligned (aligned on addresses in memory that are integer multiples of the volume's sector size). Depending on the disk, this requirement may not be enforced.

One way to align buffers on integer multiples of the volume sector size is to use VirtualAlloc to allocate the buffers. It allocates memory that is aligned on addresses that are integer multiples of the operating system's memory page size. Because both memory page and volume sector sizes are powers of 2, this memory is also aligned on addresses that are integer multiples of a volume's sector size.

An application can determine a volume's sector size by calling the GetDiskFreeSpace function.

FILE_FLAG_OPEN_NO_RECALL

Indicates that the file data is requested, but it should continue to reside in remote storage. It should not be transported back to local storage. This flag is intended for use by remote storage systems.

FILE_FLAG_OPEN_REPARSE_POINT

Specifying this flag inhibits the reparse behavior of NTFS reparse points. When the file is opened, a file handle is returned, whether the filter that controls the reparse point is operational or not. This flag cannot be used with the CREATE_ALWAYS flag.

FILE_FLAG_OVERLAPPED

Instructs the system to initialize the object, so that operations that take a significant amount of time to process return ERROR_IO_PENDING. When the operation is finished, the specified event is set to the signaled state.

When you specify FILE_FLAG_OVERLAPPED, the file read and write functions must specify an OVERLAPPED structure. That is, when FILE_FLAG_OVERLAPPED is specified, an application must perform overlapped reading and writing.

When FILE_FLAG_OVERLAPPED is specified, the system does not maintain the file pointer. The file position must be passed as part of the lpOverlapped parameter (pointing to an OVERLAPPED structure) to the file read and write functions.

This flag also enables more than one operation to be performed simultaneously with the handle (a simultaneous read and write operation, for example).

FILE_FLAG_POSIX_SEMANTICS

Indicates that the file is to be accessed according to POSIX rules. This includes allowing multiple files with names, differing only in case, for file systems that support such naming. Use care when using this option because files created with this flag may not be accessible by applications written for MS-DOS or 16-bit Windows.

FILE_FLAG_RANDOM_ACCESS

Indicates that the file is accessed randomly. The system can use this as a hint to optimize file caching.

FILE_FLAG_SEQUENTIAL_SCAN

Indicates that the file is to be accessed sequentially from beginning to end. The system can use this as a hint to optimize file caching. If an application moves the file pointer for random access, optimum caching may not occur; however, correct operation is still guaranteed.

Specifying this flag can increase performance for applications that read large files using sequential access. Performance gains can be even more noticeable for applications that read large files mostly sequentially, but occasionally skip over small ranges of bytes.

FILE_FLAG_WRITE_THROUGH

Instructs the system to write through any intermediate cache and go directly to disk.

If FILE_FLAG_NO_BUFFERING is not also specified, so that system caching is in effect, then the data is written to the system cache, but is flushed to disk without delay.

If FILE_FLAG_NO_BUFFERING is also specified, so that system caching is not in effect, then the data is immediately flushed to disk without going through the system cache. The operating system also requests a write-through the hard disk cache to persistent media. However, not all hardware supports this write-through capability.

If the CreateFile function opens the client side of a named pipe, the dwFlagsAndAttributes parameter can also contain Security Quality of Service information. For more information, see Impersonation Levels. When the calling application specifies the SECURITY_SQOS_PRESENT flag, the dwFlagsAndAttributes parameter can contain one or more of the following values.

Value

Meaning

SECURITY_ANONYMOUS

Impersonate the client at the Anonymous impersonation level.

SECURITY_CONTEXT_TRACKING

The security tracking mode is dynamic. If this flag is not specified, the security tracking mode is static.

SECURITY_DELEGATION

Impersonate the client at the Delegation impersonation level.

SECURITY_EFFECTIVE_ONLY

Only the enabled aspects of the client's security context are available to the server. If you do not specify this flag, all aspects of the client's security context are available.

This allows the client to limit the groups and privileges that a server can use while impersonating the client.

SECURITY_IDENTIFICATION

Impersonate the client at the Identification impersonation level.

SECURITY_IMPERSONATION

Impersonate the client at the Impersonation impersonation level.

hTemplateFile

[in] Handle to a template file, with the GENERIC_READ access right. The template file supplies file attributes and extended attributes for the file being created. This parameter can be NULL.

If opening an existing file, CreateFile ignores the template file.

Windows Me/98/95:  The hTemplateFile parameter must be NULL. If you supply a handle, the call fails and GetLastError returns ERROR_NOT_SUPPORTED.

Return Values

If the function succeeds, the return value is an open handle to the specified file. If the specified file exists before the function call and dwCreationDisposition is CREATE_ALWAYS or OPEN_ALWAYS, a call to GetLastError returns ERROR_ALREADY_EXISTS (even though the function has succeeded). If the file does not exist before the call, GetLastError returns zero.

If the function fails, the return value is INVALID_HANDLE_VALUE. To get extended error information, call GetLastError.

Remarks

Use the CloseHandle function to close an object handle returned by CreateFile.

Windows Server 2003, Windows XP, Windows 2000:  A sharing violation will occur if an attempt is made to open a file or directory for deletion on a remote computer when the value of the dwDesiredAccess parameter is the DELETE access flag OR'ed with any other access flag, and the remote file or directory has not been opened with FILE_SHARE_DELETE. To avoid the sharing violation in this scenario, open the remote file or directory with the DELETE access right only or call DeleteFile without first opening the file or directory for deletion.

Some file systems, such as NTFS, support compression or encryption for individual files and directories. On volumes formatted for such a file system, a new file inherits the compression and encryption attributes of its directory.

You cannot use CreateFile to control compression on a file or directory. See File Compression and Decompression for information on compressing files, and enabling or disabling file compression within a directory.

See File Encryption for more information on encrypting and decrypting files, and enabling or disabling file encryption within a directory.

Windows Server 2003, Windows XP, Windows 2000:  For backward compatibility purposes, CreateFile does not apply Windows 2000 inheritance rules when you specify a security descriptor in lpSecurityAttributes. To support inheritance on Windows 2000 and later, APIs that later query the security descriptor of this object may heuristically determine and report that inheritance is in effect. See Automatic Propagation of Inheritable ACEs for more information about inheritance rules in Windows 2000 and later operating systems, and how they differ from previous versions of Windows.

Windows Me/98/95:  CreateFileW is supported by the Microsoft Layer for Unicode. To use this, you must add certain files to your application, as outlined in Microsoft Layer for Unicode on Windows 95/98/Me Systems.

Files

If you are attempting to create a file on a floppy drive that does not have a floppy disk or a CD-ROM drive that does not have a CD, the system displays a message box asking the user to insert a disk or a CD, respectively. To prevent the system from displaying this message box, call the SetErrorMode function with SEM_FAILCRITICALERRORS.

Windows Server 2003, Windows XP, Windows 2000:  If CREATE_ALWAYS and FILE_ATTRIBUTE_NORMAL are specified, CreateFile will fail and set the last error to ERROR_ACCESS_DENIED if the file exists and has the FILE_ATTRIBUTE_HIDDEN or FILE_ATTRIBUTE_SYSTEM attribute. To avoid the error, specify the same attributes as the existing file.

See Creating and Opening Files for a list of actions CreateFile takes to create a new file, or to open an existing file.

If you rename or delete a file, then restore it shortly thereafter, the system searches the cache for file information to restore. Cached information includes its short/long name pair and creation time.

Windows Me/98/95:  This remark does not apply.

If there are multiple attempts to open the same file, there may be sharing violations depending on the sharing modes and access modes across the set of calls. See Creating and Opening Files for details and examples.

If you call CreateFile on a file that is pending deletion as a result of a previous call to DeleteFile, the function fails. The operating system delays file deletion until all handles to the file are closed. GetLastError returns ERROR_ACCESS_DENIED.

Directories

An application cannot create a directory with CreateFile; it must call CreateDirectory or CreateDirectoryEx to create a directory. Opening a directory with CreateFile requires the FILE_FLAG_BACKUP_SEMANTICS flag.

When using CreateFile to open a directory during defragmentation of a FAT or FAT32 volume, do not specify the MAXIMUM_ALLOWED access right. Access to the directory will be denied if this is done. Specify the GENERIC_READ access right instead.

Physical Disks and Volumes

You can use the CreateFile function to open a physical disk drive or a volume. The function returns a handle that can be used with the DeviceIoControl function. This enables you to access the disk's partition table. It is potentially dangerous to do so, since an incorrect write to a disk could make its contents inaccessible. The following requirements must be met for such a call to succeed:

·                       The caller must have administrative privileges. For more information, see Running with Special Privileges.

·                       The dwCreationDisposition parameter must have the OPEN_EXISTING flag.

·                       When opening a volume or floppy disk, the dwShareMode parameter must have the FILE_SHARE_WRITE flag.

When opening a physical drive, x, the lpFileName string should be of the form \\.\PHYSICALDRIVE<x>. Hard disk numbers start at zero. The following table shows some example physical drive strings.

String

Meaning

\\.\PHYSICALDRIVE0

Opens the first physical drive.

\\.\PHYSICALDRIVE2

Opens the third physical drive.

For an example showing how to open a physical drive, see Calling DeviceIoControl.

When opening a volume or floppy drive, the lpFileName string should be of the form \\.\<x>:. Do not use a trailing backslash. This would indicate the root directory of the drive. The following table shows some example drive strings.

String

Meaning

\\.\A:

Opens drive A (floppy drive).

\\.\C:

Opens drive C (volume).

You can also open a volume by referring to its volume name. For more information, see Naming a Volume.

Volume handles may be opened as noncached at the discretion of the file system, even when the noncached option is not specified with CreateFile. You should assume that all Microsoft file systems open volume handles as noncached. The restrictions on noncached I/O for files apply to volumes as well.

A file system may or may not require buffer alignment even though the data is noncached. However, if the noncached option is specified when opening a volume, buffer alignment is enforced regardless of the file system on the volume. It is recommended on all file systems that you open volume handles as noncached and follow the noncached I/O restrictions.

Tape Drives

You can open tape drives using a file name of the form \\.\TAPE<x> where <x> is a number indicating which drive to open, starting with tape drive 0. To open tape drive 0 in an application written in C or C++, use the file name "\\\\.\\TAPE0". For more information on manipulating tape drives for backup or other applications, see Backup.

Windows Me/98/95:  Opening tape drives is not supported.

Communications Resources

The CreateFile function can create a handle to a communications resource, such as the serial port COM1. For communications resources, the dwCreationDisposition parameter must be OPEN_EXISTING, and the hTemplate parameter must be NULL. Read, write, or read/write access can be specified, and the handle can be opened for overlapped I/O. For more information about communications, see Communications.

Consoles

The CreateFile function can create a handle to console input (CONIN$). If the process has an open handle to it as a result of inheritance or duplication, it can also create a handle to the active screen buffer (CONOUT$). The calling process must be attached to an inherited console or one allocated by the AllocConsole function. For console handles, set the CreateFile parameters as follows.

Parameters

Value

lpFileName

Use the CONIN$ value to specify console input and the CONOUT$ value to specify console output.

CONIN$ gets a handle to the console's input buffer, even if the SetStdHandle function redirected the standard input handle. To get the standard input handle, use the GetStdHandle function.

CONOUT$ gets a handle to the active screen buffer, even if SetStdHandle redirected the standard output handle. To get the standard output handle, use GetStdHandle.

dwDesiredAccess

GENERIC_READ | GENERIC_WRITE is preferred, but either one can limit access.

dwShareMode

When opening CONIN$, be sure to specify FILE_SHARE_READ. When opening CONOUT$, be sure to specify FILE_SHARE_WRITE.

If the calling process inherited the console or if a child process should be able to access the console, this parameter must be FILE_SHARE_READ | FILE_SHARE_WRITE.

lpSecurityAttributes

If you want the console to be inherited, the bInheritHandle member of the SECURITY_ATTRIBUTES structure must be TRUE.

dwCreationDisposition

You should specify OPEN_EXISTING when using CreateFile to open the console.

dwFlagsAndAttributes

Ignored.

hTemplateFile

Ignored.

The following list shows the effects of various settings of dwDesiredAccess and lpFileName.

lpFileName

dwDesiredAccess

Result

CON

GENERIC_READ

Opens console for input.

CON

GENERIC_WRITE

Opens console for output.

CON

GENERIC_READ GENERIC_WRITE

Causes CreateFile to fail; GetLastError returns ERROR_FILE_NOT_FOUND.

Windows Me/98/95:  Causes CreateFile to fail; GetLastError returns ERROR_PATH_NOT_FOUND.

Mailslots

If CreateFile opens the client end of a mailslot, the function returns INVALID_HANDLE_VALUE if the mailslot client attempts to open a local mailslot before the mailslot server has created it with the CreateMailSlot function. For more information about mailslots, see Mailslots.

Pipes

If CreateFile opens the client end of a named pipe, the function uses any instance of the named pipe that is in the listening state. The opening process can duplicate the handle as many times as required but, once opened, the named pipe instance cannot be opened by another client. The access specified when a pipe is opened must be compatible with the access specified in the dwOpenMode parameter of the CreateNamedPipe function. For more information about pipes, see Pipes.

Example Code

For an example, see Creating and Opening Files.

Requirements

Client: Included in Windows XP, Windows 2000 Professional, Windows NT Workstation, Windows Me, Windows 98, and Windows 95.
Server: Included in Windows Server 2003, Windows 2000 Server, and Windows NT Server.
Unicode: Implemented as Unicode and ANSI versions. Note that Unicode support on Windows Me/98/95 requires Microsoft Layer for Unicode.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

AllocConsole, CloseHandle, ConnectNamedPipe, CreateDirectory, CreateDirectoryEx, CreateNamedPipe, DeleteFile, DeviceIoControl, File Management Functions, GetDiskFreeSpace, GetOverlappedResult, GetStdHandle, OpenFile, ReadFile, SetErrorMode, SetStdHandle, TransactNamedPipe, VirtualAlloc, WriteFile, ACCESS_MASK, OVERLAPPED, SECURITY_ATTRIBUTES

 

DeviceIoControl

The DeviceIoControl function sends a control code directly to a specified device driver, causing the corresponding device to perform the corresponding operation.

BOOL DeviceIoControl(

  HANDLE hDevice,

  DWORD dwIoControlCode,

  LPVOID lpInBuffer,

  DWORD nInBufferSize,

  LPVOID lpOutBuffer,

  DWORD nOutBufferSize,

  LPDWORD lpBytesReturned,

  LPOVERLAPPED lpOverlapped

);

Parameters

hDevice

[in] Handle to the device on which the operation is to be performed. The device is typically a volume, directory, file, or stream. To retrieve a device handle, use the CreateFile function. For more information, see Remarks.

dwIoControlCode

[in] Control code for the operation. This value identifies the specific operation to be performed and the type of device on which to perform it.

For a list of the control codes, see Remarks. The documentation for each control code provides usage details for the lpInBuffer, nInBufferSize, lpOutBuffer, and nOutBufferSize parameters.

lpInBuffer

[in] Pointer to the input buffer that contains the data required to perform the operation. The format of this data depends on the value of the dwIoControlCode parameter.

This parameter can be NULL if dwIoControlCode specifies an operation that does not require input data.

nInBufferSize

[in] Size of the input buffer, in bytes.

lpOutBuffer

[out] Pointer to the output buffer that is to receive the data returned by the operation. The format of this data depends on the value of the dwIoControlCode parameter.

This parameter can be NULL if dwIoControlCode specifies an operation that does not return data.

nOutBufferSize

[in] Size of the output buffer, in bytes.

lpBytesReturned

[out] Pointer to a variable that receives the size of the data stored in the output buffer, in bytes.

If the output buffer is too small to receive any data, the call fails, GetLastError returns ERROR_INSUFFICIENT_BUFFER, and lpBytesReturned is zero.

If the output buffer is too small to hold all of the data but can hold some entries, some drivers will return as much data as fits. In this case, the call fails, GetLastError returns ERROR_MORE_DATA, and lpBytesReturned indicates the amount of data received. Your application should call DeviceIoControl again with the same operation, specifying a new starting point.

If lpOverlapped is NULL, lpBytesReturned cannot be NULL. Even when an operation returns no output data and lpOutBuffer is NULL, DeviceIoControl makes use of lpBytesReturned. After such an operation, the value of lpBytesReturned is meaningless.

If lpOverlapped is not NULL, lpBytesReturned can be NULL. If this parameter is not NULL and the operation returns data, lpBytesReturned is meaningless until the overlapped operation has completed. To retrieve the number of bytes returned, call GetOverlappedResult. If hDevice is associated with an I/O completion port, you can retrieve the number of bytes returned by calling GetQueuedCompletionStatus.

lpOverlapped

[in] Pointer to an OVERLAPPED structure.

If hDevice was opened without specifying FILE_FLAG_OVERLAPPED, lpOverlapped is ignored.

If hDevice was opened with the FILE_FLAG_OVERLAPPED flag, the operation is performed as an overlapped (asynchronous) operation. In this case, lpOverlapped must point to a valid OVERLAPPED structure that contains a handle to an event object. Otherwise, the function fails in unpredicatable ways.

For overlapped operations, DeviceIoControl returns immediately, and the event object is signaled when the operation has been completed. Otherwise, the function does not return until the operation has been completed or an error occurs.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

To retrieve a handle to the device, you must call the CreateFile function with either the name of a device or the name of the driver associated with a device. To specify a device name, use the following format:

\\.\DeviceName

DeviceIoControl can accept a handle to a specific device. For example, to open a handle to the logical drive A: with CreateFile, specify \\.\a:. Alternatively, you can use the names \\.\PhysicalDrive0, \\.\PhysicalDrive1, and so on, to open handles to the physical drives on a system.

Windows Me/98/95:  DeviceIoControl can only accept a handle to a virtual device driver. For example, to open a handle to the system VxD with CreateFile, specify \\.\vwin32.

You should specify the FILE_SHARE_READ and FILE_SHARE_WRITE access flags when calling CreateFile to open a handle to a device driver. However, when you open a communications resource, such as a serial port, you must specify exclusive access. Use the other CreateFile parameters as follows when opening a device handle:

·                       The fdwCreate parameter must specify OPEN_EXISTING.

·                       The hTemplateFile parameter must be NULL.

·                       The fdwAttrsAndFlags parameter can specify FILE_FLAG_OVERLAPPED to indicate that the returned handle can be used in overlapped (asynchronous) I/O operations.

For lists of supported control codes, see the following topics:

·                       Communications Control Codes

·                       Device Management Control Codes

·                       Directory Management Control Codes

·                       Disk Management Control Codes

·                       File Management Control Codes

·                       File Systems Control Codes

·                       Power Management Control Codes

·                       Volume Management Control Codes

Example Code

For examples that use DeviceIoControl, see the following topics:

·                       Calling DeviceIoControl

·                       Calling DeviceIoControl on Windows Me/98/95

Requirements

Client: Included in Windows XP, Windows 2000 Professional, Windows NT Workstation, Windows Me, Windows 98, and Windows 95.
Server: Included in Windows Server 2003, Windows 2000 Server, and Windows NT Server.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

CreateEvent, CreateFile, GetOverlappedResult, GetQueuedCompletionStatus, OVERLAPPED

 

ControlService

The ControlService function sends a control code to a service.

BOOL ControlService(

  SC_HANDLE hService,

  DWORD dwControl,

  LPSERVICE_STATUS lpServiceStatus

);

Parameters

hService

[in] Handle to the service. This handle is returned by the OpenService or CreateService function. The access rights required for this handle depend on the dwControl code requested.

dwControl

[in] This parameter can be one of the following control codes.

Control code

Meaning

SERVICE_CONTROL_CONTINUE

Notifies a paused service that it should resume. The hService handle must have the SERVICE_PAUSE_CONTINUE access right.

SERVICE_CONTROL_INTERROGATE

Notifies a service that it should report its current status information to the service control manager. The hService handle must have the SERVICE_INTERROGATE access right.

SERVICE_CONTROL_NETBINDADD

Notifies a network service that there is a new component for binding. The hService handle must have the SERVICE_PAUSE_CONTINUE access right.

Windows NT:  This value is not supported.

SERVICE_CONTROL_NETBINDDISABLE

Notifies a network service that one of its bindings has been disabled. The hService handle must have the SERVICE_PAUSE_CONTINUE access right.

Windows NT:  This value is not supported.

SERVICE_CONTROL_NETBINDENABLE

Notifies a network service that a disabled binding has been enabled. The hService handle must have the SERVICE_PAUSE_CONTINUE access right.

Windows NT:  This value is not supported.

SERVICE_CONTROL_NETBINDREMOVE

Notifies a network service that that a component for binding has been removed. The hService handle must have the SERVICE_PAUSE_CONTINUE access right.

Windows NT:  This value is not supported.

SERVICE_CONTROL_PARAMCHANGE

Notifies a service that its startup parameters have changed. The hService handle must have the SERVICE_PAUSE_CONTINUE access right.

Windows NT:  This value is not supported.

SERVICE_CONTROL_PAUSE

Notifies a service that it should pause. The hService handle must have the SERVICE_PAUSE_CONTINUE access right.

SERVICE_CONTROL_STOP

Notifies a service that it should stop. The hService handle must have the SERVICE_STOP access right.

 

This value can also be a user-defined control code, as described in the following table.

Control code

Meaning

Range 128 to 255.

The service defines the action associated with the control code. The hService handle must have the SERVICE_USER_DEFINED_CONTROL access right.

lpServiceStatus

[out] Pointer to a SERVICE_STATUS structure that receives the latest service status information. The information returned reflects the most recent status that the service reported to the service control manager.

The service control manager fills in the structure only when ControlService returns one of the following error codes: NO_ERROR, ERROR_INVALID_SERVICE_CONTROL, ERROR_SERVICE_CANNOT_ACCEPT_CTRL, or ERROR_SERVICE_NOT_ACTIVE. Otherwise, the structure is not filled in.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

The following error codes can be set by the service control manager. Other error codes can be set by the registry functions that are called by the service control manager.

Return Code

Description

ERROR_ACCESS_DENIED

The handle does not have the required access right.

ERROR_DEPENDENT_SERVICES_RUNNING

The service cannot be stopped because other running services are dependent on it.

ERROR_INVALID_HANDLE

The specified handle was not obtained using CreateService or OpenService, or the handle is no longer valid.

ERROR_INVALID_PARAMETER

The requested control code is undefined.

ERROR_INVALID_SERVICE_CONTROL

The requested control code is not valid, or it is unacceptable to the service.

ERROR_SERVICE_CANNOT_ACCEPT_CTRL

The requested control code cannot be sent to the service because the state of the service is SERVICE_STOPPED, SERVICE_START_PENDING, or SERVICE_STOP_PENDING.

ERROR_SERVICE_NOT_ACTIVE

The service has not been started.

ERROR_SERVICE_REQUEST_TIMEOUT

The process for the service was started, but it did not call StartServiceCtrlDispatcher, or the thread that called StartServiceCtrlDispatcher may be blocked in a control handler function.

ERROR_SHUTDOWN_IN_PROGRESS

The system is shutting down.

Remarks

The ControlService function asks the service control manager to send the requested control code to the service. The service control manager sends the code if the service accepts the control and if the service is in a state in which a control can be sent to it. A call to ControlService will block for 30 seconds is any service is busy handling a control code. If the busy service still has not returned from its handler function when the timeout expires, ControlService fails with ERROR_SERVICE_REQUEST_TIMEOUT.

To stop and start a service requires a security descriptor that allows you to do so. The default security descriptor allows the LocalSystem account, and members of the Administrators and Power Users groups to stop and start services. To change the security descriptor of a service, see Modifying the DACL for a Service.

The QueryServiceStatus or function returns a SERVICE_STATUS structure whose dwCurrentState and dwControlsAccepted members indicate the current state and controls accepted by a running service. All running services accept the SERVICE_CONTROL_INTERROGATE control code by default. Drivers do not accept control codes other than SERVICE_CONTROL_STOP and SERVICE_CONTROL_INTERROGATE. Each service specifies the other control codes that it accepts when it calls the SetServiceStatus function to report its status. A service should always accept these codes when it is running, no matter what it is doing.

The following table shows the action of the service control manager in each of the possible service states.

Service state

Stop

Other controls

STOPPED

(c)

(c)

STOP_PENDING

(b)

(b)

START_PENDING

(a)

(b)

RUNNING

(a)

(a)

CONTINUE_PENDING

(a)

(a)

PAUSE_PENDING

(a)

(a)

PAUSED

(a)

(a)

 

(a)

If the service accepts this control code, send the request to the service; otherwise, ControlService returns zero and GetLastError returns ERROR_INVALID_SERVICE_CONTROL.

 

(b)

The service is not in a state in which a control can be sent to it, so ControlService returns zero and GetLastError returns ERROR_SERVICE_CANNOT_ACCEPT_CTRL.

 

(c)

The service is not active, so ControlService returns zero and GetLastError returns ERROR_SERVICE_NOT_ACTIVE.

Example Code

For an example, see Sending Control Requests to a Service.

Requirements

Client: Included in Windows XP, Windows 2000 Professional, and Windows NT Workstation.
Server: Included in Windows Server 2003, Windows 2000 Server, and Windows NT Server.
Header: Declared in Winsvc.h; include Windows.h.
Library: Use Advapi32.lib.

See Also

Services Overview, Service Functions, CreateService, OpenService, QueryServiceStatus, SetServiceObjectSecurity, SetServiceStatus, SERVICE_STATUS

 

CloseServiceHandle

The CloseServiceHandle function closes a handle to a service control manager or service object.

BOOL CloseServiceHandle(

  SC_HANDLE hSCObject

);

Parameters

hSCObject

[in] Handle to the service control manager object or the service object to close. Handles to service control manager objects are returned by the OpenSCManager function, and handles to service objects are returned by either the OpenService or CreateService function

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

The following error code can be set by the service control manager. Other error codes can be set by registry functions that are called by the service control manager.

Return Code

Description

ERROR_INVALID_HANDLE

The specified handle is invalid.

Remarks

The CloseServiceHandle function does not destroy the service control manager object referred to by the handle. A service control manager object cannot be destroyed. A service object can be destroyed by calling the DeleteService function.

Example Code

For an example, see Deleting a Service.

Requirements

Client: Included in Windows XP, Windows 2000 Professional, and Windows NT Workstation.
Server: Included in Windows Server 2003, Windows 2000 Server, and Windows NT Server.
Header: Declared in Winsvc.h; include Windows.h.
Library: Use Advapi32.lib.

See Also

Services Overview, Service Functions, CreateService, DeleteService, OpenSCManager, OpenService

 

DeleteService

The DeleteService function marks the specified service for deletion from the service control manager database.

BOOL DeleteService(

  SC_HANDLE hService

);

Parameters

hService

[in] Handle to the service. This handle is returned by the OpenService or CreateService function, and it must have the DELETE access right. For more information, see Service Security and Access Rights.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

The following error codes may be set by the service control manager. Others may be set by the registry functions that are called by the service control manager.

Return Code

Description

ERROR_ACCESS_DENIED

The handle does not have the DELETE access right.

ERROR_INVALID_HANDLE

The specified handle is invalid.

ERROR_SERVICE_MARKED_FOR_DELETE

The specified service has already been marked for deletion.

Remarks

The DeleteService function marks a service for deletion from the service control manager database. The database entry is not removed until all open handles to the service have been closed by calls to the CloseServiceHandle function, and the service is not running. A running service is stopped by a call to the ControlService function with the SERVICE_CONTROL_STOP control code. If the service cannot be stopped, the database entry is removed when the system is restarted.

The service control manager deletes the service by deleting the service key and its subkeys from the registry.

Example Code

For an example, see Deleting a Service.

Requirements

Client: Included in Windows XP, Windows 2000 Professional, and Windows NT Workstation.
Server: Included in Windows Server 2003, Windows 2000 Server, and Windows NT Server.
Header: Declared in Winsvc.h; include Windows.h.
Library: Use Advapi32.lib.

See Also

CloseServiceHandle, ControlService, CreateService, OpenService, Service Functions, Services Overview