Native API Architecture
The Windows NT Native API serves one purpose: as a means for calling operating system services located in kernel mode in a controlled manner. Kernel mode is where the core of NT executes, and it's in kernel mode that components have direct access to hardware and services that perform management of the computer's resources including memory, devices and processes. Thus, whenever a program executing in user mode wants to perform I/O, allocate or deallocate virtual memory, start a thread or process, or interact with global resources, it must call upon one or more services that live in kernel mode.
The Native API is equivalent to the system call interface on traditional monolithic operating systems such as most UNIXes. On most UNIXes, however, the system call interface is well documented and is generally available for use by standard applications. For example, the read() call for reading data from a file, socket, or input device in most flavors of UNIX is a system call that is handled by code in kernel mode. In Windows NT the Native API, its system call interface, is hidden from programmers behind higher level APIs such as Win32, OS/2, POSIX or DOS/Win16. The reason behind this is NT's architecture.
NT is a "modified microkernel" architecture. Instead of supporting one basic operating system API, NT implements several. It does this efficiently by implementing operating environment subsystems in user mode that export particular APIs to client programs. The "national language" API of NT is Win32, and the Win32 architecture demonstrates this concept. The Win32 operating environment subsystem is divided among a server process, CSRSS.EXE (Client/Server Runtime SubSystem), and client-side DLLs that are linked with programs that use the Win32 API. The core of the Win32 API is divided into three categories: windowing and messaging, drawing, and base services. Windows and messaging APIs include CreateWindow() and SendMessage(), and are exported to Win32 programs via the USER32.DLL library. BitBlt() and LineTo() are Win32 drawing functions and are provided in GDI32.DLL. Finally, base services include all Win32 I/O, process and thread, memory management, and synchronization APIs, and KERNEL32.DLL is the library that exports them.
When a Win32 program calls a Win32 API control is transferred within its address space into one of Win32's client-side DLLs. The DLL can execute one or more of the following options:
Ø return immediately to the caller
Ø send a message to the Win32 server to request help
Ø invoke Native APIs to carry out the function
The first option of returning to the caller is rarely possible and is only possible when the DLL can service the function without the help of operating system services. An example of this is GetCurrentProcess(). This API simply returns a handle to the current process that is cached in KERNEL32 when the process is started.
The second option is also rarely required. A client-side DLL only needs to send messages to the Win32 server when the server must participate with, and be aware of, the function's execution. The Win32 server creates a Win32 execution environment for its clients that involves maintaining some state associated with its client processes. Thus, the CreateProcess() API, exported by KERNEL32, requires an interaction with the Win32 server. The server in this case prepares a new process for execution by mapping in an executable image, creating a command-line argument structure, and so on. The Win32 server calls Native API functions to create the actual process image and prepare its address map.
The final option is the most frequently exercised. Let's talk about USER32 and GDI32 APIs first, before talking about KERNEL32's use of Native APIs. In versions of NT prior to 4.0, windowing and drawing functions were located in the Win32 server (CSRSS.EXE). This meant that whenever an application used these function a message would be sent to the server. In NT 4.0 the windowing and drawing components of Win32 were moved into a kernel mode component named WIN32K.SYS. Instead of sending a message to the server, the client-side DLLs just call directly into the kernel, saving the overhead of messaging and context switching to another process. This has enhanced NT's graphics performance (as evidenced by the Pinball sample game). GDI and USER functions have become NT's second Native API, but they are less mysterious than the primary Native API since drawing, windowing, and messaging APIs are well-documented.
KERNEL32 functions that call the Native API directly include all of its I/O (e.g CreateFile(), ReadFile(), WriteFile()), synchronization (e.g. WaitForSingleObject(), SetEvent()), and memory management (e.g. VirtualAlloc(), VirtualProtect()) functions. In fact, the majority of KERNEL32's exported routines use the Native API directly. The figure below shows the flow of control from a Win32 application executing a Win32 call (CreateFile()), through KERNEL32, NTDLL, and into kernel mode where control is transferred to the NtCreateFile system service. I'll talk about this process in detail.
全文下載