diff --git a/documentation/Makefile.in b/documentation/Makefile.in index f80417e7b2..bbabb82b1b 100644 --- a/documentation/Makefile.in +++ b/documentation/Makefile.in @@ -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 \ diff --git a/documentation/architecture.sgml b/documentation/architecture.sgml index 66afd02199..62f9f89426 100644 --- a/documentation/architecture.sgml +++ b/documentation/architecture.sgml @@ -659,6 +659,125 @@ shared library. + + Wine/Windows DLLs + + + This document mainly deals with the status of current DLL + support by Wine. The Wine ini file currently supports + settings to change the load order of DLLs. The load order + depends on several issues, which results in different settings + for various DLLs. + + + + Pros of Native DLLs + + + Native DLLs of course guarantee 100% compatibility for + routines they implement. For example, using the native USER + DLL would maintain a virtually perfect and Windows 95-like + look for window borders, dialog controls, and so on. Using + the built-in Wine version of this library, on the other + hand, would produce a display that does not precisely mimic + that of Windows 95. Such subtle differences can be + engendered in other important DLLs, such as the common + controls library COMMCTRL or the common dialogs library + COMMDLG, when built-in Wine DLLs outrank other types in load + order. + + + More significant, less aesthetically-oriented problems can + result if the built-in Wine version of the SHELL DLL is + loaded before the native version of this library. SHELL + contains routines such as those used by installer utilities + to create desktop shortcuts. Some installers might fail when + using Wine's built-in SHELL. + + + + + Cons of Native DLLs + + + Not every application performs better under native DLLs. If + a library tries to access features of the rest of the system + that are not fully implemented in Wine, the native DLL might + work much worse than the corresponding built-in one, if at + all. For example, the native Windows GDI library must be + paired with a Windows display driver, which of course is not + present under Intel Unix and Wine. + + + Finally, occasionally built-in Wine DLLs implement more + features than the corresponding native Windows DLLs. + Probably the most important example of such behavior is the + integration of Wine with X provided by Wine's built-in USER + DLL. Should the native Windows USER library take load-order + precedence, such features as the ability to use the + clipboard or drag-and-drop between Wine windows and X + windows will be lost. + + + + + Deciding Between Native and Built-In DLLs + + + Clearly, there is no one rule-of-thumb regarding which + load-order to use. So, you must become familiar with + what specific DLLs do and which other DLLs or features + a given library interacts with, and use this information + to make a case-by-case decision. + + + + + Load Order for DLLs + + + Using the DLL sections from the wine configuration file, the + load order can be tweaked to a high degree. In general it is + advised not to change the settings of the configuration + file. The default configuration specifies the right load + order for the most important DLLs. + + + The default load order follows this algorithm: for all DLLs + which have a fully-functional Wine implementation, or where + the native DLL is known not to work, the built-in library + will be loaded first. In all other cases, the native DLL + takes load-order precedence. + + + The DefaultLoadOrder from the + [DllDefaults] section specifies for all DLLs which version + to try first. See manpage for explanation of the arguments. + + + The [DllOverrides] section deals with DLLs, which need a + different-from-default treatment. + + + The [DllPairs] section is for DLLs, which must be loaded in + pairs. In general, these are DLLs for either 16-bit or + 32-bit applications. In most cases in Windows, the 32-bit + version cannot be used without its 16-bit counterpart. For + Wine, it is customary that the 16-bit implementations rely + on the 32-bit implementations and cast the results back to + 16-bit arguments. Changing anything in this section is bound + to result in errors. + + + For the future, the Wine implementation of Windows DLL seems + to head towards unifying the 16 and 32 bit DLLs wherever + possible, resulting in larger DLLs. They are stored in the + dlls/ subdirectory using the 32-bit + name. + + + + Memory management @@ -828,7 +947,116 @@ Wine is using, the glibc malloc arena and so on. + + + Laying out the address space + + + Up until about the start of 2004, the Linux address space + very much resembled the Windows 9x layout: the kernel sat + in the top gigabyte, the bottom pages were unmapped to + catch null pointer dereferences, and the rest was + free. The kernels mmap algorithm was predictable: it would + start by mapping files at low addresses and work up from + there. + + + + The development of a series of new low level patches + violated many of these assumptions, and resulted in Wine + needing to force the Win32 address space layout upon the + system. This section looks at why and how this is done. + + + + The exec-shield patch increases security by randomizing + the kernels mmap algorithms. Rather than consistently + choosing the same addresses given the same sequence of + requests, the kernel will now choose randomized + addresses. Because the Linux dynamic linker + (ld-linux.so.2) loads DSOs into memory by using mmap, this + means that DSOs are no longer loaded at predictable + addresses, so making it harder to attack software by using + buffer overflows. It also attempts to relocate certain + binaries into a special low area of memory known as the + ASCII armor so making it harder to jump into them when + using string based attacks. + + + + Prelink is a technology that enhances startup times by + precalculating ELF global offset tables then saving the + results inside the native binaries themselves. By grid + fitting each DSO into the address space, the dynamic + linker does not have to perform as many relocations so + allowing applications that heavily rely on dynamic linkage + to be loaded into memory much quicker. Complex C++ + applications such as Mozilla, OpenOffice and KDE can + especially benefit from this technique. + + + + The 4G VM split patch was developed by Ingo Molnar. It + gives the Linux kernel its own address space, thereby + allowing processes to access the maximum addressable + amount of memory on a 32-bit machine: 4 gigabytes. It + allows people with lots of RAM to fully utilise that in + any given process at the cost of performance: the reason + behind giving the kernel a part of each processes address + space was to avoid the overhead of switching on each + syscall. + + + + Each of these changes alter the address space in a way + incompatible with Windows. Prelink and exec-shield mean + that the libraries Wine uses can be placed at any point in + the address space: typically this meant that a library was + sitting in the region that the EXE you wanted to run had + to be loaded (remember that unlike DLLs, EXE files cannot + be moved around in memory). The 4G VM split means that + programs could receive pointers to the top gigabyte of + address space which some are not prepared for (they may + store extra information in the high bits of a pointer, for + instance). In particular, in combination with exec-shield + this one is especially deadly as it's possible the process + heap could be allocated beyond ADDRESS_SPACE_LIMIT which + causes Wine initialization to fail. + + + + The solution to these problems is for Wine to reserve + particular parts of the address space so that areas that + we don't want the system to use will be avoided. We later + on (re/de)allocate those areas as needed. One problem is + that some of these mappings are put in place automatically + by the dynamic linker: for instance any libraries that + Wine is linked to (like libc, libwine, libpthread etc) + will be mapped into memory before Wine even gets + control. In order to solve that, Wine overrides the + default ELF initialization sequence at a low level and + reserves the needed areas by using direct syscalls into + the kernel (ie without linking against any other code to + do it) before restarting the standard initialization and + letting the dynamic linker continue. This is referred to + as the preloader and is found in loader/preloader.c. + + + + Once the usual ELF boot sequence has been completed, some + native libraries may well have been mapped above the 3gig + limit: however, this doesn't matter as 3G is a Windows + limit, not a Linux limit. We still have to prevent the + system from allocating anything else above there (like the + heap or other DLLs) though so Wine performs a binary + search over the upper gig of address space in order to + iteratively fill in the holes with MAP_NORESERVE mappings + so the address space is allocated but the memory to + actually back it is not. This code can be found in libs/wine/mmap.c:reserve_area. + + + Processes @@ -1124,971 +1352,8 @@ - - - - Module Overview - - NTDLL Module - - NTDLL provides most of the services you'd expect from a - kernel. - - - 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. - - - Wine also provide fibers (which is the Windows name of - co-routines). - - - 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). - - - - File management - - 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. - - - File handles can be waitable objects, as Windows define - them. - - - 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). - - - FIXME: this should be enhanced and updated to latest work - on FS. - - - - - Synchronization - - 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. - - - - - Module (DLL) loading - - Wine is able to load any NE and PE module. In all cases, - the module's binary code is directly executed by the - processor. - - - - - Device management - - Wine allows usage a wide variety of devices: - - - - Communication ports are mapped to Unix - communication ports (if they have sufficient - permissions). - - - - - Parallel ports are mapped to Unix parallel ports (if - they have sufficient permissions). - - - - - CDROM: the Windows device I/O control calls are - mapped onto Unix ioctl(). - - - - - 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. - - - Wine will not support native VxD. - - - - - - - - - KERNEL Module - - - FIXME: Needs some content... - - - - - GDI Module - - - X Windows System interface - - - 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 XInitThreads()). However, - Wine does not use this approach. Instead Wine performs its - own synchronization using the - wine_tsx11_lock() / wine_tsx11_unlock() - functions. This locking protects library access - with a critical section, and also arranges things so that - X libraries compiled without - (eg. with global errno variable) will - work with Wine. - - - In the past, all calls to X used to go through a wrapper called - TSX...() (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. - - - - - - USER Module - - - 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 windows/, - controls/, and - misc/ directories. - - - - Windowing subsystem - - windows/win.c - windows/winpos.c - - 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 WS_CHILD - style bit is set), a pointer to the sibling (returned by - GetWindow(..., GW_NEXT)), a pointer - to the owner window (set only for popup window if it was - created with valid hwndParent - parameter), and a pointer to the first child window - (GetWindow(.., GW_CHILD)). All popup - and non-child windows are therefore placed in the first - level of this hierarchy and their ancestor link - (wnd->parent) points to the desktop - window. - - - Desktop window - root window - | \ `-. - | \ `-. - popup -> wnd1 -> wnd2 - top level windows - | \ `-. `-. - | \ `-. `-. - child1 child2 -> child3 child4 - child windows - - - 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). - - - Another fairly important concept is - z-order. 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 - - -child1->popup->child2->child3->wnd1->child4->wnd2->desktop. - - - Current active window ("foreground window" in Win32) is - moved to the front of z-order unless its top-level - ancestor owns popup windows. - - - All these issues are dealt with (or supposed to be) in - windows/winpos.c with - SetWindowPos() being the primary - interface to the window manager. - - - 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, SetWindowPos() should - eventually be implemented via - Begin/End/DeferWindowPos() calls and - not the other way around. - - - - Visible region, clipping region and update region - - windows/dce.c - windows/winpos.c - windows/painting.c - - - ________________________ - |_________ | A and B are child windows of C - | A |______ | - | | | | - |---------' | | - | | B | | - | | | | - | `------------' | - | C | - `------------------------' - - - Visible region determines which part of the window is - not obscured by other windows. If a window has the - WS_CLIPCHILDREN style then all - areas below its children are considered invisible. - Similarly, if the WS_CLIPSIBLINGS - 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. - - - B has a WS_CLIPSIBLINGS style: - - - . ______ - : | | - | ,-----' | - | | B | - visible region of B - | | | - : `------------' - - - When the program requests a display - context (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. - - - Program asked for a DC with a clipping region: - - - ______ - ,--|--. | . ,--. - ,--+--' | | : _: | - | | B | | => | | | - DC region where the painting will - | | | | | | | be visible - `--|-----|---' : `----' - `-----' - - - 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 WM_ERASEBKGND and - WM_PAINT messages. In addition, - WM_NCPAINT message is sent when the - uncovered area intersects a nonclient part of the window. - Application must reply to the WM_PAINT - message by calling the - BeginPaint()/EndPaint() - pair of functions. BeginPaint() 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 WM_PAINT until the window - manager creates a new update region. - - - A was moved to the left: - - - ________________________ ... / C update region - |______ | : .___ / - | A |_________ | => | ...|___|.. - | | | | | : | | - |------' | | | : '---' - | | B | | | : \ - | | | | : \ - | `------------' | B update region - | C | - `------------------------' - - - 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). - - - - - - Messaging subsystem - - windows/queue.c - windows/message.c - - - Each Windows task/thread has its own message queue - this - is where it gets messages from. Messages can be: - - - - generated on the fly (WM_PAINT, - WM_NCPAINT, - WM_TIMER) - - - - - created by the system (hardware messages) - - - - - posted by other tasks/threads (PostMessage) - - - - - sent by other tasks/threads (SendMessage) - - - - - - Message priority: - - - 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 - windows/message.c. - - - 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 - Get/PeekMessage 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 QS_PAINT bit in the - owning queue and eventually this window receives a - WM_PAINT message - (WM_NCPAINT 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 DispatchMessage - either calls the callback function or the window - procedure. If there are no messages pending the - task/thread sleeps until messages appear. - - - There are several tricky moments (open for discussion) - - - - - - - System message order has to be honored and messages - should be processed within correct task/thread - context. Therefore when Get/PeekMessage 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: - -
- by David Charlap - - " Here's the problem in a nutshell, and there is no - good solution. Every possible solution creates a - different problem. - - - 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.) - - - Mouse input events go to the window you click on - (unless some window captures the mouse). - - - 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. - - - 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. - - - 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. - - - 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. - - - 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. - - - 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. - - - 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. - - - 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. - - - There are a few solutions to this problem. - - - 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. - - - 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. - - - 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. - - - 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. - - - - As for the pros and cons: - - - 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. - - - 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." - - - 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." - -
-
- - - - Intertask/interthread - SendMessage. 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 - DirectedYield() function. - However, in Win32 there could be several messages - pending sent by preemptively executing threads, and in - this case SendMessage 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 - SendMessage. - - -
-
-
-
- - - Wine/Windows DLLs - - - This document mainly deals with the status of current DLL - support by Wine. The Wine ini file currently supports - settings to change the load order of DLLs. The load order - depends on several issues, which results in different settings - for various DLLs. - - - - Pros of Native DLLs - - - Native DLLs of course guarantee 100% compatibility for - routines they implement. For example, using the native USER - DLL would maintain a virtually perfect and Windows 95-like - look for window borders, dialog controls, and so on. Using - the built-in Wine version of this library, on the other - hand, would produce a display that does not precisely mimic - that of Windows 95. Such subtle differences can be - engendered in other important DLLs, such as the common - controls library COMMCTRL or the common dialogs library - COMMDLG, when built-in Wine DLLs outrank other types in load - order. - - - More significant, less aesthetically-oriented problems can - result if the built-in Wine version of the SHELL DLL is - loaded before the native version of this library. SHELL - contains routines such as those used by installer utilities - to create desktop shortcuts. Some installers might fail when - using Wine's built-in SHELL. - - - - - Cons of Native DLLs - - - Not every application performs better under native DLLs. If - a library tries to access features of the rest of the system - that are not fully implemented in Wine, the native DLL might - work much worse than the corresponding built-in one, if at - all. For example, the native Windows GDI library must be - paired with a Windows display driver, which of course is not - present under Intel Unix and Wine. - - - Finally, occasionally built-in Wine DLLs implement more - features than the corresponding native Windows DLLs. - Probably the most important example of such behavior is the - integration of Wine with X provided by Wine's built-in USER - DLL. Should the native Windows USER library take load-order - precedence, such features as the ability to use the - clipboard or drag-and-drop between Wine windows and X - windows will be lost. - - - - - Deciding Between Native and Built-In DLLs - - - Clearly, there is no one rule-of-thumb regarding which - load-order to use. So, you must become familiar with - what specific DLLs do and which other DLLs or features - a given library interacts with, and use this information - to make a case-by-case decision. - - - - - - Load Order for DLLs - - - Using the DLL sections from the wine configuration file, the - load order can be tweaked to a high degree. In general it is - advised not to change the settings of the configuration - file. The default configuration specifies the right load - order for the most important DLLs. - - - The default load order follows this algorithm: for all DLLs - which have a fully-functional Wine implementation, or where - the native DLL is known not to work, the built-in library - will be loaded first. In all other cases, the native DLL - takes load-order precedence. - - - The DefaultLoadOrder from the - [DllDefaults] section specifies for all DLLs which version - to try first. See manpage for explanation of the arguments. - - - The [DllOverrides] section deals with DLLs, which need a - different-from-default treatment. - - - The [DllPairs] section is for DLLs, which must be loaded in - pairs. In general, these are DLLs for either 16-bit or - 32-bit applications. In most cases in Windows, the 32-bit - version cannot be used without its 16-bit counterpart. For - Wine, it is customary that the 16-bit implementations rely - on the 32-bit implementations and cast the results back to - 16-bit arguments. Changing anything in this section is bound - to result in errors. - - - For the future, the Wine implementation of Windows DLL seems - to head towards unifying the 16 and 32 bit DLLs wherever - possible, resulting in larger DLLs. They are stored in the - dlls/ subdirectory using the 32-bit - name. - - - - - Understanding What DLLs Do - - - The following list briefly describes each of the DLLs - commonly found in Windows whose load order may be modified - during the configuration and compilation of Wine. - - - (See also ./DEVELOPER-HINTS or the - dlls/ subdirectory to see which DLLs - are currently being rewritten for Wine) - - - - -ADVAPI32.DLL: 32-bit application advanced programming interfaces - like crypto, systeminfo, security and event logging -AVIFILE.DLL: 32-bit application programming interfaces for the - Audio Video Interleave (AVI) Windows-specific - Microsoft audio-video standard -COMMCTRL.DLL: 16-bit common controls -COMCTL32.DLL: 32-bit common controls -COMDLG32.DLL: 32-bit common dialogs -COMMDLG.DLL: 16-bit common dialogs -COMPOBJ.DLL: OLE 16- and 32-bit compatibility libraries -CRTDLL.DLL: Microsoft C runtime -DCIMAN.DLL: 16-bit -DCIMAN32.DLL: 32-bit display controls -DDEML.DLL: DDE messaging -D3D*.DLL DirectX/Direct3D drawing libraries -DDRAW.DLL: DirectX drawing libraries -DINPUT.DLL: DirectX input libraries -DISPLAY.DLL: Display libraries -DPLAY.DLL, DPLAYX.DLL: DirectX playback libraries -DSOUND.DLL: DirectX audio libraries -GDI.DLL: 16-bit graphics driver interface -GDI32.DLL: 32-bit graphics driver interface -IMAGEHLP.DLL: 32-bit IMM API helper libraries (for PE-executables) -IMM32.DLL: 32-bit IMM API -IMGUTIL.DLL: -KERNEL32.DLL 32-bit kernel DLL -KEYBOARD.DLL: Keyboard drivers -LZ32.DLL: 32-bit Lempel-Ziv or LZ file compression - used by the installshield installers (???). -LZEXPAND.DLL: LZ file expansion; needed for Windows Setup -MMSYSTEM.DLL: Core of the Windows multimedia system -MOUSE.DLL: Mouse drivers -MPR.DLL: 32-bit Windows network interface -MSACM.DLL: Core of the Addressed Call Mode or ACM system -MSACM32.DLL: Core of the 32-bit ACM system - Audio Compression Manager ??? -MSNET32.DLL 32-bit network APIs -MSVFW32.DLL: 32-bit Windows video system -MSVIDEO.DLL: 16-bit Windows video system -OLE2.DLL: OLE 2.0 libraries -OLE32.DLL: 32-bit OLE 2.0 components -OLE2CONV.DLL: Import filter for graphics files -OLE2DISP.DLL, OLE2NLS.DLL: OLE 2.1 16- and 32-bit interoperability -OLE2PROX.DLL: Proxy server for OLE 2.0 -OLE2THK.DLL: Thunking for OLE 2.0 -OLEAUT32.DLL 32-bit OLE 2.0 automation -OLECLI.DLL: 16-bit OLE client -OLECLI32.DLL: 32-bit OLE client -OLEDLG.DLL: OLE 2.0 user interface support -OLESVR.DLL: 16-bit OLE server libraries -OLESVR32.DLL: 32-bit OLE server libraries -PSAPI.DLL: Proces Status API libraries -RASAPI16.DLL: 16-bit Remote Access Services libraries -RASAPI32.DLL: 32-bit Remote Access Services libraries -SHELL.DLL: 16-bit Windows shell used by Setup -SHELL32.DLL: 32-bit Windows shell (COM object?) -TAPI/TAPI32/TAPIADDR: Telephone API (for Modems) -W32SKRNL: Win32s Kernel ? (not in use for Win95 and up!) -WIN32S16.DLL: Application compatibility for Win32s -WIN87EM.DLL: 80387 math-emulation libraries -WINASPI.DLL: Advanced SCSI Peripheral Interface or ASPI libraries -WINDEBUG.DLL Windows debugger -WINMM.DLL: Libraries for multimedia thunking -WING.DLL: Libraries required to "draw" graphics -WINSOCK.DLL: Sockets APIs -WINSPOOL.DLL: Print spooler libraries -WNASPI32.DLL: 32-bit ASPI libraries -WSOCK32.DLL: 32-bit sockets APIs - - - - - The Wine initialization process - - - Wine has a rather complex startup procedure, so unlike many programs the best place to begin - exploring the code-base is not in fact at the main() function but instead - at some of the more straightforward DLLs that exist on the periphery such as MSI, the widget - library (in USER and COMCTL32) etc. The purpose of this section is to document and explain how - Wine starts up from the moment the user runs "wine myprogram.exe" to the point at which - myprogram gets control. - - - - First Steps - - - 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 - loader/glibc.c. The result of this check is an exec of either - wine-pthread or wine-kthread, potentially (on Linux) via - the preloader. 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. - - - - The Wine preloader is found in loader/preloader.c, 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 __libc_start_main which - initializes glibc before passing control to the main function as defined by the programmer. - - - - 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). - - - - 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. - - - - 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. - - - - - - Starting the emulator - - - The process of starting up the emulator itself is mostly one of chaining through various - initializer functions defined in the core libraries and DLLs: libwine, then NTDLL, then kernel32. - - - - Both the wine-pthread and wine-kthread binaries share a common main - function, defined in loader/main.c, so no matter which binary is selected - after the preloader has run we start here. This passes the information provided by the - preloader into libwine and then calls wine_init, defined - in libs/wine/loader.c. This is where the emulation really starts: - wine_init can, with the correct preparation, - be called from programs other than the wine loader itself. - - - - wine_init does some very basic setup tasks such as initializing the - debugging infrastructure, yet more address space manipulation (see the information on the - 4G/4G VM split in the address space chapter), before loading NTDLL - the core of both Wine and - the Windows NT series - and jumping to the __wine_process_init function defined - in dlls/ntdll/loader.c - - - - This function is responsible for initializing the primary Win32 environment. In thread_init(), - it sets up the TEB, the wineserver connection for the main thread and the process heap. See - the threading chapter for more information on this. - - - - Finally, it loads and jumps to __wine_kernel_init in kernel32.dll: this - is defined in dlls/kernel32/process.c. This is where the bulk of the work - is done. The kernel32 initialization code retrieves the startup info for the process from the - server, initializes the registry, sets up the drive mapping system and locale data, then - begins loading the requested application itself. Each process has a STARTUPINFO block that can - be passed into CreateProcess specifying various things like how the first - window should be displayed: this is sent to the new process via the wineserver. - - - - After determining the type of file given to Wine by the user (a Win32 EXE file, a Win16 EXE, a - Winelib app etc), the program is loaded into memory (which may involve loading and - initializing other DLLs, the bulk of Wines startup code), before control reaches the end of - __wine_kernel_init. This function ends with the new process stack being - initialized, and start_process being called on the new stack. Nearly there! - - - - The final element of initializing Wine is starting the newly loaded program - itself. start_process sets up the SEH backstop handler, calls - LdrInitializeThunk which performs the last part of the process - initialization (such as performing relocations and calling the DllMains with PROCESS_ATTACH), - grabs the entry point of the executable and then on this line: - - - - ExitProcess( entry( peb ) ); - - - - ... jumps to the entry point of the program. At this point the users program is running and - the API provided by Wine is ready to be used. When entry returns, - the ExitProcess API will be used to initialize a graceful shutdown. - - - - diff --git a/documentation/cvs-regression.sgml b/documentation/cvs-regression.sgml deleted file mode 100644 index a0dbd9782c..0000000000 --- a/documentation/cvs-regression.sgml +++ /dev/null @@ -1,142 +0,0 @@ - - How to do regression testing using CVS - - - 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 - NOT for casual users. - - - - - - Get the full CVS 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-<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). - - - - - untar it into a repository directory: - -cd /home/gerard -tar -zxf full-cvs-2003-08-18.tar.gz -mv wine repository - - - - - - extract a new destination directory. This directory must - not be in a subdirectory of the repository else - cvs will think it's part of the - repository and deny you an extraction in the repository: - -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 - - - - 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. - - - 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. - - - - - you will have now in the ~/wine - directory an image of the CVS tree, on the client side. - Now update this image to the date you want: - -cd /home/gerard/wine -cvs update -PAd -D "2004-08-23 CDT" - - - - The date format is YYYY-MM-DD HH:MM:SS. - 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 - - http://www.winehq.org/hypermail/wine-cvs - - - 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: - -cvs update: tsx11/ts_xf86dga2.c is no longer in the repository - - - - cvs update is not limited to upgrade to - a newer version as I have believed for - far too long :-( - - - - - Now proceed as for a normal update: - - -./configure -make depend && make - - - 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. - - - 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 make distclean before going back in - time, so you have to make everything if you don't backup the older - version) - - - 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 : - -cvs update -PAd -D "2004-08-23 15:17:25 CDT" - - This will allow you to find easily the exact patch that did it. - - - - - If you find the patch that is the cause of the problem, you have - almost won; report about it to - Wine Bugzilla - 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 :-) - - - - - - diff --git a/documentation/i18n.sgml b/documentation/i18n.sgml deleted file mode 100644 index b2498d3a1a..0000000000 --- a/documentation/i18n.sgml +++ /dev/null @@ -1,66 +0,0 @@ - - Internationalization - - - Adding New Languages - - - 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. - - - - Language dependent resources reside in files - named somefile_Xx.rc or - Xx.rc, where Xx - is your language abbreviation (look for it in - include/winnls.h). These are included - in a master file named somefile.rc or - rsrc.rc, located in the same - directory as the language files. - - - - To add a new language to one of these resources you - need to make a copy of the English resource (located - in the somefile_En.rc file) over to - your somefile_Xx.rc file, include this - file in the master somefile.rc 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. - - - - In menus, the character "&" means that the next - character will be highlighted and that pressing that - letter will select the item. You should place these - "&" characters suitably for your language, not just - copy the positions from English. In particular, - items within one menu should have different highlighted - letters. - - - - To get a list of the files that need translating, - run the following command in the root of your Wine tree: - find -name "*En.rc". - - - - When adding a new language, also make sure the parameters - defined in ./dlls/kernel/nls/*.nls - fit your local habits and language. - - - - - diff --git a/documentation/implementation.sgml b/documentation/implementation.sgml deleted file mode 100644 index e190f53b80..0000000000 --- a/documentation/implementation.sgml +++ /dev/null @@ -1,608 +0,0 @@ - - Low-level Implementation - Details of Wine's Low-level Implementation... - - -Keyboard - - -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. - - -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. - - -To do this, open the file -dlls/x11drv/keyboard.c and take a look -at the existing tables. Make a backup copy of it, especially -if you don't use CVS. - - -What you really would need to do, is find out which scancode -each key needs to generate. Find it in the -main_key_scan table, which looks like -this: - - -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) */ -}; - - -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 -keyboard.c. It also shows that if there -is no 102nd key, you can skip that. - - -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 -main_key_scan, 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 Z), must be placed on a separate -line after the last line. - - -For example, my Norwegian keyboard looks like this - - -§ ! " # ¤ % & / ( ) = ? ` 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 < , . - - -Ctrl Alt Spacebar AltGr Ctrl - - -Note the 102nd key, which is the <> key, to -the left of Z. The character to the right of -the main character is the character generated by -AltGr. - - -This keyboard is defined as follows: - - -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",",;",".:","-_", -"<>" -}; - - -Except that " and \ needs to be quoted with a backslash, and -that the 102nd key is on a separate line, it's pretty -straightforward. - - -After you have written such a table, you need to add it to the -main_key_tab[] layout index table. This -will look like this: - - -static struct { -WORD lang, ansi_codepage, oem_codepage; -const char (*key)[MAIN_LEN][4]; -} main_key_tab[]={ -... -... -{MAKELANGID(LANG_NORWEGIAN,SUBLANG_DEFAULT), 1252, 865, &main_key_NO}, -... - - -After you have added your table, recompile Wine and test that -it works. If it fails to detect your table, try running - - -WINEDEBUG=+key,+keyboard wine > key.log 2>&1 - - - and look in the resulting key.log file to - find the error messages it gives for your layout. - - - Note that the LANG_* and - SUBLANG_* definitions are in - include/winnls.h, 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 - (SUBLANG * 0x400 + LANG), so, for example - the combination LANG_NORWEGIAN (0x14) and - SUBLANG_DEFAULT (0x1) will be (in hex) - 14 + 1*400 = 414, so since I'm Norwegian, I - could look for 0414 in the WINEDEBUG output - to find out why my keyboard won't detect. - - - Once it works, submit it to the Wine project. If you use CVS, - you will just have to do - - -cvs -z3 diff -u dlls/x11drv/keyboard.c > layout.diff - - - from your main Wine directory, then submit - layout.diff to - wine-patches@winehq.org along with a brief note - of what it is. - - - If you don't use CVS, you need to do - - -diff -u the_backup_file_you_made dlls/x11drv/keyboard.c > layout.diff - - - and submit it as explained above. - - - 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. - - - - - - Undocumented APIs - - - 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 - esp register, points to the last valid entry; - thus, the operation of pushing a value onto the stack involves - decrementing esp and then moving the value into - the memory pointed to by esp - (i.e., push p in assembly resembles - *(--esp) = p; in C). Removing (popping) - values off the stack is the reverse (i.e., pop p - corresponds to p = *(esp++); in C). - - - - In the stdcall calling convention, arguments are - pushed onto the stack right-to-left. For example, the C call - myfunction(40, 20, 70, 30); is expressed in - Intel assembly as: - - push 30 - push 70 - push 20 - push 40 - call myfunction - - The called function is responsible for removing the arguments - off the stack. Thus, before the call to myfunction, the - stack would look like: - - [local variable or temporary] - [local variable or temporary] - 30 - 70 - 20 - esp -> 40 - - After the call returns, it should look like: - - [local variable or temporary] - esp -> [local variable or temporary] - - - - - 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. - - - - 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. - - - - 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 (ntdll.dll) 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. - - - - 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, ret hhll (where - hhll is the number of bytes to remove, i.e. the - number of arguments times 4), contains the bytes - 0xc2 ll hh in memory. It is a reasonable - assumption that few, if any, functions take more than 16 arguments; - therefore, simply searching for - hh == 0 && ll < 0x40 starting from the - address of a function yields the correct number of arguments most - of the time. - - - - Of course, this is not without errors. ret 00ll - is not the only instruction that can have the byte sequence - 0xc2 ll 0x0; for example, - push 0x000040c2 has the byte sequence - 0x68 0xc2 0x40 0x0 0x0, 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. - - - - Much more troublesome is the non-linear flow of a function. For - example, consider the following two functions: - - somefunction1: - jmp somefunction1_impl - - somefunction2: - ret 0004 - - somefunction1_impl: - ret 0008 - - In this case, we would incorrectly detect both - somefunction1 and - somefunction2 as taking only a single - argument, whereas somefunction1 really - takes two arguments. - - - - With these limitations in mind, it is possible to implement more stubs - in Wine and, eventually, the functions themselves. - - - - - Accelerators - - - There are three differently sized - accelerator structures exposed to the user: - - - - - Accelerators in NE resources. This is also the internal - layout of the global handle HACCEL (16 and - 32) in Windows 95 and Wine. Exposed to the user as Win16 - global handles HACCEL16 and - HACCEL32 by the Win16/Win32 API. - These are 5 bytes long, with no padding: - -BYTE fVirt; -WORD key; -WORD cmd; - - - - - - Accelerators in PE resources. They are exposed to the user - only by direct accessing PE resources. - These have a size of 8 bytes: - - -BYTE fVirt; -BYTE pad0; -WORD key; -WORD cmd; -WORD pad1; - - - - - Accelerators in the Win32 API. These are exposed to the - user by the CopyAcceleratorTable - and CreateAcceleratorTable functions - in the Win32 API. - These have a size of 6 bytes: - - -BYTE fVirt; -BYTE pad0; -WORD key; -WORD cmd; - - - - - - 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 ACCEL - is defined using #pragma(2) for the - compiler but without any packing for RC, so it will assume - #pragma(4). - - - - - - Doing A Hardware Trace - - - 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. - - - 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. - - - 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 config - (usually in ~/.wine/) and in the - ports section add the following two lines - - -read=0x378,0x379,0x37a,0x37c,0x77a -write=0x378,x379,0x37a,0x37c,0x77a - - - 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. - - - When starting wine use the following command line, where - XXXX is the program you need to run in - order to access your scanner, and YYYY is - the file your trace will be stored in: - - -WINEDEBUG=+io wine XXXX 2> >(sed 's/^[^:]*:io:[^ ]* //' > YYYY) - - - 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. - - - You will need to postprocess the output into a more manageable - format, using the shrink program. First - you need to compile the source (which is located at the end of - this section): - -cc shrink.c -o shrink - - - - Use the shrink program to reduce the - physical size of the raw log as follows: - - -cat log | shrink > log2 - - - The trace has the basic form of - - -XXXX > YY @ ZZZZ:ZZZZ - - - where XXXX is the port in hexadecimal being - accessed, YY is the data written (or read) - from the port, and ZZZZ:ZZZZ 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. - - -> data was written to the port -< data was read from the port - - - 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 - - -0x378 > 55 @ 0297:01ec -0x37a > 05 @ 0297:01f5 -0x379 < 8f @ 0297:01fa -0x37a > 04 @ 0297:0211 -0x378 > aa @ 0297:01ec -0x37a > 05 @ 0297:01f5 -0x379 < 8f @ 0297:01fa -0x37a > 04 @ 0297:0211 -0x378 > 00 @ 0297:01ec -0x37a > 05 @ 0297:01f5 -0x379 < 8f @ 0297:01fa -0x37a > 04 @ 0297:0211 -0x378 > 00 @ 0297:01ec -0x37a > 05 @ 0297:01f5 -0x379 < 8f @ 0297:01fa -0x37a > 04 @ 0297:0211 -0x378 > 00 @ 0297:01ec -0x37a > 05 @ 0297:01f5 -0x379 < 8f @ 0297:01fa -0x37a > 04 @ 0297:0211 -0x378 > 00 @ 0297:01ec -0x37a > 05 @ 0297:01f5 -0x379 < 8f @ 0297:01fa -0x37a > 04 @ 0297:0211 - - - As you can see there is a repeating structure starting at - address 0297:01ec 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 0x05 to the control - port, then a value which always seems to - 0x8f is read from the status port at which - point a byte 0x04 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. - - -#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 < 10; loop++) - if ((value = r_str(udpp_base)) & 0x80) - { - w_ctr(udpp_base, 0x04); - return value & 0xf8; - } - - return (value & 0xf8) | 0x01; -} - - - 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. - - - 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) - - -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 - - - From this it is easy to see that put - 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. - - - - The following is the shrink.c program: - -/* Copyright David Campbell <campbell@torque.net> */ -#include <stdio.h> -#include <string.h> - -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 > 1) - printf ("# Last line repeated %i times #\n", count); - printf ("%s", buff); - strcpy (lastline, buff); - count = 1; - } - else count++; - } - return 0; -} - - - - - - - diff --git a/documentation/porting.sgml b/documentation/porting.sgml deleted file mode 100644 index a7326702e5..0000000000 --- a/documentation/porting.sgml +++ /dev/null @@ -1,219 +0,0 @@ - - Porting Wine to new Platforms - - This document provides a few tips on porting Wine to your - favorite (UNIX-based) operating system. - - - - Porting Wine to new Platforms - - Why <symbol>#ifdef MyOS</symbol> is probably a mistake. - - - Operating systems change. Maybe yours doesn't have the - foo.h header, but maybe a future - version will have it. If you want to #include - <foo.h>, it doesn't matter what operating - system you are using; it only matters whether - foo.h is there. - - - Furthermore, operating systems change names or "fork" into - several ones. An #ifdef MyOs will break - over time. - - - If you use the feature of autoconf -- the - Gnu auto-configuration utility -- wisely, you will help - future porters automatically because your changes will test - for features, not names of operating - systems. A feature can be many things: - - - - - - existence of a header file - - - - - existence of a library function - - - - - existence of libraries - - - - - bugs in header files, library functions, the compiler, ... - - - - - You will need Gnu Autoconf, which you can get from your - friendly Gnu mirror. This program takes Wine's - configure.ac file and produces a - configure shell script that users use - to configure Wine to their system. - - - There are exceptions to the "avoid - #ifdef MyOS" 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 - autoconf's HAVE_* - symbols in Wine's headers, as these may be used by Winelib - users who may not be using a configure - script. - - - Let's now turn to specific porting problems and how to solve - them. - - - - - MyOS doesn't have the <filename>foo.h</filename> header! - - - This first step is to make autoconf check - for this header. In configure.in you - add a segment like this in the section that checks for - header files (search for "header files"): - - -AC_CHECK_HEADER(foo.h, AC_DEFINE(HAVE_FOO_H)) - - - If your operating system supports a header file with the - same contents but a different name, say - bar.h, add a check for that also. - - - Now you can change - - -#include <foo.h> - - - to - - -#ifdef HAVE_FOO_H -#include <foo.h> -#elif defined (HAVE_BAR_H) -#include <bar.h> -#endif - - - 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 #else section to the - conditional. Avoid this if you can. - - - You will also need to add #undef HAVE_FOO_H - (etc.) to include/config.h.in - - - Finish up with make configure and - ./configure. - - - - - MyOS doesn't have the <function>bar</function> function! - - - A typical example of this is the - memmove function. To solve this - problem you would add memmove to the - list of functions that autoconf checks - for. In configure.in you search for - AC_CHECK_FUNCS and add - memmove. (You will notice that someone - already did this for this particular function.) - - - Secondly, you will also need to add #undef - HAVE_BAR to - include/config.h.in - - - The next step depends on the nature of the missing function. - - - - - Case 1: - - - It's easy to write a complete implementation of the - function. (memmove belongs to - this case.) - - - You add your implementation in - misc/port.c surrounded by - #ifndef HAVE_MEMMOVE and - #endif. - - - You might have to add a prototype for your function. - If so, include/miscemu.h might be the place. Don't - forget to protect that definition by #ifndef - HAVE_MEMMOVE and #endif also! - - - - - Case 2: - - - A general implementation is hard, but Wine is only - using a special case. - - - An example is the various wait - calls used in SIGNAL_child from - loader/signal.c. Here we have a - multi-branch case on features: - - -#ifdef HAVE_THIS -... -#elif defined (HAVE_THAT) -... -#elif defined (HAVE_SOMETHING_ELSE) -... -#endif - - - 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. - - - - - - Finish up with make configure and - ./configure. - - - - - - - - diff --git a/documentation/wine-devel.sgml b/documentation/wine-devel.sgml index 8217b98d6b..c8243a8762 100644 --- a/documentation/wine-devel.sgml +++ b/documentation/wine-devel.sgml @@ -1,24 +1,20 @@ - - + + + - + - + + + - - - - - - - ]> @@ -114,31 +110,23 @@ Developing Wine &debugger; - &documentation; - &patches; + &debugging; + &otherdebug; + &codingpractice; &testing; - &i18n; + &documentation; Wine Architecture &architecture; - &debugging; + &kernel; + &graphical; + &windowing; &ole; &opengl; &ddraw; &multimedia; - &threading; - - - Advanced Topics - &implementation; - &porting; - &consoles; - &address-space; - &cvs-regression; - - diff --git a/documentation/winedev-coding.sgml b/documentation/winedev-coding.sgml new file mode 100644 index 0000000000..e8f80cd2cc --- /dev/null +++ b/documentation/winedev-coding.sgml @@ -0,0 +1,514 @@ + + Coding Practice + + + This chapter describes the relevant coding practices in Wine, + that you should be aware of before doing any serious development + in Wine. + + + Patch Format + + + Patches are submitted via email to the Wine patches mailing + list, wine-patches@winehq.org. Your patch + should include: + + + + + + A meaningful subject (very short description of patch) + + + + + A long (paragraph) description of what was wrong and what + is now better. (recommended) + + + + + A change log entry (short description of what was + changed). + + + + + The patch in diff -u format + + + + + + + + cvs diff -u works great for the common case + where a file is edited. However, if you add or remove a file + cvs diff will not report that correctly so + make sure you explicitly take care of this rare case. + + + For additions simply include them by appending the + diff -u /dev/null /my/new/file output of + them to any cvs diff -u output you may + have. Alternatively, use diff -Nu olddir/ + newdir/ in case of multiple new files to add. + + + For removals, clearly list the files in the description of the + patch. + + + 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 diff -u against + the old file. I.E. + + +diff -u file.old file.c > file.txt + + + + + Some notes about style + + + There are a few conventions that about coding style that have + been adopted over the years of development. The rational for + these rules is explained for each one. + + + + + 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. + + + + + 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. + + + + + Tabs are not forbidden but discouraged. A tab is defined + as 8 characters and the usual amount of indentation is 4 + characters. + + + + + C++ style comments are discouraged since some compilers + choke on them. + + + + + Commenting out a block of code is usually done by + enclosing it in #if 0 ... #endif + Statements. For example. + + +/* note about reason for commenting block */ +#if 0 +code +code /* comments */ +code +#endif + + + The reason for using this method is that it does not + require that you edit comments that may be inside the + block of code. + + + + + 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. + + + + + Code is usually limited to 80 columns. This helps prevent + mailers mangling patches by line wrap. Also it generally + makes code easier to read. + + + + + 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. + + + + + Inline attachments with Outlook Express + + Outlook Express is notorious for mangling + attachments. Giving the patch a .txt + extension and attaching will solve the problem for most + mailers including Outlook. Also, there is a way to enable + Outlook Express send .diff + attachments. + + + You need following two things to make it work. + + + + + Make sure that .diff 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. + + + + + Using regedit add key "Content Type" + with value "text/plain" to the + .diff extension under + HKEY_CLASSES_ROOT (same as for .txt + extension). This tells OE to use + Content-Type: text/plain instead of + application/octet-stream. + + + + + 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. + + + + Alexandre's Bottom Line + + The basic rules are: no attachments, no MIME crap, no + line wrapping, a single patch per mail. Basically if I can't + do "cat raw_mail | patch -p0" it's in the + wrong format. + + + + + + Quality Assurance + + + (Or, "How do I get Alexandre to apply my patch quickly so I + can build on it and it will not go stale?") + + + 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! cvs update is your + friend! + + + 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 make test. You may + need to run make testclean to undo the results + of a previous test run. See the testing guide for + more details on Wine's conformance tests. + + + + + Porting Wine to new Platforms + + This document provides a few tips on porting Wine to your + favorite (UNIX-based) operating system. + + + + + Why <symbol>#ifdef MyOS</symbol> is probably a mistake. + + + + Operating systems change. Maybe yours doesn't have the + foo.h header, but maybe a future + version will have it. If you want to #include + <foo.h>, it doesn't matter what operating + system you are using; it only matters whether + foo.h is there. + + + Furthermore, operating systems change names or "fork" into + several ones. An #ifdef MyOs will break + over time. + + + If you use the feature of autoconf -- the + Gnu auto-configuration utility -- wisely, you will help + future porters automatically because your changes will test + for features, not names of operating + systems. A feature can be many things: + + + + + + existence of a header file + + + + + existence of a library function + + + + + existence of libraries + + + + + bugs in header files, library functions, the compiler, ... + + + + + You will need Gnu Autoconf, which you can get from your + friendly Gnu mirror. This program takes Wine's + configure.ac file and produces a + configure shell script that users use + to configure Wine to their system. + + + There are exceptions to the "avoid + #ifdef MyOS" 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 + autoconf's HAVE_* + symbols in Wine's headers, as these may be used by Winelib + users who may not be using a configure + script. + + + Let's now turn to specific porting problems and how to solve + them. + + + + + + MyOS doesn't have the <filename>foo.h</filename> header! + + + + This first step is to make autoconf check + for this header. In configure.in you + add a segment like this in the section that checks for + header files (search for "header files"): + + +AC_CHECK_HEADER(foo.h, AC_DEFINE(HAVE_FOO_H)) + + + If your operating system supports a header file with the + same contents but a different name, say + bar.h, add a check for that also. + + + Now you can change + + +#include <foo.h> + + + to + + +#ifdef HAVE_FOO_H +#include <foo.h> +#elif defined (HAVE_BAR_H) +#include <bar.h> +#endif + + + 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 #else section to the + conditional. Avoid this if you can. + + + You will also need to add #undef HAVE_FOO_H + (etc.) to include/config.h.in + + + Finish up with make configure and + ./configure. + + + + + + MyOS doesn't have the <function>bar</function> function! + + + + A typical example of this is the memmove + function. To solve this problem you would add + memmove to the list of functions that + autoconf checks for. In + configure.in you search for + AC_CHECK_FUNCS and add + memmove. (You will notice that someone + already did this for this particular function.) + + + Secondly, you will also need to add + #undef HAVE_BAR to + include/config.h.in + + + The next step depends on the nature of the missing function. + + + + + Case 1: + + + It's easy to write a complete implementation of the + function. (memmove belongs to + this case.) + + + You add your implementation in + misc/port.c surrounded by + #ifndef HAVE_MEMMOVE and + #endif. + + + You might have to add a prototype for your function. + If so, include/miscemu.h might be + the place. Don't forget to protect that definition by + #ifndef HAVE_MEMMOVE and + #endif also! + + + + + Case 2: + + + A general implementation is hard, but Wine is only + using a special case. + + + An example is the various wait + calls used in SIGNAL_child from + loader/signal.c. Here we have a + multi-branch case on features: + + +#ifdef HAVE_THIS +... +#elif defined (HAVE_THAT) +... +#elif defined (HAVE_SOMETHING_ELSE) +... +#endif + + + 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. + + + + + + Finish up with make configure and + ./configure. + + + + + + Adding New Languages + + + 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. + + + + Language dependent resources reside in files + named somefile_Xx.rc or + Xx.rc, where Xx + is your language abbreviation (look for it in + include/winnls.h). These are included + in a master file named somefile.rc or + rsrc.rc, located in the same + directory as the language files. + + + + To add a new language to one of these resources you + need to make a copy of the English resource (located + in the somefile_En.rc file) over to + your somefile_Xx.rc file, include this + file in the master somefile.rc 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. + + + + In menus, the character "&" means that the next + character will be highlighted and that pressing that + letter will select the item. You should place these + "&" characters suitably for your language, not just + copy the positions from English. In particular, + items within one menu should have different highlighted + letters. + + + + To get a list of the files that need translating, + run the following command in the root of your Wine tree: + find -name "*En.rc". + + + + When adding a new language, also make sure the parameters + defined in ./dlls/kernel/nls/*.nls + fit your local habits and language. + + + + + diff --git a/documentation/winedev-graphical.sgml b/documentation/winedev-graphical.sgml new file mode 100644 index 0000000000..72c3a04ebb --- /dev/null +++ b/documentation/winedev-graphical.sgml @@ -0,0 +1,40 @@ + + Graphical modules + + GDI Module + + + X Windows System interface + + + 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 XInitThreads()). However, + Wine does not use this approach. Instead Wine performs its + own synchronization using the + wine_tsx11_lock() / wine_tsx11_unlock() + functions. This locking protects library access + with a critical section, and also arranges things so that + X libraries compiled without + (eg. with global errno variable) will + work with Wine. + + + In the past, all calls to X used to go through a wrapper called + TSX...() (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. + + + + + + diff --git a/documentation/winedev-kernel.sgml b/documentation/winedev-kernel.sgml new file mode 100644 index 0000000000..700835f97f --- /dev/null +++ b/documentation/winedev-kernel.sgml @@ -0,0 +1,823 @@ + + Kernel modules + + 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. + + + NTDLL + + NTDLL provides most of the services you'd expect from a + kernel. + + + 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. + + + Wine also provide fibers (which is the Windows name of + co-routines). + + + 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). + + + + File management + + 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. + + + File handles can be waitable objects, as Windows define + them. + + + 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). + + + FIXME: this should be enhanced and updated to latest work + on FS. + + + + + Synchronization + + 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. + + + + + Module (DLL) loading + + Wine is able to load any NE and PE module. In all cases, + the module's binary code is directly executed by the + processor. + + + + + Device management + + Wine allows usage a wide variety of devices: + + + + Communication ports are mapped to Unix + communication ports (if they have sufficient + permissions). + + + + + Parallel ports are mapped to Unix parallel ports (if + they have sufficient permissions). + + + + + CDROM: the Windows device I/O control calls are + mapped onto Unix ioctl(). + + + + + 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. + + + Wine will not support native VxD. + + + + + + + Multi-threading in Wine + + + 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. + + + + 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. + + + + Threading support in Win32 + + + 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. + + + + 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! + + + + Win32 provides many different ways you can make your code + thread safe however the most common are critical + section and the interlocked + functions. 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 + EnterCriticalSection and + LeaveCriticalSection. The first call + to EnterCriticalSection 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 + LeaveCriticalSection again. + + + + 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: + + + +if (res != ERROR_SUCCESS) return res; + + + + is extremely suspect in a function that also contains a + call to EnterCriticalSection. Be + careful. + + + + If a thread blocks while waiting for another thread to + leave a critical section, you will see an error from the + RtlpWaitForCriticalSection 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 + LeaveCriticalSection, 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. + + + + Another popular mechanism available is the use of + functions like InterlockedIncrement + and InterlockedExchange. 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. + + + + 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 TlsAlloc + 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. + + + + + SysLevels + + + 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. + + + + When entering a syslevel, the code (in + dlls/kernel/syslevel.c) 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. + + + + Throughout the code you may see calls to + _ConfirmSysLevel() and + _CheckNotSysLevel(). 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, + _CheckNotSysLevel() 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. + + + + + + POSIX threading vs kernel threading + + + 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. + + + + 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. + + + + 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 clone(2) syscall. Pthreads + provides a nicer (more portable) interface to this + functionality and also provides APIs for controlling + mutexes. There is a + good tutorial on pthreads available if you want + to learn more. + + + + 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 clone + 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. + + + + The solution was simple yet ingenius: Wine would provide + its own implementation of the pthread library + inside 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. + + + + 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. + + + + The fake pthread implementation can be found in + loader/kthread.c, 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. + + + + 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. + + + + 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 + loader/kthread.c and + loader/pthread.c 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. + + + + 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. + + + + + The Win32 thread environment + + + 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. + + + + The first thing Win32 code requires is the + TEB 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 + include/thread.h, 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. + + + + A pointer to the TEB is stored in the %fs register and can + be accessed using NtCurrentTeb() 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 + lib/wine/ldt.c. + + + + 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: + + + movl %esp, %fs:0 + + + ... 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. + + + + 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). + + + + + + + KERNEL Module + + + FIXME: Needs some content... + + + Consoles in Wine + + 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. + + + The following table describes the main implementation + differences between the three approaches. + + Function consoles implementation comparison + + + + Function + Bare streams + Wineconsole & user backend + Wineconsole & curses backend + + + + + + Console as a Win32 Object (and associated + handles) + + + 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 + (GetConsoleMode / + SetConsoleMode) are not + supported. + + + 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. + + + 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. + + + + + Inheritance (including handling in + CreateProcess of + CREATE_DETACHED, + CREATE_NEW_CONSOLE flags). + + + Not supported. Every process child of a process + will inherit the Unix streams, so will also + inherit the Win32 standard streams. + + + Fully supported (each new console creation will + be handled by the creation of a new USER32 + window) + + + 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. + + + + + ReadFile / + WriteFile + operations + + Fully supported + Fully supported + Fully supported + + + + Screen-buffer manipulation (creation, deletion, + resizing...) + + Not supported + Fully supported + + Partly supported (this won't work too well as we + don't control (so far) the size of underlying + Unix terminal + + + + + APIs for reading/writing screen-buffer content, + cursor position + + Not supported + Fully supported + Fully supported + + + + APIs for manipulating the rendering window size + + Not supported + Fully supported + + Partly supported (this won't work too well as we + don't control (so far) the size of underlying + Unix terminal + + + + + Signaling (in particular, Ctrl-C handling) + + + Nothing is done, which means that Ctrl-C will + generate (as usual) a + SIGINT which will terminate + the program. + + + Partly supported (Ctrl-C behaves as expected, + however the other Win32 CUI signaling isn't + properly implemented). + + + Partly supported (Ctrl-C behaves as expected, + however the other Win32 CUI signaling isn't + properly implemented). + + + + +
+
+ + + The Win32 objects behind a console can be created in + several occasions: + + + + When the program is started from wineconsole, a new + console object is created and will be used + (inherited) by the process launched from + wineconsole. + + + + + When a program, which isn't attached to a console, + calls AllocConsole, 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. + + + + + + Please also note, that starting a child process with the + CREATE_NEW_CONSOLE flag, will end-up + calling AllocConsole in the child + process, hence creating a wineconsole with the USER32 + backend. + +
+
+ + + + The Wine initialization process + + + Wine has a rather complex startup procedure, so unlike many + programs the best place to begin exploring the code-base is + not in fact at the + main() function but instead at some of the + more straightforward DLLs that exist on the periphery such as + MSI, the widget library (in USER and COMCTL32) etc. The purpose + of this section is to document and explain how Wine starts up + from the moment the user runs "wine myprogram.exe" to the point + at which myprogram gets control. + + + + First Steps + + + 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 + loader/glibc.c. The result of this check is an exec of either + wine-pthread or wine-kthread, potentially (on Linux) via + the preloader. 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. + + + + The Wine preloader is found in loader/preloader.c, 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 __libc_start_main which + initializes glibc before passing control to the main function as defined by the programmer. + + + + 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). + + + + 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. + + + + 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. + + + + + + Starting the emulator + + + The process of starting up the emulator itself is mostly one of chaining through various + initializer functions defined in the core libraries and DLLs: libwine, then NTDLL, then kernel32. + + + + Both the wine-pthread and wine-kthread binaries share a common main + function, defined in loader/main.c, so no matter which binary is selected + after the preloader has run we start here. This passes the information provided by the + preloader into libwine and then calls wine_init, defined + in libs/wine/loader.c. This is where the emulation really starts: + wine_init can, with the correct preparation, + be called from programs other than the wine loader itself. + + + + wine_init does some very basic setup tasks such as initializing the + debugging infrastructure, yet more address space manipulation (see the information on the + 4G/4G VM split in the address space chapter), before loading NTDLL - the core of both Wine and + the Windows NT series - and jumping to the __wine_process_init function defined + in dlls/ntdll/loader.c + + + + This function is responsible for initializing the primary Win32 environment. In thread_init(), + it sets up the TEB, the wineserver connection for the main thread and the process heap. See + the threading chapter for more information on this. + + + + Finally, it loads and jumps to __wine_kernel_init in kernel32.dll: this + is defined in dlls/kernel32/process.c. This is where the bulk of the work + is done. The kernel32 initialization code retrieves the startup info for the process from the + server, initializes the registry, sets up the drive mapping system and locale data, then + begins loading the requested application itself. Each process has a STARTUPINFO block that can + be passed into CreateProcess specifying various things like how the first + window should be displayed: this is sent to the new process via the wineserver. + + + + After determining the type of file given to Wine by the user (a Win32 EXE file, a Win16 EXE, a + Winelib app etc), the program is loaded into memory (which may involve loading and + initializing other DLLs, the bulk of Wines startup code), before control reaches the end of + __wine_kernel_init. This function ends with the new process stack being + initialized, and start_process being called on the new stack. Nearly there! + + + + The final element of initializing Wine is starting the newly loaded program + itself. start_process sets up the SEH backstop handler, calls + LdrInitializeThunk which performs the last part of the process + initialization (such as performing relocations and calling the DllMains with PROCESS_ATTACH), + grabs the entry point of the executable and then on this line: + + + +ExitProcess( entry( peb ) ); + + + + ... jumps to the entry point of the program. At this point the users program is running and + the API provided by Wine is ready to be used. When entry returns, + the ExitProcess API will be used to initialize a graceful shutdown. + + + +
+ + diff --git a/documentation/winedev-otherdebug.sgml b/documentation/winedev-otherdebug.sgml new file mode 100644 index 0000000000..da501c4eb1 --- /dev/null +++ b/documentation/winedev-otherdebug.sgml @@ -0,0 +1,508 @@ + + Other debugging techniques + + Doing A Hardware Trace + + + 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. + + + 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. + + + 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 config + (usually in ~/.wine/) and in the + ports section add the following two lines + + +read=0x378,0x379,0x37a,0x37c,0x77a +write=0x378,x379,0x37a,0x37c,0x77a + + + 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. + + + When starting wine use the following command line, where + XXXX is the program you need to run in + order to access your scanner, and YYYY is + the file your trace will be stored in: + + +WINEDEBUG=+io wine XXXX 2> >(sed 's/^[^:]*:io:[^ ]* //' > YYYY) + + + 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. + + + You will need to postprocess the output into a more manageable + format, using the shrink program. First + you need to compile the source (which is located at the end of + this section): + +cc shrink.c -o shrink + + + + Use the shrink program to reduce the + physical size of the raw log as follows: + + +cat log | shrink > log2 + + + The trace has the basic form of + + +XXXX > YY @ ZZZZ:ZZZZ + + + where XXXX is the port in hexadecimal being + accessed, YY is the data written (or read) + from the port, and ZZZZ:ZZZZ 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. + + +> data was written to the port +< data was read from the port + + + 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 + + +0x378 > 55 @ 0297:01ec +0x37a > 05 @ 0297:01f5 +0x379 < 8f @ 0297:01fa +0x37a > 04 @ 0297:0211 +0x378 > aa @ 0297:01ec +0x37a > 05 @ 0297:01f5 +0x379 < 8f @ 0297:01fa +0x37a > 04 @ 0297:0211 +0x378 > 00 @ 0297:01ec +0x37a > 05 @ 0297:01f5 +0x379 < 8f @ 0297:01fa +0x37a > 04 @ 0297:0211 +0x378 > 00 @ 0297:01ec +0x37a > 05 @ 0297:01f5 +0x379 < 8f @ 0297:01fa +0x37a > 04 @ 0297:0211 +0x378 > 00 @ 0297:01ec +0x37a > 05 @ 0297:01f5 +0x379 < 8f @ 0297:01fa +0x37a > 04 @ 0297:0211 +0x378 > 00 @ 0297:01ec +0x37a > 05 @ 0297:01f5 +0x379 < 8f @ 0297:01fa +0x37a > 04 @ 0297:0211 + + + As you can see there is a repeating structure starting at + address 0297:01ec 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 0x05 to the control + port, then a value which always seems to + 0x8f is read from the status port at which + point a byte 0x04 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. + + +#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 < 10; loop++) + if ((value = r_str(udpp_base)) & 0x80) + { + w_ctr(udpp_base, 0x04); + return value & 0xf8; + } + + return (value & 0xf8) | 0x01; +} + + + 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. + + + 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) + + +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 + + + From this it is easy to see that put + 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. + + + + The following is the shrink.c program: + +/* Copyright David Campbell <campbell@torque.net> */ +#include <stdio.h> +#include <string.h> + +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 > 1) + printf ("# Last line repeated %i times #\n", count); + printf ("%s", buff); + strcpy (lastline, buff); + count = 1; + } + else count++; + } + return 0; +} + + + + + + Understanding undocumented APIs + + + 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 + esp register, points to the last valid entry; + thus, the operation of pushing a value onto the stack involves + decrementing esp and then moving the value into + the memory pointed to by esp + (i.e., push p in assembly resembles + *(--esp) = p; in C). Removing (popping) + values off the stack is the reverse (i.e., pop p + corresponds to p = *(esp++); in C). + + + + In the stdcall calling convention, arguments are + pushed onto the stack right-to-left. For example, the C call + myfunction(40, 20, 70, 30); is expressed in + Intel assembly as: + + push 30 + push 70 + push 20 + push 40 + call myfunction + + The called function is responsible for removing the arguments + off the stack. Thus, before the call to myfunction, the + stack would look like: + + [local variable or temporary] + [local variable or temporary] + 30 + 70 + 20 + esp -> 40 + + After the call returns, it should look like: + + [local variable or temporary] + esp -> [local variable or temporary] + + + + + 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. + + + + 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. + + + + 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 (ntdll.dll) 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. + + + + 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, ret hhll (where + hhll is the number of bytes to remove, i.e. the + number of arguments times 4), contains the bytes + 0xc2 ll hh in memory. It is a reasonable + assumption that few, if any, functions take more than 16 arguments; + therefore, simply searching for + hh == 0 && ll < 0x40 starting from the + address of a function yields the correct number of arguments most + of the time. + + + + Of course, this is not without errors. ret 00ll + is not the only instruction that can have the byte sequence + 0xc2 ll 0x0; for example, + push 0x000040c2 has the byte sequence + 0x68 0xc2 0x40 0x0 0x0, 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. + + + + Much more troublesome is the non-linear flow of a function. For + example, consider the following two functions: + + somefunction1: + jmp somefunction1_impl + + somefunction2: + ret 0004 + + somefunction1_impl: + ret 0008 + + In this case, we would incorrectly detect both + somefunction1 and + somefunction2 as taking only a single + argument, whereas somefunction1 really + takes two arguments. + + + + With these limitations in mind, it is possible to implement + more stubs + in Wine and, eventually, the functions themselves. + + + + How to do regression testing using CVS + + + 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 NOT for casual users. + + + + + + Get the full CVS 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-<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). + + + + + untar it into a repository directory: + +cd /home/gerard +tar -zxf full-cvs-2003-08-18.tar.gz +mv wine repository + + + + + + extract a new destination directory. This directory must + not be in a subdirectory of the repository else + cvs will think it's part of the + repository and deny you an extraction in the repository: + +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 + + + + 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. + + + 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. + + + + + you will have now in the ~/wine + directory an image of the CVS tree, on the client side. + Now update this image to the date you want: + +cd /home/gerard/wine +cvs update -PAd -D "2004-08-23 CDT" + + + + The date format is YYYY-MM-DD HH:MM:SS. + 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 + + http://www.winehq.org/hypermail/wine-cvs + + + 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: + +cvs update: tsx11/ts_xf86dga2.c is no longer in the repository + + + + cvs update is not limited to upgrade to + a newer version as I have believed for + far too long :-( + + + + + Now proceed as for a normal update: + + +./configure +make depend && make + + + 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. + + + 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 make + distclean before going back in time, so you + have to make everything if you don't backup the older + version) + + + 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: + +cvs update -PAd -D "2004-08-23 15:17:25 CDT" + + This will allow you to find easily the exact patch that + did it. + + + + + If you find the patch that is the cause of the problem, + you have almost won; report about it to + Wine Bugzilla + 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 :-) + + + + + + + + diff --git a/documentation/winedev-windowing.sgml b/documentation/winedev-windowing.sgml new file mode 100644 index 0000000000..8d8cccc8d2 --- /dev/null +++ b/documentation/winedev-windowing.sgml @@ -0,0 +1,673 @@ + + Windowing system + + USER Module + + + 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 windows/, + controls/, and + misc/ directories. + + + + Windowing subsystem + + windows/win.c + windows/winpos.c + + 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 WS_CHILD + style bit is set), a pointer to the sibling (returned by + GetWindow(..., GW_NEXT)), a pointer + to the owner window (set only for popup window if it was + created with valid hwndParent + parameter), and a pointer to the first child window + (GetWindow(.., GW_CHILD)). All popup + and non-child windows are therefore placed in the first + level of this hierarchy and their ancestor link + (wnd->parent) points to the desktop + window. + + + Desktop window - root window + | \ `-. + | \ `-. + popup -> wnd1 -> wnd2 - top level windows + | \ `-. `-. + | \ `-. `-. + child1 child2 -> child3 child4 - child windows + + + 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). + + + Another fairly important concept is + z-order. 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 + + +child1->popup->child2->child3->wnd1->child4->wnd2->desktop. + + + Current active window ("foreground window" in Win32) is + moved to the front of z-order unless its top-level + ancestor owns popup windows. + + + All these issues are dealt with (or supposed to be) in + windows/winpos.c with + SetWindowPos() being the primary + interface to the window manager. + + + 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, SetWindowPos() should + eventually be implemented via + Begin/End/DeferWindowPos() calls and + not the other way around. + + + + Visible region, clipping region and update region + + windows/dce.c + windows/winpos.c + windows/painting.c + + + ________________________ + |_________ | A and B are child windows of C + | A |______ | + | | | | + |---------' | | + | | B | | + | | | | + | `------------' | + | C | + `------------------------' + + + Visible region determines which part of the window is + not obscured by other windows. If a window has the + WS_CLIPCHILDREN style then all + areas below its children are considered invisible. + Similarly, if the WS_CLIPSIBLINGS + 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. + + + B has a WS_CLIPSIBLINGS style: + + + . ______ + : | | + | ,-----' | + | | B | - visible region of B + | | | + : `------------' + + + When the program requests a display + context (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. + + + Program asked for a DC with a clipping region: + + + ______ + ,--|--. | . ,--. + ,--+--' | | : _: | + | | B | | => | | | - DC region where the painting will + | | | | | | | be visible + `--|-----|---' : `----' + `-----' + + + 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 WM_ERASEBKGND and + WM_PAINT messages. In addition, + WM_NCPAINT message is sent when the + uncovered area intersects a nonclient part of the window. + Application must reply to the WM_PAINT + message by calling the + BeginPaint()/EndPaint() + pair of functions. BeginPaint() 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 WM_PAINT until the window + manager creates a new update region. + + + A was moved to the left: + + + ________________________ ... / C update region + |______ | : .___ / + | A |_________ | => | ...|___|.. + | | | | | : | | + |------' | | | : '---' + | | B | | | : \ + | | | | : \ + | `------------' | B update region + | C | + `------------------------' + + + 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). + + + + + + Messaging subsystem + + windows/queue.c + windows/message.c + + + Each Windows task/thread has its own message queue - this + is where it gets messages from. Messages can be: + + + + generated on the fly (WM_PAINT, + WM_NCPAINT, + WM_TIMER) + + + + + created by the system (hardware messages) + + + + + posted by other tasks/threads (PostMessage) + + + + + sent by other tasks/threads (SendMessage) + + + + + + Message priority: + + + 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 + windows/message.c. + + + 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 + Get/PeekMessage 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 QS_PAINT bit in the + owning queue and eventually this window receives a + WM_PAINT message + (WM_NCPAINT 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 DispatchMessage + either calls the callback function or the window + procedure. If there are no messages pending the + task/thread sleeps until messages appear. + + + There are several tricky moments (open for discussion) - + + + + + + System message order has to be honored and messages + should be processed within correct task/thread + context. Therefore when Get/PeekMessage 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: + +
+ by David Charlap + + " Here's the problem in a nutshell, and there is no + good solution. Every possible solution creates a + different problem. + + + 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.) + + + Mouse input events go to the window you click on + (unless some window captures the mouse). + + + 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. + + + 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. + + + 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. + + + 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. + + + 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. + + + 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. + + + 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. + + + 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. + + + There are a few solutions to this problem. + + + 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. + + + 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. + + + 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. + + + 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. + + + + As for the pros and cons: + + + 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. + + + 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." + + + 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." + +
+
+ + + + Intertask/interthread + SendMessage. 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 + DirectedYield() function. + However, in Win32 there could be several messages + pending sent by preemptively executing threads, and in + this case SendMessage 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 + SendMessage. + + +
+
+ + Accelerators + + + There are three differently sized + accelerator structures exposed to the user: + + + + + Accelerators in NE resources. This is also the internal + layout of the global handle HACCEL (16 and + 32) in Windows 95 and Wine. Exposed to the user as Win16 + global handles HACCEL16 and + HACCEL32 by the Win16/Win32 API. + These are 5 bytes long, with no padding: + +BYTE fVirt; +WORD key; +WORD cmd; + + + + + + Accelerators in PE resources. They are exposed to the + user only by direct accessing PE resources. These have a + size of 8 bytes: + + +BYTE fVirt; +BYTE pad0; +WORD key; +WORD cmd; +WORD pad1; + + + + + Accelerators in the Win32 API. These are exposed to the + user by the CopyAcceleratorTable + and CreateAcceleratorTable functions + in the Win32 API. + These have a size of 6 bytes: + + +BYTE fVirt; +BYTE pad0; +WORD key; +WORD cmd; + + + + + + 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 ACCEL + is defined using #pragma(2) for the + compiler but without any packing for RC, so it will assume + #pragma(4). + + +
+ + X Windows System interface + + + Keyboard mapping + + 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. + + + 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. + + + To do this, open the file + dlls/x11drv/keyboard.c and take a look + at the existing tables. Make a backup copy of it, especially + if you don't use CVS. + + + What you really would need to do, is find out which scancode + each key needs to generate. Find it in the + main_key_scan table, which looks like + this: + + +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) */ +}; + + + 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 + keyboard.c. It also shows that if there + is no 102nd key, you can skip that. + + + 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 + main_key_scan, 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 Z), must be placed on a + separate line after the last line. + + + For example, my Norwegian keyboard looks like this + + +§ ! " # ¤ % & / ( ) = ? ` 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 < , . - + +Ctrl Alt Spacebar AltGr Ctrl + + + Note the 102nd key, which is the <> key, to + the left of Z. The character to the right of + the main character is the character generated by + AltGr. + + + This keyboard is defined as follows: + + +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",",;",".:","-_", +"<>" +}; + + + Except that " and \ needs to be quoted with a backslash, and + that the 102nd key is on a separate line, it's pretty + straightforward. + + + After you have written such a table, you need to add it to the + main_key_tab[] layout index table. This + will look like this: + + +static struct { +WORD lang, ansi_codepage, oem_codepage; +const char (*key)[MAIN_LEN][4]; +} main_key_tab[]={ +... +... +{MAKELANGID(LANG_NORWEGIAN,SUBLANG_DEFAULT), 1252, 865, &main_key_NO}, +... + + + After you have added your table, recompile Wine and test that + it works. If it fails to detect your table, try running + + +WINEDEBUG=+key,+keyboard wine > key.log 2>&1 + + + and look in the resulting key.log file to + find the error messages it gives for your layout. + + + Note that the LANG_* and + SUBLANG_* definitions are in + include/winnls.h, 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 + (SUBLANG * 0x400 + LANG), so, for example + the combination LANG_NORWEGIAN (0x14) and + SUBLANG_DEFAULT (0x1) will be (in hex) + 14 + 1*400 = 414, so since I'm Norwegian, + I could look for 0414 in the WINEDEBUG + output to find out why my keyboard won't detect. + + + +
+ +