I’m sure Maxim is aware of this, but others who are encountering the split between CreateFile / NtCreateFile for the first time should be aware of a few things. CreateFile does a lot more than validate and reformat parameters. In *most* situations, CreateFile maps fairly directly to NtCreateFile. However, for certain “pseudo-devices” (devices that are not implemented as NT kernel devices, i.e. IoCreateDevice) and for certain legacy device names, CreateFile directly examines and acts on the filename being created, rather than just passing it to NtCreateFile.
The “pseudo-devices” are things like CON: (I think “CON” works, too), which requests a “handle” to the current console of the calling application. There is no “console” device, in the NT kernel sense. Instead, Win32 consoles are implemented in user-mode, using LPC messages between application processes and CSRSS. CreateFile returns a HANDLE value whose lower two bits (tag bits) are set to a special value, where “special” just means “not zero”. ReadFile, WriteFile, CloseHandle, etc. examine these tag bits, and change their behavior based on them. 00 means “kernel handle”, so you get the usual mapping to NtReadFile and friends. The tag value for a console maps to an LPC request.
(It would have been nice if the tag bits had been used to flag a HANDLE as a vtable-based pointer, so we could have implemented arbitrary user-mode devices. But that decision was made fifteen years ago.)
CreateFile also looks for other legacy device names, such as “COM1:”, “LPT”, “PRN”, “AUX”, and maybe a few others. CreateFile maps these to the equivalent NT device names, usually just by decorating them with ??\COM1 and using a root handle value of NULL.
This special behavior means that apps that use CreateFile (directly or indirectly) can never create or use files or directories that use these reserved files. Which is why you cannot create a file or directory called “aux”, or “aux.c”, or whatever. Various Windows apps and tools fail in inconsistent ways when you try to use these reserved names.
There is an escape mechanism, documented in MSDN. If you pass a path to CreateFile that begins with \?, then the remainder of the path will be passed to NtCreateFile unmodified.
The only reason I bring all this up is to make sure that people realize that the Win32 API is more than just a shim over the NT native API – in many places, it’s not even a 1:1 mapping. A lot of functionality is implemented in the Win32 APIs, and sometimes there can be some real surprises.
– arlie
-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Maxim S. Shatskih
Sent: Saturday, August 19, 2006 1:04 PM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] Complete lifecycle of I/O req. from User to Krnl mode
The question arises in the mind that how a User-mode I/O request is
converted in system call…and want to know about complete life-cycle of
that req. from
user
to krnl mode… and how various calls get invoked and who invoke them
kernel32 routines like CreateFileW or ReadFile are wrappers around the routines in ntdll.dll - NtReadFile, NtCreateFile etc. They do some parameter reformatting and then the error code translation from NTSTATUS to Win32 ERROR_xxx “last error” values.
The bodies of ntdll routines are very short code sequences to do syscalls to the kernel. Before XP, “int 2eh” was used for syscall, in XP and later, “sysenter” will be used if the CPU supports it.
Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com
Questions? First check the Kernel Driver FAQ at http://www.osronline.com/article.cfm?id=256
To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer