Reorganizing wine-devel:

- killing the advanced part (and moving its chapters in both
  developing Wine and Wine archi parts)
- creating a new book on coding practices from i18n.sgml, patches.sgml
  and porting.sgml
- creating a new book on some debugging strategies from the old
  advanced book and cvs-regression.sgml
- creating a new book on the kernel modules (NTDLL & KERNEL32) from
  architecture.sgml / related DLLs and address-space.sgml,
  console.sgml, threading.sgml
- creating a new book on the windowing from architecture.sgml / USER32
  and related
- creating a new book on the graphical parts from architecture.sgml /
  GDI32 and related
Other changes:
- removed list of DLLs and their role (from the modules overview)
- removed in X11 keyboard mapping section the part related to submit a
  patch
This commit is contained in:
Eric Pouech 2004-10-26 22:45:47 +00:00 committed by Alexandre Julliard
parent 0e3c524f4c
commit e86389e057
13 changed files with 2806 additions and 2204 deletions

View File

@ -26,20 +26,20 @@ WINE_USER_SRCS = \
WINE_DEVEL_SRCS = \
address-space.sgml \
architecture.sgml \
consoles.sgml \
cvs-regression.sgml \
ddraw.sgml \
debugger.sgml \
debugging.sgml \
documentation.sgml \
i18n.sgml \
implementation.sgml \
multimedia.sgml \
ole.sgml \
opengl.sgml \
patches.sgml \
porting.sgml \
testing.sgml
testing.sgml \
winedev-coding.sgml \
winedev-graphical.sgml \
winedev-kernel.sgml \
winedev-otherdebug.sgml \
winedev-windowing.sgml
WINELIB_USER_SRCS = \
winelib-bindlls.sgml \

File diff suppressed because it is too large Load Diff

View File

