mirror of
https://github.com/reactos/wine.git
synced 2024-11-26 13:10:28 +00:00
2099 lines
85 KiB
Plaintext
2099 lines
85 KiB
Plaintext
<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:
|
|
-->
|