1 <chapter id=
"implementation">
2 <title>Low-level Implementation
</title>
3 <para>Details of Wine's Low-level Implementation...
</para>
5 <sect1 id=
"builtin-dlls">
6 <title>Builtin DLLs
</title>
9 Written by &name-juergen-schmied;
<email>&email-juergen-schmied;
</email>
12 (Extracted from
<filename>wine/documentation/internal-dll
</filename>)
16 This document describes some points you should know before
17 implementing the internal counterparts to external DLL's.
18 Only
32 bit DLL's are considered.
22 <title>1. The LibMain function
</title>
25 This is the way to do some initializing when a process or
26 thread is attached to the DLL. The function name is taken
27 from a
<filename>*.spec
</filename> file line:
33 Then, you have to implement the function:
36 BOOL32 WINAPI YourLibMain(HINSTANCE32 hinstDLL,
37 DWORD fdwReason, LPVOID lpvReserved)
38 { if (fdwReason==DLL_PROCESS_ATTACH)
47 <title>2. Using functions from other built-in DLL's
</title>
50 The problem here is, that you can't know if you have to call
51 the function from the internal or the external DLL. If you
52 just call the function you will get the internal
53 implementation. If the external DLL is loaded the executed
54 program will use the external DLL and you the internal one.
55 When you -as an example- fill an iconlist placed in the
56 internal DLL the application won't get the icons from the
60 To work around this, you should always use a pointer to call
64 /* definition of the pointer type*/
65 void (CALLBACK* pDLLInitComctl)();
67 /* getting the function address this should be done in the
68 LibMain function when called with DLL_PROCESS_ATTACH*/
70 BOOL32 WINAPI Shell32LibMain(HINSTANCE32 hinstDLL, DWORD fdwReason,
72 { HINSTANCE32 hComctl32;
73 if (fdwReason==DLL_PROCESS_ATTACH)
74 { /* load the external / internal DLL*/
75 hComctl32 = LoadLibrary32A(
"COMCTL32.DLL");
77 { /* get the function pointer */
78 pDLLInitComctl=GetProcAddress32(hComctl32,
"InitCommonControlsEx");
86 /* free the DLL / decrease the ref count */
87 FreeLibrary32(hComctl32);
91 ERR(shell,
"P A N I C error getting functionpointers\n");
100 <title>3. Getting resources from a
<filename>*.rc
</filename> file linked to the DLL
</title>
103 < If you know how, write some lines
>
108 <sect1 id=
"accel-impl">
109 <title>Accelerators
</title>
112 Findings researched by Uwe Bonnes, Ulrich Weigand and Marcus Meissner.
115 (Extracted from
<filename>wine/documentation/accelerators
</filename>)
119 Some notes concerning accelerators.
122 There are
<emphasis>three
</emphasis> differently sized
123 accelerator structures exposed to the user. The general layout
132 We now have three different appearances:
138 Accelerators in NE resources. These have a size of
5 byte
139 and do not have any padding. This is also the internal
140 layout of the global handle
<type>HACCEL
</type> (
16 and
141 32) in Windows
95 and Wine. Exposed to the user as Win16
142 global handles
<type>HACCEL16
</type> and
143 <type>HACCEL32
</type> by the Win16/Win32 API.
148 Accelerators in PE resources. These have a size of
8 byte.
159 They are exposed to the user only by direct accessing PE
165 Accelerators in the Win32 API. These have a size of
6
175 These are exposed to the user by the
176 <function>CopyAcceleratorTable
</function> and
177 <function>CreateAcceleratorTable
</function> functions in
184 Why two types of accelerators in the Win32 API? We can only
185 guess, but my best bet is that the Win32 resource compiler
186 can/does not handle struct packing. Win32
<type>ACCEL
</type>
187 is defined using
<function>#pragma(
2)
</function> for the
188 compiler but without any packing for RC, so it will assume
189 <function>#pragma(
4)
</function>.
194 <sect1 id=
"file-handles">
195 <title>File Handles
</title>
201 (Extracted from
<filename>wine/documentation/filehandles
</filename>)
205 DOS treats the first
5 file handles as special cases. They
206 map directly to
<filename>stdin
</filename>,
207 <filename>stdout
</filename>,
<filename>stderr
</filename>,
208 <filename>stdaux
</filename> and
<filename>stdprn
</filename>.
209 Windows
16 inherits this behavior, and in fact, win16 handles
210 are interchangeable with DOS handles. Some nasty windows
211 programs even do this!
214 Windows32 issues file handles starting from
215 <literal>1</literal>, on the grounds that most GUI processes
216 don't need a
<filename>stdin
</filename>,
217 <filename>stdout
</filename>, etc.
220 The Wine handle code is implemented in the Win32 style, and
221 the Win16 functions use two macros to convert to and from the
226 The macros are defined in
<filename>file.h
</filename> as follows:
229 #define HFILE16_TO_HFILE32(handle) \
230 (((handle)==
0) ? GetStdHandle(STD_INPUT_HANDLE) : \
231 ((handle)==
1) ? GetStdHandle(STD_OUTPUT_HANDLE) : \
232 ((handle)==
2) ? GetStdHandle(STD_ERROR_HANDLE) : \
233 ((handle)
>0x400) ? handle : \
236 #define HFILE32_TO_HFILE16(handle) ({ HFILE32 hnd=handle; \
237 ((hnd==HFILE_ERROR32) ? HFILE_ERROR16 : \
238 ((handle
>0x400) ? handle : \
244 Be careful not to use the macro
245 <function>HFILE16_TO_HFILE32
</function> on functions with
246 side-effects, as it will cause them to be evaluated several
247 times. This could be considered a bug, but the use of this
248 macro is limited enough not to need a rewrite.
253 The
<literal>0x400</literal> special case above deals with
254 LZW filehandles (see
<filename>misc/lzexpand.c
</filename>).
259 <sect1 id=
"hardware-trace">
260 <title>Doing A Hardware Trace In Wine
</title>
263 Written by &name-jonathan-buzzard;
<email>&email-jonathan-buzzard;
</email>
266 (Extracted from
<filename>wine/documentation/ioport-trace-hints
</filename>)
270 The primary reason to do this is to reverse engineer a
271 hardware device for which you don't have documentation, but
272 can get to work under Wine.
275 This lot is aimed at parallel port devices, and in particular
276 parallel port scanners which are now so cheap they are
277 virtually being given away. The problem is that few
278 manufactures will release any programming information which
279 prevents drivers being written for Sane, and the traditional
280 technique of using DOSemu to produce the traces does not work
281 as the scanners invariably only have drivers for Windows.
284 Please note that I have not been able to get my scanner
285 working properly (a UMAX Astra
600P), but a couple of people
286 have reported success with at least the Artec AS6e scanner. I
287 am not in the process of developing any driver nor do I intend
288 to, so don't bug me about it. My time is now spent writing
289 programs to set things like battery save options under Linux
290 on Toshiba laptops, and as such I don't have any spare time
291 for writing a driver for a parallel port scanner etc.
294 Presuming that you have compiled and installed wine the first
295 thing to do is is to enable direct hardware access to your
296 parallel port. To do this edit
<filename>wine.conf
</filename>
297 (usually in
<filename>/usr/local/etc
</filename>) and in the
298 ports section add the following two lines
301 read=
0x378,
0x379,
0x37a,
0x37c,
0x77a
302 write=
0x378,x379,
0x37a,
0x37c,
0x77a
305 This adds the necessary access required for SPP/PS2/EPP/ECP
306 parallel port on LPT1. You will need to adjust these number
307 accordingly if your parallel port is on LPT2 or LPT0.
310 When starting wine use the following command line, where
311 <literal>XXXX
</literal> is the program you need to run in
312 order to access your scanner, and
<literal>YYYY
</literal> is
313 the file your trace will be stored in:
316 wine -debugmsg +io XXXX
2> >(sed 's/^[^:]*:io:[^ ]* //'
> YYYY)
319 You will need large amounts of hard disk space (read hundreds
320 of megabytes if you do a full page scan), and for reasonable
321 performance a really fast processor and lots of RAM.
324 You might well find the log compression program that
<email>David
325 Campbell campbell@torque.net
</email> wrote helpful in
326 reducing the size of the log files. This can be obtained by
327 the following command:
330 sh ioport-trace-hints
333 This should extract
<filename>shrink.c
</filename> (which is
334 located at the end of this file. Compile the log compression
338 cc shrink.c -o shrink
341 Use the
<command>shrink
</command> program to reduce the
342 physical size of the raw log as follows:
345 cat log | shrink
> log2
348 The trace has the basic form of
351 XXXX
> YY @ ZZZZ:ZZZZ
354 where
<literal>XXXX
</literal> is the port in hexidecimal being
355 accessed,
<literal>YY
</literal> is the data written (or read)
356 from the port, and
<literal>ZZZZ:ZZZZ
</literal> is the address
357 in memory of the instruction that accessed the port. The
358 direction of the arrow indicates whether the data was written
359 or read from the port.
362 > data was written to the port
363 < data was read from the port
366 My basic tip for interpreting these logs is to pay close
367 attention to the addresses of the IO instructions. Their
368 grouping and sometimes proximity should reveal the presence of
369 subroutines in the driver. By studying the different versions
370 you should be able to work them out. For example consider the
371 following section of trace from my UMAX Astra
600P
374 0x378 > 55 @
0297:
01ec
375 0x37a > 05 @
0297:
01f5
376 0x379 < 8f @
0297:
01fa
377 0x37a > 04 @
0297:
0211
378 0x378 > aa @
0297:
01ec
379 0x37a > 05 @
0297:
01f5
380 0x379 < 8f @
0297:
01fa
381 0x37a > 04 @
0297:
0211
382 0x378 > 00 @
0297:
01ec
383 0x37a > 05 @
0297:
01f5
384 0x379 < 8f @
0297:
01fa
385 0x37a > 04 @
0297:
0211
386 0x378 > 00 @
0297:
01ec
387 0x37a > 05 @
0297:
01f5
388 0x379 < 8f @
0297:
01fa
389 0x37a > 04 @
0297:
0211
390 0x378 > 00 @
0297:
01ec
391 0x37a > 05 @
0297:
01f5
392 0x379 < 8f @
0297:
01fa
393 0x37a > 04 @
0297:
0211
394 0x378 > 00 @
0297:
01ec
395 0x37a > 05 @
0297:
01f5
396 0x379 < 8f @
0297:
01fa
397 0x37a > 04 @
0297:
0211
400 As you can see there is a repeating structure starting at
401 address
<literal>0297:
01ec
</literal> that consists of four io
402 accesses on the parallel port. Looking at it the first io
403 access writes a changing byte to the data port the second
404 always writes the byte
<literal>0x05</literal> to the control
405 port, then a value which always seems to
406 <literal>0x8f</literal> is read from the status port at which
407 point a byte
<literal>0x04</literal> is written to the control
408 port. By studying this and other sections of the trace we can
409 write a C routine that emulates this, shown below with some
410 macros to make reading/writing on the parallel port easier to
414 #define r_dtr(x) inb(x)
415 #define r_str(x) inb(x+
1)
416 #define r_ctr(x) inb(x+
2)
417 #define w_dtr(x,y) outb(y, x)
418 #define w_str(x,y) outb(y, x+
1)
419 #define w_ctr(x,y) outb(y, x+
2)
422 * Seems to be sending a command byte to the scanner
425 int udpp_put(int udpp_base, unsigned char command)
429 w_dtr(udpp_base, command);
430 w_ctr(udpp_base,
0x05);
432 for (loop=
0;loop
<10;loop++)
433 if (((value=r_str(udpp_base)) &
0x80)!=
0x00) {
434 w_ctr(udpp_base,
0x04);
438 return (value &
0xf8) |
0x01;
442 For the UMAX Astra
600P only seven such routines exist (well
443 14 really, seven for SPP and seven for EPP). Whether you
444 choose to disassemble the driver at this point to verify the
445 routines is your own choice. If you do, the address from the
446 trace should help in locating them in the disassembly.
449 You will probably then find it useful to write a script/perl/C
450 program to analyse the logfile and decode them futher as this
451 can reveal higher level grouping of the low level routines.
452 For example from the logs from my UMAX Astra
600P when decoded
453 further reveal (this is a small snippet)
478 From this it is easy to see that
<varname>put
</varname>
479 routine is often grouped together in five successive calls
480 sending information to the scanner. Once these are understood
481 it should be possible to process the logs further to show the
482 higher level routines in an easy to see format. Once the
483 highest level format that you can derive from this process is
484 understood, you then need to produce a series of scans varying
485 only one parameter between them, so you can discover how to
486 set the various parameters for the scanner.
490 The following is the
<filename>shrink.c
</filename> program.
494 cat
> shrink.c
<<EOF
495 #include
<stdio.h
>
496 #include
<string.h
>
501 char buff[
256], lastline[
256];
507 while (!feof (stdin))
509 fgets (buff, sizeof (buff), stdin);
510 if (strcmp (buff, lastline) ==
0)
517 fprintf (stdout,
"# Last line repeated %i times #\n", count);
518 fprintf (stdout,
"%s", buff);
519 strcpy (lastline, buff);
530 <!-- Keep this comment at the end of the file
533 sgml-parent-document:("wine-devel.sgml" "set" "book" "part" "chapter" "")