@ -1,174 +0,0 @@
<chapter id="consoles">
<title>Consoles in Wine</title>
<para>
As described in the Wine User Guide's CUI section, Wine
manipulates three kinds of "consoles" in order to support
properly the Win32 CUI API.
</para>
<para>
The following table describes the main implementation
differences between the three approaches.
<table>
<title>Function consoles implementation comparison</title>
<tgroup cols="4" align="left">
<thead>
<row>
<entry>Function</entry>
<entry>Bare streams</entry>
<entry>Wineconsole &amp; user backend</entry>
<entry>Wineconsole &amp; curses backend</entry>
</row>
</thead>
<tbody>
<row>
<entry>
Console as a Win32 Object (and associated
handles)
</entry>
<entry>
No specific Win32 object is used in this case. The
handles manipulated for the standard Win32 streams
are in fact "bare handles" to their corresponding
Unix streams. The mode manipulation functions
(<function>GetConsoleMode</function> /
<function>SetConsoleMode</function>) are not
supported.
</entry>
<entry>
Implemented in server, and a specific Winelib
program (wineconsole) is in charge of the
rendering and user input. The mode manipulation
functions behave as expected.
</entry>
<entry>
Implemented in server, and a specific Winelib
program (wineconsole) is in charge of the
rendering and user input. The mode manipulation
functions behave as expected.
</entry>
</row>
<row>
<entry>
Inheritance (including handling in
<function>CreateProcess</function> of
<constant>CREATE_DETACHED</constant>,
<constant>CREATE_NEW_CONSOLE</constant> flags).
</entry>
<entry>
Not supported. Every process child of a process
will inherit the Unix streams, so will also
inherit the Win32 standard streams.
</entry>
<entry>
Fully supported (each new console creation will be
handled by the creation of a new USER32 window)
</entry>
<entry>
Fully supported, except for the creation of a new
console, which will be rendered on the same Unix
terminal as the previous one, leading to
unpredictable results.
</entry>
</row>
<row>
<entry><function>ReadFile</function> / <function>WriteFile</function> operations</entry>
<entry>Fully supported</entry>
<entry>Fully supported</entry>
<entry>Fully supported</entry>
</row>
<row>
<entry>
Screen-buffer manipulation (creation, deletion, resizing...)
</entry>
<entry>Not supported</entry>
<entry>Fully supported</entry>
<entry>
Partly supported (this won't work too well as we
don't control (so far) the size of underlying Unix
terminal
</entry>
</row>
<row>
<entry>
APIs for reading/writing screen-buffer content,
cursor position
</entry>
<entry>Not supported</entry>
<entry>Fully supported</entry>
<entry>Fully supported</entry>
</row>
<row>
<entry>
APIs for manipulating the rendering window size
</entry>
<entry>Not supported</entry>
<entry>Fully supported</entry>
<entry>
Partly supported (this won't work too well as we
don't control (so far) the size of underlying Unix
terminal
</entry>
</row>
<row>
<entry>
Signaling (in particular, Ctrl-C handling)
</entry>
<entry>
Nothing is done, which means that Ctrl-C will
generate (as usual) a <constant>SIGINT</constant>
which will terminate the program.
</entry>
<entry>
Partly supported (Ctrl-C behaves as expected,
however the other Win32 CUI signaling isn't
properly implemented).
</entry>
<entry>
Partly supported (Ctrl-C behaves as expected,
however the other Win32 CUI signaling isn't
properly implemented).
</entry>
</row>
</tbody>
</tgroup>
</table>
</para>
<para>
The Win32 objects behind a console can be created in several occasions:
<itemizedlist>
<listitem>
<para>
When the program is started from wineconsole, a new
console object is created and will be used (inherited)
by the process launched from wineconsole.
</para>
</listitem>
<listitem>
<para>
When a program, which isn't attached to a console, calls
<function>AllocConsole</function>, Wine then launches
wineconsole, and attaches the current program to this
console. In this mode, the USER32 mode is always
selected as Wine cannot tell the current state of the
Unix console.
</para>
</listitem>
</itemizedlist>
</para>
<para>
Please also note, that starting a child process with the
<constant>CREATE_NEW_CONSOLE</constant> flag, will end-up
calling <function>AllocConsole</function> in the child
process, hence creating a wineconsole with the USER32 backend.
</para>
</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:
-->

View File

@ -1,142 +0,0 @@
<chapter id="cvs-regression">
<title>How to do regression testing using CVS</title>
<para>
A problem that can happen sometimes is 'it used to work
before, now it doesn't anymore...'. Here is a step by step
procedure to try to pinpoint when the problem occurred. This is
<emphasis>NOT</emphasis> for casual users.
</para>
<orderedlist>
<listitem>
<para>
Get the <quote>full CVS</quote> archive from winehq. This archive is
the CVS tree but with the tags controlling the versioning
system. It's a big file (> 40 meg) with a name like
full-cvs-&lt;last update date> (it's more than 100mb
when uncompressed, you can't very well do this with
small, old computers or slow Internet connections).
</para>
</listitem>
<listitem>
<para>
untar it into a repository directory:
<screen>
cd /home/gerard
tar -zxf full-cvs-2003-08-18.tar.gz
mv wine repository
</screen>
</para>
</listitem>
<listitem>
<para>
extract a new destination directory. This directory must
not be in a subdirectory of the repository else
<command>cvs</command> will think it's part of the
repository and deny you an extraction in the repository:
<screen>
cd /home/gerard
mv wine wine_current (-> this protects your current wine sandbox, if any)
export CVSROOT=/home/gerard/repository
cvs -d $CVSROOT checkout wine
</screen>
</para>
<para>
Note that it's not possible to do a checkout at a given
date; you always do the checkout for the last date where
the full-cvs-xxx snapshot was generated.
</para>
<para>
Note also that it is possible to do all this with a direct
CVS connection, of course. The full CVS file method is less
painful for the WineHQ CVS server and probably a bit faster
if you don't have a very good net connection.
</para>
</listitem>
<listitem>
<para>
you will have now in the <filename>~/wine</filename>
directory an image of the CVS tree, on the client side.
Now update this image to the date you want:
<screen>
cd /home/gerard/wine
cvs update -PAd -D "2004-08-23 CDT"
</screen>
</para>
<para>
The date format is <literal>YYYY-MM-DD HH:MM:SS</literal>.
Using the CST date format ensure that you will be able to
extract patches in a way that will be compatible with the
wine-cvs archive
<ulink url="http://www.winehq.org/hypermail/wine-cvs">
http://www.winehq.org/hypermail/wine-cvs</ulink>
</para>
<para>
Many messages will inform you that more recent files have
been deleted to set back the client cvs tree to the date
you asked, for example:
<screen>
cvs update: tsx11/ts_xf86dga2.c is no longer in the repository
</screen>
</para>
<para>
<command>cvs update</command> is not limited to upgrade to
a <emphasis>newer</emphasis> version as I have believed for
far too long :-(
</para>
</listitem>
<listitem>
<para>
Now proceed as for a normal update:
</para>
<screen>
./configure
make depend && make
</screen>
<para>
If any non-programmer reads this, the fastest method to get
at the point where the problem occurred is to use a binary
search, that is, if the problem occurred in 1999, start at
mid-year, then is the problem is already here, back to 1st
April, if not, to 1st October, and so on.
</para>
<para>
If you have lot of hard disk free space (a full compile currently
takes 400 Mb), copy the oldest known working version before
updating it, it will save time if you need to go back. (it's
better to <command>make distclean</command> before going back in
time, so you have to make everything if you don't backup the older
version)
</para>
<para>
When you have found the day where the problem happened, continue
the search using the wine-cvs archive (sorted by date) and a
more precise cvs update including hour, minute, second :
<screen>
cvs update -PAd -D "2004-08-23 15:17:25 CDT"
</screen>
This will allow you to find easily the exact patch that did it.
</para>
</listitem>
<listitem>
<para>
If you find the patch that is the cause of the problem, you have
almost won; report about it to
<ulink url="http://bugs.winehq.org/">Wine Bugzilla</ulink>
or subscribe to wine-devel and post it there. There is a chance
that the author
will jump in to suggest a fix; or there is always the possibility
to look hard at the patch until it is coerced to reveal where is
the bug :-)
</para>
</listitem>
</orderedlist>
</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:
-->

View File

@ -1,66 +0,0 @@
<chapter id="i18n">
<title>Internationalization</title>
<sect1 id="adding-languages">
<title>Adding New Languages</title>
<para>
This file documents the necessary procedure for adding a new
language to the list of languages that Wine can display system
menus and forms in. Adding new translations is not hard as
it requires no programming knowledge or special skills.
</para>
<para>
Language dependent resources reside in files
named <filename>somefile_Xx.rc</filename> or
<filename>Xx.rc</filename>, where <literal>Xx</literal>
is your language abbreviation (look for it in
<filename>include/winnls.h</filename>). These are included
in a master file named <filename>somefile.rc</filename> or
<filename>rsrc.rc</filename>, located in the same
directory as the language files.
</para>
<para>
To add a new language to one of these resources you
need to make a copy of the English resource (located
in the <filename>somefile_En.rc</filename> file) over to
your <filename>somefile_Xx.rc</filename> file, include this
file in the master <filename>somefile.rc</filename> file,
and edit the new file to translate the English text.
You may also need to rearrange some of the controls
to better fit the newly translated strings. Test your changes
to make sure they properly layout on the screen.
</para>
<para>
In menus, the character "&amp;" means that the next
character will be highlighted and that pressing that
letter will select the item. You should place these
"&amp;" characters suitably for your language, not just
copy the positions from English. In particular,
items within one menu should have different highlighted
letters.
</para>
<para>
To get a list of the files that need translating,
run the following command in the root of your Wine tree:
<command>find -name "*En.rc"</command>.
</para>
<para>
When adding a new language, also make sure the parameters
defined in <filename>./dlls/kernel/nls/*.nls</filename>
fit your local habits and language.
</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:
-->

View File

@ -1,608 +0,0 @@
<chapter id="implementation">
<title>Low-level Implementation</title>
<para>Details of Wine's Low-level Implementation...</para>
<sect1 id="config-keyboard">
<title>Keyboard</title>
<para>
Wine now needs to know about your keyboard layout. This
requirement comes from a need from many apps to have the
correct scancodes available, since they read these directly,
instead of just taking the characters returned by the X
server. This means that Wine now needs to have a mapping from
X keys to the scancodes these programs expect.
</para>
<para>
On startup, Wine will try to recognize the active X layout by
seeing if it matches any of the defined tables. If it does,
everything is alright. If not, you need to define it.
</para>
<para>
To do this, open the file
<filename>dlls/x11drv/keyboard.c</filename> and take a look
at the existing tables. Make a backup copy of it, especially
if you don't use CVS.
</para>
<para>
What you really would need to do, is find out which scancode
each key needs to generate. Find it in the
<function>main_key_scan</function> table, which looks like
this:
</para>
<programlisting>
static const int main_key_scan[MAIN_LEN] =
{
/* this is my (102-key) keyboard layout, sorry if it doesn't quite match yours */
0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
0x56 /* the 102nd key (actually to the right of l-shift) */
};
</programlisting>
<para>
Next, assign each scancode the characters imprinted on the
keycaps. This was done (sort of) for the US 101-key keyboard,
which you can find near the top in
<filename>keyboard.c</filename>. It also shows that if there
is no 102nd key, you can skip that.
</para>
<para>
However, for most international 102-key keyboards, we have
done it easy for you. The scancode layout for these already
pretty much matches the physical layout in the
<function>main_key_scan</function>, so all you need to do is
to go through all the keys that generate characters on your
main keyboard (except spacebar), and stuff those into an
appropriate table. The only exception is that the 102nd key,
which is usually to the left of the first key of the last line
(usually <keycap>Z</keycap>), must be placed on a separate
line after the last line.
</para>
<para>
For example, my Norwegian keyboard looks like this
</para>
<screen>
§ ! " # ¤ % & / ( ) = ? ` Back-
| 1 2@ 3£ 4$ 5 6 7{ 8[ 9] 0} + \´ space
Tab Q W E R T Y U I O P Å ^
¨~
Enter
Caps A S D F G H J K L Ø Æ *
Lock '
Sh- > Z X C V B N M ; : _ Shift
ift &lt; , . -
Ctrl Alt Spacebar AltGr Ctrl
</screen>
<para>
Note the 102nd key, which is the <keycap>&lt;></keycap> key, to
the left of <keycap>Z</keycap>. The character to the right of
the main character is the character generated by
<keycap>AltGr</keycap>.
</para>
<para>
This keyboard is defined as follows:
</para>
<programlisting>
static const char main_key_NO[MAIN_LEN][4] =
{
"|§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","\\´",
"qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
"aA","sS","dD","fF","gG","hH","jJ","kK","lL","øØ","æÆ","'*",
"zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
"&lt;>"
};
</programlisting>
<para>
Except that " and \ needs to be quoted with a backslash, and
that the 102nd key is on a separate line, it's pretty
straightforward.
</para>
<para>
After you have written such a table, you need to add it to the
<function>main_key_tab[]</function> layout index table. This
will look like this:
</para>
<programlisting>
static struct {
WORD lang, ansi_codepage, oem_codepage;
const char (*key)[MAIN_LEN][4];
} main_key_tab[]={
...
...
{MAKELANGID(LANG_NORWEGIAN,SUBLANG_DEFAULT), 1252, 865, &amp;main_key_NO},
...
</programlisting>
<para>
After you have added your table, recompile Wine and test that
it works. If it fails to detect your table, try running
</para>
<screen>
WINEDEBUG=+key,+keyboard wine > key.log 2>&1
</screen>
<para>
and look in the resulting <filename>key.log</filename> file to
find the error messages it gives for your layout.
</para>
<para>
Note that the <constant>LANG_*</constant> and
<constant>SUBLANG_*</constant> definitions are in
<filename>include/winnls.h</filename>, which you might need to
know to find out which numbers your language is assigned, and
find it in the WINEDEBUG output. The numbers will be
<literal>(SUBLANG * 0x400 + LANG)</literal>, so, for example
the combination <literal>LANG_NORWEGIAN (0x14)</literal> and
<literal>SUBLANG_DEFAULT (0x1)</literal> will be (in hex)
<literal>14 + 1*400 = 414</literal>, so since I'm Norwegian, I
could look for <literal>0414</literal> in the WINEDEBUG output
to find out why my keyboard won't detect.
</para>
<para>
Once it works, submit it to the Wine project. If you use CVS,
you will just have to do
</para>
<screen>
cvs -z3 diff -u dlls/x11drv/keyboard.c > layout.diff
</screen>
<para>
from your main Wine directory, then submit
<filename>layout.diff</filename> to
<email>wine-patches@winehq.org</email> along with a brief note
of what it is.
</para>
<para>
If you don't use CVS, you need to do
</para>
<screen>
diff -u the_backup_file_you_made dlls/x11drv/keyboard.c > layout.diff
</screen>
<para>
and submit it as explained above.
</para>
<para>
If you did it right, it will be included in the next Wine
release, and all the troublesome programs (especially
remote-control programs) and games that use scancodes will
be happily using your keyboard layout, and you won't get those
annoying fixme messages either.
</para>
</sect1>
<sect1 id="undoc-func">
<title>Undocumented APIs</title>
<para>
Some background: On the i386 class of machines, stack entries are
usually dword (4 bytes) in size, little-endian. The stack grows
downward in memory. The stack pointer, maintained in the
<literal>esp</literal> register, points to the last valid entry;
thus, the operation of pushing a value onto the stack involves
decrementing <literal>esp</literal> and then moving the value into
the memory pointed to by <literal>esp</literal>
(i.e., <literal>push p</literal> in assembly resembles
<literal>*(--esp) = p;</literal> in C). Removing (popping)
values off the stack is the reverse (i.e., <literal>pop p</literal>
corresponds to <literal>p = *(esp++);</literal> in C).
</para>
<para>
In the <literal>stdcall</literal> calling convention, arguments are
pushed onto the stack right-to-left. For example, the C call
<function>myfunction(40, 20, 70, 30);</function> is expressed in
Intel assembly as:
<screen>
push 30
push 70
push 20
push 40
call myfunction
</screen>
The called function is responsible for removing the arguments
off the stack. Thus, before the call to myfunction, the
stack would look like:
<screen>
[local variable or temporary]
[local variable or temporary]
30
70
20
esp -> 40
</screen>
After the call returns, it should look like:
<screen>
[local variable or temporary]
esp -> [local variable or temporary]
</screen>
</para>
<para>
To restore the stack to this state, the called function must know how
many arguments to remove (which is the number of arguments it takes).
This is a problem if the function is undocumented.
</para>
<para>
One way to attempt to document the number of arguments each function
takes is to create a wrapper around that function that detects the
stack offset. Essentially, each wrapper assumes that the function will
take a large number of arguments. The wrapper copies each of these
arguments into its stack, calls the actual function, and then calculates
the number of arguments by checking esp before and after the call.
</para>
<para>
The main problem with this scheme is that the function must actually
be called from another program. Many of these functions are seldom
used. An attempt was made to aggressively query each function in a
given library (<filename>ntdll.dll</filename>) by passing 64 arguments,
all 0, to each function. Unfortunately, Windows NT quickly goes to a
blue screen of death, even if the program is run from a
non-administrator account.
</para>
<para>
Another method that has been much more successful is to attempt to
figure out how many arguments each function is removing from the
stack. This instruction, <literal>ret hhll</literal> (where
<symbol>hhll</symbol> is the number of bytes to remove, i.e. the
number of arguments times 4), contains the bytes
<literal>0xc2 ll hh</literal> in memory. It is a reasonable
assumption that few, if any, functions take more than 16 arguments;
therefore, simply searching for
<literal>hh == 0 && ll &lt; 0x40</literal> starting from the
address of a function yields the correct number of arguments most
of the time.
</para>
<para>
Of course, this is not without errors. <literal>ret 00ll</literal>
is not the only instruction that can have the byte sequence
<literal>0xc2 ll 0x0</literal>; for example,
<literal>push 0x000040c2</literal> has the byte sequence
<literal>0x68 0xc2 0x40 0x0 0x0</literal>, which matches
the above. Properly, the utility should look for this sequence
only on an instruction boundary; unfortunately, finding
instruction boundaries on an i386 requires implementing a full
disassembler -- quite a daunting task. Besides, the probability
of having such a byte sequence that is not the actual return
instruction is fairly low.
</para>
<para>
Much more troublesome is the non-linear flow of a function. For
example, consider the following two functions:
<screen>
somefunction1:
jmp somefunction1_impl
somefunction2:
ret 0004
somefunction1_impl:
ret 0008
</screen>
In this case, we would incorrectly detect both
<function>somefunction1</function> and
<function>somefunction2</function> as taking only a single
argument, whereas <function>somefunction1</function> really
takes two arguments.
</para>
<para>
With these limitations in mind, it is possible to implement more stubs
in Wine and, eventually, the functions themselves.
</para>
</sect1>
<sect1 id="accel-impl">
<title>Accelerators</title>
<para>
There are <emphasis>three</emphasis> differently sized
accelerator structures exposed to the user:
</para>
<orderedlist>
<listitem>
<para>
Accelerators in NE resources. This is also the internal
layout of the global handle <type>HACCEL</type> (16 and
32) in Windows 95 and Wine. Exposed to the user as Win16
global handles <type>HACCEL16</type> and
<type>HACCEL32</type> by the Win16/Win32 API.
These are 5 bytes long, with no padding:
<programlisting>
BYTE fVirt;
WORD key;
WORD cmd;
</programlisting>
</para>
</listitem>
<listitem>
<para>
Accelerators in PE resources. They are exposed to the user
only by direct accessing PE resources.
These have a size of 8 bytes:
</para>
<programlisting>
BYTE fVirt;
BYTE pad0;
WORD key;
WORD cmd;
WORD pad1;
</programlisting>
</listitem>
<listitem>
<para>
Accelerators in the Win32 API. These are exposed to the
user by the <function>CopyAcceleratorTable</function>
and <function>CreateAcceleratorTable</function> functions
in the Win32 API.
These have a size of 6 bytes:
</para>
<programlisting>
BYTE fVirt;
BYTE pad0;
WORD key;
WORD cmd;
</programlisting>
</listitem>
</orderedlist>
<para>
Why two types of accelerators in the Win32 API? We can only
guess, but my best bet is that the Win32 resource compiler
can/does not handle struct packing. Win32 <type>ACCEL</type>
is defined using <function>#pragma(2)</function> for the
compiler but without any packing for RC, so it will assume
<function>#pragma(4)</function>.
</para>
</sect1>
<sect1 id="hardware-trace">
<title>Doing A Hardware Trace</title>
<para>
The primary reason to do this is to reverse engineer a
hardware device for which you don't have documentation, but
can get to work under Wine.
</para>
<para>
This lot is aimed at parallel port devices, and in particular
parallel port scanners which are now so cheap they are
virtually being given away. The problem is that few
manufactures will release any programming information which
prevents drivers being written for Sane, and the traditional
technique of using DOSemu to produce the traces does not work
as the scanners invariably only have drivers for Windows.
</para>
<para>
Presuming that you have compiled and installed wine the first
thing to do is is to enable direct hardware access to your
parallel port. To do this edit <filename>config</filename>
(usually in <filename>~/.wine/</filename>) and in the
ports section add the following two lines
</para>
<programlisting>
read=0x378,0x379,0x37a,0x37c,0x77a
write=0x378,x379,0x37a,0x37c,0x77a
</programlisting>
<para>
This adds the necessary access required for SPP/PS2/EPP/ECP
parallel port on LPT1. You will need to adjust these number
accordingly if your parallel port is on LPT2 or LPT0.
</para>
<para>
When starting wine use the following command line, where
<literal>XXXX</literal> is the program you need to run in
order to access your scanner, and <literal>YYYY</literal> is
the file your trace will be stored in:
</para>
<programlisting>
WINEDEBUG=+io wine XXXX 2&gt; &gt;(sed 's/^[^:]*:io:[^ ]* //' &gt; YYYY)
</programlisting>
<para>
You will need large amounts of hard disk space (read hundreds
of megabytes if you do a full page scan), and for reasonable
performance a really fast processor and lots of RAM.
</para>
<para>
You will need to postprocess the output into a more manageable
format, using the <command>shrink</command> program. First
you need to compile the source (which is located at the end of
this section):
<programlisting>
cc shrink.c -o shrink
</programlisting>
</para>
<para>
Use the <command>shrink</command> program to reduce the
physical size of the raw log as follows:
</para>
<programlisting>
cat log | shrink &gt; log2
</programlisting>
<para>
The trace has the basic form of
</para>
<programlisting>
XXXX &gt; YY @ ZZZZ:ZZZZ
</programlisting>
<para>
where <literal>XXXX</literal> is the port in hexadecimal being
accessed, <literal>YY</literal> is the data written (or read)
from the port, and <literal>ZZZZ:ZZZZ</literal> is the address
in memory of the instruction that accessed the port. The
direction of the arrow indicates whether the data was written
or read from the port.
</para>
<programlisting>
&gt; data was written to the port
&lt; data was read from the port
</programlisting>
<para>
My basic tip for interpreting these logs is to pay close
attention to the addresses of the IO instructions. Their
grouping and sometimes proximity should reveal the presence of
subroutines in the driver. By studying the different versions
you should be able to work them out. For example consider the
following section of trace from my UMAX Astra 600P
</para>
<programlisting>
0x378 &gt; 55 @ 0297:01ec
0x37a &gt; 05 @ 0297:01f5
0x379 &lt; 8f @ 0297:01fa
0x37a &gt; 04 @ 0297:0211
0x378 &gt; aa @ 0297:01ec
0x37a &gt; 05 @ 0297:01f5
0x379 &lt; 8f @ 0297:01fa
0x37a &gt; 04 @ 0297:0211
0x378 &gt; 00 @ 0297:01ec
0x37a &gt; 05 @ 0297:01f5
0x379 &lt; 8f @ 0297:01fa
0x37a &gt; 04 @ 0297:0211
0x378 &gt; 00 @ 0297:01ec
0x37a &gt; 05 @ 0297:01f5
0x379 &lt; 8f @ 0297:01fa
0x37a &gt; 04 @ 0297:0211
0x378 &gt; 00 @ 0297:01ec
0x37a &gt; 05 @ 0297:01f5
0x379 &lt; 8f @ 0297:01fa
0x37a &gt; 04 @ 0297:0211
0x378 &gt; 00 @ 0297:01ec
0x37a &gt; 05 @ 0297:01f5
0x379 &lt; 8f @ 0297:01fa
0x37a &gt; 04 @ 0297:0211
</programlisting>
<para>
As you can see there is a repeating structure starting at
address <literal>0297:01ec</literal> that consists of four io
accesses on the parallel port. Looking at it the first io
access writes a changing byte to the data port the second
always writes the byte <literal>0x05</literal> to the control
port, then a value which always seems to
<literal>0x8f</literal> is read from the status port at which
point a byte <literal>0x04</literal> is written to the control
port. By studying this and other sections of the trace we can
write a C routine that emulates this, shown below with some
macros to make reading/writing on the parallel port easier to
read.
</para>
<programlisting>
#define r_dtr(x) inb(x)
#define r_str(x) inb(x+1)
#define r_ctr(x) inb(x+2)
#define w_dtr(x,y) outb(y, x)
#define w_str(x,y) outb(y, x+1)
#define w_ctr(x,y) outb(y, x+2)
/* Seems to be sending a command byte to the scanner */
int udpp_put(int udpp_base, unsigned char command)
{
int loop, value;
w_dtr(udpp_base, command);
w_ctr(udpp_base, 0x05);
for (loop=0; loop &lt; 10; loop++)
if ((value = r_str(udpp_base)) & 0x80)
{
w_ctr(udpp_base, 0x04);
return value & 0xf8;
}
return (value & 0xf8) | 0x01;
}
</programlisting>
<para>
For the UMAX Astra 600P only seven such routines exist (well
14 really, seven for SPP and seven for EPP). Whether you
choose to disassemble the driver at this point to verify the
routines is your own choice. If you do, the address from the
trace should help in locating them in the disassembly.
</para>
<para>
You will probably then find it useful to write a script/perl/C
program to analyse the logfile and decode them futher as this
can reveal higher level grouping of the low level routines.
For example from the logs from my UMAX Astra 600P when decoded
further reveal (this is a small snippet)
</para>
<programlisting>
start:
put: 55 8f
put: aa 8f
put: 00 8f
put: 00 8f
put: 00 8f
put: c2 8f
wait: ff
get: af,87
wait: ff
get: af,87
end: cc
start:
put: 55 8f
put: aa 8f
put: 00 8f
put: 03 8f
put: 05 8f
put: 84 8f
wait: ff
</programlisting>
<para>
From this it is easy to see that <varname>put</varname>
routine is often grouped together in five successive calls
sending information to the scanner. Once these are understood
it should be possible to process the logs further to show the
higher level routines in an easy to see format. Once the
highest level format that you can derive from this process is
understood, you then need to produce a series of scans varying
only one parameter between them, so you can discover how to
set the various parameters for the scanner.
</para>
<para>
The following is the <filename>shrink.c</filename> program:
<programlisting>
/* Copyright David Campbell &lt;campbell@torque.net&gt; */
#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
int main (void)
{
char buff[256], lastline[256] = "";
int count = 0;
while (!feof (stdin))
{
fgets (buff, sizeof (buff), stdin);
if (strcmp (buff, lastline))
{
if (count &gt; 1)
printf ("# Last line repeated %i times #\n", count);
printf ("%s", buff);
strcpy (lastline, buff);
count = 1;
}
else count++;
}
return 0;
}
</programlisting>
</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:
-->

View File

@ -1,219 +0,0 @@
<chapter id="porting">
<title>Porting Wine to new Platforms</title>
<para>
This document provides a few tips on porting Wine to your
favorite (UNIX-based) operating system.
</para>
<sect1 id="wine-porting">
<title>Porting Wine to new Platforms</title>
<sect2>
<title>Why <symbol>#ifdef MyOS</symbol> is probably a mistake.</title>
<para>
Operating systems change. Maybe yours doesn't have the
<filename>foo.h</filename> header, but maybe a future
version will have it. If you want to <symbol>#include
&lt;foo.h&gt;</symbol>, it doesn't matter what operating
system you are using; it only matters whether
<filename>foo.h</filename> is there.
</para>
<para>
Furthermore, operating systems change names or "fork" into
several ones. An <symbol>#ifdef MyOs</symbol> will break
over time.
</para>
<para>
If you use the feature of <command>autoconf</command> -- the
Gnu auto-configuration utility -- wisely, you will help
future porters automatically because your changes will test
for <emphasis>features</emphasis>, not names of operating
systems. A feature can be many things:
</para>
<itemizedlist>
<listitem>
<para>
existence of a header file
</para>
</listitem>
<listitem>
<para>
existence of a library function
</para>
</listitem>
<listitem>
<para>
existence of libraries
</para>
</listitem>
<listitem>
<para>
bugs in header files, library functions, the compiler, ...
</para>
</listitem>
</itemizedlist>
<para>
You will need Gnu Autoconf, which you can get from your
friendly Gnu mirror. This program takes Wine's
<filename>configure.ac</filename> file and produces a
<filename>configure</filename> shell script that users use
to configure Wine to their system.
</para>
<para>
There <emphasis>are</emphasis> exceptions to the "avoid
<symbol>#ifdef MyOS</symbol>" rule. Wine, for example, needs
the internals of the signal stack -- that cannot easily be
described in terms of features. Moreover, you can not use
<filename>autoconf</filename>'s <symbol>HAVE_*</symbol>
symbols in Wine's headers, as these may be used by Winelib
users who may not be using a <filename>configure</filename>
script.
</para>
<para>
Let's now turn to specific porting problems and how to solve
them.
</para>
</sect2>
<sect2>
<title>MyOS doesn't have the <filename>foo.h</filename> header!</title>
<para>
This first step is to make <command>autoconf</command> check
for this header. In <filename>configure.in</filename> you
add a segment like this in the section that checks for
header files (search for "header files"):
</para>
<programlisting>
AC_CHECK_HEADER(foo.h, AC_DEFINE(HAVE_FOO_H))
</programlisting>
<para>
If your operating system supports a header file with the
same contents but a different name, say
<filename>bar.h</filename>, add a check for that also.
</para>
<para>
Now you can change
</para>
<programlisting>
#include &lt;foo.h&gt;
</programlisting>
<para>
to
</para>
<programlisting>
#ifdef HAVE_FOO_H
#include &lt;foo.h&gt;
#elif defined (HAVE_BAR_H)
#include &lt;bar.h&gt;
#endif
</programlisting>
<para>
If your system doesn't have a corresponding header file even
though it has the library functions being used, you might
have to add an <symbol>#else</symbol> section to the
conditional. Avoid this if you can.
</para>
<para>
You will also need to add <symbol>#undef HAVE_FOO_H</symbol>
(etc.) to <filename>include/config.h.in</filename>
</para>
<para>
Finish up with <command>make configure</command> and
<command>./configure</command>.
</para>
</sect2>
<sect2>
<title>MyOS doesn't have the <function>bar</function> function!</title>
<para>
A typical example of this is the
<function>memmove</function> function. To solve this
problem you would add <function>memmove</function> to the
list of functions that <command>autoconf</command> checks
for. In <filename>configure.in</filename> you search for
<function>AC_CHECK_FUNCS</function> and add
<function>memmove</function>. (You will notice that someone
already did this for this particular function.)
</para>
<para>
Secondly, you will also need to add <symbol>#undef
HAVE_BAR</symbol> to
<filename>include/config.h.in</filename>
</para>
<para>
The next step depends on the nature of the missing function.
</para>
<variablelist>
<varlistentry>
<term>Case 1:</term>
<listitem>
<para>
It's easy to write a complete implementation of the
function. (<function>memmove</function> belongs to
this case.)
</para>
<para>
You add your implementation in
<filename>misc/port.c</filename> surrounded by
<symbol>#ifndef HAVE_MEMMOVE</symbol> and
<symbol>#endif</symbol>.
</para>
<para>
You might have to add a prototype for your function.
If so, <filename>include/miscemu.h</filename> might be the place. Don't
forget to protect that definition by <symbol>#ifndef
HAVE_MEMMOVE</symbol> and <symbol>#endif</symbol> also!
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Case 2:</term>
<listitem>
<para>
A general implementation is hard, but Wine is only
using a special case.
</para>
<para>
An example is the various <function>wait</function>
calls used in <function>SIGNAL_child</function> from
<filename>loader/signal.c</filename>. Here we have a
multi-branch case on features:
</para>
<programlisting>
#ifdef HAVE_THIS
...
#elif defined (HAVE_THAT)
...
#elif defined (HAVE_SOMETHING_ELSE)
...
#endif
</programlisting>
<para>
Note that this is very different from testing on
operating systems. If a new version of your operating
systems comes out and adds a new function, this code
will magically start using it.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
Finish up with <command>make configure</command> and
<command>./configure</command>.
</para>
</sect2>
</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:
-->

View File

@ -1,24 +1,20 @@
<!doctype book PUBLIC "-//OASIS//DTD DocBook V3.1//EN" [
<!entity debugger SYSTEM "debugger.sgml">
<!entity documentation SYSTEM "documentation.sgml">
<!entity patches SYSTEM "patches.sgml">
<!entity debugging SYSTEM "debugging.sgml">
<!entity otherdebug SYSTEM "winedev-otherdebug.sgml">
<!entity codingpractice SYSTEM "winedev-coding.sgml">
<!entity testing SYSTEM "testing.sgml">
<!entity i18n SYSTEM "i18n.sgml">
<!entity documentation SYSTEM "documentation.sgml">
<!entity architecture SYSTEM "architecture.sgml">
<!entity debugging SYSTEM "debugging.sgml">
<!entity kernel SYSTEM "winedev-kernel.sgml">
<!entity graphical SYSTEM "winedev-graphical.sgml">
<!entity windowing SYSTEM "winedev-windowing.sgml">
<!entity ole SYSTEM "ole.sgml">
<!entity opengl SYSTEM "opengl.sgml">
<!entity ddraw SYSTEM "ddraw.sgml">
<!entity multimedia SYSTEM "multimedia.sgml">
<!entity threading SYSTEM "threading.sgml">
<!entity address-space SYSTEM "address-space.sgml">
<!entity implementation SYSTEM "implementation.sgml">
<!entity porting SYSTEM "porting.sgml">
<!entity consoles SYSTEM "consoles.sgml">
<!entity cvs-regression SYSTEM "cvs-regression.sgml">
]>
@ -114,31 +110,23 @@
<title>Developing Wine</title>
&debugger;
&documentation;
&patches;
&debugging;
&otherdebug;
&codingpractice;
&testing;
&i18n;
&documentation;
</part>
<part id="part-two">
<title>Wine Architecture</title>
&architecture;
&debugging;
&kernel;
&graphical;
&windowing;
&ole;
&opengl;
&ddraw;
&multimedia;
&threading;
</part>
<part id="part-three">
<title>Advanced Topics</title>
&implementation;
&porting;
&consoles;
&address-space;
&cvs-regression;
</part>
</book>

View File

@ -0,0 +1,514 @@
<chapter id="codingpractice">
<title>Coding Practice</title>
<para>
This chapter describes the relevant coding practices in Wine,
that you should be aware of before doing any serious development
in Wine.
</para>
<sect1 id="patch-format">
<title>Patch Format</title>
<para>
Patches are submitted via email to the Wine patches mailing
list, <email>wine-patches@winehq.org</email>. Your patch
should include:
</para>
<itemizedlist>
<listitem>
<para>
A meaningful subject (very short description of patch)
</para>
</listitem>
<listitem>
<para>
A long (paragraph) description of what was wrong and what
is now better. (recommended)
</para>
</listitem>
<listitem>
<para>
A change log entry (short description of what was
changed).
</para>
</listitem>
<listitem>
<para>
The patch in <command>diff -u</command> format
</para>
</listitem>
</itemizedlist>
<para></para>
<para>
<command>cvs diff -u</command> works great for the common case
where a file is edited. However, if you add or remove a file
<command>cvs diff</command> will not report that correctly so
make sure you explicitly take care of this rare case.
</para>
<para>
For additions simply include them by appending the
<command>diff -u /dev/null /my/new/file</command> output of
them to any <command>cvs diff -u</command> output you may
have. Alternatively, use <command>diff -Nu olddir/
newdir/</command> in case of multiple new files to add.
</para>
<para>
For removals, clearly list the files in the description of the
patch.
</para>
<para>
Since wine is constantly changing due to development it is
strongly recommended that you use cvs for patches, if you
cannot use cvs for some reason, you can submit patches against
the latest tarball. To do this make a copy of the files that
you will be modifying and <command>diff -u</command> against
the old file. I.E.
</para>
<screen>
diff -u file.old file.c > file.txt
</screen>
</sect1>
<sect1 id="Style-notes">
<title>Some notes about style</title>
<para>
There are a few conventions that about coding style that have
been adopted over the years of development. The rational for
these <quote>rules</quote> is explained for each one.
</para>
<itemizedlist>
<listitem>
<para>
No HTML mail, since patches should be in-lined and HTML
turns the patch into garbage. Also it is considered bad
etiquette as it uglifies the message, and is not viewable
by many of the subscribers.
</para>
</listitem>
<listitem>
<para>
Only one change set per patch. Patches should address only
one bug/problem at a time. If a lot of changes need to be
made then it is preferred to break it into a series of
patches. This makes it easier to find regressions.
</para>
</listitem>
<listitem>
<para>
Tabs are not forbidden but discouraged. A tab is defined
as 8 characters and the usual amount of indentation is 4
characters.
</para>
</listitem>
<listitem>
<para>
C++ style comments are discouraged since some compilers
choke on them.
</para>
</listitem>
<listitem>
<para>
Commenting out a block of code is usually done by
enclosing it in <command>#if 0 ... #endif</command>
Statements. For example.
</para>
<screen>
/* note about reason for commenting block */
#if 0
code
code /* comments */
code
#endif
</screen>
<para>
The reason for using this method is that it does not
require that you edit comments that may be inside the
block of code.
</para>
</listitem>
<listitem>
<para>
Patches should be in-lined (if you can configure your
email client to not wrap lines), or attached as plain text
attachments so they can be read inline. This may mean some
more work for you. However it allows others to review your
patch easily and decreases the chances of it being
overlooked or forgotten.
</para>
</listitem>
<listitem>
<para>
Code is usually limited to 80 columns. This helps prevent
mailers mangling patches by line wrap. Also it generally
makes code easier to read.
</para>
</listitem>
<listitem>
<para>
If the patch fixes a bug in Bugzilla please provide a link
to the bug in the comments of the patch. This will make it
easier for the maintainers of Bugzilla.
</para>
</listitem>
</itemizedlist>
<sect2 id="Inline-Attachments-with-OE">
<title>Inline attachments with Outlook Express</title>
<para>
Outlook Express is notorious for mangling
attachments. Giving the patch a <filename>.txt</filename>
extension and attaching will solve the problem for most
mailers including Outlook. Also, there is a way to enable
Outlook Express send <filename>.diff</filename>
attachments.
</para>
<para>
You need following two things to make it work.
</para>
<orderedlist>
<listitem>
<para>
Make sure that <filename>.diff</filename> files have
\r\n line ends, because if OE detects that there is no
\r\n line endings it switches to quoted-printable format
attachments.
</para>
</listitem>
<listitem>
<para>
Using regedit add key "Content Type"
with value "text/plain" to the
<filename>.diff</filename> extension under
HKEY_CLASSES_ROOT (same as for <filename>.txt</filename>
extension). This tells OE to use
Content-Type:&nbsp;text/plain instead of
application/octet-stream.
</para>
</listitem>
</orderedlist>
<para>
Item #1 is important. After you hit "Send" button, go to
"Outbox" and using "Properties" verify the message source to
make sure that the mail has correct format. You might want
to send several test emails to yourself too.
</para>
</sect2>
<sect2 id="Alexandre-Bottom-Line">
<title>Alexandre's Bottom Line</title>
<para>
<quote>The basic rules are: no attachments, no MIME crap, no
line wrapping, a single patch per mail. Basically if I can't
do <command>"cat raw_mail | patch -p0"</command> it's in the
wrong format.</quote>
</para>
</sect2>
</sect1>
<sect1 id="patch-quality">
<title>Quality Assurance</title>
<para>
(Or, "How do I get Alexandre to apply my patch quickly so I
can build on it and it will not go stale?")
</para>
<para>
Make sure your patch applies to the current CVS head
revisions. If a bunch of patches are committed to CVS that may
affect whether your patch will apply cleanly then verify that
your patch does apply! <command>cvs update</command> is your
friend!
</para>
<para>
Save yourself some embarrassment and run your patched code
against more than just your current test example. Experience
will tell you how much effort to apply here. If there are
any conformance tests for the code you're working on, run them
and make sure they still pass after your patch is applied. Running
tests can be done by running <command>make test</command>. You may
need to run <command>make testclean</command> to undo the results
of a previous test run. See the <quote>testing</quote> guide for
more details on Wine's conformance tests.
</para>
</sect1>
<sect1 id="porting">
<title>Porting Wine to new Platforms</title>
<para>
This document provides a few tips on porting Wine to your
favorite (UNIX-based) operating system.
</para>
<sect2>
<title>
Why <symbol>#ifdef MyOS</symbol> is probably a mistake.
</title>
<para>
Operating systems change. Maybe yours doesn't have the
<filename>foo.h</filename> header, but maybe a future
version will have it. If you want to <symbol>#include
&lt;foo.h&gt;</symbol>, it doesn't matter what operating
system you are using; it only matters whether
<filename>foo.h</filename> is there.
</para>
<para>
Furthermore, operating systems change names or "fork" into
several ones. An <symbol>#ifdef MyOs</symbol> will break
over time.
</para>
<para>
If you use the feature of <command>autoconf</command> -- the
Gnu auto-configuration utility -- wisely, you will help
future porters automatically because your changes will test
for <emphasis>features</emphasis>, not names of operating
systems. A feature can be many things:
</para>
<itemizedlist>
<listitem>
<para>
existence of a header file
</para>
</listitem>
<listitem>
<para>
existence of a library function
</para>
</listitem>
<listitem>
<para>
existence of libraries
</para>
</listitem>
<listitem>
<para>
bugs in header files, library functions, the compiler, ...
</para>
</listitem>
</itemizedlist>
<para>
You will need Gnu Autoconf, which you can get from your
friendly Gnu mirror. This program takes Wine's
<filename>configure.ac</filename> file and produces a
<filename>configure</filename> shell script that users use
to configure Wine to their system.
</para>
<para>
There <emphasis>are</emphasis> exceptions to the "avoid
<symbol>#ifdef MyOS</symbol>" rule. Wine, for example, needs
the internals of the signal stack -- that cannot easily be
described in terms of features. Moreover, you can not use
<filename>autoconf</filename>'s <symbol>HAVE_*</symbol>
symbols in Wine's headers, as these may be used by Winelib
users who may not be using a <filename>configure</filename>
script.
</para>
<para>
Let's now turn to specific porting problems and how to solve
them.
</para>
</sect2>
<sect2>
<title>
MyOS doesn't have the <filename>foo.h</filename> header!
</title>
<para>
This first step is to make <command>autoconf</command> check
for this header. In <filename>configure.in</filename> you
add a segment like this in the section that checks for
header files (search for "header files"):
</para>
<programlisting>
AC_CHECK_HEADER(foo.h, AC_DEFINE(HAVE_FOO_H))
</programlisting>
<para>
If your operating system supports a header file with the
same contents but a different name, say
<filename>bar.h</filename>, add a check for that also.
</para>
<para>
Now you can change
</para>
<programlisting>
#include &lt;foo.h&gt;
</programlisting>
<para>
to
</para>
<programlisting>
#ifdef HAVE_FOO_H
#include &lt;foo.h&gt;
#elif defined (HAVE_BAR_H)
#include &lt;bar.h&gt;
#endif
</programlisting>
<para>
If your system doesn't have a corresponding header file even
though it has the library functions being used, you might
have to add an <symbol>#else</symbol> section to the
conditional. Avoid this if you can.
</para>
<para>
You will also need to add <symbol>#undef HAVE_FOO_H</symbol>
(etc.) to <filename>include/config.h.in</filename>
</para>
<para>
Finish up with <command>make configure</command> and
<command>./configure</command>.
</para>
</sect2>
<sect2>
<title>
MyOS doesn't have the <function>bar</function> function!
</title>
<para>
A typical example of this is the <function>memmove</function>
function. To solve this problem you would add
<function>memmove</function> to the list of functions that
<command>autoconf</command> checks for. In
<filename>configure.in</filename> you search for
<function>AC_CHECK_FUNCS</function> and add
<function>memmove</function>. (You will notice that someone
already did this for this particular function.)
</para>
<para>
Secondly, you will also need to add
<symbol>#undef HAVE_BAR</symbol> to
<filename>include/config.h.in</filename>
</para>
<para>
The next step depends on the nature of the missing function.
</para>
<variablelist>
<varlistentry>
<term>Case 1:</term>
<listitem>
<para>
It's easy to write a complete implementation of the
function. (<function>memmove</function> belongs to
this case.)
</para>
<para>
You add your implementation in
<filename>misc/port.c</filename> surrounded by
<symbol>#ifndef HAVE_MEMMOVE</symbol> and
<symbol>#endif</symbol>.
</para>
<para>
You might have to add a prototype for your function.
If so, <filename>include/miscemu.h</filename> might be
the place. Don't forget to protect that definition by
<symbol>#ifndef HAVE_MEMMOVE</symbol> and
<symbol>#endif</symbol> also!
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Case 2:</term>
<listitem>
<para>
A general implementation is hard, but Wine is only
using a special case.
</para>
<para>
An example is the various <function>wait</function>
calls used in <function>SIGNAL_child</function> from
<filename>loader/signal.c</filename>. Here we have a
multi-branch case on features:
</para>
<programlisting>
#ifdef HAVE_THIS
...
#elif defined (HAVE_THAT)
...
#elif defined (HAVE_SOMETHING_ELSE)
...
#endif
</programlisting>
<para>
Note that this is very different from testing on
operating systems. If a new version of your operating
systems comes out and adds a new function, this code
will magically start using it.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
Finish up with <command>make configure</command> and
<command>./configure</command>.
</para>
</sect2>
</sect1>
<sect1 id="adding-languages">
<title>Adding New Languages</title>
<para>
This file documents the necessary procedure for adding a new
language to the list of languages that Wine can display system
menus and forms in. Adding new translations is not hard as it
requires no programming knowledge or special skills.
</para>
<para>
Language dependent resources reside in files
named <filename>somefile_Xx.rc</filename> or
<filename>Xx.rc</filename>, where <literal>Xx</literal>
is your language abbreviation (look for it in
<filename>include/winnls.h</filename>). These are included
in a master file named <filename>somefile.rc</filename> or
<filename>rsrc.rc</filename>, located in the same
directory as the language files.
</para>
<para>
To add a new language to one of these resources you
need to make a copy of the English resource (located
in the <filename>somefile_En.rc</filename> file) over to
your <filename>somefile_Xx.rc</filename> file, include this
file in the master <filename>somefile.rc</filename> file,
and edit the new file to translate the English text.
You may also need to rearrange some of the controls
to better fit the newly translated strings. Test your changes
to make sure they properly layout on the screen.
</para>
<para>
In menus, the character "&amp;" means that the next
character will be highlighted and that pressing that
letter will select the item. You should place these
"&amp;" characters suitably for your language, not just
copy the positions from English. In particular,
items within one menu should have different highlighted
letters.
</para>
<para>
To get a list of the files that need translating,
run the following command in the root of your Wine tree:
<command>find -name "*En.rc"</command>.
</para>
<para>
When adding a new language, also make sure the parameters
defined in <filename>./dlls/kernel/nls/*.nls</filename>
fit your local habits and language.
</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:
-->

View File

@ -0,0 +1,40 @@
<chapter>
<title>Graphical modules</title>
<sect1>
<title>GDI Module</title>
<sect2>
<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>
</sect2>
</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:
-->

View File

@ -0,0 +1,823 @@
<chapter>
<title>Kernel modules</title>
<para>
This section cover the kernel modules. As already stated, Wine
implements the NT architecture, hence provides NTDLL for the
core kernel functions, and KERNEL32, which is the
implementation of the basis of the Win32 subsystem, on top of
NTDLL.
</para>
<sect1 id="ntdll">
<title>NTDLL</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>
<sect2>
<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>
</sect2>
<sect2>
<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>
</sect2>
<sect2>
<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>
</sect2>
<sect2>
<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>
</sect2>
<sect2 id="threading">
<title>Multi-threading in Wine</title>
<para>
This section will assume you understand the basics of
multithreading. If not there are plenty of good tutorials
available on the net to get you started.
</para>
<para>
Threading in Wine is somewhat complex due to several
factors. The first is the advanced level of multithreading
support provided by Windows - there are far more threading
related constructs available in Win32 than the Linux
equivalent (pthreads). The second is the need to be able to
map Win32 threads to native Linux threads which provides us
with benefits like having the kernel schedule them without
our intervention. While it's possible to implement threading
entirely without kernel support, doing so is not desirable
on most platforms that Wine runs on.
</para>
<sect3>
<title> Threading support in Win32 </title>
<para>
Win32 is an unusually thread friendly API. Not only is it
entirely thread safe, but it provides many different
facilities for working with threads. These range from the
basics such as starting and stopping threads, to the
extremely complex such as injecting threads into other
processes and COM inter-thread marshalling.
</para>
<para>
One of the primary challenges of writing Wine code
therefore is ensuring that all our DLLs are thread safe,
free of race conditions and so on. This isn't simple -
don't be afraid to ask if you aren't sure whether a piece
of code is thread safe or not!
</para>
<para>
Win32 provides many different ways you can make your code
thread safe however the most common are <emphasis>critical
section</emphasis> and the <emphasis>interlocked
functions</emphasis>. Critical sections are a type of
mutex designed to protect a geographic area of code. If
you don't want multiple threads running in a piece of code
at once, you can protect them with calls to
<function>EnterCriticalSection</function> and
<function>LeaveCriticalSection</function>. The first call
to <function>EnterCriticalSection</function> by a thread
will lock the section and continue without stopping. If
another thread calls it then it will block until the
original thread calls
<function>LeaveCriticalSection</function> again.
</para>
<para>
It is therefore vitally important that if you use critical
sections to make some code thread-safe, that you check
every possible codepath out of the code to ensure that any
held sections are left. Code like this:
</para>
<programlisting>
if (res != ERROR_SUCCESS) return res;
</programlisting>
<para>
is extremely suspect in a function that also contains a
call to <function>EnterCriticalSection</function>. Be
careful.
</para>
<para>
If a thread blocks while waiting for another thread to
leave a critical section, you will see an error from the
<function>RtlpWaitForCriticalSection</function> function,
along with a note of which thread is holding the
lock. This only appears after a certain timeout, normally
a few seconds. It's possible the thread holding the lock
is just being really slow which is why Wine won't
terminate the app like a non-checked build of Windows
would, but the most common cause is that for some reason a
thread forgot to call
<function>LeaveCriticalSection</function>, or died while
holding the lock (perhaps because it was in turn waiting
for another lock). This doesn't just happen in Wine code:
a deadlock while waiting for a critical section could be
due to a bug in the app triggered by a slight difference
in the emulation.
</para>
<para>
Another popular mechanism available is the use of
functions like <function>InterlockedIncrement</function>
and <function>InterlockedExchange</function>. These make
use of native CPU abilities to execute a single
instruction while ensuring any other processors on the
system cannot access memory, and allow you to do common
operations like add/remove/check a variable in thread-safe
code without holding a mutex. These are useful for
reference counting especially in free-threaded (thread
safe) COM objects.
</para>
<para>
Finally, the usage of TLS slots are also popular. TLS
stands for thread-local storage, and is a set of slots
scoped local to a thread which you can store pointers
in. Look on MSDN for the <function>TlsAlloc</function>
function to learn more about the Win32 implementation of
this. Essentially, the contents of a given slot will be
different in each thread, so you can use this to store
data that is only meaningful in the context of a single
thread. On recent versions of Linux the __thread keyword
provides a convenient interface to this functionality - a
more portable API is exposed in the pthread
library. However, these facilities is not used by Wine,
rather, we implement Win32 TLS entirely ourselves.
</para>
</sect3>
<sect3>
<title> SysLevels </title>
<para>
SysLevels are an undocumented Windows-internal
thread-safety system. They are basically critical sections
which must be taken in a particular order. The mechanism
is generic but there are always three syslevels: level 1
is the Win16 mutex, level 2 is the USER mutex and level 3
is the GDI mutex.
</para>
<para>
When entering a syslevel, the code (in
<filename>dlls/kernel/syslevel.c</filename>) will check
that a higher syslevel is not already held and produce an
error if so. This is because it's not legal to enter level
2 while holding level 3 - first, you must leave level 3.
</para>
<para>
Throughout the code you may see calls to
<function>_ConfirmSysLevel()</function> and
<function>_CheckNotSysLevel()</function>. These functions
are essentially assertions about the syslevel states and
can be used to check that the rules have not been
accidentally violated. In particular,
<function>_CheckNotSysLevel()</function> will break
(probably into the debugger) if the check fails. If this
happens the solution is to get a backtrace and find out,
by reading the source of the wine functions called along
the way, how Wine got into the invalid state.
</para>
</sect3>
<sect3>
<title> POSIX threading vs kernel threading </title>
<para>
Wine runs in one of two modes: either pthreads (posix
threading) or kthreads (kernel threading). This section
explains the differences between them. The one that is
used is automatically selected on startup by a small test
program which then execs the correct binary, either
wine-kthread or wine-pthread. On NPTL-enabled systems
pthreads will be used, and on older non-NPTL systems
kthreads is selected.
</para>
<para>
Let's start with a bit of history. Back in the dark ages
when Wines threading support was first implemented a
problem was faced - Windows had much more capable
threading APIs than Linux did. This presented a problem -
Wine works either by reimplementing an API entirely or by
mapping it onto the underlying systems equivalent. How
could Win32 threading be implemented using a library which
did not have all the neeed features? The answer, of
course, was that it couldn't be.
</para>
<para>
On Linux the pthreads interface is used to start, stop and
control threads. The pthreads library in turn is based on
top of so-called "kernel threads" which are created using
the <function>clone(2)</function> syscall. Pthreads
provides a nicer (more portable) interface to this
functionality and also provides APIs for controlling
mutexes. There is a <ulink
url="http://www.llnl.gov/computing/tutorials/pthreads/">
good tutorial on pthreads </ulink> available if you want
to learn more.
</para>
<para>
As pthreads did not provide the necessary semantics to
implement Win32 threading, the decision was made to
implement Win32 threading on top of the underlying kernel
threads by using syscalls like <function>clone</function>
directly. This provided maximum flexibility and allowed a
correct implementation but caused some bad side
effects. Most notably, all the userland Linux APIs assumed
that the user was utilising the pthreads library. Some
only enabled thread safety when they detected that
pthreads was in use - this is true of glibc, for
instance. Worse, pthreads and pure kernel threads had
strange interactions when run in the same process yet some
libraries used by Wine used pthreads internally. Throw in
source code porting using WineLib - where you have both
UNIX and Win32 code in the same process - and chaos was
the result.
</para>
<para>
The solution was simple yet ingenius: Wine would provide
its own implementation of the pthread library
<emphasis>inside</emphasis> its own binary. Due to the
semantics of ELF symbol scoping, this would cause Wines
own implementations to override any implementation loaded
later on (like the real libpthread.so). Therefore, any
calls to the pthread APIs in external libraries would be
linked to Wines instead of the systems pthreads library,
and Wine implemented pthreads by using the standard
Windows threading APIs it in turn implemented itself.
</para>
<para>
As a result, libraries that only became thread-safe in the
presence of a loaded pthreads implementation would now do
so, and any external code that used pthreads would
actually end up creating Win32 threads that Wine was aware
of and controlled. This worked quite nicely for a long
time, even though it required doing some extremely
un-kosher things like overriding internal libc structures
and functions. That is, it worked until NPTL was developed
at which point the underlying thread implementation on
Linux changed dramatically.
</para>
<para>
The fake pthread implementation can be found in
<filename>loader/kthread.c</filename>, which is used to
produce to wine-kthread binary. In contrast,
loader/pthread.c produces the wine-pthread binary which is
used on newer NPTL systems.
</para>
<para>
NPTL is a new threading subsystem for Linux that hugely
improves its performance and flexibility. By allowing
threads to become much more scalable and adding new
pthread APIs, NPTL made Linux competitive with Windows in
the multi-threaded world. Unfortunately it also broke many
assumptions made by Wine (as well as other applications
such as the Sun JVM and RealPlayer) in the process.
</para>
<para>
There was, however, some good news. NPTL made Linux
threading powerful enough that Win32 threads could now be
implemented on top of pthreads like any other normal
application. There would no longer be problems with mixing
win32-kthreads and pthreads created by external libraries,
and no need to override glibc internals. As you can see
from the relative sizes of the
<filename>loader/kthread.c</filename> and
<filename>loader/pthread.c</filename> files, the
difference in code complexity is considerable. NPTL also
made several other semantic changes to things such as
signal delivery so changes were required in many different
places in Wine.
</para>
<para>
On non-Linux systems the threading interface is typically
not powerful enough to replicate the semantics Win32
applications expect and so kthreads with the pthread
overrides are used.
</para>
</sect3>
<sect3>
<title> The Win32 thread environment </title>
<para>
All Win32 code, whether from a native EXE/DLL or in Wine
itself, expects certain constructs to be present in its
environment. This section explores what those constructs
are and how Wine sets them up. The lack of this
environment is one thing that makes it hard to use Wine
code directly from standard Linux applications - in order
to interact with Win32 code a thread must first be
"adopted" by Wine.
</para>
<para>
The first thing Win32 code requires is the
<emphasis>TEB</emphasis> or "Thread Environment
Block". This is an internal (undocumented) Windows
structure associated with every thread which stores a
variety of things such as TLS slots, a pointer to the
threads message queue, the last error code and so on. You
can see the definition of the TEB in
<filename>include/thread.h</filename>, or at least what we
know of it so far. Being internal and subject to change,
the layout of the TEB has had to be reverse engineered
from scratch.
</para>
<para>
A pointer to the TEB is stored in the %fs register and can
be accessed using <function>NtCurrentTeb()</function> from
within Wine code. %fs actually stores a selector, and
setting it therefore requires modifying the processes
local descriptor table (LDT) - the code to do this is in
<filename>lib/wine/ldt.c</filename>.
</para>
<para>
The TEB is required by nearly all Win32 code run in the
Wine environment, as any wineserver RPC will use it, which
in turn implies that any code which could possibly block
(for instance by using a critical section) needs it. The
TEB also holds the SEH exception handler chain as the
first element, so if when disassembling you see code like
this:
</para>
<programlisting> movl %esp, %fs:0 </programlisting>
<para>
... then you are seeing the program set up an SEH handler
frame. All threads must have at least one SEH entry, which
normally points to the backstop handler which is
ultimately responsible for popping up the all-too-familiar
"This program has performed an illegal operation and will
be terminated" message. On Wine we just drop straight into
the debugger. A full description of SEH is out of the
scope of this section, however there are some good
articles in MSJ if you are interested.
</para>
<para>
All Win32-aware threads must have a wineserver
connection. Many different APIs require the ability to
communicate with the wineserver. In turn, the wineserver
must be aware of Win32 threads in order to be able to
accurately report information to other parts of the program
and do things like route inter-thread messages, dispatch
APCs (asynchronous procedure calls) and so on. Therefore a
part of thread initialization is initializing the thread
serverside. The result is not only correct information in
the server, but a set of file descriptors the thread can use
to communicate with the server - the request fd, reply fd
and wait fd (used for blocking).
</para>
</sect3>
</sect2>
</sect1>
<sect1>
<title>KERNEL Module</title>
<para>
FIXME: Needs some content...
</para>
<sect2 id="consoles">
<title>Consoles in Wine</title>
<para>
As described in the Wine User Guide's CUI section, Wine
manipulates three kinds of "consoles" in order to support
properly the Win32 CUI API.
</para>
<para>
The following table describes the main implementation
differences between the three approaches.
<table>
<title>Function consoles implementation comparison</title>
<tgroup cols="4" align="left">
<thead>
<row>
<entry>Function</entry>
<entry>Bare streams</entry>
<entry>Wineconsole &amp; user backend</entry>
<entry>Wineconsole &amp; curses backend</entry>
</row>
</thead>
<tbody>
<row>
<entry>
Console as a Win32 Object (and associated
handles)
</entry>
<entry>
No specific Win32 object is used in this
case. The handles manipulated for the standard
Win32 streams are in fact "bare handles" to
their corresponding Unix streams. The mode
manipulation functions
(<function>GetConsoleMode</function> /
<function>SetConsoleMode</function>) are not
supported.
</entry>
<entry>
Implemented in server, and a specific Winelib
program (wineconsole) is in charge of the
rendering and user input. The mode manipulation
functions behave as expected.
</entry>
<entry>
Implemented in server, and a specific Winelib
program (wineconsole) is in charge of the
rendering and user input. The mode manipulation
functions behave as expected.
</entry>
</row>
<row>
<entry>
Inheritance (including handling in
<function>CreateProcess</function> of
<constant>CREATE_DETACHED</constant>,
<constant>CREATE_NEW_CONSOLE</constant> flags).
</entry>
<entry>
Not supported. Every process child of a process
will inherit the Unix streams, so will also
inherit the Win32 standard streams.
</entry>
<entry>
Fully supported (each new console creation will
be handled by the creation of a new USER32
window)
</entry>
<entry>
Fully supported, except for the creation of a
new console, which will be rendered on the same
Unix terminal as the previous one, leading to
unpredictable results.
</entry>
</row>
<row>
<entry>
<function>ReadFile</function> /
<function>WriteFile</function>
operations
</entry>
<entry>Fully supported</entry>
<entry>Fully supported</entry>
<entry>Fully supported</entry>
</row>
<row>
<entry>
Screen-buffer manipulation (creation, deletion,
resizing...)
</entry>
<entry>Not supported</entry>
<entry>Fully supported</entry>
<entry>
Partly supported (this won't work too well as we
don't control (so far) the size of underlying
Unix terminal
</entry>
</row>
<row>
<entry>
APIs for reading/writing screen-buffer content,
cursor position
</entry>
<entry>Not supported</entry>
<entry>Fully supported</entry>
<entry>Fully supported</entry>
</row>
<row>
<entry>
APIs for manipulating the rendering window size
</entry>
<entry>Not supported</entry>
<entry>Fully supported</entry>
<entry>
Partly supported (this won't work too well as we
don't control (so far) the size of underlying
Unix terminal
</entry>
</row>
<row>
<entry>
Signaling (in particular, Ctrl-C handling)
</entry>
<entry>
Nothing is done, which means that Ctrl-C will
generate (as usual) a
<constant>SIGINT</constant> which will terminate
the program.
</entry>
<entry>
Partly supported (Ctrl-C behaves as expected,
however the other Win32 CUI signaling isn't
properly implemented).
</entry>
<entry>
Partly supported (Ctrl-C behaves as expected,
however the other Win32 CUI signaling isn't
properly implemented).
</entry>
</row>
</tbody>
</tgroup>
</table>
</para>
<para>
The Win32 objects behind a console can be created in
several occasions:
<itemizedlist>
<listitem>
<para>
When the program is started from wineconsole, a new
console object is created and will be used
(inherited) by the process launched from
wineconsole.
</para>
</listitem>
<listitem>
<para>
When a program, which isn't attached to a console,
calls <function>AllocConsole</function>, Wine then
launches wineconsole, and attaches the current
program to this console. In this mode, the USER32
mode is always selected as Wine cannot tell the
current state of the Unix console.
</para>
</listitem>
</itemizedlist>
</para>
<para>
Please also note, that starting a child process with the
<constant>CREATE_NEW_CONSOLE</constant> flag, will end-up
calling <function>AllocConsole</function> in the child
process, hence creating a wineconsole with the USER32
backend.
</para>
</sect2>
</sect1>
<sect1 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
<function>main()</function> 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>
<sect2>
<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>
</sect2>
<sect2>
<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>
</sect2>
</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:
-->

View File

@ -0,0 +1,508 @@
<chapter id="otherdebug">
<title>Other debugging techniques</title>
<sect1 id="hardware-trace">
<title>Doing A Hardware Trace</title>
<para>
The primary reason to do this is to reverse engineer a
hardware device for which you don't have documentation, but
can get to work under Wine.
</para>
<para>
This lot is aimed at parallel port devices, and in particular
parallel port scanners which are now so cheap they are
virtually being given away. The problem is that few
manufactures will release any programming information which
prevents drivers being written for Sane, and the traditional
technique of using DOSemu to produce the traces does not work
as the scanners invariably only have drivers for Windows.
</para>
<para>
Presuming that you have compiled and installed wine the first
thing to do is is to enable direct hardware access to your
parallel port. To do this edit <filename>config</filename>
(usually in <filename>~/.wine/</filename>) and in the
ports section add the following two lines
</para>
<programlisting>
read=0x378,0x379,0x37a,0x37c,0x77a
write=0x378,x379,0x37a,0x37c,0x77a
</programlisting>
<para>
This adds the necessary access required for SPP/PS2/EPP/ECP
parallel port on LPT1. You will need to adjust these number
accordingly if your parallel port is on LPT2 or LPT0.
</para>
<para>
When starting wine use the following command line, where
<literal>XXXX</literal> is the program you need to run in
order to access your scanner, and <literal>YYYY</literal> is
the file your trace will be stored in:
</para>
<programlisting>
WINEDEBUG=+io wine XXXX 2&gt; &gt;(sed 's/^[^:]*:io:[^ ]* //' &gt; YYYY)
</programlisting>
<para>
You will need large amounts of hard disk space (read hundreds
of megabytes if you do a full page scan), and for reasonable
performance a really fast processor and lots of RAM.
</para>
<para>
You will need to postprocess the output into a more manageable
format, using the <command>shrink</command> program. First
you need to compile the source (which is located at the end of
this section):
<programlisting>
cc shrink.c -o shrink
</programlisting>
</para>
<para>
Use the <command>shrink</command> program to reduce the
physical size of the raw log as follows:
</para>
<programlisting>
cat log | shrink &gt; log2
</programlisting>
<para>
The trace has the basic form of
</para>
<programlisting>
XXXX &gt; YY @ ZZZZ:ZZZZ
</programlisting>
<para>
where <literal>XXXX</literal> is the port in hexadecimal being
accessed, <literal>YY</literal> is the data written (or read)
from the port, and <literal>ZZZZ:ZZZZ</literal> is the address
in memory of the instruction that accessed the port. The
direction of the arrow indicates whether the data was written
or read from the port.
</para>
<programlisting>
&gt; data was written to the port
&lt; data was read from the port
</programlisting>
<para>
My basic tip for interpreting these logs is to pay close
attention to the addresses of the IO instructions. Their
grouping and sometimes proximity should reveal the presence of
subroutines in the driver. By studying the different versions
you should be able to work them out. For example consider the
following section of trace from my UMAX Astra 600P
</para>
<programlisting>
0x378 &gt; 55 @ 0297:01ec
0x37a &gt; 05 @ 0297:01f5
0x379 &lt; 8f @ 0297:01fa
0x37a &gt; 04 @ 0297:0211
0x378 &gt; aa @ 0297:01ec
0x37a &gt; 05 @ 0297:01f5
0x379 &lt; 8f @ 0297:01fa
0x37a &gt; 04 @ 0297:0211
0x378 &gt; 00 @ 0297:01ec
0x37a &gt; 05 @ 0297:01f5
0x379 &lt; 8f @ 0297:01fa
0x37a &gt; 04 @ 0297:0211
0x378 &gt; 00 @ 0297:01ec
0x37a &gt; 05 @ 0297:01f5
0x379 &lt; 8f @ 0297:01fa
0x37a &gt; 04 @ 0297:0211
0x378 &gt; 00 @ 0297:01ec
0x37a &gt; 05 @ 0297:01f5
0x379 &lt; 8f @ 0297:01fa
0x37a &gt; 04 @ 0297:0211
0x378 &gt; 00 @ 0297:01ec
0x37a &gt; 05 @ 0297:01f5
0x379 &lt; 8f @ 0297:01fa
0x37a &gt; 04 @ 0297:0211
</programlisting>
<para>
As you can see there is a repeating structure starting at
address <literal>0297:01ec</literal> that consists of four io
accesses on the parallel port. Looking at it the first io
access writes a changing byte to the data port the second
always writes the byte <literal>0x05</literal> to the control
port, then a value which always seems to
<literal>0x8f</literal> is read from the status port at which
point a byte <literal>0x04</literal> is written to the control
port. By studying this and other sections of the trace we can
write a C routine that emulates this, shown below with some
macros to make reading/writing on the parallel port easier to
read.
</para>
<programlisting>
#define r_dtr(x) inb(x)
#define r_str(x) inb(x+1)
#define r_ctr(x) inb(x+2)
#define w_dtr(x,y) outb(y, x)
#define w_str(x,y) outb(y, x+1)
#define w_ctr(x,y) outb(y, x+2)
/* Seems to be sending a command byte to the scanner */
int udpp_put(int udpp_base, unsigned char command)
{
int loop, value;
w_dtr(udpp_base, command);
w_ctr(udpp_base, 0x05);
for (loop=0; loop &lt; 10; loop++)
if ((value = r_str(udpp_base)) & 0x80)
{
w_ctr(udpp_base, 0x04);
return value & 0xf8;
}
return (value & 0xf8) | 0x01;
}
</programlisting>
<para>
For the UMAX Astra 600P only seven such routines exist (well
14 really, seven for SPP and seven for EPP). Whether you
choose to disassemble the driver at this point to verify the
routines is your own choice. If you do, the address from the
trace should help in locating them in the disassembly.
</para>
<para>
You will probably then find it useful to write a script/perl/C
program to analyse the logfile and decode them futher as this
can reveal higher level grouping of the low level routines.
For example from the logs from my UMAX Astra 600P when decoded
further reveal (this is a small snippet)
</para>
<programlisting>
start:
put: 55 8f
put: aa 8f
put: 00 8f
put: 00 8f
put: 00 8f
put: c2 8f
wait: ff
get: af,87
wait: ff
get: af,87
end: cc
start:
put: 55 8f
put: aa 8f
put: 00 8f
put: 03 8f
put: 05 8f
put: 84 8f
wait: ff
</programlisting>
<para>
From this it is easy to see that <varname>put</varname>
routine is often grouped together in five successive calls
sending information to the scanner. Once these are understood
it should be possible to process the logs further to show the
higher level routines in an easy to see format. Once the
highest level format that you can derive from this process is
understood, you then need to produce a series of scans varying
only one parameter between them, so you can discover how to
set the various parameters for the scanner.
</para>
<para>
The following is the <filename>shrink.c</filename> program:
<programlisting>
/* Copyright David Campbell &lt;campbell@torque.net&gt; */
#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
int main (void)
{
char buff[256], lastline[256] = "";
int count = 0;
while (!feof (stdin))
{
fgets (buff, sizeof (buff), stdin);
if (strcmp (buff, lastline))
{
if (count &gt; 1)
printf ("# Last line repeated %i times #\n", count);
printf ("%s", buff);
strcpy (lastline, buff);
count = 1;
}
else count++;
}
return 0;
}
</programlisting>
</para>
</sect1>
<sect1 id="undoc-func">
<title>Understanding undocumented APIs</title>
<para>
Some background: On the i386 class of machines, stack entries are
usually dword (4 bytes) in size, little-endian. The stack grows
downward in memory. The stack pointer, maintained in the
<literal>esp</literal> register, points to the last valid entry;
thus, the operation of pushing a value onto the stack involves
decrementing <literal>esp</literal> and then moving the value into
the memory pointed to by <literal>esp</literal>
(i.e., <literal>push p</literal> in assembly resembles
<literal>*(--esp) = p;</literal> in C). Removing (popping)
values off the stack is the reverse (i.e., <literal>pop p</literal>
corresponds to <literal>p = *(esp++);</literal> in C).
</para>
<para>
In the <literal>stdcall</literal> calling convention, arguments are
pushed onto the stack right-to-left. For example, the C call
<function>myfunction(40, 20, 70, 30);</function> is expressed in
Intel assembly as:
<screen>
push 30
push 70
push 20
push 40
call myfunction
</screen>
The called function is responsible for removing the arguments
off the stack. Thus, before the call to myfunction, the
stack would look like:
<screen>
[local variable or temporary]
[local variable or temporary]
30
70
20
esp -> 40
</screen>
After the call returns, it should look like:
<screen>
[local variable or temporary]
esp -> [local variable or temporary]
</screen>
</para>
<para>
To restore the stack to this state, the called function must know how
many arguments to remove (which is the number of arguments it takes).
This is a problem if the function is undocumented.
</para>
<para>
One way to attempt to document the number of arguments each function
takes is to create a wrapper around that function that detects the
stack offset. Essentially, each wrapper assumes that the function will
take a large number of arguments. The wrapper copies each of these
arguments into its stack, calls the actual function, and then calculates
the number of arguments by checking esp before and after the call.
</para>
<para>
The main problem with this scheme is that the function must actually
be called from another program. Many of these functions are seldom
used. An attempt was made to aggressively query each function in a
given library (<filename>ntdll.dll</filename>) by passing 64 arguments,
all 0, to each function. Unfortunately, Windows NT quickly goes to a
blue screen of death, even if the program is run from a
non-administrator account.
</para>
<para>
Another method that has been much more successful is to attempt to
figure out how many arguments each function is removing from the
stack. This instruction, <literal>ret hhll</literal> (where
<symbol>hhll</symbol> is the number of bytes to remove, i.e. the
number of arguments times 4), contains the bytes
<literal>0xc2 ll hh</literal> in memory. It is a reasonable
assumption that few, if any, functions take more than 16 arguments;
therefore, simply searching for
<literal>hh == 0 && ll &lt; 0x40</literal> starting from the
address of a function yields the correct number of arguments most
of the time.
</para>
<para>
Of course, this is not without errors. <literal>ret 00ll</literal>
is not the only instruction that can have the byte sequence
<literal>0xc2 ll 0x0</literal>; for example,
<literal>push 0x000040c2</literal> has the byte sequence
<literal>0x68 0xc2 0x40 0x0 0x0</literal>, which matches
the above. Properly, the utility should look for this sequence
only on an instruction boundary; unfortunately, finding
instruction boundaries on an i386 requires implementing a full
disassembler -- quite a daunting task. Besides, the probability
of having such a byte sequence that is not the actual return
instruction is fairly low.
</para>
<para>
Much more troublesome is the non-linear flow of a function. For
example, consider the following two functions:
<screen>
somefunction1:
jmp somefunction1_impl
somefunction2:
ret 0004
somefunction1_impl:
ret 0008
</screen>
In this case, we would incorrectly detect both
<function>somefunction1</function> and
<function>somefunction2</function> as taking only a single
argument, whereas <function>somefunction1</function> really
takes two arguments.
</para>
<para>
With these limitations in mind, it is possible to implement
more stubs
in Wine and, eventually, the functions themselves.
</para>
</sect1>
<sect1>
<title>How to do regression testing using CVS</title>
<para>
A problem that can happen sometimes is 'it used to work
before, now it doesn't anymore...'. Here is a step by step
procedure to try to pinpoint when the problem occurred. This
is <emphasis>NOT</emphasis> for casual users.
</para>
<orderedlist>
<listitem>
<para>
Get the <quote>full CVS</quote> archive from winehq. This
archive is the CVS tree but with the tags controlling the
versioning system. It's a big file (> 40 meg) with a name
like full-cvs-&lt;last update date> (it's more than 100mb
when uncompressed, you can't very well do this with
small, old computers or slow Internet connections).
</para>
</listitem>
<listitem>
<para>
untar it into a repository directory:
<screen>
cd /home/gerard
tar -zxf full-cvs-2003-08-18.tar.gz
mv wine repository
</screen>
</para>
</listitem>
<listitem>
<para>
extract a new destination directory. This directory must
not be in a subdirectory of the repository else
<command>cvs</command> will think it's part of the
repository and deny you an extraction in the repository:
<screen>
cd /home/gerard
mv wine wine_current (-> this protects your current wine sandbox, if any)
export CVSROOT=/home/gerard/repository
cvs -d $CVSROOT checkout wine
</screen>
</para>
<para>
Note that it's not possible to do a checkout at a given
date; you always do the checkout for the last date where
the full-cvs-xxx snapshot was generated.
</para>
<para>
Note also that it is possible to do all this with a direct
CVS connection, of course. The full CVS file method is less
painful for the WineHQ CVS server and probably a bit faster
if you don't have a very good net connection.
</para>
</listitem>
<listitem>
<para>
you will have now in the <filename>~/wine</filename>
directory an image of the CVS tree, on the client side.
Now update this image to the date you want:
<screen>
cd /home/gerard/wine
cvs update -PAd -D "2004-08-23 CDT"
</screen>
</para>
<para>
The date format is <literal>YYYY-MM-DD HH:MM:SS</literal>.
Using the CST date format ensure that you will be able to
extract patches in a way that will be compatible with the
wine-cvs archive
<ulink url="http://www.winehq.org/hypermail/wine-cvs">
http://www.winehq.org/hypermail/wine-cvs</ulink>
</para>
<para>
Many messages will inform you that more recent files have
been deleted to set back the client cvs tree to the date
you asked, for example:
<screen>
cvs update: tsx11/ts_xf86dga2.c is no longer in the repository
</screen>
</para>
<para>
<command>cvs update</command> is not limited to upgrade to
a <emphasis>newer</emphasis> version as I have believed for
far too long :-(
</para>
</listitem>
<listitem>
<para>
Now proceed as for a normal update:
</para>
<screen>
./configure
make depend && make
</screen>
<para>
If any non-programmer reads this, the fastest method to
get at the point where the problem occurred is to use a
binary search, that is, if the problem occurred in 1999,
start at mid-year, then is the problem is already here,
back to 1st April, if not, to 1st October, and so on.
</para>
<para>
If you have lot of hard disk free space (a full compile
currently takes 400 Mb), copy the oldest known working
version before updating it, it will save time if you need
to go back. (it's better to <command>make
distclean</command> before going back in time, so you
have to make everything if you don't backup the older
version)
</para>
<para>
When you have found the day where the problem happened,
continue the search using the wine-cvs archive (sorted by
date) and a more precise cvs update including hour,
minute, second:
<screen>
cvs update -PAd -D "2004-08-23 15:17:25 CDT"
</screen>
This will allow you to find easily the exact patch that
did it.
</para>
</listitem>
<listitem>
<para>
If you find the patch that is the cause of the problem,
you have almost won; report about it to
<ulink url="http://bugs.winehq.org/">Wine Bugzilla</ulink>
or subscribe to wine-devel and post it there. There is a
chance that the author will jump in to suggest a fix; or
there is always the possibility to look hard at the patch
until it is coerced to reveal where is the bug :-)
</para>
</listitem>
</orderedlist>
</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:
-->

View File

@ -0,0 +1,673 @@
<chapter>
<title>Windowing system</title>
<sect1>
<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>
<sect2>
<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-&gt;parent</varname>) points to the desktop
window.
</para>
<screen>
Desktop window - root window
| \ `-.
| \ `-.
popup -&gt; wnd1 -&gt; wnd2 - top level windows
| \ `-. `-.
| \ `-. `-.
child1 child2 -&gt; 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-&gt;popup-&gt;child2-&gt;child3-&gt;wnd1-&gt;child4-&gt;wnd2-&gt;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>
<sect3>
<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 | | =&gt; | | | - 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 |_________ | =&gt; | ...|___|..
| | | | | : | |
|------' | | | : '---'
| | 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>
</sect3>
</sect2>
<sect2>
<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>
</sect2>
<sect2 id="accel-impl">
<title>Accelerators</title>
<para>
There are <emphasis>three</emphasis> differently sized
accelerator structures exposed to the user:
</para>
<orderedlist>
<listitem>
<para>
Accelerators in NE resources. This is also the internal
layout of the global handle <type>HACCEL</type> (16 and
32) in Windows 95 and Wine. Exposed to the user as Win16
global handles <type>HACCEL16</type> and
<type>HACCEL32</type> by the Win16/Win32 API.
These are 5 bytes long, with no padding:
<programlisting>
BYTE fVirt;
WORD key;
WORD cmd;
</programlisting>
</para>
</listitem>
<listitem>
<para>
Accelerators in PE resources. They are exposed to the
user only by direct accessing PE resources. These have a
size of 8 bytes:
</para>
<programlisting>
BYTE fVirt;
BYTE pad0;
WORD key;
WORD cmd;
WORD pad1;
</programlisting>
</listitem>
<listitem>
<para>
Accelerators in the Win32 API. These are exposed to the
user by the <function>CopyAcceleratorTable</function>
and <function>CreateAcceleratorTable</function> functions
in the Win32 API.
These have a size of 6 bytes:
</para>
<programlisting>
BYTE fVirt;
BYTE pad0;
WORD key;
WORD cmd;
</programlisting>
</listitem>
</orderedlist>
<para>
Why two types of accelerators in the Win32 API? We can only
guess, but my best bet is that the Win32 resource compiler
can/does not handle struct packing. Win32 <type>ACCEL</type>
is defined using <function>#pragma(2)</function> for the
compiler but without any packing for RC, so it will assume
<function>#pragma(4)</function>.
</para>
</sect2>
</sect1>
<sect1>
<title>X Windows System interface</title>
<para></para>
<sect2>
<title>Keyboard mapping</title>
<para>
Wine now needs to know about your keyboard layout. This
requirement comes from a need from many apps to have the
correct scancodes available, since they read these directly,
instead of just taking the characters returned by the X
server. This means that Wine now needs to have a mapping
from X keys to the scancodes these programs expect.
</para>
<para>
On startup, Wine will try to recognize the active X layout
by seeing if it matches any of the defined tables. If it
does, everything is alright. If not, you need to define it.
</para>
<para>
To do this, open the file
<filename>dlls/x11drv/keyboard.c</filename> and take a look
at the existing tables. Make a backup copy of it, especially
if you don't use CVS.
</para>
<para>
What you really would need to do, is find out which scancode
each key needs to generate. Find it in the
<function>main_key_scan</function> table, which looks like
this:
</para>
<programlisting>
static const int main_key_scan[MAIN_LEN] =
{
/* this is my (102-key) keyboard layout, sorry if it doesn't quite match yours */
0x29,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,
0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x2B,
0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,
0x56 /* the 102nd key (actually to the right of l-shift) */
};
</programlisting>
<para>
Next, assign each scancode the characters imprinted on the
keycaps. This was done (sort of) for the US 101-key keyboard,
which you can find near the top in
<filename>keyboard.c</filename>. It also shows that if there
is no 102nd key, you can skip that.
</para>
<para>
However, for most international 102-key keyboards, we have
done it easy for you. The scancode layout for these already
pretty much matches the physical layout in the
<function>main_key_scan</function>, so all you need to do is
to go through all the keys that generate characters on your
main keyboard (except spacebar), and stuff those into an
appropriate table. The only exception is that the 102nd key,
which is usually to the left of the first key of the last
line (usually <keycap>Z</keycap>), must be placed on a
separate line after the last line.
</para>
<para>
For example, my Norwegian keyboard looks like this
</para>
<screen>
§ ! " # ¤ % & / ( ) = ? ` Back-
| 1 2@ 3£ 4$ 5 6 7{ 8[ 9] 0} + \´ space
Tab Q W E R T Y U I O P Å ^
¨~
Enter
Caps A S D F G H J K L Ø Æ *
Lock '
Sh- > Z X C V B N M ; : _ Shift
ift &lt; , . -
Ctrl Alt Spacebar AltGr Ctrl
</screen>
<para>
Note the 102nd key, which is the <keycap>&lt;></keycap> key, to
the left of <keycap>Z</keycap>. The character to the right of
the main character is the character generated by
<keycap>AltGr</keycap>.
</para>
<para>
This keyboard is defined as follows:
</para>
<programlisting>
static const char main_key_NO[MAIN_LEN][4] =
{
"|§","1!","2\"@","3#£","4¤$","5%","6&","7/{","8([","9)]","0=}","+?","\\´",
"qQ","wW","eE","rR","tT","yY","uU","iI","oO","pP","åÅ","¨^~",
"aA","sS","dD","fF","gG","hH","jJ","kK","lL","øØ","æÆ","'*",
"zZ","xX","cC","vV","bB","nN","mM",",;",".:","-_",
"&lt;>"
};
</programlisting>
<para>
Except that " and \ needs to be quoted with a backslash, and
that the 102nd key is on a separate line, it's pretty
straightforward.
</para>
<para>
After you have written such a table, you need to add it to the
<function>main_key_tab[]</function> layout index table. This
will look like this:
</para>
<programlisting>
static struct {
WORD lang, ansi_codepage, oem_codepage;
const char (*key)[MAIN_LEN][4];
} main_key_tab[]={
...
...
{MAKELANGID(LANG_NORWEGIAN,SUBLANG_DEFAULT), 1252, 865, &amp;main_key_NO},
...
</programlisting>
<para>
After you have added your table, recompile Wine and test that
it works. If it fails to detect your table, try running
</para>
<screen>
WINEDEBUG=+key,+keyboard wine > key.log 2>&1
</screen>
<para>
and look in the resulting <filename>key.log</filename> file to
find the error messages it gives for your layout.
</para>
<para>
Note that the <constant>LANG_*</constant> and
<constant>SUBLANG_*</constant> definitions are in
<filename>include/winnls.h</filename>, which you might need
to know to find out which numbers your language is assigned,
and find it in the WINEDEBUG output. The numbers will be
<literal>(SUBLANG * 0x400 + LANG)</literal>, so, for example
the combination <literal>LANG_NORWEGIAN (0x14)</literal> and
<literal>SUBLANG_DEFAULT (0x1)</literal> will be (in hex)
<literal>14 + 1*400 = 414</literal>, so since I'm Norwegian,
I could look for <literal>0414</literal> in the WINEDEBUG
output to find out why my keyboard won't detect.
</para>
</sect2>
</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:
-->