|
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
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
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
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
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
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_INTERNAL_DEVICE_CONTROL
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.
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
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
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
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
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
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:
The MDL describes an empty buffer that the device or
driver fills in.
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:
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.
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:
NULL.
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 \
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.
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
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.
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.
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
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.
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
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.
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
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
·
Power Management Control
Codes
·
Volume Management Control Codes
Example Code
For examples that use DeviceIoControl, see the following
topics:
·
Calling DeviceIoControl on
Windows Me/98/95
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
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.
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
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.
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
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.
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