| <chapter id="architecture"> | |
| <title>Overview</title> | |
| <para>Brief overview of Wine's architecture...</para> | |
| <sect1 id="basic-overview"> | |
| <title>Wine Overview</title> | |
| <para> | |
| With the fundamental architecture of Wine stabilizing, and | |
| people starting to think that we might soon be ready to | |
| actually release this thing, it may be time to take a look at | |
| how Wine actually works and operates. | |
| </para> | |
| <sect2> | |
| <title>Foreword</title> | |
| <para> | |
| Wine is often used as a recursive acronym, standing for | |
| "Wine Is Not an Emulator". Sometimes it is also known to be | |
| used for "Windows Emulator". In a way, both meanings are | |
| correct, only seen from different perspectives. The first | |
| meaning says that Wine is not a virtual machine, it does not | |
| emulate a CPU, and you are not supposed to install | |
| Windows nor any Windows device drivers on top of it; rather, | |
| Wine is an implementation of the Windows API, and can be | |
| used as a library to port Windows applications to Unix. The | |
| second meaning, obviously, is that to Windows binaries | |
| (<filename>.exe</filename> files), Wine does look like | |
| Windows, and emulates its behaviour and quirks rather | |
| closely. | |
| </para> | |
| <note> | |
| <title>"Emulator"</title> | |
| <para> | |
| The "Emulator" perspective should not be thought of as if | |
| Wine is a typical inefficient emulation layer that means | |
| Wine can't be anything but slow - the faithfulness to the | |
| badly designed Windows API may of course impose a minor | |
| overhead in some cases, but this is both balanced out by | |
| the higher efficiency of the Unix platforms Wine runs on, | |
| and that other possible abstraction libraries (like Motif, | |
| GTK+, CORBA, etc) has a runtime overhead typically | |
| comparable to Wine's. | |
| </para> | |
| </note> | |
| </sect2> | |
| <sect2> | |
| <title>Executables</title> | |
| <para> | |
| Wine's main task is to run Windows executables under non | |
| Windows operating systems. It supports different types of | |
| executables: | |
| <itemizedlist> | |
| <listitem> | |
| <para> | |
| DOS executable. Those are even older programs, using | |
| the DOS format (either <filename>.com</filename> or | |
| <filename>.exe</filename> (the later being also called | |
| MZ)). | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| Windows NE executable, also called 16 bit. They were | |
| the native processes run by Windows 2.x and 3.x. NE | |
| stands for New Executable <g>. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| Windows PE executable. These are programs were | |
| introduced in Windows 95 (and became the native | |
| formats for all later Windows version), even if 16 bit | |
| applications were still supported. PE stands for | |
| Portable Executable, in a sense where the format of | |
| the executable (as a file) is independent of the CPU | |
| (even if the content of the file - the code - is CPU | |
| dependent). | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| WineLib executable. These are applications, written | |
| using the Windows API, but compiled as a Unix | |
| executable. Wine provides the tools to create such | |
| executables. | |
| </para> | |
| </listitem> | |
| </itemizedlist> | |
| </para> | |
| <para> | |
| Let's quickly review the main differences for the supported | |
| executables: | |
| <table> | |
| <title>Wine executables</title> | |
| <tgroup cols="5" align="left" colsep="1" rowsep="1"> | |
| <thead> | |
| <row> | |
| <entry></entry> | |
| <entry>DOS (.COM or .EXE)</entry> | |
| <entry>Win16 (NE)</entry> | |
| <entry>Win32 (PE)</entry> | |
| <entry>WineLib</entry> | |
| </row> | |
| </thead> | |
| <tbody> | |
| <row> | |
| <entry>Multitasking</entry> | |
| <entry>Only one application at a time (except for TSR)</entry> | |
| <entry>Cooperative</entry> | |
| <entry>Preemptive</entry> | |
| <entry>Preemptive</entry> | |
| </row> | |
| <row> | |
| <entry>Address space</entry> | |
| <entry> | |
| One MB of memory, where each application is loaded | |
| and unloaded. | |
| </entry> | |
| <entry> | |
| All 16 bit applications share a single address | |
| space, protected mode. | |
| </entry> | |
| <entry> | |
| Each application has it's own address | |
| space. Requires MMU support from CPU. | |
| </entry> | |
| <entry> | |
| Each application has it's own address | |
| space. Requires MMU support from CPU. | |
| </entry> | |
| </row> | |
| <row> | |
| <entry>Windows API</entry> | |
| <entry> | |
| No Windows API but the DOS API (like <function>Int | |
| 21h</function> traps). | |
| </entry> | |
| <entry> | |
| Will call the 16 bit Windows API. | |
| </entry> | |
| <entry> | |
| Will call the 32 bit Windows API. | |
| </entry> | |
| <entry> | |
| Will call the 32 bit Windows API, and possibly | |
| also the Unix APIs. | |
| </entry> | |
| </row> | |
| <row> | |
| <entry>Code (CPU level)</entry> | |
| <entry> | |
| Only available on x86 in real mode. Code and data | |
| are in segmented forms, with 16 bit | |
| offsets. Processor is in real mode. | |
| </entry> | |
| <entry> | |
| Only available on IA-32 architectures, code and | |
| data are in segmented forms, with 16 bit offsets | |
| (hence the 16 bit name). Processor is in protected | |
| mode. | |
| </entry> | |
| <entry> | |
| Available (with NT) on several CPUs, including | |
| IA-32. On this CPU, uses a flat memory model with | |
| 32 bit offsets (hence the 32 bit name). | |
| </entry> | |
| <entry> | |
| Flat model, with 32 bit addresses. | |
| </entry> | |
| </row> | |
| <row> | |
| <entry>Multi-threading</entry> | |
| <entry>Not available.</entry> | |
| <entry>Not available.</entry> | |
| <entry> | |
| Available. | |
| </entry> | |
| <entry> | |
| Available, but must use the Win32 APIs for | |
| threading and synchronization, not the Unix ones. | |
| </entry> | |
| </row> | |
| </tbody> | |
| </tgroup> | |
| </table> | |
| </para> | |
| <para> | |
| Wine deals with this issue by launching a separate Wine | |
| process (which is in fact a Unix process) for each Win32 | |
| process, but not for Win16 tasks. Win16 tasks (as well as | |
| DOS programs) are run as different intersynchronized | |
| Unix-threads in the same dedicated Wine process; this Wine | |
| process is commonly known as a <firstterm>WOW</firstterm> | |
| process (Windows on Windows), referring to a similar | |
| mechanism used by Windows NT. | |
| </para> | |
| <para> | |
| Synchronization between the Win16 tasks running in the WOW | |
| process is normally done through the Win16 mutex - whenever | |
| one of them is running, it holds the Win16 mutex, keeping | |
| the others from running. When the task wishes to let the | |
| other tasks run, the thread releases the Win16 mutex, and | |
| one of the waiting threads will then acquire it and let its | |
| task run. | |
| </para> | |
| </sect2> | |
| </sect1> | |
| <sect1> | |
| <title>Standard Windows Architectures</title> | |
| <sect2> | |
| <title>Windows 9x architecture</title> | |
| <para> | |
| The windows architecture (Win 9x way) looks like this: | |
| <screen> | |
| +---------------------+ \ | |
| | Windows EXE | } application | |
| +---------------------+ / | |
| +---------+ +---------+ \ | |
| | Windows | | Windows | \ application & system DLLs | |
| | DLL | | DLL | / | |
| +---------+ +---------+ / | |
| +---------+ +---------+ \ | |
| | GDI32 | | USER32 | \ | |
| | DLL | | DLL | \ | |
| +---------+ +---------+ } core system DLLs | |
| +---------------------+ / | |
| | Kernel32 DLL | / | |
| +---------------------+ / | |
| +---------------------+ \ | |
| | Win9x kernel | } kernel space | |
| +---------------------+ / | |
| +---------------------+ \ | |
| | Windows low-level | \ drivers (kernel space) | |
| | drivers | / | |
| +---------------------+ / | |
| </screen> | |
| </para> | |
| </sect2> | |
| <sect2> | |
| <title>Windows NT architecture</title> | |
| <para> | |
| The windows architecture (Windows NT way) looks like the | |
| following drawing. Note the new DLL (NTDLL) which allows | |
| implementing different subsystems (as win32); kernel32 in NT | |
| architecture implements the Win32 subsystem on top of NTDLL. | |
| <screen> | |
| +---------------------+ \ | |
| | Windows EXE | } application | |
| +---------------------+ / | |
| +---------+ +---------+ \ | |
| | Windows | | Windows | \ application & system DLLs | |
| | DLL | | DLL | / | |
| +---------+ +---------+ / | |
| +---------+ +---------+ +-----------+ \ | |
| | GDI32 | | USER32 | | | \ | |
| | DLL | | DLL | | | \ | |
| +---------+ +---------+ | | \ core system DLLs | |
| +---------------------+ | | / (on the left side) | |
| | Kernel32 DLL | | Subsystem | / | |
| | (Win32 subsystem) | |Posix, OS/2| / | |
| +---------------------+ +-----------+ / | |
| +---------------------------------------+ | |
| | NTDLL.DLL | | |
| +---------------------------------------+ | |
| +---------------------------------------+ \ | |
| | NT kernel | } NT kernel (kernel space) | |
| +---------------------------------------+ / | |
| +---------------------------------------+ \ | |
| | Windows low-level drivers | } drivers (kernel space) | |
| +---------------------------------------+ / | |
| </screen> | |
| </para> | |
| <para> | |
| Note also (not depicted in schema above) that the 16 bit | |
| applications are supported in a specific subsystem. | |
| Some basic differences between the Win9x and the NT | |
| architectures include: | |
| <itemizedlist> | |
| <listitem> | |
| <para> | |
| Several subsystems (Win32, Posix...) can be run on NT, | |
| while not on Win 9x | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| Win 9x roots its architecture in 16 bit systems, while | |
| NT is truely a 32 bit system. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| The drivers model and interfaces in Win 9x and NT are | |
| different (even if Microsoft tried to bridge the gap | |
| with some support of WDM drivers in Win 98 and above). | |
| </para> | |
| </listitem> | |
| </itemizedlist> | |
| </para> | |
| </sect2> | |
| </sect1> | |
| <sect1> | |
| <title>Wine architecture</title> | |
| <sect2> | |
| <title>Global picture</title> | |
| <para> | |
| Wine implementation is closer to the Windows NT | |
| architecture, even if several subsystems are not implemented | |
| yet (remind also that 16bit support is implemented in a 32-bit | |
| Windows EXE, not as a subsystem). Here's the overall picture: | |
| <screen> | |
| +---------------------+ \ | |
| | Windows EXE | } application | |
| +---------------------+ / | |
| +---------+ +---------+ \ | |
| | Windows | | Windows | \ application & system DLLs | |
| | DLL | | DLL | / | |
| +---------+ +---------+ / | |
| +---------+ +---------+ +-----------+ +--------+ \ | |
| | GDI32 | | USER32 | | | | | \ | |
| | DLL | | DLL | | | | Wine | \ | |
| +---------+ +---------+ | | | Server | \ core system DLLs | |
| +---------------------+ | | | | / (on the left side) | |
| | Kernel32 DLL | | Subsystem | | NT-like| / | |
| | (Win32 subsystem) | |Posix, OS/2| | Kernel | / | |
| +---------------------+ +-----------+ | | / | |
| | | | |
| +---------------------------------------+ | | | |
| | NTDLL | | | | |
| +---------------------------------------+ +--------+ | |
| +---------------------------------------+ \ | |
| | Wine executable (wine-?thread) | } unix executable | |
| +---------------------------------------+ / | |
| +---------------------------------------------------+ \ | |
| | Wine drivers | } Wine specific DLLs | |
| +---------------------------------------------------+ / | |
| +------------+ +------------+ +--------------+ \ | |
| | libc | | libX11 | | other libs | } unix shared libraries | |
| +------------+ +------------+ +--------------+ / (user space) | |
| +---------------------------------------------------+ \ | |
| | Unix kernel (Linux,*BSD,Solaris,OS/X) | } (Unix) kernel space | |
| +---------------------------------------------------+ / | |
| +---------------------------------------------------+ \ | |
| | Unix device drivers | } Unix drivers (kernel space) | |
| +---------------------------------------------------+ / | |
| </screen> | |
| </para> | |
| <para> | |
| Wine must at least completely replace the "Big Three" DLLs | |
| (KERNEL/KERNEL32, GDI/GDI32, and USER/USER32), which all | |
| other DLLs are layered on top of. But since Wine is (for | |
| various reasons) leaning towards the NT way of implementing | |
| things, the NTDLL is another core DLL to be implemented in | |
| Wine, and many KERNEL32 and ADVAPI32 features will be | |
| implemented through the NTDLL. | |
| </para> | |
| <para> | |
| As of today, no real subsystem (apart the Win32 one) has | |
| been implemented in Wine. | |
| </para> | |
| <para> | |
| The Wine server provides the backbone for the implementation | |
| of the core DLLs. It mainly implementents inter-process | |
| synchronization and object sharing. It can be seen, from a | |
| functional point of view, as a NT kernel (even if the APIs | |
| and protocols used between Wine's DLL and the Wine server | |
| are Wine specific). | |
| </para> | |
| <para> | |
| Wine uses the Unix drivers to access the various hardware | |
| pieces on the box. However, in some cases, Wine will | |
| provide a driver (in Windows sense) to a physical hardware | |
| device. This driver will be a proxy to the Unix driver | |
| (this is the case, for example, for the graphical part | |
| with X11 or SDL drivers, audio with OSS or ALSA drivers...). | |
| </para> | |
| <para> | |
| All DLLs provided by Wine try to stick as much as possible | |
| to the exported APIs from the Windows platforms. There are | |
| rare cases where this is not the case, and have been | |
| propertly documented (Wine DLLs export some Wine specific | |
| APIs). Usually, those are prefixed with | |
| <function>__wine</function>. | |
| </para> | |
| <para> | |
| Let's now review in greater details all of those components. | |
| </para> | |
| </sect2> | |
| <sect2> | |
| <title>The Wine server</title> | |
| <para> | |
| The Wine server is among the most confusing concepts in | |
| Wine. What is its function in Wine? Well, to be brief, it | |
| provides Inter-Process Communication (IPC), | |
| synchronization, and process/thread management. When the | |
| Wine server launches, it creates a Unix socket for the | |
| current host based on (see below) your home directory's | |
| <filename>.wine</filename> subdirectory (or wherever the | |
| <constant>WINEPREFIX</constant> environment variable | |
| points to) - all Wine processes launched later connects to | |
| the Wine server using this socket. (If a Wine server was | |
| not already running, the first Wine process will start up | |
| the Wine server in auto-terminate mode (i.e. the Wine | |
| server will then terminate itself once the last Wine | |
| process has terminated).) | |
| </para> | |
| <para> | |
| In earlier versions of Wine the master socket mentioned | |
| above was actually created in the configuration directory; | |
| either your home directory's <filename>/wine</filename> | |
| subdirectory or wherever the | |
| <constant>WINEPREFIX</constant> environment variable | |
| points>. Since that might not be possible the socket is | |
| actually created within the <filename>/tmp</filename> | |
| directory with a name that reflects the configuration | |
| directory. This means that there can actually be several | |
| separate copies of the Wine server running; one per | |
| combination of user and configuration directory. Note that | |
| you should not have several users using the same | |
| configuration directory at the same time; they will have | |
| different copies of the Wine server running and this could | |
| well lead to problems with the registry information that | |
| they are sharing. | |
| </para> | |
| <para> | |
| Every thread in each Wine process has its own request | |
| buffer, which is shared with the Wine server. When a | |
| thread needs to synchronize or communicate with any other | |
| thread or process, it fills out its request buffer, then | |
| writes a command code through the socket. The Wine server | |
| handles the command as appropriate, while the client | |
| thread waits for a reply. In some cases, like with the | |
| various <function>WaitFor???</function> synchronization | |
| primitives, the server handles it by marking the client | |
| thread as waiting and does not send it a reply before the | |
| wait condition has been satisfied. | |
| </para> | |
| <para> | |
| The Wine server itself is a single and separate Unix | |
| process and does not have its own threading - instead, it | |
| is built on top of a large <function>poll()</function> | |
| loop that alerts the Wine server whenever anything | |
| happens, such as a client having sent a command, or a wait | |
| condition having been satisfied. There is thus no danger | |
| of race conditions inside the Wine server itself - it is | |
| often called upon to do operations that look completely | |
| atomic to its clients. | |
| </para> | |
| <para> | |
| Because the Wine server needs to manage processes, | |
| threads, shared handles, synchronization, and any related | |
| issues, all the clients' Win32 objects are also managed by | |
| the Wine server, and the clients must send requests to the | |
| Wine server whenever they need to know any Win32 object | |
| handle's associated Unix file descriptor (in which case | |
| the Wine server duplicates the file descriptor, transmits | |
| it back to the client, and leaves it to the client to | |
| close the duplicate when the client has finished with | |
| it). | |
| </para> | |
| </sect2> | |
| <sect2> | |
| <title> | |
| Wine builtin DLLs: about Relays, Thunks, and DLL | |
| descriptors | |
| </title> | |
| <para> | |
| This section mainly applies to builtin DLLs (DLLs provided | |
| by Wine). See section <xref linkend="arch-dlls"> for the | |
| details on native vs. builtin DLL handling. | |
| </para> | |
| <para> | |
| Loading a Windows binary into memory isn't that hard by | |
| itself, the hard part is all those various DLLs and entry | |
| points it imports and expects to be there and function as | |
| expected; this is, obviously, what the entire Wine | |
| implementation is all about. Wine contains a range of DLL | |
| implementations. You can find the DLLs implementation in the | |
| <filename>dlls/</filename> directory. | |
| </para> | |
| <para> | |
| Each DLL (at least, the 32 bit version, see below) is | |
| implemented in a Unix shared library. The file name of this | |
| shared library is the module name of the DLL with a | |
| <filename>.dll.so</filename> suffix (or | |
| <filename>.drv.so</filename> or any other relevant extension | |
| depending on the DLL type). This shared library contains the | |
| code itself for the DLL, as well as some more information, | |
| as the DLL resources and a Wine specific DLL descriptor. | |
| </para> | |
| <para> | |
| The DLL descriptor, when the DLL is instanciated, is used to | |
| create an in-memory PE header, which will provide access to | |
| various information about the DLL, including but not limited | |
| to its entry point, its resources, its sections, its debug | |
| information... | |
| </para> | |
| <para> | |
| The DLL descriptor and entry point table is generated by | |
| the <command>winebuild</command> tool (previously just | |
| named <command>build</command>), taking DLL specification | |
| files with the extension <filename>.spec</filename> as | |
| input. Resources (after compilation by | |
| <command>wrc</command>) or message tables (after | |
| compilation by <command>wmc</command>) are also added to | |
| the descriptor by <command>winebuild</command>. | |
| </para> | |
| <para> | |
| Once an application module wants to import a DLL, Wine | |
| will look at: | |
| <itemizedlist> | |
| <listitem> | |
| <para> | |
| through its list of registered DLLs (in fact, both | |
| the already loaded DLLs, and the already loaded | |
| shared libraries which has registered a DLL | |
| descriptor). Since, the DLL descriptor is | |
| automatically registered when the shared library is | |
| loaded - remember, registration call is put inside a | |
| shared library constructor - using the | |
| <constant>PRELOAD</constant> environment variable | |
| when running a Wine process can force the | |
| registration of some DLL descriptors. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| If it's not registered, Wine will look for it on | |
| disk, building the shared library name from the DLL | |
| module name. Directory searched for are specified by | |
| the <constant>WINEDLLPATH</constant> environment | |
| variable. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| Failing that, it will look for a real Windows | |
| <filename>.DLL</filename> file to use, and look | |
| through its imports, etc) and use the loading of | |
| native DLLs. | |
| </para> | |
| </listitem> | |
| </itemizedlist> | |
| </para> | |
| <para> | |
| After the DLL has been identified (assuming it's still a | |
| native one), it's mapped into memory using a | |
| <function>dlopen()</function> call. Note, that Wine doesn't | |
| use the shared library mechanisms for resolving and/or | |
| importing functions between two shared libraries (for two | |
| DLLs). The shared library is only used for providing a way | |
| to load a piece of code on demand. This piece of code, | |
| thanks the DLL descriptor, will provide the same type of | |
| information a native DLL would. Wine can then use the same | |
| code for native and builtin DLL to handle imports/exports. | |
| </para> | |
| <para> | |
| Wine also relies on the dynamic loading features of the Unix | |
| shared libraries to relocate the DLLs if needed (the same | |
| DLL can be loaded at different address in two different | |
| processes, and even in two consecutive run of the same | |
| executable if the order of loading the DLLs differ). | |
| </para> | |
| <para> | |
| The DLL descriptor is registered in the Wine realm using | |
| some tricks. The <command>winebuild</command> tool, while | |
| creating the code for DLL descriptor, also creates a | |
| constructor, that will be called when the shared library is | |
| loaded into memory. This constructor will actually register | |
| the descriptor to the Wine DLL loader. Hence, before the | |
| <function>dlopen</function> call returns, the DLL descriptor | |
| will be known and registered. This also helps to deal with | |
| the cases where there's still dependencies (at the ELF | |
| shared lib level, not at the embedded DLL level) between | |
| different shared libraries: the embedded DLLs will be | |
| properly registered, and even loaded (from a Windows point | |
| of view). | |
| </para> | |
| <para> | |
| Since Wine is 32-bit code itself, and if the compiler | |
| supports Windows' calling convention, <type>stdcall</type> | |
| (<command>gcc</command> does), Wine can resolve imports | |
| into Win32 code by substituting the addresses of the Wine | |
| handlers directly without any thunking layer in | |
| between. This eliminates the overhead most people | |
| associate with "emulation", and is what the applications | |
| expect anyway. | |
| </para> | |
| <para> | |
| However, if the user specified <parameter>WINEDEBUG=+relay | |
| </parameter>, a thunk layer is inserted between the | |
| application imports and the Wine handlers (actually the | |
| export table of the DLL is modified, and a thunk is | |
| inserted in the table); this layer is known as "relay" | |
| because all it does is print out the arguments/return | |
| values (by using the argument lists in the DLL | |
| descriptor's entry point table), then pass the call on, | |
| but it's invaluable for debugging misbehaving calls into | |
| Wine code. A similar mechanism also exists between Windows | |
| DLLs - Wine can optionally insert thunk layers between | |
| them, by using <parameter>WINEDEBUG=+snoop</parameter>, | |
| but since no DLL descriptor information exists for | |
| non-Wine DLLs, this is less reliable and may lead to | |
| crashes. | |
| </para> | |
| <para> | |
| For Win16 code, there is no way around thunking - Wine | |
| needs to relay between 16-bit and 32-bit code. These | |
| thunks switch between the app's 16-bit stack and Wine's | |
| 32-bit stack, copies and converts arguments as appropriate | |
| (an int is 16 bit 16-bit and 32 bits in 32-bit, pointers | |
| are segmented in 16 bit (and also near or far) but are 32 | |
| bit linear values in 32 bit), and handles the Win16 | |
| mutex. Some finer control can be obtained on the | |
| conversion, see <command>winebuild</command> reference | |
| manual for the details. Suffice to say that the kind of | |
| intricate stack content juggling this results in, is not | |
| exactly suitable study material for beginners. | |
| </para> | |
| <para> | |
| A DLL descriptor is also created for every 16 bit | |
| DLL. However, this DLL normally paired with a 32 bit | |
| DLL. Either, it's the 16 bit counterpart of the 16 bit DLL | |
| (KRNL386.EXE for KERNEL32, USER for USER32...), or a 16 | |
| bit DLL directly linked to a 32 bit DLL (like SYSTEM for | |
| KERNEL32, or DDEML for USER32). In those cases, the 16 bit | |
| descriptor(s) is (are) inserted in the same shared library | |
| as the the corresponding 32 bit DLL. Wine will also create | |
| symbolic links between kernel32.dll.so and system.dll.so | |
| so that loading of either | |
| <filename>kernel32.dll</filename> or | |
| <filename>system.dll</filename> will end up on the same | |
| shared library. | |
| </para> | |
| </sect2> | |
| <sect2 id="arch-mem"> | |
| <title>Memory management</title> | |
| <para> | |
| Every Win32 process in Wine has its own dedicated native | |
| process on the host system, and therefore its own address | |
| space. This section explores the layout of the Windows | |
| address space and how it is emulated. | |
| </para> | |
| <para> | |
| Firstly, a quick recap of how virtual memory works. Physical | |
| memory in RAM chips is split into | |
| <emphasis>frames</emphasis>, and the memory that each | |
| process sees is split into <emphasis>pages</emphasis>. Each | |
| process has its own 4 gigabytes of address space (4gig being | |
| the maximum space addressable with a 32 bit pointer). Pages | |
| can be mapped or unmapped: attempts to access an unmapped | |
| page cause an | |
| <constant>EXCEPTION_ACCESS_VIOLATION</constant> which has | |
| the easily recognizable code of | |
| <constant>0xC0000005</constant>. Any page can be mapped to | |
| any frame, therefore you can have multiple addresses which | |
| actually "contain" the same memory. Pages can also be mapped | |
| to things like files or swap space, in which case accessing | |
| that page will cause a disk access to read the contents into | |
| a free frame. | |
| </para> | |
| <sect3> | |
| <title>Initial layout (in Windows)</title> | |
| <para> | |
| When a Win32 process starts, it does not have a clear | |
| address space to use as it pleases. Many pages are already | |
| mapped by the operating system. In particular, the EXE | |
| file itself and any DLLs it needs are mapped into memory, | |
| and space has been reserved for the stack and a couple of | |
| heaps (zones used to allocate memory to the app | |
| from). Some of these things need to be at a fixed address, | |
| and others can be placed anywhere. | |
| </para> | |
| <para> | |
| The EXE file itself is usually mapped at address 0x400000 | |
| and up: indeed, most EXEs have their relocation records | |
| stripped which means they must be loaded at their base | |
| address and cannot be loaded at any other address. | |
| </para> | |
| <para> | |
| DLLs are internally much the same as EXE files but they | |
| have relocation records, which means that they can be | |
| mapped at any address in the address space. Remember we | |
| are not dealing with physical memory here, but rather | |
| virtual memory which is different for each | |
| process. Therefore <filename>OLEAUT32.DLL</filename> may | |
| be loaded at one address in one process, and a totally | |
| different one in another. Ensuring all the functions | |
| loaded into memory can find each other is the job of the | |
| Windows dynamic linker, which is a part of NTDLL. | |
| </para> | |
| <para> | |
| So, we have the EXE and its DLLs mapped into memory. Two | |
| other very important regions also exist: the stack and the | |
| process heap. The process heap is simply the equivalent of | |
| the libc <function>malloc</function> arena on UNIX: it's a | |
| region of memory managed by the OS which | |
| <function>malloc</function>/<function>HeapAlloc</function> | |
| partitions and hands out to the application. Windows | |
| applications can create several heaps but the process heap | |
| always exists. | |
| </para> | |
| <para> | |
| Windows 9x also implements another kind of heap: the | |
| shared heap. The shared heap is unusual in that | |
| anything allocated from it will be visible in every other | |
| process. | |
| </para> | |
| </sect3> | |
| <sect3> | |
| <title>Comparison</title> | |
| <para> | |
| So far we've assumed the entire 4 gigs of address space is | |
| available for the application. In fact that's not so: only | |
| the lower 2 gigs are available, the upper 2 gigs are on | |
| Windows NT used by the operating system and hold the | |
| kernel (from 0x80000000). Why is the kernel mapped into | |
| every address space? Mostly for performance: while it's | |
| possible to give the kernel its own address space too - | |
| this is what Ingo Molnars 4G/4G VM split patch does for | |
| Linux - it requires that every system call into the kernel | |
| switches address space. As that is a fairly expensive | |
| operation (requires flushing the translation lookaside | |
| buffers etc) and syscalls are made frequently it's best | |
| avoided by keeping the kernel mapped at a constant | |
| position in every processes address space. | |
| </para> | |
| <para> | |
| Basically, the comparison of memory mappings looks as | |
| follows: | |
| <table> | |
| <title>Memory layout (Windows and Wine)</title> | |
| <tgroup cols="4" align="left" colsep="1" rowsep="1"> | |
| <thead> | |
| <row> | |
| <entry>Address</entry> | |
| <entry>Windows 9x</entry> | |
| <entry>Windows NT</entry> | |
| <entry>Linux</entry> | |
| </row> | |
| </thead> | |
| <tbody> | |
| <row> | |
| <entry>00000000-7fffffff</entry> | |
| <entry>User</entry> | |
| <entry>User</entry> | |
| <entry>User</entry> | |
| </row> | |
| <row> | |
| <entry>80000000-bfffffff</entry> | |
| <entry>Shared</entry> | |
| <entry>User</entry> | |
| <entry>User</entry> | |
| </row> | |
| <row> | |
| <entry>c0000000-ffffffff</entry> | |
| <entry>Kernel</entry> | |
| <entry>Kernel</entry> | |
| <entry>Kernel</entry> | |
| </row> | |
| </tbody> | |
| </tgroup> | |
| </table> | |
| </para> | |
| <para> | |
| On Windows 9x, in fact only the upper gigabyte | |
| (<constant>0xC0000000</constant> and up) is used by the | |
| kernel, the region from 2 to 3 gigs is a shared area used | |
| for loading system DLLs and for file mappings. The bottom | |
| 2 gigs on both NT and 9x are available for the programs | |
| memory allocation and stack. | |
| </para> | |
| </sect3> | |
| <sect3> | |
| <title>Implementation</title> | |
| <para> | |
| Wine (with a bit of black magic) is able to map all items | |
| at the correct locations as depicted above. | |
| </para> | |
| <para> | |
| Wine also implements the shared heap so native win9x DLLs | |
| can be used. This heap is always created at the | |
| <constant>SYSTEM_HEAP_BASE</constant> address or | |
| <constant>0x80000000</constant> and defaults to 16 | |
| megabytes in size. | |
| </para> | |
| <para> | |
| There are a few other magic locations. The bottom 64k of | |
| memory is deliberately left unmapped to catch null pointer | |
| dereferences. The region from 64k to 1mb+64k are reserved | |
| for DOS compatibility and contain various DOS data | |
| structures. Finally, the address space also contains | |
| mappings for the Wine binary itself, any native libaries | |
| Wine is using, the glibc malloc arena and so on. | |
| </para> | |
| </sect3> | |
| </sect2> | |
| <sect2> | |
| <title>Processes</title> | |
| <para> | |
| Let's take a closer look at the way Wine loads and run | |
| processes in memory. | |
| </para> | |
| <sect3> | |
| <title>Starting a process from command line</title> | |
| <para> | |
| When starting a Wine process from command line (we'll get | |
| later on to the differences between NE, PE and Winelib | |
| executables), there are a couple of things Wine need to do | |
| first. A first executable is run to check the threading | |
| model of the underlying OS (see <xref linkend="threading"> | |
| for the details) and will start the real Wine loader | |
| corresponding to the choosen threading model. | |
| </para> | |
| <para> | |
| Then Wine graps a few elements from the Unix world: the | |
| environment, the program arguments. Then the | |
| <filename>ntdll.dll.so</filename> is loaded into memory | |
| using the standard shared library dynamic loader. When | |
| loaded, NTDLL will mainly first create a decent Windows | |
| environment: | |
| <itemizedlist> | |
| <listitem> | |
| <para>create a PEB and a TEB</para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| set up the connection to the Wine server - and | |
| eventually launching the Wine server if none runs | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para>create the process heap</para> | |
| </listitem> | |
| </itemizedlist> | |
| </para> | |
| <para> | |
| Then <filename>Kernel32</filename> is loaded (but now | |
| using the Windows dynamic loading capabilities) and a Wine | |
| specific entry point is called | |
| <function>__wine_kernel_init</function>. This function | |
| will actually handle all the logic of the process loading | |
| and execution, and will never return from it's call. | |
| </para> | |
| <para> | |
| <function>__wine_kernel_init</function> will undergo the | |
| following tasks: | |
| <itemizedlist> | |
| <listitem> | |
| <para> | |
| initialization of program arguments from Unix | |
| program arguments | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| lookup of executable in the file system | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| If the file is not found, then an error is printed | |
| and the Wine loader stops. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| We'll cover the non-PE file type later on, so assume | |
| for now it's a PE file. The PE module is loaded in | |
| memory using the Windows shared library | |
| mechanism. Note that the dependencies on the module | |
| are not resolved at this point. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| A new stack is created, which size is given in the | |
| PE header, and this stack is made the one of the | |
| running thread (which is still the only one in the | |
| process). The stack used at startup will no longer | |
| be used. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| Which this new stack, | |
| <function>ntdll.LdrInitializeThunk</function> is | |
| called which performs the remaining initialization | |
| parts, including resolving all the DLL imports on | |
| the PE module, and doing the init of the TLS slots. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| Control can now be passed to the | |
| <function>EntryPoint</function> of the PE module, | |
| which will let the executable run. | |
| </para> | |
| </listitem> | |
| </itemizedlist> | |
| </para> | |
| </sect3> | |
| <sect3> | |
| <title>Creating a child process from a running process</title> | |
| <para> | |
| The steps used are closely link to what is done in the | |
| previous case. | |
| </para> | |
| <para> | |
| There are however a few points to look at a bit more | |
| closely. The inner implementation creates the child | |
| process using the <function>fork()</function> and | |
| <function>exec()</function> calls. This means that we | |
| don't need to check again for the threading model, we can | |
| use what the parent (or the grand-parent process...) | |
| started from command line has found. | |
| </para> | |
| <para> | |
| The Win32 process creation allows to pass a lot of | |
| information between the parent and the child. This | |
| includes object handles, windows title, console | |
| parameters, environment strings... Wine makes use of both | |
| the standard Unix inheritance mechanisms (for environment | |
| for example) and the Wine server (to pass from parent to | |
| child a chunk of data containing the relevant information). | |
| </para> | |
| <para> | |
| The previously described loading mechanism will check in | |
| the Wine server if such a chunk exists, and, if so, will | |
| perform the relevant initialization. | |
| </para> | |
| <para> | |
| Some further synchronization is also put in place: a | |
| parent will wait until the child has started, or has | |
| failed. The Wine server is also used to perform those | |
| tasks. | |
| </para> | |
| </sect3> | |
| <sect3> | |
| <title>Starting a Winelib process</title> | |
| <para> | |
| Before going into the gory details, let's first go back to | |
| what a Winelib application is. It can be either a regular | |
| Unix executable, or a more specific Wine beast. This later | |
| form in fact creates two files for a given executable (say | |
| <filename>foo.exe</filename>). The first one, named | |
| <filename>foo</filename> will be a symbolic link to the | |
| Wine loader (<filename>wine</filename>). The second one, | |
| named <filename>foo.exe.so</filename>, is the equivalent | |
| of the <filename>.dll.so</filename> files we've already | |
| described for DLLs. As in Windows, an executable is, among | |
| other things, a module with its import and export | |
| information, as any DLL, it makes sense Wine uses the same | |
| mechanisms for loading native executables and DLLs. | |
| </para> | |
| <para> | |
| When starting a Winelib application from the command line | |
| (say with <command>foo arg1 arg2</command>), the Unix | |
| shell will execute <command>foo</command> as a Unix | |
| executable. Since this is in fact the Wine loader, Wine | |
| will fire up. However, will notice that it hasn't been | |
| started as <command>wine</command> but as | |
| <command>foo</command>, and hence, will try to load (using | |
| Unix shared library mechanism) the second file | |
| <filename>foo.exe.so</filename>. Wine will recognize a 32 | |
| bit module (with its descriptor) embedded in the shared | |
| library, and once the shared library loaded, it will | |
| proceed the same path as when loading a standard native PE | |
| executable. | |
| </para> | |
| <para> | |
| Wine needs to implement this second form of executable in | |
| order to maintain the order of initialization of some | |
| elements in the executable. One particular issue is when | |
| dealing with global C++ objects. In standard Unix | |
| executable, the call of the constructor to such objects is | |
| stored in the specific section of the executable | |
| (<function>.init</function> not to name it). All | |
| constructors in this section are called before the | |
| <function>main</function> function is called. Creating a | |
| Wine executable using the first form mentionned above will | |
| let those constructors being called before Wine gets a | |
| chance to initialize itself. So, any constructor using a | |
| Windows API will fail, because Wine infrastructure isn't | |
| in place. The use of the second form for Winelib | |
| executables ensures that we do the initialization using | |
| the following steps: | |
| <itemizedlist> | |
| <listitem> | |
| <para> | |
| initialize the Wine infrastructure | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| load the executable into memory | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| handle the import sections for the executable | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| call the global object constructors (if any). They | |
| now can properly call the Windows APIs | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| call the executable entry point | |
| </para> | |
| </listitem> | |
| </itemizedlist> | |
| </para> | |
| <para> | |
| The attentive reader would have noted that the resolution | |
| of imports for the executable is done, as for a DLL, when | |
| the executable/DLL descriptor is registered. However, this | |
| is done also by adding a specific constructor in the | |
| <function>.init</function> section. For the above describe | |
| scheme to function properly, this constructor must be the | |
| first constructor to be called, before all the other | |
| constructors, generated by the executable itself. The Wine | |
| build chain takes care of that, and also generating the | |
| executable/DLL descriptor for the Winelib executable. | |
| </para> | |
| </sect3> | |
| <sect3> | |
| <title>Starting a NE (Win16) process</title> | |
| <para> | |
| When Wine is requested to run a NE (Win 16 process), it | |
| will in fact hand over the execution of it to a specific | |
| executable <filename>winevdm</filename>. VDM stands for | |
| Virtual DOS Machine. This <filename>winevdm</filename> | |
| will in fact set up the correct 16 bit environment to run | |
| the executable. Any new 16 bit process created by this | |
| executable (or its children) will run into the same | |
| <filename>winevdm</filename> instance. Among one instance, | |
| several functionalities will be provided to those 16 bit | |
| processes, including the cooperative multitasking, sharing | |
| the same address space, managing the selectors for the 16 | |
| bit segments needed for code, data and stack. | |
| </para> | |
| <para> | |
| Note that several <filename>winevdm</filename> instances | |
| can run in the same Wine session, but the functionalities | |
| described above are only shared among a given instance, | |
| not among all the instances. <filename>winevdm</filename> | |
| is built as Winelib application, and hence has access to | |
| any facility a 32 bit application has. | |
| </para> | |
| <para> | |
| The behaviour we just described also applies to DOS | |
| executables, which are handled the same way by | |
| <filename>winevdm</filename>. | |
| </para> | |
| </sect3> | |
| </sect2> | |
| <sect2> | |
| <title>Wine drivers</title> | |
| <para> | |
| Wine will not allow running native Windows drivers under | |
| Unix. This comes mainly because (look at the generic | |
| architecture schemas) Wine doesn't implement the kernel | |
| features of Windows (kernel here really means the kernel, | |
| not the KERNEL32 DLL), but rather sets up a proxy layer on | |
| top of the Unix kernel to provide the NTDLL and KERNEL32 | |
| features. This means that Wine doesn't provide the inner | |
| infrastructure to run native drivers, either from the Win9x | |
| family or from the NT family. | |
| </para> | |
| <para> | |
| In other words, Wine will only be able to provide access to | |
| a specific device, if and only if, 1/ this device is | |
| supported in Unix (there is Unix-driver to talk to it), 2/ | |
| Wine has implemented the proxy code to make the glue between | |
| the API of a Windows driver, and the Unix interface of the | |
| Unix driver. | |
| </para> | |
| <para> | |
| Wine, however, tries to implement in the various DLLs | |
| needing to access devices to do it through the standard | |
| Windows APIs for device drivers in user space. This is for | |
| example the case for the multimedia drivers, where Wine | |
| loads Wine builtin DLLs to talk to the OSS interface, or the | |
| ALSA interface. Those DLLs implement the same interface as | |
| any user space audio driver in Windows. | |
| </para> | |
| </sect2> | |
| </sect1> | |
| <sect1 id="module-overview"> | |
| <title>Module Overview</title> | |
| <sect2> | |
| <title>NTDLL Module</title> | |
| <para> | |
| NTDLL provides most of the services you'd expect from a | |
| kernel. | |
| </para> | |
| <para> | |
| Process and thread management are part of them (even if | |
| process management is still mainly done in KERNEL32, unlike | |
| NT). A Windows process runs as a Unix process, and a Windows | |
| thread runs as a Unix thread. | |
| </para> | |
| <para> | |
| Wine also provide fibers (which is the Windows name of | |
| co-routines). | |
| </para> | |
| <para> | |
| Most of the Windows memory handling (Heap, Global and Local | |
| functions, virtual memory...) are easily mapped upon their | |
| Unix equivalents. Note the NTDLL doesn't know about 16 bit | |
| memory, which is only handled in KERNEL32/KRNL386.EXE (and | |
| also the DOS routines). | |
| </para> | |
| <sect3> | |
| <title>File management</title> | |
| <para> | |
| Wine uses some configuration in order to map Windows | |
| filenames (either defined with drive letters, or as UNC | |
| names) to the unix filenames. Wine also uses some | |
| incantation so that most of file related APIs can also | |
| take full unix names. This is handy when passing filenames | |
| on the command line. | |
| </para> | |
| <para> | |
| File handles can be waitable objects, as Windows define | |
| them. | |
| </para> | |
| <para> | |
| Asynchronous I/O is implemented on file handles by | |
| queueing pseudo APC. They are not real APC in the sense | |
| that they have the same priority as the threads in the | |
| considered process (while APCs on NT have normally a | |
| higher priority). These APCs get called when invoking | |
| Wine server (which should lead to correct behavior when the | |
| program ends up waiting on some object - waiting always | |
| implies calling Wine server). | |
| </para> | |
| <para> | |
| FIXME: this should be enhanced and updated to latest work | |
| on FS. | |
| </para> | |
| </sect3> | |
| <sect3> | |
| <title>Synchronization</title> | |
| <para> | |
| Most of the synchronization (between threads or processes) | |
| is done in Wine server, which handles both the waiting | |
| operation (on a single object or a set of objects) and the | |
| signaling of objects. | |
| </para> | |
| </sect3> | |
| <sect3> | |
| <title>Module (DLL) loading</title> | |
| <para> | |
| Wine is able to load any NE and PE module. In all cases, | |
| the module's binary code is directly executed by the | |
| processor. | |
| </para> | |
| </sect3> | |
| <sect3> | |
| <title>Device management</title> | |
| <para> | |
| Wine allows usage a wide variety of devices: | |
| <itemizedlist> | |
| <listitem> | |
| <para> | |
| Communication ports are mapped to Unix | |
| communication ports (if they have sufficient | |
| permissions). | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| Parallel ports are mapped to Unix parallel ports (if | |
| they have sufficient permissions). | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| CDROM: the Windows device I/O control calls are | |
| mapped onto Unix <function>ioctl()</function>. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| Some Win9x VxDs are supported, by rewriting some of | |
| their internal behavior. But this support is | |
| limited. Portable programs to Windows NT shouldn't | |
| need them. | |
| </para> | |
| <para> | |
| Wine will not support native VxD. | |
| </para> | |
| </listitem> | |
| </itemizedlist> | |
| </para> | |
| </sect3> | |
| </sect2> | |
| <sect2> | |
| <title>KERNEL Module</title> | |
| <para> | |
| FIXME: Needs some content... | |
| </para> | |
| </sect2> | |
| <sect2> | |
| <title>GDI Module</title> | |
| <sect3> | |
| <title>X Windows System interface</title> | |
| <para> | |
| The X libraries used to implement X clients (such as Wine) | |
| do not work properly if multiple threads access the same | |
| display concurrently. It is possible to compile the X | |
| libraries to perform their own synchronization (initiated | |
| by calling <function>XInitThreads()</function>). However, | |
| Wine does not use this approach. Instead Wine performs its | |
| own synchronization using the | |
| <function>wine_tsx11_lock()</function> / <function>wine_tsx11_unlock()</function> | |
| functions. This locking protects library access | |
| with a critical section, and also arranges things so that | |
| X libraries compiled without <option>-D_REENTRANT</option> | |
| (eg. with global <varname>errno</varname> variable) will | |
| work with Wine. | |
| </para> | |
| <para> | |
| In the past, all calls to X used to go through a wrapper called | |
| <function>TSX...()</function> (for "Thread Safe X ..."). | |
| While it is still being used in the code, it's inefficient | |
| as the lock is potentially aquired and released unnecessarily. | |
| New code should explicitly aquire the lock. | |
| </para> | |
| </sect3> | |
| </sect2> | |
| <sect2> | |
| <title>USER Module</title> | |
| <para> | |
| USER implements windowing and messaging subsystems. It also | |
| contains code for common controls and for other | |
| miscellaneous stuff (rectangles, clipboard, WNet, etc). | |
| Wine USER code is located in <filename>windows/</filename>, | |
| <filename>controls/</filename>, and | |
| <filename>misc/</filename> directories. | |
| </para> | |
| <sect3> | |
| <title>Windowing subsystem</title> | |
| <para><filename>windows/win.c</filename></para> | |
| <para><filename>windows/winpos.c</filename></para> | |
| <para> | |
| Windows are arranged into parent/child hierarchy with one | |
| common ancestor for all windows (desktop window). Each | |
| window structure contains a pointer to the immediate | |
| ancestor (parent window if <constant>WS_CHILD</constant> | |
| style bit is set), a pointer to the sibling (returned by | |
| <function>GetWindow(..., GW_NEXT)</function>), a pointer | |
| to the owner window (set only for popup window if it was | |
| created with valid <varname>hwndParent</varname> | |
| parameter), and a pointer to the first child window | |
| (<function>GetWindow(.., GW_CHILD)</function>). All popup | |
| and non-child windows are therefore placed in the first | |
| level of this hierarchy and their ancestor link | |
| (<varname>wnd->parent</varname>) points to the desktop | |
| window. | |
| </para> | |
| <screen> | |
| Desktop window - root window | |
| | \ `-. | |
| | \ `-. | |
| popup -> wnd1 -> wnd2 - top level windows | |
| | \ `-. `-. | |
| | \ `-. `-. | |
| child1 child2 -> child3 child4 - child windows | |
| </screen> | |
| <para> | |
| Horizontal arrows denote sibling relationship, vertical | |
| lines - ancestor/child. To summarize, all windows with the | |
| same immediate ancestor are sibling windows, all windows | |
| which do not have desktop as their immediate ancestor are | |
| child windows. Popup windows behave as topmost top-level | |
| windows unless they are owned. In this case the only | |
| requirement is that they must precede their owners in the | |
| top-level sibling list (they are not topmost). Child | |
| windows are confined to the client area of their parent | |
| windows (client area is where window gets to do its own | |
| drawing, non-client area consists of caption, menu, | |
| borders, intrinsic scrollbars, and | |
| minimize/maximize/close/help buttons). | |
| </para> | |
| <para> | |
| Another fairly important concept is | |
| <firstterm>z-order</firstterm>. It is derived from the | |
| ancestor/child hierarchy and is used to determine | |
| "above/below" relationship. For instance, in the example | |
| above, z-order is | |
| </para> | |
| <screen> | |
| child1->popup->child2->child3->wnd1->child4->wnd2->desktop. | |
| </screen> | |
| <para> | |
| Current active window ("foreground window" in Win32) is | |
| moved to the front of z-order unless its top-level | |
| ancestor owns popup windows. | |
| </para> | |
| <para> | |
| All these issues are dealt with (or supposed to be) in | |
| <filename>windows/winpos.c</filename> with | |
| <function>SetWindowPos()</function> being the primary | |
| interface to the window manager. | |
| </para> | |
| <para> | |
| Wine specifics: in default and managed mode each top-level | |
| window gets its own X counterpart with desktop window | |
| being basically a fake stub. In desktop mode, however, | |
| only desktop window has an X window associated with it. | |
| Also, <function>SetWindowPos()</function> should | |
| eventually be implemented via | |
| <function>Begin/End/DeferWindowPos()</function> calls and | |
| not the other way around. | |
| </para> | |
| <sect4> | |
| <title>Visible region, clipping region and update region</title> | |
| <para><filename>windows/dce.c</filename></para> | |
| <para><filename>windows/winpos.c</filename></para> | |
| <para><filename>windows/painting.c</filename></para> | |
| <screen> | |
| ________________________ | |
| |_________ | A and B are child windows of C | |
| | A |______ | | |
| | | | | | |
| |---------' | | | |
| | | B | | | |
| | | | | | |
| | `------------' | | |
| | C | | |
| `------------------------' | |
| </screen> | |
| <para> | |
| Visible region determines which part of the window is | |
| not obscured by other windows. If a window has the | |
| <constant>WS_CLIPCHILDREN</constant> style then all | |
| areas below its children are considered invisible. | |
| Similarly, if the <constant>WS_CLIPSIBLINGS</constant> | |
| bit is in effect then all areas obscured by its siblings | |
| are invisible. Child windows are always clipped by the | |
| boundaries of their parent windows. | |
| </para> | |
| <para> | |
| B has a <constant>WS_CLIPSIBLINGS</constant> style: | |
| </para> | |
| <screen> | |
| . ______ | |
| : | | | |
| | ,-----' | | |
| | | B | - visible region of B | |
| | | | | |
| : `------------' | |
| </screen> | |
| <para> | |
| When the program requests a <firstterm>display | |
| context</firstterm> (DC) for a window it can specify | |
| an optional clipping region that further restricts the | |
| area where the graphics output can appear. This area is | |
| calculated as an intersection of the visible region and | |
| a clipping region. | |
| </para> | |
| <para> | |
| Program asked for a DC with a clipping region: | |
| </para> | |
| <screen> | |
| ______ | |
| ,--|--. | . ,--. | |
| ,--+--' | | : _: | | |
| | | B | | => | | | - DC region where the painting will | |
| | | | | | | | be visible | |
| `--|-----|---' : `----' | |
| `-----' | |
| </screen> | |
| <para> | |
| When the window manager detects that some part of the window | |
| became visible it adds this area to the update region of this | |
| window and then generates <constant>WM_ERASEBKGND</constant> and | |
| <constant>WM_PAINT</constant> messages. In addition, | |
| <constant>WM_NCPAINT</constant> message is sent when the | |
| uncovered area intersects a nonclient part of the window. | |
| Application must reply to the <constant>WM_PAINT</constant> | |
| message by calling the | |
| <function>BeginPaint()</function>/<function>EndPaint()</function> | |
| pair of functions. <function>BeginPaint()</function> returns a DC | |
| that uses accumulated update region as a clipping region. This | |
| operation cleans up invalidated area and the window will not | |
| receive another <constant>WM_PAINT</constant> until the window | |
| manager creates a new update region. | |
| </para> | |
| <para> | |
| A was moved to the left: | |
| </para> | |
| <screen> | |
| ________________________ ... / C update region | |
| |______ | : .___ / | |
| | A |_________ | => | ...|___|.. | |
| | | | | | : | | | |
| |------' | | | : '---' | |
| | | B | | | : \ | |
| | | | | : \ | |
| | `------------' | B update region | |
| | C | | |
| `------------------------' | |
| </screen> | |
| <para> | |
| Windows maintains a display context cache consisting of | |
| entries that include the DC itself, the window to which | |
| it belongs, and an optional clipping region (visible | |
| region is stored in the DC itself). When an API call | |
| changes the state of the window tree, window manager has | |
| to go through the DC cache to recalculate visible | |
| regions for entries whose windows were involved in the | |
| operation. DC entries (DCE) can be either private to the | |
| window, or private to the window class, or shared | |
| between all windows (Windows 3.1 limits the number of | |
| shared DCEs to 5). | |
| </para> | |
| </sect4> | |
| </sect3> | |
| <sect3> | |
| <title>Messaging subsystem</title> | |
| <para><filename>windows/queue.c</filename></para> | |
| <para><filename>windows/message.c</filename></para> | |
| <para> | |
| Each Windows task/thread has its own message queue - this | |
| is where it gets messages from. Messages can be: | |
| <orderedlist> | |
| <listitem> | |
| <para> | |
| generated on the fly (<constant>WM_PAINT</constant>, | |
| <constant>WM_NCPAINT</constant>, | |
| <constant>WM_TIMER</constant>) | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| created by the system (hardware messages) | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| posted by other tasks/threads (<function>PostMessage</function>) | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| sent by other tasks/threads (<function>SendMessage</function>) | |
| </para> | |
| </listitem> | |
| </orderedlist> | |
| </para> | |
| <para> | |
| Message priority: | |
| </para> | |
| <para> | |
| First the system looks for sent messages, then for posted | |
| messages, then for hardware messages, then it checks if | |
| the queue has the "dirty window" bit set, and, finally, it | |
| checks for expired timers. See | |
| <filename>windows/message.c</filename>. | |
| </para> | |
| <para> | |
| From all these different types of messages, only posted | |
| messages go directly into the private message queue. | |
| System messages (even in Win95) are first collected in the | |
| system message queue and then they either sit there until | |
| <function>Get/PeekMessage</function> gets to process them | |
| or, as in Win95, if system queue is getting clobbered, a | |
| special thread ("raw input thread") assigns them to the | |
| private queues. Sent messages are queued separately and | |
| the sender sleeps until it gets a reply. Special messages | |
| are generated on the fly depending on the window/queue | |
| state. If the window update region is not empty, the | |
| system sets the <constant>QS_PAINT</constant> bit in the | |
| owning queue and eventually this window receives a | |
| <constant>WM_PAINT</constant> message | |
| (<constant>WM_NCPAINT</constant> too if the update region | |
| intersects with the non-client area). A timer event is | |
| raised when one of the queue timers expire. Depending on | |
| the timer parameters <function>DispatchMessage</function> | |
| either calls the callback function or the window | |
| procedure. If there are no messages pending the | |
| task/thread sleeps until messages appear. | |
| </para> | |
| <para> | |
| There are several tricky moments (open for discussion) - | |
| </para> | |
| <itemizedlist> | |
| <listitem> | |
| <para> | |
| System message order has to be honored and messages | |
| should be processed within correct task/thread | |
| context. Therefore when <function>Get/PeekMessage</function> encounters | |
| unassigned system message and this message appears not | |
| to be for the current task/thread it should either | |
| skip it (or get rid of it by moving it into the | |
| private message queue of the target task/thread - | |
| Win95, AFAIK) and look further or roll back and then | |
| yield until this message gets processed when system | |
| switches to the correct context (Win16). In the first | |
| case we lose correct message ordering, in the second | |
| case we have the infamous synchronous system message | |
| queue. Here is a post to one of the OS/2 newsgroup I | |
| found to be relevant: | |
| </para> | |
| <blockquote> | |
| <attribution>by David Charlap</attribution> | |
| <para> | |
| " Here's the problem in a nutshell, and there is no | |
| good solution. Every possible solution creates a | |
| different problem. | |
| </para> | |
| <para> | |
| With a windowing system, events can go to many | |
| different windows. Most are sent by applications or | |
| by the OS when things relating to that window happen | |
| (like repainting, timers, etc.) | |
| </para> | |
| <para> | |
| Mouse input events go to the window you click on | |
| (unless some window captures the mouse). | |
| </para> | |
| <para> | |
| So far, no problem. Whenever an event happens, you | |
| put a message on the target window's message queue. | |
| Every process has a message queue. If the process | |
| queue fills up, the messages back up onto the system | |
| queue. | |
| </para> | |
| <para> | |
| This is the first cause of apps hanging the GUI. If | |
| an app doesn't handle messages and they back up into | |
| the system queue, other apps can't get any more | |
| messages. The reason is that the next message in | |
| line can't go anywhere, and the system won't skip | |
| over it. | |
| </para> | |
| <para> | |
| This can be fixed by making apps have bigger private | |
| message queues. The SIQ fix does this. PMQSIZE does | |
| this for systems without the SIQ fix. Applications | |
| can also request large queues on their own. | |
| </para> | |
| <para> | |
| Another source of the problem, however, happens when | |
| you include keyboard events. When you press a key, | |
| there's no easy way to know what window the | |
| keystroke message should be delivered to. | |
| </para> | |
| <para> | |
| Most windowing systems use a concept known as | |
| "focus". The window with focus gets all incoming | |
| keyboard messages. Focus can be changed from window | |
| to window by apps or by users clicking on windows. | |
| </para> | |
| <para> | |
| This is the second source of the problem. Suppose | |
| window A has focus. You click on window B and start | |
| typing before the window gets focus. Where should | |
| the keystrokes go? On the one hand, they should go | |
| to A until the focus actually changes to B. On the | |
| other hand, you probably want the keystrokes to go | |
| to B, since you clicked there first. | |
| </para> | |
| <para> | |
| OS/2's solution is that when a focus-changing event | |
| happens (like clicking on a window), OS/2 holds all | |
| messages in the system queue until the focus change | |
| actually happens. This way, subsequent keystrokes | |
| go to the window you clicked on, even if it takes a | |
| while for that window to get focus. | |
| </para> | |
| <para> | |
| The downside is that if the window takes a real long | |
| time to get focus (maybe it's not handling events, | |
| or maybe the window losing focus isn't handling | |
| events), everything backs up in the system queue and | |
| the system appears hung. | |
| </para> | |
| <para> | |
| There are a few solutions to this problem. | |
| </para> | |
| <para> | |
| One is to make focus policy asynchronous. That is, | |
| focus changing has absolutely nothing to do with the | |
| keyboard. If you click on a window and start typing | |
| before the focus actually changes, the keystrokes go | |
| to the first window until focus changes, then they | |
| go to the second. This is what X-windows does. | |
| </para> | |
| <para> | |
| Another is what NT does. When focus changes, | |
| keyboard events are held in the system message | |
| queue, but other events are allowed through. This is | |
| "asynchronous" because the messages in the system | |
| queue are delivered to the application queues in a | |
| different order from that with which they were | |
| posted. If a bad app won't handle the "lose focus" | |
| message, it's of no consequence - the app receiving | |
| focus will get its "gain focus" message, and the | |
| keystrokes will go to it. | |
| </para> | |
| <para> | |
| The NT solution also takes care of the application | |
| queue filling up problem. Since the system delivers | |
| messages asynchronously, messages waiting in the | |
| system queue will just sit there and the rest of the | |
| messages will be delivered to their apps. | |
| </para> | |
| <para> | |
| The OS/2 SIQ solution is this: When a | |
| focus-changing event happens, in addition to | |
| blocking further messages from the application | |
| queues, a timer is started. When the timer goes | |
| off, if the focus change has not yet happened, the | |
| bad app has its focus taken away and all messages | |
| targeted at that window are skipped. When the bad | |
| app finally handles the focus change message, OS/2 | |
| will detect this and stop skipping its messages. | |
| </para> | |
| <para> | |
| As for the pros and cons: | |
| </para> | |
| <para> | |
| The X-windows solution is probably the easiest. The | |
| problem is that users generally don't like having to | |
| wait for the focus to change before they start | |
| typing. On many occasions, you can type and the | |
| characters end up in the wrong window because | |
| something (usually heavy system load) is preventing | |
| the focus change from happening in a timely manner. | |
| </para> | |
| <para> | |
| The NT solution seems pretty nice, but making the | |
| system message queue asynchronous can cause similar | |
| problems to the X-windows problem. Since messages | |
| can be delivered out of order, programs must not | |
| assume that two messages posted in a particular | |
| order will be delivered in that same order. This | |
| can break legacy apps, but since Win32 always had an | |
| asynchronous queue, it is fair to simply tell app | |
| designers "don't do that". It's harder to tell app | |
| designers something like that on OS/2 - they'll | |
| complain "you changed the rules and our apps are | |
| breaking." | |
| </para> | |
| <para> | |
| The OS/2 solution's problem is that nothing happens | |
| until you try to change window focus, and then wait | |
| for the timeout. Until then, the bad app is not | |
| detected and nothing is done." | |
| </para> | |
| </blockquote> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| Intertask/interthread | |
| <function>SendMessage</function>. The system has to | |
| inform the target queue about the forthcoming message, | |
| then it has to carry out the context switch and wait | |
| until the result is available. Win16 stores necessary | |
| parameters in the queue structure and then calls | |
| <function>DirectedYield()</function> function. | |
| However, in Win32 there could be several messages | |
| pending sent by preemptively executing threads, and in | |
| this case <function>SendMessage</function> has to | |
| build some sort of message queue for sent messages. | |
| Another issue is what to do with messages sent to the | |
| sender when it is blocked inside its own | |
| <function>SendMessage</function>. | |
| </para> | |
| </listitem> | |
| </itemizedlist> | |
| </sect3> | |
| </sect2> | |
| </sect1> | |
| <sect1 id="arch-dlls"> | |
| <title>Wine/Windows DLLs</title> | |
| <para> | |
| This document mainly deals with the status of current DLL | |
| support by Wine. The Wine ini file currently supports | |
| settings to change the load order of DLLs. The load order | |
| depends on several issues, which results in different settings | |
| for various DLLs. | |
| </para> | |
| <sect2> | |
| <title>Pros of Native DLLs</title> | |
| <para> | |
| Native DLLs of course guarantee 100% compatibility for | |
| routines they implement. For example, using the native USER | |
| DLL would maintain a virtually perfect and Windows 95-like | |
| look for window borders, dialog controls, and so on. Using | |
| the built-in Wine version of this library, on the other | |
| hand, would produce a display that does not precisely mimic | |
| that of Windows 95. Such subtle differences can be | |
| engendered in other important DLLs, such as the common | |
| controls library COMMCTRL or the common dialogs library | |
| COMMDLG, when built-in Wine DLLs outrank other types in load | |
| order. | |
| </para> | |
| <para> | |
| More significant, less aesthetically-oriented problems can | |
| result if the built-in Wine version of the SHELL DLL is | |
| loaded before the native version of this library. SHELL | |
| contains routines such as those used by installer utilities | |
| to create desktop shortcuts. Some installers might fail when | |
| using Wine's built-in SHELL. | |
| </para> | |
| </sect2> | |
| <sect2> | |
| <title>Cons of Native DLLs</title> | |
| <para> | |
| Not every application performs better under native DLLs. If | |
| a library tries to access features of the rest of the system | |
| that are not fully implemented in Wine, the native DLL might | |
| work much worse than the corresponding built-in one, if at | |
| all. For example, the native Windows GDI library must be | |
| paired with a Windows display driver, which of course is not | |
| present under Intel Unix and Wine. | |
| </para> | |
| <para> | |
| Finally, occasionally built-in Wine DLLs implement more | |
| features than the corresponding native Windows DLLs. | |
| Probably the most important example of such behavior is the | |
| integration of Wine with X provided by Wine's built-in USER | |
| DLL. Should the native Windows USER library take load-order | |
| precedence, such features as the ability to use the | |
| clipboard or drag-and-drop between Wine windows and X | |
| windows will be lost. | |
| </para> | |
| </sect2> | |
| <sect2> | |
| <title>Deciding Between Native and Built-In DLLs</title> | |
| <para> | |
| Clearly, there is no one rule-of-thumb regarding which | |
| load-order to use. So, you must become familiar with | |
| what specific DLLs do and which other DLLs or features | |
| a given library interacts with, and use this information | |
| to make a case-by-case decision. | |
| </para> | |
| </sect2> | |
| <sect2> | |
| <title>Load Order for DLLs</title> | |
| <para> | |
| Using the DLL sections from the wine configuration file, the | |
| load order can be tweaked to a high degree. In general it is | |
| advised not to change the settings of the configuration | |
| file. The default configuration specifies the right load | |
| order for the most important DLLs. | |
| </para> | |
| <para> | |
| The default load order follows this algorithm: for all DLLs | |
| which have a fully-functional Wine implementation, or where | |
| the native DLL is known not to work, the built-in library | |
| will be loaded first. In all other cases, the native DLL | |
| takes load-order precedence. | |
| </para> | |
| <para> | |
| The <varname>DefaultLoadOrder</varname> from the | |
| [DllDefaults] section specifies for all DLLs which version | |
| to try first. See manpage for explanation of the arguments. | |
| </para> | |
| <para> | |
| The [DllOverrides] section deals with DLLs, which need a | |
| different-from-default treatment. | |
| </para> | |
| <para> | |
| The [DllPairs] section is for DLLs, which must be loaded in | |
| pairs. In general, these are DLLs for either 16-bit or | |
| 32-bit applications. In most cases in Windows, the 32-bit | |
| version cannot be used without its 16-bit counterpart. For | |
| Wine, it is customary that the 16-bit implementations rely | |
| on the 32-bit implementations and cast the results back to | |
| 16-bit arguments. Changing anything in this section is bound | |
| to result in errors. | |
| </para> | |
| <para> | |
| For the future, the Wine implementation of Windows DLL seems | |
| to head towards unifying the 16 and 32 bit DLLs wherever | |
| possible, resulting in larger DLLs. They are stored in the | |
| <filename>dlls/</filename> subdirectory using the 32-bit | |
| name. | |
| </para> | |
| </sect2> | |
| <sect2> | |
| <title>Understanding What DLLs Do</title> | |
| <para> | |
| The following list briefly describes each of the DLLs | |
| commonly found in Windows whose load order may be modified | |
| during the configuration and compilation of Wine. | |
| </para> | |
| <para> | |
| (See also <filename>./DEVELOPER-HINTS</filename> or the | |
| <filename>dlls/</filename> subdirectory to see which DLLs | |
| are currently being rewritten for Wine) | |
| </para> | |
| <!-- FIXME: Should convert this table into a VariableList element --> | |
| <screen> | |
| ADVAPI32.DLL: 32-bit application advanced programming interfaces | |
| like crypto, systeminfo, security and event logging | |
| AVIFILE.DLL: 32-bit application programming interfaces for the | |
| Audio Video Interleave (AVI) Windows-specific | |
| Microsoft audio-video standard | |
| COMMCTRL.DLL: 16-bit common controls | |
| COMCTL32.DLL: 32-bit common controls | |
| COMDLG32.DLL: 32-bit common dialogs | |
| COMMDLG.DLL: 16-bit common dialogs | |
| COMPOBJ.DLL: OLE 16- and 32-bit compatibility libraries | |
| CRTDLL.DLL: Microsoft C runtime | |
| DCIMAN.DLL: 16-bit | |
| DCIMAN32.DLL: 32-bit display controls | |
| DDEML.DLL: DDE messaging | |
| D3D*.DLL DirectX/Direct3D drawing libraries | |
| DDRAW.DLL: DirectX drawing libraries | |
| DINPUT.DLL: DirectX input libraries | |
| DISPLAY.DLL: Display libraries | |
| DPLAY.DLL, DPLAYX.DLL: DirectX playback libraries | |
| DSOUND.DLL: DirectX audio libraries | |
| GDI.DLL: 16-bit graphics driver interface | |
| GDI32.DLL: 32-bit graphics driver interface | |
| IMAGEHLP.DLL: 32-bit IMM API helper libraries (for PE-executables) | |
| IMM32.DLL: 32-bit IMM API | |
| IMGUTIL.DLL: | |
| KERNEL32.DLL 32-bit kernel DLL | |
| KEYBOARD.DLL: Keyboard drivers | |
| LZ32.DLL: 32-bit Lempel-Ziv or LZ file compression | |
| used by the installshield installers (???). | |
| LZEXPAND.DLL: LZ file expansion; needed for Windows Setup | |
| MMSYSTEM.DLL: Core of the Windows multimedia system | |
| MOUSE.DLL: Mouse drivers | |
| MPR.DLL: 32-bit Windows network interface | |
| MSACM.DLL: Core of the Addressed Call Mode or ACM system | |
| MSACM32.DLL: Core of the 32-bit ACM system | |
| Audio Compression Manager ??? | |
| MSNET32.DLL 32-bit network APIs | |
| MSVFW32.DLL: 32-bit Windows video system | |
| MSVIDEO.DLL: 16-bit Windows video system | |
| OLE2.DLL: OLE 2.0 libraries | |
| OLE32.DLL: 32-bit OLE 2.0 components | |
| OLE2CONV.DLL: Import filter for graphics files | |
| OLE2DISP.DLL, OLE2NLS.DLL: OLE 2.1 16- and 32-bit interoperability | |
| OLE2PROX.DLL: Proxy server for OLE 2.0 | |
| OLE2THK.DLL: Thunking for OLE 2.0 | |
| OLEAUT32.DLL 32-bit OLE 2.0 automation | |
| OLECLI.DLL: 16-bit OLE client | |
| OLECLI32.DLL: 32-bit OLE client | |
| OLEDLG.DLL: OLE 2.0 user interface support | |
| OLESVR.DLL: 16-bit OLE server libraries | |
| OLESVR32.DLL: 32-bit OLE server libraries | |
| PSAPI.DLL: Proces Status API libraries | |
| RASAPI16.DLL: 16-bit Remote Access Services libraries | |
| RASAPI32.DLL: 32-bit Remote Access Services libraries | |
| SHELL.DLL: 16-bit Windows shell used by Setup | |
| SHELL32.DLL: 32-bit Windows shell (COM object?) | |
| TAPI/TAPI32/TAPIADDR: Telephone API (for Modems) | |
| W32SKRNL: Win32s Kernel ? (not in use for Win95 and up!) | |
| WIN32S16.DLL: Application compatibility for Win32s | |
| WIN87EM.DLL: 80387 math-emulation libraries | |
| WINASPI.DLL: Advanced SCSI Peripheral Interface or ASPI libraries | |
| WINDEBUG.DLL Windows debugger | |
| WINMM.DLL: Libraries for multimedia thunking | |
| WING.DLL: Libraries required to "draw" graphics | |
| WINSOCK.DLL: Sockets APIs | |
| WINSPOOL.DLL: Print spooler libraries | |
| WNASPI32.DLL: 32-bit ASPI libraries | |
| WSOCK32.DLL: 32-bit sockets APIs | |
| </screen> | |
| </sect2> | |
| </sect1> | |
| </chapter> | |
| <chapter id="initialization"> | |
| <title> The Wine initialization process </title> | |
| <para> | |
| Wine has a rather complex startup procedure, so unlike many programs the best place to begin | |
| exploring the code-base is <emphasis>not</emphasis> in fact at the main() function but instead | |
| at some of the more straightforward DLLs that exist on the periphery such as MSI, the widget | |
| library (in USER and COMCTL32) etc. The purpose of this section is to document and explain how | |
| Wine starts up from the moment the user runs "wine myprogram.exe" to the point at which | |
| myprogram gets control. | |
| </para> | |
| <sect1> | |
| <title> First Steps </title> | |
| <para> | |
| The actual wine binary that the user runs does not do very much, in fact it is only | |
| responsible for checking the threading model in use (NPTL vs LinuxThreads) and then invoking | |
| a new binary which performs the next stage in the startup sequence. See the threading chapter | |
| for more information on this check and why it's necessary. You can find this code in | |
| <filename>loader/glibc.c</filename>. The result of this check is an exec of either | |
| wine-pthread or wine-kthread, potentially (on Linux) via | |
| the <emphasis>preloader</emphasis>. We need to use separate binaries here because overriding | |
| the native pthreads library requires us to exploit a property of ELF symbol fixup semantics: | |
| it's not possible to do this without starting a new process. | |
| </para> | |
| <para> | |
| The Wine preloader is found in <filename>loader/preloader.c</filename>, and is required in | |
| order to impose a Win32 style address space layout upon the newly created Win32 process. The | |
| details of what this does is covered in the address space layout chapter. The preloader is a | |
| statically linked ELF binary which is passed the name of the actual Wine binary to run (either | |
| wine-kthread or wine-pthread) along with the arguments the user passed in from the command | |
| line. The preloader is an unusual program: it does not have a main() function. In standard ELF | |
| applications, the entry point is actually at a symbol named _start: this is provided by the | |
| standard gcc infrastructure and normally jumps to <function>__libc_start_main</function> which | |
| initializes glibc before passing control to the main function as defined by the programmer. | |
| </para> | |
| <para> | |
| The preloader takes control direct from the entry point for a few reasons. Firstly, it is | |
| required that glibc is not initialized twice: the result of such behaviour is undefined and | |
| subject to change without notice. Secondly, it's possible that as part of initializing glibc, | |
| the address space layout could be changed - for instance, any call to malloc will initialize a | |
| heap arena which modifies the VM mappings. Finally, glibc does not return to _start at any | |
| point, so by reusing it we avoid the need to recreate the ELF bootstrap stack (env, argv, | |
| auxiliary array etc). | |
| </para> | |
| <para> | |
| The preloader is responsible for two things: protecting important regions of the address | |
| space so the dynamic linker does not map shared libraries into them, and once that is done | |
| loading the real Wine binary off disk, linking it and starting it up. Normally all this is | |
| done automatically by glibc and the kernel but as we intercepted this process by using a | |
| static binary it's up to us to restart the process. The bulk of the code in the preloader is | |
| about loading wine-[pk]thread and ld-linux.so.2 off disk, linking them together, then | |
| starting the dynamic linking process. | |
| </para> | |
| <para> | |
| One of the last things the preloader does before jumping into the dynamic linker is scan the | |
| symbol table of the loaded Wine binary and set the value of a global variable directly: this | |
| is a more efficient way of passing information to the main Wine program than flattening the | |
| data structures into an environment variable or command line parameter then unpacking it on | |
| the other side, but it achieves pretty much the same thing. The global variable set points to | |
| the preload descriptor table, which contains the VMA regions protected by the preloader. This | |
| allows Wine to unmap them once the dynamic linker has been run, so leaving gaps we can | |
| initialize properly later on. | |
| </para> | |
| </sect1> | |
| <sect1> | |
| <title> Starting the emulator </title> | |
| <para> | |
| 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. | |
| </para> | |
| <para> | |
| Both the wine-pthread and wine-kthread binaries share a common <function>main</function> | |
| function, defined in <filename>loader/main.c</filename>, 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 <filename>libs/wine/loader.c</filename>. This is where the emulation really starts: | |
| <function>wine_init</function> can, with the correct preparation, | |
| be called from programs other than the wine loader itself. | |
| </para> | |
| <para> | |
| <function>wine_init</function> 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 <function>__wine_process_init</function> function defined | |
| in <filename>dlls/ntdll/loader.c</filename> | |
| </para> | |
| <para> | |
| 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. | |
| </para> | |
| <para> | |
| Finally, it loads and jumps to <function>__wine_kernel_init</function> in kernel32.dll: this | |
| is defined in <filename>dlls/kernel32/process.c</filename>. 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 <function>CreateProcess</function> specifying various things like how the first | |
| window should be displayed: this is sent to the new process via the wineserver. | |
| </para> | |
| <para> | |
| 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 | |
| <function>__wine_kernel_init</function>. This function ends with the new process stack being | |
| initialized, and start_process being called on the new stack. Nearly there! | |
| </para> | |
| <para> | |
| The final element of initializing Wine is starting the newly loaded program | |
| itself. <function>start_process</function> sets up the SEH backstop handler, calls | |
| <function>LdrInitializeThunk</function> 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: | |
| </para> | |
| <programlisting> | |
| ExitProcess( entry( peb ) ); | |
| </programlisting> | |
| <para> | |
| ... 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 <function>ExitProcess</function> API will be used to initialize a graceful shutdown. | |
| </para> | |
| </sect1> | |
| </chapter> | |
| <!-- Keep this comment at the end of the file | |
| Local variables: | |
| mode: sgml | |
| sgml-parent-document:("wine-devel.sgml" "set" "book" "part" "chapter" "") | |
| End: | |
| --> |