The process of starting up the emulator itself is mostly one of chaining through various initializer functions defined in the core libraries and DLLs: libwine, then NTDLL, then kernel32.
Both the wine-pthread and wine-kthread binaries share a common main
function, defined in loader/main.c, so no matter which binary is selected
after the preloader has run we start here. This passes the information provided by the
preloader into libwine and then calls wine_init, defined
in libs/wine/loader.c. This is where the emulation really starts:
wine_init
can, with the correct preparation,
be called from programs other than the wine loader itself.
wine_init
does some very basic setup tasks such as initializing the
debugging infrastructure, yet more address space manipulation (see the information on the
4G/4G VM split in the address space chapter), before loading NTDLL - the core of both Wine and
the Windows NT series - and jumping to the __wine_process_init
function defined
in dlls/ntdll/loader.c
This function is responsible for initializing the primary Win32 environment. In thread_init(), it sets up the TEB, the wineserver connection for the main thread and the process heap. See the threading chapter for more information on this.
Finally, it loads and jumps to __wine_kernel_init
in kernel32.dll: this
is defined in dlls/kernel32/process.c. This is where the bulk of the work
is done. The kernel32 initialization code retrieves the startup info for the process from the
server, initializes the registry, sets up the drive mapping system and locale data, then
begins loading the requested application itself. Each process has a STARTUPINFO block that can
be passed into CreateProcess
specifying various things like how the first
window should be displayed: this is sent to the new process via the wineserver.
After determining the type of file given to Wine by the user (a Win32 EXE file, a Win16 EXE, a
Winelib app etc), the program is loaded into memory (which may involve loading and
initializing other DLLs, the bulk of Wines startup code), before control reaches the end of
__wine_kernel_init
. This function ends with the new process stack being
initialized, and start_process being called on the new stack. Nearly there!
The final element of initializing Wine is starting the newly loaded program
itself. start_process
sets up the SEH backstop handler, calls
LdrInitializeThunk
which performs the last part of the process
initialization (such as performing relocations and calling the DllMains with PROCESS_ATTACH),
grabs the entry point of the executable and then on this line:
ExitProcess( entry( peb ) );
... jumps to the entry point of the program. At this point the users program is running and
the API provided by Wine is ready to be used. When entry returns,
the ExitProcess
API will be used to initialize a graceful shutdown.