| <chapter> | |
| <title>Kernel modules</title> | |
| <para> | |
| This section covers the kernel modules. As already stated, Wine | |
| implements the NT architecture, hence provides <filename>NTDLL</filename> | |
| for the core kernel functions, and <filename>KERNEL32</filename>, which is | |
| the implementation of the basis of the Win32 subsystem, on top of | |
| <filename>NTDLL</filename>. | |
| </para> | |
| <para> | |
| This chapter is made of two types of material (depending of their point of | |
| view). Some items will be tackled from a global point of view and then, | |
| when needed, explaining the split of work between | |
| <filename>NTDLL</filename> and <filename>KERNEL32</filename>; some others | |
| will be tackled from a DLL point of view (<filename>NTDLL</filename> or | |
| <filename>KERNEL32</filename>). The choice is made so that the output is | |
| more readable and understantable. At least, that's the intend (sigh). | |
| </para> | |
| <sect1 id="initialization"> | |
| <title>The Wine initialization process</title> | |
| <para> | |
| Wine has a rather complex startup procedure, so unlike many programs the | |
| best place to begin exploring the code-base is | |
| <emphasis>not</emphasis> in fact at the <function>main()</function> | |
| function but instead at some of the more straightforward DLLs that | |
| exist on the periphery such as MSI, the widget library (in | |
| <filename>USER</filename> and <filename>COMCTL32</filename>) etc. The | |
| purpose of this section is to document and explain how Wine starts up | |
| from the moment the user runs "<command>wine myprogram.exe</command>" to | |
| the point at which <filename>myprogram</filename> gets control. | |
| </para> | |
| <sect2> | |
| <title>First Steps</title> | |
| <para> | |
| The actual wine binary that the user runs does not do very much, in | |
| fact it is only responsible for checking the threading model in use | |
| (NPTL vs LinuxThreads) and then invoking a new binary which performs | |
| the next stage in the startup sequence. See the beginning of this | |
| chapter for more information on this check and why it's necessary. You | |
| can find this code in <filename>loader/glibc.c</filename>. The result | |
| of this check is an exec of either <command>wine-pthread</command> or | |
| <command>wine-kthread</command>, potentially (on Linux) via the | |
| <emphasis>preloader</emphasis>. We need to use separate binaries here | |
| because overriding the native pthreads library requires us to exploit | |
| a property of ELF symbol fixup semantics: it's not possible to do this | |
| without starting a new process. | |
| </para> | |
| <para> | |
| The Wine preloader is found in | |
| <filename>loader/preloader.c</filename>, and is required in order to | |
| impose a Win32 style address space layout upon the newly created Win32 | |
| process. The details of what this does is covered in the address space | |
| layout chapter. The preloader is a statically linked ELF binary which | |
| is passed the name of the actual Wine binary to run (either | |
| <command>wine-kthread</command> or <command>wine-pthread</command>) | |
| along with the arguments the user passed in from the command line. The | |
| preloader is an unusual program: it does not have a | |
| <function>main()</function> function. In standard ELF applications, | |
| the entry point is actually at a symbol named | |
| <function>_start()</function>: this is provided by the | |
| standard <command>gcc</command> infrastructure and normally jumps to | |
| <function>__libc_start_main()</function> which initializes glibc before | |
| passing control to the main function as defined by the programmer. | |
| </para> | |
| <para> | |
| The preloader takes control direct from the entry point for a few | |
| reasons. Firstly, it is required that glibc is not initialized twice: | |
| the result of such behaviour is undefined and subject to change | |
| without notice. Secondly, it's possible that as part of initializing | |
| glibc, the address space layout could be changed - for instance, any | |
| call to <function>malloc()</function> will initialize a heap arena | |
| which modifies the VM mappings. Finally, glibc does not return to | |
| <function>_start()</function> at any point, so by reusing it we avoid | |
| the need to recreate the ELF bootstrap stack | |
| (<varname>env</varname>, <varname>argv</varname>, auxiliary array etc). | |
| </para> | |
| <para> | |
| The preloader is responsible for two things: protecting important | |
| regions of the address space so the dynamic linker does not map shared | |
| libraries into them, and once that is done loading the real Wine | |
| binary off disk, linking it and starting it up. Normally all this is | |
| 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 | |
| <command>wine-[pk]thread</command> and | |
| <filename>ld-linux.so.2</filename> off disk, linking them together, | |
| then starting the dynamic linking process. | |
| </para> | |
| <para> | |
| One of the last things the preloader does before jumping into the | |
| dynamic linker is scan the symbol table of the loaded Wine binary and | |
| set the value of a global variable directly: this is a more efficient | |
| way of passing information to the main Wine program than flattening | |
| the data structures into an environment variable or command line | |
| parameter then unpacking it on the other side, but it achieves pretty | |
| much the same thing. The global variable set points to the preload | |
| descriptor table, which contains the VMA regions protected by the | |
| preloader. This allows Wine to unmap them once the dynamic linker has | |
| been run, so leaving gaps we can initialize properly later on. | |
| </para> | |
| </sect2> | |
| <sect2> | |
| <title>Starting the emulator</title> | |
| <para> | |
| The process of starting up the emulator itself is mostly one of | |
| chaining through various initializer functions defined in the core | |
| libraries and DLLs: <filename>libwine</filename>, then | |
| <filename>NTDLL</filename>, then <filename>KERNEL32</filename>. | |
| </para> | |
| <para> | |
| Both the <command>wine-pthread</command> and | |
| <command>wine-kthread</command> binaries share a common | |
| <function>main()</function> function, defined in | |
| <filename>loader/main.c</filename>, so no matter which binary is | |
| selected after the preloader has run we start here. This passes the | |
| information provided by the preloader into | |
| <filename>libwine</filename> and then calls | |
| <function>wine_init()</function>, defined in | |
| <filename>libs/wine/loader.c</filename>. This is where the emulation | |
| really starts: | |
| <function>wine_init()</function> can, with the correct preparation, | |
| be called from programs other than the wine loader itself. | |
| </para> | |
| <para> | |
| <function>wine_init()</function> does some very basic setup tasks such | |
| as initializing the debugging infrastructure, yet more address space | |
| manipulation (see the information on the 4G/4G VM split in the address | |
| space chapter), before loading <filename>NTDLL</filename> - the core | |
| of both Wine and the Windows NT series - and jumping to the | |
| <function>__wine_process_init()</function> function defined | |
| in <filename>dlls/ntdll/loader.c</filename> | |
| </para> | |
| <para> | |
| This function is responsible for initializing the primary Win32 | |
| environment. In <function>thread_init()</function>, it sets up the | |
| TEB, the <command>wineserver</command> connection for the main thread | |
| and the process heap. See the beginning of this chapter for more | |
| information on this. | |
| </para> | |
| <para> | |
| Finally, it loads and jumps to | |
| <function>__wine_kernel_init()</function> in | |
| <filename>KERNEL32.DLL</filename>: this is defined in | |
| <filename>dlls/kernel32/process.c</filename>. This is where the bulk | |
| of the work is done. The <filename>KERNEL32</filename> 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 <structname>STARTUPINFO</structname> block that can be | |
| passed into <function>CreateProcess</function> specifying various | |
| things like how the first window should be displayed: this is sent to | |
| the new process via the <command>wineserver</command>. | |
| </para> | |
| <para> | |
| After determining the type of file given to Wine by the user (a Win32 | |
| EXE file, a Win16 EXE, a Winelib app etc), the program is loaded into | |
| memory (which may involve loading and initializing other DLLs, the | |
| bulk of Wines startup code), before control reaches the end of | |
| <function>__wine_kernel_init()</function>. This function ends with the | |
| new process stack being initialized, and start_process being called on | |
| the new stack. Nearly there! | |
| </para> | |
| <para> | |
| The final element of initializing Wine is starting the newly loaded | |
| program itself. <function>start_process()</function> sets up the SEH | |
| backstop handler, calls <function>LdrInitializeThunk()</function> | |
| which performs the last part of the process initialization (such as | |
| performing relocations and calling the <function>DllMain()</function> | |
| with <constant>PROCESS_ATTACH</constant>), grabs the entry point of | |
| the executable and then on this line: | |
| </para> | |
| <programlisting> | |
| ExitProcess( entry( peb ) ); | |
| </programlisting> | |
| <para> | |
| ... jumps to the entry point of the program. At this point the users | |
| program is running and the API provided by Wine is ready to be | |
| used. When entry returns, the <function>ExitProcess()</function> API | |
| will be used to initialize a graceful shutdown. | |
| </para> | |
| </sect2> | |
| </sect1> | |
| <sect1 id="threading"> | |
| <title>Multi-threading in Wine</title> | |
| <para> | |
| This section will assume you understand the basics of multithreading. If | |
| not there are plenty of good tutorials available on the net to get you | |
| started. | |
| </para> | |
| <para> | |
| Threading in Wine is somewhat complex due to several factors. The first | |
| is the advanced level of multithreading support provided by Windows - | |
| there are far more threading related constructs available in Win32 than | |
| the Linux equivalent (pthreads). The second is the need to be able to | |
| map Win32 threads to native Linux threads which provides us with | |
| benefits like having the kernel schedule them without our | |
| intervention. While it's possible to implement threading entirely | |
| without kernel support, doing so is not desirable on most platforms that | |
| Wine runs on. | |
| </para> | |
| <sect2> | |
| <title>Threading support in Win32</title> | |
| <para> | |
| Win32 is an unusually thread friendly API. Not only is it entirely | |
| thread safe, but it provides many different facilities for working | |
| with threads. These range from the basics such as starting and | |
| stopping threads, to the extremely complex such as injecting threads | |
| into other processes and COM inter-thread marshalling. | |
| </para> | |
| <para> | |
| One of the primary challenges of writing Wine code therefore is | |
| ensuring that all our DLLs are thread safe, free of race conditions | |
| and so on. This isn't simple - don't be afraid to ask if you aren't | |
| sure whether a piece of code is thread safe or not! | |
| </para> | |
| <para> | |
| Win32 provides many different ways you can make your code thread safe | |
| however the most common are <emphasis>critical section</emphasis> and | |
| the <emphasis>interlocked functions</emphasis>. Critical sections are | |
| a type of mutex designed to protect a geographic area of code. If you | |
| don't want multiple threads running in a piece of code at once, you | |
| can protect them with calls to | |
| <function>EnterCriticalSection()</function> and | |
| <function>LeaveCriticalSection()</function>. The first call to | |
| <function>EnterCriticalSection()</function> by a thread will lock the | |
| section and continue without stopping. If another thread calls it then | |
| it will block until the original thread calls | |
| <function>LeaveCriticalSection()</function> again. | |
| </para> | |
| <para> | |
| It is therefore vitally important that if you use critical sections to | |
| make some code thread-safe, that you check every possible codepath out | |
| of the code to ensure that any held sections are left. Code like this: | |
| </para> | |
| <programlisting> | |
| if (res != ERROR_SUCCESS) return res; | |
| </programlisting> | |
| <para> | |
| is extremely suspect in a function that also contains a call to | |
| <function>EnterCriticalSection()</function>. Be careful. | |
| </para> | |
| <para> | |
| If a thread blocks while waiting for another thread to leave a | |
| critical section, you will see an error from the | |
| <function>RtlpWaitForCriticalSection()</function> function, along with | |
| a note of which thread is holding the lock. This only appears after a | |
| certain timeout, normally a few seconds. It's possible the thread | |
| holding the lock is just being really slow which is why Wine won't | |
| terminate the app like a non-checked build of Windows would, but the | |
| most common cause is that for some reason a thread forgot to call | |
| <function>LeaveCriticalSection()</function>, or died while holding the | |
| lock (perhaps because it was in turn waiting for another lock). This | |
| doesn't just happen in Wine code: a deadlock while waiting for a | |
| critical section could be due to a bug in the app triggered by a | |
| slight difference in the emulation. | |
| </para> | |
| <para> | |
| Another popular mechanism available is the use of functions like | |
| <function>InterlockedIncrement()</function> | |
| and <function>InterlockedExchange()</function>. These make use of native | |
| CPU abilities to execute a single instruction while ensuring any other | |
| processors on the system cannot access memory, and allow you to do | |
| common operations like add/remove/check a variable in thread-safe code | |
| without holding a mutex. These are useful for reference counting | |
| especially in free-threaded (thread safe) COM objects. | |
| </para> | |
| <para> | |
| Finally, the usage of TLS slots are also popular. TLS stands for | |
| thread-local storage, and is a set of slots scoped local to a thread | |
| which you can store pointers in. Look on MSDN for the | |
| <function>TlsAlloc()</function> function to learn more about the Win32 | |
| implementation of this. Essentially, the contents of a given slot will | |
| be different in each thread, so you can use this to store data that is | |
| only meaningful in the context of a single thread. On recent versions | |
| of Linux the __thread keyword provides a convenient interface to this | |
| functionality - a more portable API is exposed in the pthread | |
| library. However, these facilities are not used by Wine, rather, we | |
| implement Win32 TLS entirely ourselves. | |
| </para> | |
| </sect2> | |
| <sect2> | |
| <title>SysLevels</title> | |
| <para> | |
| SysLevels are an undocumented Windows-internal thread-safety | |
| system. They are basically critical sections which must be taken in a | |
| particular order. The mechanism is generic but there are always three | |
| syslevels: level 1 is the Win16 mutex, level 2 is the | |
| <filename>USER</filename> mutex and level 3 is the | |
| <filename>GDI</filename> mutex. | |
| </para> | |
| <para> | |
| When entering a syslevel, the code (in | |
| <filename>dlls/kernel/syslevel.c</filename>) will check that a higher | |
| syslevel is not already held and produce an error if so. This is | |
| because it's not legal to enter level 2 while holding level 3 - first, | |
| you must leave level 3. | |
| </para> | |
| <para> | |
| Throughout the code you may see calls to | |
| <function>_ConfirmSysLevel()</function> and | |
| <function>_CheckNotSysLevel()</function>. These functions are | |
| essentially assertions about the syslevel states and can be used to | |
| check that the rules have not been accidentally violated. In | |
| particular, <function>_CheckNotSysLevel()</function> will break | |
| probably into the debugger) if the check fails. If this happens the | |
| solution is to get a backtrace and find out, by reading the source of | |
| the wine functions called along the way, how Wine got into the invalid | |
| state. | |
| </para> | |
| </sect2> | |
| <sect2> | |
| <title>POSIX threading vs. kernel threading</title> | |
| <para> | |
| Wine runs in one of two modes: either pthreads (posix threading) or | |
| kthreads (kernel threading). This section explains the differences | |
| between them. The one that is used is automatically selected on | |
| startup by a small test program which then execs the correct binary, | |
| either <command>wine-kthread</command> or | |
| <command>wine-pthread</command>. On NPTL-enabled systems pthreads | |
| will be used, and on older non-NPTL systems kthreads is selected. | |
| </para> | |
| <para> | |
| Let's start with a bit of history. Back in the dark ages when Wine's | |
| 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 | |
| needed features? The answer, of course, was that it couldn't be. | |
| </para> | |
| <para> | |
| On Linux the pthreads interface is used to start, stop and control | |
| threads. The pthreads library in turn is based on top of so-called | |
| "kernel threads" which are created using the | |
| <function>clone(2)</function> syscall. Pthreads provides a nicer (more | |
| portable) interface to this functionality and also provides APIs for | |
| controlling mutexes. There is a <ulink | |
| url="http://www.llnl.gov/computing/tutorials/pthreads/"> good | |
| tutorial on pthreads</ulink> available if you want to learn more. | |
| </para> | |
| <para> | |
| As pthreads did not provide the necessary semantics to implement Win32 | |
| threading, the decision was made to implement Win32 threading on top | |
| of the underlying kernel threads by using syscalls like | |
| <function>clone()</function> directly. This provided maximum | |
| flexibility and allowed a correct implementation but caused some bad | |
| side effects. Most notably, all the userland Linux APIs assumed that | |
| the user was utilising the pthreads library. Some only enabled thread | |
| safety when they detected that pthreads was in use - this is true of | |
| glibc, for instance. Worse, pthreads and pure kernel threads had | |
| strange interactions when run in the same process yet some libraries | |
| used by Wine used pthreads internally. Throw in source code porting | |
| using WineLib - where you have both UNIX and Win32 code in the same | |
| process - and chaos was the result. | |
| </para> | |
| <para> | |
| The solution was simple yet ingenious: Wine would provide its own | |
| implementation of the pthread library <emphasis>inside</emphasis> its | |
| own binary. Due to the semantics of ELF symbol scoping, this would | |
| cause Wine's own implementation 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 Wine's instead | |
| of the system's pthreads library, and Wine implemented pthreads by | |
| using the standard Windows threading APIs it in turn implemented | |
| itself. | |
| </para> | |
| <para> | |
| As a result, libraries that only became thread-safe in the presence of | |
| a loaded pthreads implementation would now do so, and any external | |
| code that used pthreads would actually end up creating Win32 threads | |
| that Wine was aware of and controlled. This worked quite nicely for a | |
| long time, even though it required doing some extremely un-kosher | |
| things like overriding internal libc structures and functions. That | |
| is, it worked until NPTL was developed at which point the underlying | |
| thread implementation on Linux changed dramatically. | |
| </para> | |
| <para> | |
| The fake pthread implementation can be found in | |
| <filename>loader/kthread.c</filename>, which is used to | |
| produce the <command>wine-kthread</command> binary. In contrast, | |
| <filename>loader/pthread.c</filename> produces the | |
| <command>wine-pthread</command> binary which is used on newer NPTL | |
| systems. | |
| </para> | |
| <para> | |
| NPTL is a new threading subsystem for Linux that hugely improves its | |
| performance and flexibility. By allowing threads to become much more | |
| scalable and adding new pthread APIs, NPTL made Linux competitive with | |
| Windows in the multi-threaded world. Unfortunately it also broke many | |
| assumptions made by Wine (as well as other applications such as the | |
| Sun JVM and RealPlayer) in the process. | |
| </para> | |
| <para> | |
| There was, however, some good news. NPTL made Linux threading powerful | |
| enough that Win32 threads could now be implemented on top of pthreads | |
| like any other normal application. There would no longer be problems | |
| with mixing win32-kthreads and pthreads created by external libraries, | |
| and no need to override glibc internals. As you can see from the | |
| relative sizes of the <filename>loader/kthread.c</filename> and | |
| <filename>loader/pthread.c</filename> files, the difference in code | |
| complexity is considerable. NPTL also made several other semantic | |
| changes to things such as signal delivery so changes were required in | |
| many different places in Wine. | |
| </para> | |
| <para> | |
| On non-Linux systems the threading interface is typically not powerful | |
| enough to replicate the semantics Win32 applications expect and so | |
| kthreads with the pthread overrides are used. | |
| </para> | |
| </sect2> | |
| <sect2> | |
| <title>The Win32 thread environment</title> | |
| <para> | |
| All Win32 code, whether from a native EXE/DLL or in Wine itself, | |
| expects certain constructs to be present in its environment. This | |
| section explores what those constructs are and how Wine sets them | |
| up. The lack of this environment is one thing that makes it hard to | |
| use Wine code directly from standard Linux applications - in order to | |
| interact with Win32 code a thread must first be | |
| "adopted" by Wine. | |
| </para> | |
| <para> | |
| The first thing Win32 code requires is the | |
| <emphasis>TEB</emphasis> or "Thread Environment Block". This is an | |
| internal (undocumented) Windows structure associated with every thread | |
| which stores a variety of things such as TLS slots, a pointer to the | |
| threads message queue, the last error code and so on. You can see the | |
| definition of the TEB in <filename>include/thread.h</filename>, or at | |
| least what we know of it so far. Being internal and subject to change, | |
| the layout of the TEB has had to be reverse engineered from scratch. | |
| </para> | |
| <para> | |
| A pointer to the TEB is stored in the %fs register and can be accessed | |
| using <function>NtCurrentTeb()</function> from within Wine code. %fs | |
| actually stores a selector, and setting it therefore requires | |
| modifying the processes local descriptor table (LDT) - the code to do | |
| this is in <filename>lib/wine/ldt.c</filename>. | |
| </para> | |
| <para> | |
| The TEB is required by nearly all Win32 code run in the Wine | |
| environment, as any <command>wineserver</command> 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 disassembling | |
| you see code like this: | |
| </para> | |
| <programlisting>movl %esp, %fs:0</programlisting> | |
| <para> | |
| ... then you are seeing the program set up an SEH handler frame. All | |
| threads must have at least one SEH entry, which normally points to the | |
| backstop handler which is ultimately responsible for popping up the | |
| all-too-familiar This program has performed an illegal operation and | |
| will be terminated" message. On Wine we just drop straight into the | |
| debugger. A full description of SEH is out of the scope of this | |
| section, however there are some good articles in MSJ if you are | |
| interested. | |
| </para> | |
| <para> | |
| All Win32-aware threads must have a <command>wineserver</command> | |
| connection. Many different APIs require the ability to communicate | |
| with the <command>wineserver</command>. In turn, the | |
| <command>wineserver</command> 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 server-side. The result is | |
| not only correct information in the server, but a set of file | |
| descriptors the thread can use to communicate with the server - the | |
| request fd, reply fd and wait fd (used for blocking). | |
| </para> | |
| </sect2> | |
| </sect1> | |
| <sect1 id="seh"> | |
| <title>Structured Exception Handling</title> | |
| <para> | |
| Structured Exception Handling (or SEH) is an implementation of | |
| exceptions inside the Windows core. It allows code written in different | |
| languages to throw exceptions across DLL boundaries, and Windows reports | |
| various errors like access violations by throwing them. This section | |
| looks at how it works, and how it's implemented in Wine. | |
| </para> | |
| <sect2> | |
| <title>How SEH works</title> | |
| <para> | |
| SEH is based on embedding | |
| <structname>EXCEPTION_REGISTRATION_RECORD</structname> structures in | |
| the stack. Together they form a linked list rooted at offset zero in | |
| the TEB (see the threading section if you don't know what this is). A | |
| registration record points to a handler function, and when an | |
| exception is thrown the handlers are executed in turn. Each handler | |
| returns a code, and they can elect to either continue through the | |
| handler chain or it can handle the exception and then restart the | |
| program. This is referred to as unwinding the stack. After each | |
| handler is called it's popped off the chain. | |
| </para> | |
| <para> | |
| Before the system begins unwinding the stack, it runs vectored | |
| handlers. This is an extension to SEH available in Windows XP, and | |
| allows registered functions to get a first chance to watch or deal | |
| with any exceptions thrown in the entire program, from any thread. | |
| </para> | |
| <para> | |
| A thrown exception is represented by an | |
| <structname>EXCEPTION_RECORD</structname> structure. It consists of a | |
| code, flags, an address and an arbitrary number of <type>DWORD</type> | |
| parameters. Language runtimes can use these parameters to associate | |
| language-specific information with the exception. | |
| </para> | |
| <para> | |
| Exceptions can be triggered by many things. They can be thrown | |
| explicitly by using the RaiseException API, or they can be triggered | |
| by a crash (ie, translated from a signal). They may be used internally | |
| by a language runtime to implement language-specific exceptions. They | |
| can also be thrown across DCOM connections. | |
| </para> | |
| <para> | |
| Visual C++ has various extensions to SEH which it uses to implement, | |
| eg, object destruction on stack unwind as well as the ability to throw | |
| arbitrary types. The code for this is in | |
| <filename>dlls/msvcrt/except.c</filename> | |
| </para> | |
| </sect2> | |
| <sect2> | |
| <title>Translating signals to exceptions</title> | |
| <para> | |
| In Windows, compilers are expected to use the system exception | |
| interface, and the kernel itself uses the same interface to | |
| dynamically insert exceptions into a running program. By contrast on | |
| Linux the exception ABI is implemented at the compiler level | |
| (inside GCC and the linker) and the kernel tells a thread of | |
| exceptional events by sending <emphasis>signals</emphasis>. The | |
| language runtime may or may not translate these signals into native | |
| exceptions, but whatever happens the kernel does not care. | |
| </para> | |
| <para> | |
| You may think that if an app crashes, it's game over and it really | |
| shouldn't matter how Wine handles this. It's what you might | |
| intuitively guess, but you'd be wrong. In fact some Windows programs | |
| expect to be able to crash themselves and recover later without the | |
| user noticing, some contain buggy binary-only components from third | |
| parties and use SEH to swallow crashes, and still others execute | |
| priviledged (kernel-level) instructions and expect it to work. In | |
| fact, at least one set of APIs (the <function>IsBad*Ptr()</function> | |
| series) can only be implemented by performing an operation that may | |
| crash and returning <constant>TRUE</constant> if it does, and | |
| <constant>FALSE</constant> if it doesn't! So, Wine needs to not only | |
| implement the SEH infrastructure but also translate Unix signals into | |
| SEH exceptions. | |
| </para> | |
| <para> | |
| The code to translate signals into exceptions is a part of | |
| <filename>NTDLL</filename>, and can be found in | |
| <filename>dlls/ntdll/signal_i386.c</filename>. This file sets up | |
| handlers for various signals during Wine startup, and for the ones | |
| that indicate exceptional conditions translates them into | |
| exceptions. Some signals are used by Wine internally and have nothing | |
| to do with SEH. | |
| </para> | |
| <para> | |
| Signal handlers in Wine run on their own stack. Each thread has its | |
| own signal stack which resides 4k after the TEB. This is important for | |
| a couple of reasons. Firstly, because there's no guarantee that the | |
| app thread which triggered the signal has enough stack space for the | |
| Wine signal handling code. In Windows, if a thread hits the limits of | |
| its stack it triggers a fault on the stack guard page. The language | |
| runtime can use this to grow the stack if it wants to. | |
| <!-- fixme: is it really the language runtime that does this? i | |
| can't find any code in Wine to reallocate the stack on | |
| STATUS_GUARD_PAGE_VIOLATION --> | |
| However, because a guard page violation is just a regular segfault to | |
| the kernel, that would lead to a nested signal handler and that gets | |
| messy really quick so we disallow that in Wine. Secondly, setting up | |
| the exception to throw requires modifying the stack of the thread | |
| which triggered it, which is quite hard to do when you're still | |
| running on it. | |
| </para> | |
| <para> | |
| Windows exceptions typically contain more information than the Unix | |
| standard APIs provide. For instance, a | |
| <constant>STATUS_ACCESS_VIOLATION</constant> exception (0xC0000005) | |
| structure contains the faulting address, whereas a standard Unix | |
| SIGSEGV just tells the app that it crashed. Usually this information | |
| is passed as an extra parameter to the signal handler, however its | |
| location and contents vary between kernels (BSD, Solaris, | |
| etc). This data is provided in a <structname>SIGCONTEXT</structname> | |
| structure, and on entry to the signal handler it contains the register | |
| state of the CPU before the signal was sent. Modifying it will cause | |
| the kernel to adjust the context before restarting the thread. | |
| </para> | |
| </sect2> | |
| </sect1> | |
| <sect1> | |
| <title>File management</title> | |
| <para> | |
| With time, Windows API comes closer to the old Unix paradigm "Everything | |
| is a file". Therefore, this whole section dedicated to file management | |
| will cover firstly the file management, but also some other objects like | |
| directories, and even devices, which are manipulated in Windows in a | |
| rather coherent way. We'll see later on some other objects fitting | |
| (more or less) in this picture (pipes or consoles to name a few). | |
| </para> | |
| <para> | |
| First of all, Wine, while implementing the file interface from Windows, | |
| needs to maps a file name (expressed in the Windows world) onto a file | |
| name in the Unix world. This encompasses several aspects: how to map | |
| the file names, how to map access rights (both on files and | |
| directories), how to map physical devices (hardisks, but also other | |
| devices - like serial or parallel interfaces - and even VxDs). | |
| </para> | |
| <sect2> | |
| <title>Various Windows formats for file names</title> | |
| <para> | |
| Let's first review a bit the various forms Windows uses when it comes | |
| to file names. | |
| </para> | |
| <sect3> | |
| <title>The DOS inheritance</title> | |
| <para> | |
| At the beginning was DOS, where each file has to sit on a drive, | |
| called from a single letter. For separating device names from | |
| directory or file names, a ':' was appended to this single letter, | |
| hence giving the (in)-famous <filename>C:</filename> drive | |
| designations. Another great invention was to use some fixed names | |
| for accessing devices: not only where these named fixed, in a way | |
| you couldn't change the name if you'd wish to, but also, they were | |
| insensible to the location where you were using them. For example, | |
| it's well known that <filename>COM1</filename> designates the first | |
| serial port, but it's also true that | |
| <filename>c:\foo\bar\com1</filename> also designates the first | |
| serial port. It's still true today: on XP, you still cannot name a | |
| file <filename>COM1</filename>, whatever the directory!!! | |
| </para> | |
| <para> | |
| Well later on (with Windows 95), Microsoft decided to overcome some | |
| little details in file names: this included being able to get out of | |
| the 8+3 format (8 letters for the name, 3 letters for the | |
| extension), and so being able to use "long names" (that's the | |
| "official" naming; as you can guess, the 8+3 format is a short | |
| name), and also to use very strange characters in a file name (like | |
| a space, or even a '.'). You could then name a file | |
| <filename>My File V0.1.txt</filename>, instead of | |
| <filename>myfile01.txt</filename>. Just to keep on the fun side of | |
| things, for many years the format used on the disk itself for | |
| storing the names has been the short name as the real one and to use | |
| some tricky aliasing techniques to store the long name. When some | |
| newer disk file systems have been introduced (NTFS with NT), in | |
| replacement of the old FAT system (which had little evolved since | |
| the first days of DOS), the long name became the real name while the | |
| short name took the alias role. | |
| </para> | |
| <para> | |
| Windows also started to support mounting network shares, and see | |
| them as they were a local disk (through a specific drive letter). | |
| The way it has been done changed along the years, so we won't go | |
| into all the details (especially on the DOS and Win9x side). | |
| </para> | |
| </sect3> | |
| <sect3> | |
| <title>The NT way</title> | |
| <para> | |
| The introduction of NT allowed a deep change in the ways DOS had | |
| been handling devices: | |
| <itemizedlist> | |
| <listitem> | |
| <para> | |
| There's no longer a forest of DOS drive letters (even if the | |
| <command>assign</command> was a way to create symbolic links | |
| in the forest), but a single hierarchical space. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| This hierarchy includes several distinct elements. For | |
| example, <filename>\Device\Hardisk0\Partition0</filename> | |
| refers to the first partition on the first physical hard disk | |
| of the system. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| This hierarchy covers way more than just the files and drives | |
| related objects, but most of the objects in the system. We'll | |
| only cover here the file related part. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| This hierarchy is not directly accessible for the Win32 API, | |
| but only the <filename>NTDLL</filename> API. The Win32 API | |
| only allows to manipulate part of this hierarchy (the rest | |
| being hidden from the Win32 API). Of course, the part you see | |
| from Win32 API looks very similar to the one that DOS | |
| provided. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| Mounting a disk is performed by creating a symbol link in this | |
| hierarchy from <filename>\Global??\C:</filename> (the name | |
| seen from the Win32 API) to | |
| <filename>\Device\Harddiskvolume1</filename> which determines | |
| the partition on a physical disk where C: is going to be seen. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| Network shares are also accessible through a symbol link. | |
| However in this case, a symbol link is created from | |
| <filename>\Global??\UNC\host\share\</filename> for the share | |
| <filename>share</filename> on the machine | |
| <filename>host</filename>) to what's called a network | |
| redirector, and which will take care of 1/ the connection to | |
| the remote share, 2/ handling with that remote share the rest | |
| of the path (after the name of the server, and the name of the | |
| share on that server). | |
| </para> | |
| <note> | |
| <para> | |
| In NT naming convention, <filename>\Global??</filename> can | |
| also be called <filename>\??</filename> to shorten the | |
| access. | |
| </para> | |
| </note> | |
| </listitem> | |
| </itemizedlist> | |
| </para> | |
| <para> | |
| All of these things, make the NT system pretty much more flexible | |
| (you can add new types of filesystems if you want), you provide a | |
| unique name space for all objects, and most operations boil down to | |
| creating relationship between different objects. | |
| </para> | |
| </sect3> | |
| <sect3> | |
| <title>Wrap up</title> | |
| <para> | |
| Let's end this chapter about files in Windows with a review of the | |
| different formats used for file names: | |
| <itemizedlist> | |
| <listitem> | |
| <para><filename>c:\foo\bar</filename> is a full path.</para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| <filename>\foo\bar</filename> is an absolute path; the full | |
| path is created by appending the default drive (ie. the drive | |
| of the current directory). | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| <filename>bar</filename> is a relative path; the full path is | |
| created by adding the current directory. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| <filename>c:bar</filename> is a drive relative path. Note | |
| that the case where <filename>c:</filename> is the drive of | |
| the current directory is rather easy; it's implemented the | |
| same way as the case just below (relative path). In the rest | |
| of this chapter, drive relative path will only cover the case | |
| where the drive in the path isn't the drive of the default | |
| directory. The resolution of this to a full pathname defers | |
| according to the version of Windows, and some parameters. | |
| Let's take some time browsing through these issues. On | |
| Windows 9x (as well as on DOS), the system maintains a process | |
| wide set of default directories per drive. Hence, in this | |
| case, it will resolve <filename>c:bar</filename> to the | |
| default directory on drive <filename>c:</filename> plus file | |
| <filename>bar</filename>. Of course, the default per drive | |
| directory is updated each time a new current directory is set | |
| (only the current directory of the drive specified is | |
| modified). On Windows NT, things differ a bit. Since NT | |
| implements a namespace for file closer to a single tree | |
| (instead of 26 drives), having a current directory per drive | |
| is a bit ackward. Hence, Windows NT default behavior is to | |
| have only one current directory across all drives (in fact, a | |
| current directory expressed in the global tree) - this | |
| directory is of course related to a given process -, | |
| <filename>c:bar</filename> is resolved this way: | |
| <itemizedlist> | |
| <listitem> | |
| <para> | |
| If <filename>c:</filename> is the drive of the default | |
| directory, the final path is the current directory plus | |
| <filename>bar</filename>. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| Otherwise it's resolved into | |
| <filename>c:\bar</filename>. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| In order to bridge the gap between the two | |
| implementations (Windows 9x and NT), NT adds a bit of | |
| complexity on the second case. If the | |
| <envar>=C:</envar> environment variable is defined, then | |
| it's value is used as a default directory for drive | |
| <filename>C:</filename>. This is handy, for example, | |
| when writing a DOS shell, where having a current drive | |
| per drive is still implemented, even on NT. This | |
| mechanism (through environment variables) is implemented | |
| on <command>CMD.EXE</command>, where those variables are | |
| set when you change directories with the | |
| <command>cd</command>. Since environment variables are | |
| inherited at process creation, the current directories | |
| settings are inherited by child processes, hence | |
| mimicing the behavior of the old DOS shell. There's no | |
| mechanism (in <filename>NTDLL</filename> or | |
| <filename>KERNEL32</filename>) to set up, when current | |
| directory changes, the relevant environment variables. | |
| This behavior is clearly band-aid, not a full featured | |
| extension of current directory behavior. | |
| </para> | |
| </listitem> | |
| </itemizedlist> | |
| Wine fully implements all those behaviors (the Windows 9x vs | |
| NT ones are triggered by the version flag in Wine). | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| <filename>\\host\share</filename> is <firstterm>UNC</firstterm> | |
| (Universal Naming Convention) path, ie. represents a file on a | |
| remote share. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| <filename>\\.\device</filename> denotes a physical device | |
| installed in the system (as seen from the Win32 subsystem). A | |
| standard NT system will map it to the | |
| <filename>\??\device</filename> NT path. Then, as a standard | |
| configuration, <filename>\??\device</filename> is likely to be | |
| a link to in a physical device described and hooked into the | |
| <filename>\Device\</filename> tree. For example, | |
| <filename>COM1</filename> is a link to | |
| <filename>\Device\Serial0</filename>. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| On some versions of Windows, paths were limited to | |
| <constant>MAX_PATH</constant> characters. To circumvent this, | |
| Microsoft allowed paths to be <constant>32,767</constant> | |
| characters long, under the conditions that the path is | |
| expressed in Unicode (no Ansi version), and that the path is | |
| prefixed with <filename>\\?\</filename>. This convention is | |
| applicable to any of the cases described above. | |
| </para> | |
| </listitem> | |
| </itemizedlist> | |
| </para> | |
| <para> | |
| To summarize, what we've discussed so, let's put everything into a | |
| single table... | |
| <table> | |
| <title>DOS, Win32 and NT paths equivalences</title> | |
| <tgroup cols="3" align="left"> | |
| <thead> | |
| <row> | |
| <entry>Type of path</entry> | |
| <entry>Win32 example</entry> | |
| <entry>NT equivalent</entry> | |
| <entry>Rule to construct</entry> | |
| </row> | |
| </thead> | |
| <tbody> | |
| <row> | |
| <entry>Full path</entry> | |
| <entry><filename>c:\foo\bar.txt</filename></entry> | |
| <entry><filename>\Global??\C:\foo\bar.txt</filename></entry> | |
| <entry>Simple concatenation</entry> | |
| </row> | |
| <row> | |
| <entry>Absolute path</entry> | |
| <entry><filename>\foo\bar.txt</filename></entry> | |
| <entry><filename>\Global??\J:\foo\bar.txt</filename></entry> | |
| <entry> | |
| Simple concatenation using the drive of the default | |
| directory (here J:) | |
| </entry> | |
| </row> | |
| <row> | |
| <entry>Relative path</entry> | |
| <entry><filename>gee\bar.txt</filename></entry> | |
| <entry> | |
| <filename> | |
| \Global??\J:\mydir\mysubdir\gee\bar.txt | |
| </filename> | |
| </entry> | |
| <entry> | |
| Simple concatenation using the default directory | |
| (here <filename>J:\mydir\mysubdir</filename>) | |
| </entry> | |
| </row> | |
| <row> | |
| <entry>Drive relative path</entry> | |
| <entry><filename>j:gee\bar.txt</filename></entry> | |
| <entry> | |
| <msgtext> | |
| <para> | |
| <itemizedlist> | |
| <listitem> | |
| <para> | |
| On Windows 9x (and DOS), | |
| <filename>J:\toto\gee\bar.txt</filename>. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| On Windows NT, | |
| <filename>J:\gee\bar.txt</filename>. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| On Windows NT, | |
| <filename>J:\tata\titi\bar.txt</filename>. | |
| </para> | |
| </listitem> | |
| </itemizedlist> | |
| </para> | |
| </msgtext> | |
| </entry> | |
| <entry> | |
| <msgtext> | |
| <para> | |
| <itemizedlist> | |
| <listitem> | |
| <para> | |
| On Windows NT (and DOS), | |
| <filename>\toto</filename> is the default | |
| directory on drive <filename>J:</filename>. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| On Windows NT, if <envar>=J:</envar> isn't set. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| On Windows NT, if <envar>=J:</envar> is set to | |
| <filename>J:\tata\titi</filename>. | |
| </para> | |
| </listitem> | |
| </itemizedlist> | |
| </para> | |
| </msgtext> | |
| </entry> | |
| </row> | |
| <row> | |
| <entry>UNC (Uniform Naming Convention) path</entry> | |
| <entry><filename>\\host\share\foo\bar.txt</filename></entry> | |
| <entry> | |
| <filename>\Global??\UNC\host\share\foo\bar.txt</filename> | |
| </entry> | |
| <entry> | |
| Simple concatenation. | |
| </entry> | |
| </row> | |
| <row> | |
| <entry>Device path</entry> | |
| <entry><filename>\\.\device</filename></entry> | |
| <entry><filename>\Global??\device</filename></entry> | |
| <entry>Simple concatenation</entry> | |
| </row> | |
| <row> | |
| <entry>Long paths</entry> | |
| <entry><filename>\\?\...</filename></entry> | |
| <entry></entry> | |
| <entry> | |
| With this prefix, paths can take up to | |
| <constant>32,767</constant> characters, instead of | |
| <constant>MAX_PATH</constant> for all the others). Once | |
| the prefix stripped, to be handled like one of the | |
| previous ones, just providing internal buffers large | |
| enough). | |
| </entry> | |
| </row> | |
| </tbody> | |
| </tgroup> | |
| </table> | |
| </para> | |
| </sect3> | |
| </sect2> | |
| <sect2> | |
| <title>Wine implementation</title> | |
| <para> | |
| We'll mainly cover in this section the way Wine opens a file (in the | |
| Unix sense) when given a Windows file name. This will include mapping | |
| the Windows path onto a Unix path (including the devices case), | |
| handling the access rights, the sharing attribute if any... | |
| </para> | |
| <sect3> | |
| <title>Mapping a Windows path into an absolute Windows path</title> | |
| <para> | |
| First of all, we described in previous section the way to convert | |
| any path in an absolute path. Wine implements all the previous algorithms | |
| in order to achieve this. Note also, that this transformation is | |
| done with information local to the process (default directory, | |
| environment variables...). We'll assume in the rest of this section | |
| that all paths have now been transformed into absolute from. | |
| </para> | |
| </sect3> | |
| <sect3> | |
| <title>Mapping a Windows (absolute) path onto a Unix path</title> | |
| <para> | |
| When Wine is requested to map a path name (in DOS form, with a drive | |
| letter, e.g. <filename>c:\foo\bar\myfile.txt</filename>), Wine | |
| converts this into the following Unix path | |
| <filename>$(WINEPREFIX)/dosdevices/c:/foo/bar/myfile.txt</filename>. | |
| The Wine configuration process is responsible for setting | |
| <filename>$(WINEPREFIX)/dosdevices/c:</filename> to be a symbolic | |
| link pointing to the directory in Unix hierarchy the user wants to | |
| expose as the <filename>C:</filename> drive in the DOS forest of | |
| drives. | |
| </para> | |
| <para> | |
| This scheme allows: | |
| <itemizedlist> | |
| <listitem> | |
| <para> | |
| a very simple algorithm to map a DOS path name into a Unix one | |
| (no need of Wine server calls) | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| a very configurable implementation: it's very easy to change a | |
| drive mapping | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| a rather readable configuration: no need of sophisticated | |
| tools to read a drive mapping, a <command>ls -l | |
| $(WINEPREFIX)/dosdevices</command> | |
| says it all. | |
| </para> | |
| </listitem> | |
| </itemizedlist> | |
| </para> | |
| <para> | |
| This scheme is also used to implement UNC path names. For example, | |
| Wine maps <filename>\\host\share\foo\bar\MyRemoteFile.txt</filename> | |
| into | |
| <filename>$(WINEPREFIX)/dosdevices/unc/host/share/foo/bar/MyRemoteFile.txt</filename>. | |
| It's then up to the user to decide where | |
| <filename>$(WINEPREFIX)/dosdevices/unc/host/share</filename> shall | |
| point to (or be). For example, it can either be a symbolic link to a | |
| directory inside the local machine (just for emulation purpose), or | |
| a symbolic link to the mount point of a remote disk (done through | |
| Samba or NFS), or even the real mount point. Wine will not do any | |
| checking here, nor will help in actually mounting the remote drive. | |
| </para> | |
| <para> | |
| We've seen how Wine maps a drive letter or a UNC path onto the Unix | |
| hierarchy, we now have to look on a the filename is searched within | |
| this hierarchy. The main issue is about case sensivity. Here's a | |
| reminder of the various properties for the file systems in the | |
| field. | |
| <table> | |
| <title>File systems' properties</title> | |
| <tgroup cols="4" align="left"> | |
| <thead> | |
| <row> | |
| <entry>FS Name</entry> | |
| <entry>Length of elements</entry> | |
| <entry>Case sensitivity (on disk)</entry> | |
| <entry>Case sensitivity for lookup</entry> | |
| </row> | |
| </thead> | |
| <tbody> | |
| <row> | |
| <entry>FAT, FAT16 or FAT32</entry> | |
| <entry>Short name (8+3)</entry> | |
| <entry>Names are always stored in upper-case</entry> | |
| <entry>Case insensitive</entry> | |
| </row> | |
| <row> | |
| <entry>VFAT</entry> | |
| <entry>Short name (8+3) + alias on long name</entry> | |
| <entry> | |
| Short names are always stored in upper-case. Long names | |
| are stored with case preservation. | |
| </entry> | |
| <entry>Case insensitive</entry> | |
| </row> | |
| <row> | |
| <entry>NTFS</entry> | |
| <entry>Long name + alias on short name (8+3).</entry> | |
| <entry> | |
| Long names are stored with case preservation. Short names | |
| are always stored in upper-case. | |
| </entry> | |
| <entry>Case insentivite</entry> | |
| </row> | |
| <row> | |
| <entry>Linux FS (ext2fs, ext3fs, reiserfs...)</entry> | |
| <entry>Long name</entry> | |
| <entry>Case preserving</entry> | |
| <entry>Case sensitive</entry> | |
| </row> | |
| </tbody> | |
| </tgroup> | |
| </table> | |
| </para> | |
| <para> | |
| <note> | |
| <para> | |
| When we say that most systems in NT are case insensitive, this | |
| has to be understood for looking up for a file, where the | |
| matches are made in a case insensitive mode. This is different | |
| from VFAT or NTFS "case preservation" mechanism, which stores | |
| the file names as they are given when creating the file, while | |
| doing case insensitive matches. | |
| </para> | |
| </note> | |
| Since most file systems used in NT are case insensitive and since | |
| most Unix file systems are case sensitive, Wine undergo a case | |
| insensitive search when it has found the Unix path is has to look | |
| for. This means, for example, that for opening the | |
| <filename>$(WINEPREFIX)/dosdevices/c:/foo/bar/myfile.txt</filename>, | |
| Wine will recursively open all directories in the path, and check, | |
| in this order, for the existence of the directory entry in the form | |
| given in the file name (ie. case sensitive), and if it's not found, | |
| in a case insensitive form. This allows to also pass, in most Win32 | |
| file API also a Unix path (instead of a DOS or NT path), but we'll | |
| come back to this later. This also means that the algorithm | |
| described doesn't correctly handle the case of two files in the same | |
| directory, which names only differ on the case of the letters. This | |
| means, that if, in the same directory, two files (which names match | |
| in a case sensitive comparison), Wine will pick-up the right one if | |
| the filename given matches on of the name (in a case sensitive way), | |
| but will pickup one of the two (without defining the one it's going | |
| to pickup) if the filename given matches none of the two names in a | |
| case sensitive way (but in a case insensitive way). For example, if | |
| the two filenames are <filename>my_neat_file.txt</filename> and | |
| <filename>My_Neat_File.txt</filename>, Wine's behavior when opening | |
| <filename>MY_neat_FILE.txt</filename> is undefined. | |
| </para> | |
| <para> | |
| As Windows, at the early days, didn't support the notion of symbolic | |
| links on directories, lots of applications (and some old native | |
| DLLs) are not ready for this feature. Mainly, they imply that the | |
| directory structure is a tree, which has lots of consequences on | |
| navigating in the forest of directories (ie: there cannot be two | |
| ways for going from directory to another, there cannot be | |
| cycles...). In order to prevent some bad behavior for such | |
| applications, Wine sets up an option. By default, symbolic links on | |
| directories are not followed by Wine. There's an options to follow | |
| them (see the Wine User Guide), but this could be harmful. | |
| </para> | |
| <para> | |
| Wine considers that Unix file names <emphasis>are</emphasis> long | |
| filename. This seems a reasonable approach; this is also the | |
| approach followed by most of the Unix OSes while mounting Windows | |
| partitions (with filesystems like FAT, FAT32 or NTFS). Therefore, | |
| Wine tries to support short names the best it can. Basically, they | |
| are two options: | |
| <itemizedlist> | |
| <listitem> | |
| <para> | |
| The filesystem on which the inspected directory lies in a real | |
| Windows FS (like FAT, or FAT32, or NTFS) and the OS has | |
| support to access the short filename (for example, Linux does | |
| this on FAT, FAT32 or VFAT). In this case, Wine makes full use | |
| of this information and really mimics the Windows behavior: | |
| the short filename used for any file is the same than on | |
| Windows. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| If conditions listed above are not met (either, FS has no | |
| physical short name support, or OS doesn't provide the access | |
| access to the short name), Wine decides and computes on its | |
| own the short filename for a given long filename. We cannot | |
| ensure that the generated short name is the same than on | |
| Windows (because the algorithm on Windows takes into account | |
| the order of creation of files, which cannot be implemented in | |
| Wine: Wine would have to cache the short names of every | |
| directory it uses!). The short name is made up of part of the | |
| long name (first characters) and the rest with a hashed | |
| value. This has several advantages: | |
| <itemizedlist> | |
| <listitem> | |
| <para> | |
| The algorithm is rather simple and low cost. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| The algorithm is stateless (doesn't depend of the other | |
| files in the directory). | |
| </para> | |
| </listitem> | |
| </itemizedlist> | |
| But, it also has the drawbacks (of the advantages): | |
| <itemizedlist> | |
| <listitem> | |
| <para> | |
| The algorithm isn't the same as on Windows, which means | |
| a program cannot use short names generated on | |
| Windows. This could happen when copying an existing | |
| installed program from Windows (for example, on a dual | |
| boot machine). | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| Two long file names can end up with the same short name | |
| (Windows handles the collision in this case, while Wine | |
| doesn't). We rely on our hash algorithm to lower at most | |
| this possibility (even if it exists). | |
| </para> | |
| </listitem> | |
| </itemizedlist> | |
| </para> | |
| </listitem> | |
| </itemizedlist> | |
| </para> | |
| <para> | |
| Wine also allows in most file API to give as a parameter a full Unix | |
| path name. This is handy when running a Wine (or Winelib) program | |
| from the command line, and one doesn't need to convert the path into | |
| the Windows form. However, Wine checks that the Unix path given can | |
| be accessed from one of the defined drives, insuring that only part | |
| of the Unix <filename>/</filename> hierarchy can be accessed. | |
| </para> | |
| <para> | |
| As a side note, as Unix doesn't widely provide a Unicode interface | |
| to the filenames, and that Windows implements filenames as Unicode | |
| strings (even on the physical layer with NTFS, the FATs variant are | |
| ANSI), we need to properly map between the two. At startup, Wine | |
| defines what's called the Unix Code Page, that's is the code page | |
| the Unix kernel uses as a reference for the strings. Then Wine uses | |
| this code page for all the mappings it has to do between a Unicode | |
| path (on the Windows side) and a Ansi path to be used in a Unix path | |
| API. Note, that this will work as long as a disk isn't mounted with | |
| a different code page than the one the kernel uses as a default. | |
| </para> | |
| <para> | |
| We describe below how Windows devices are mapped to Unix devices. | |
| Before that, let's finish the pure file round-up with some basic | |
| operations. | |
| </para> | |
| </sect3> | |
| <sect3> | |
| <title>Access rights and file attributes</title> | |
| <para> | |
| Now that we have looked how Wine converts a Windows pathname into a | |
| Unix one, we need to cover the various meta-data attached to a file | |
| or a directory. | |
| </para> | |
| <para> | |
| In Windows, access rights are simplistic: a file can be read-only or | |
| read-write. Wine sets the read-only flag if the file doesn't have | |
| the Unix user-write flag set. As a matter of fact, there's no way | |
| Wine can return that a file cannot be read (that doesn't exist under | |
| Windows). The file will be seen, but trying to open it will return | |
| an error. The Unix exec-flag is never reported. Wine doesn't use | |
| this information to allow/forbid running a new process (as Unix does | |
| with the exec-flag). Last but not least: hidden files. This exists | |
| on Windows but not really on Unix! To be exact, in Windows, the | |
| hidden flag is a metadata associated to any file or directoy; in | |
| Unix, it's a convention based on the syntax of the file name | |
| (whether it starts with a '.' or not). Wine implements two behaviors | |
| (chosen by configuration). This impacts file names and directory | |
| names starting by a '.'. In first mode | |
| (<option>ShowDotFile</option> is <constant>FALSE</constant>), every | |
| file or directory starting by '.' is returned with the hidden flag | |
| turned on. This is the natural behavior on Unix (for | |
| <command>ls</command> or even file explorer). In the second mode | |
| (<option>ShowDotFile</option> is <constant>TRUE</constant>), Wine | |
| never sets the hidden flag, hence every file will be seen. | |
| </para> | |
| <para> | |
| Last but not least, before opening a file, Windows makes use of | |
| sharing attributes in order to check whether the file can be opened; | |
| for example, a process, being the first in the system to open a | |
| given file, could forbid, while it maintains the file opened, that | |
| another process opens it for write access, whereas open for read | |
| access would be granted. This is fully supported in Wine by moving | |
| all those checks in the Wine server for a global view on the system. | |
| Note also that what's moved in the Wine server is the check, when | |
| the file is opened, to implement the Windows sharing semantics. | |
| Further operation on the file (like reading and writing) will not | |
| require heavy support from the server. | |
| </para> | |
| <para> | |
| The other good reason for putting the code for actually opening a | |
| file in the server is that an opened files in Windows is managed | |
| through a handle, and handles can only be created in Wine server! | |
| </para> | |
| <para> | |
| Just a note about attributes on directories: while we can easily map | |
| the meaning of Windows' <constant>FILE_ATTRIBUTE_READONLY</constant> | |
| on a file, we cannot do it for a directory. Windows' semantic (when | |
| this flag is set) means do not delete the directory, while the | |
| <constant>w</constant> attribute in Unix means don't write nor | |
| delete it. Therefore, Wine uses an asymetric mapping here: if the | |
| directory (in Unix) isn't writable, then Wine reports the | |
| <constant>FILE_ATTRIBUTE_READONLY</constant> attribute; on the other | |
| way around, when asked to set a directory with | |
| <constant>FILE_ATTRIBUTE_READONLY</constant> attribute, Wine simply | |
| does nothing. | |
| </para> | |
| </sect3> | |
| <sect3> | |
| <title>Operations on file</title> | |
| <sect4> | |
| <title>Reading and writing</title> | |
| <para> | |
| Reading and writing are the basic operations on files. Wine of | |
| course implements this, and bases the implementation on client | |
| side calls to Unix equivalents (like <function>read()</function> | |
| or <function>write()</function>). Note, that the Wine server is | |
| involved in any read or write operation, as Wine needs to | |
| transform the Windows-handle to the file into a Unix file | |
| descriptor it can pass to any Unix file function. | |
| </para> | |
| </sect4> | |
| <sect4> | |
| <title>Getting a Unix fd</title> | |
| <para> | |
| This is major operation in any file related operation. Basically, | |
| each file opened (at the Windows level), is first opened in the | |
| Wine server, where the fd is stored. Then, Wine (on client side) | |
| uses <function>recvmsg()</function> to pass the fd from the wine | |
| server process to the client process. Since this operation could | |
| be lengthy, Wine implement some kind of cache mechanism to send it | |
| only once, but getting a fd from a handle on a file (or any other | |
| Unix object which can be manipulated through a file descriptor) | |
| still requires a round trip to the Wine server. | |
| </para> | |
| </sect4> | |
| <sect4> | |
| <title>Locking</title> | |
| <para> | |
| Windows provides file locking capabilities. When a lock is set | |
| (and a lock can be set on any contiguous range in a file), it | |
| controls how other processes in the system will have access to the | |
| range in the file. Since locking range on a file are defined on a | |
| system wide manner, its implementation resides in | |
| <command>wineserver</command>. It tries to make use Unix file | |
| locking (if the underlying OS and the mounted disk where the file | |
| sits support this feature) with <function>fcntl()</function> and | |
| the <constant>F_SETLK</constant> command. If this isn't | |
| supported, then <command>wineserver</command> just pretends it | |
| works. | |
| </para> | |
| </sect4> | |
| <sect4> | |
| <title>I/O control</title> | |
| <para> | |
| There's no need (so far) to implement support (for files and | |
| directories) for <function>DeviceIoControl()</function>, even if | |
| this is supported by Windows, but for very specific needs | |
| (like compression management, or file system related information). | |
| This isn't the case for devices (including disks), but we'll cover | |
| this in the hereafter section related to devices. | |
| </para> | |
| </sect4> | |
| <sect4> | |
| <title>Buffering</title> | |
| <para> | |
| Wine doesn't do any buffering on file accesses but rely on the | |
| underlying Unix kernel for that (when possible). This scheme is | |
| needed because it's easier to implement multiple accesses on the | |
| same file at the kernel level, rather than at Wine levels. Doing | |
| lots of small reads on the same file can turn into a performance | |
| hog, because each read operation needs a round trip to the server | |
| in order to get a file descriptor (see above). | |
| </para> | |
| </sect4> | |
| <sect4> | |
| <title>Overlapped I/O</title> | |
| <para> | |
| Windows introduced the notion of overlapped I/O. Basically, it | |
| just means that an I/O operation (think read / write to start | |
| with) will not wait until it's completed, but rather return to the | |
| caller as soon as possible, and let the caller handle the wait | |
| operation and determine when the data is ready (for a read | |
| operation) or has been sent (for a write operation). Note that the | |
| overlapped operation is linked to a specific thread. | |
| </para> | |
| <para> | |
| There are several interests to this: a server can handle several | |
| clients without requiring multi-threading techniques; you can | |
| handle an event driven model more easily (ie how to kill properly | |
| a server while waiting in the lengthy <function>read()</function> | |
| operation). | |
| </para> | |
| <para> | |
| Note that Microsoft's support for this feature evolved along the | |
| various versions of Windows. For example, Windows 95 or 98 only | |
| supports overlapped I/O for serial and parallel ports, while NT | |
| supports also files, disks, sockets, pipes, or mailslots. | |
| </para> | |
| <para> | |
| Wine implements overlapped I/O operations. This is mainly done by | |
| queueing in the server a request that will be triggered when | |
| something the current state changes (like data available for a | |
| read operation). This readiness is signaled to the calling | |
| processing by queueing a specific APC, which will be called within | |
| the next waiting operation the thread will have. This specific | |
| APC will then do the hard work of the I/O operation. This scheme | |
| allows to put in place a wait mechanism, to attach a routine to be | |
| called (on the thread context) when the state changes, and to be | |
| done is a rather transparent manner (embedded any the generic wait | |
| operation). However, it isn't 100% perfect. As the heavy | |
| operations are done in the context of the calling threads, if | |
| those operations are lengthy, there will be an impact on the | |
| calling thread, especially its latency. In order to provide an | |
| effective support for this overlapped I/O operations, we would | |
| need to rely on Unix kernel features (AIO is a good example). | |
| </para> | |
| </sect4> | |
| </sect3> | |
| <sect3> | |
| <title>Devices & volume management</title> | |
| <para> | |
| We've covered so far the ways file names are mapped into Unix | |
| pathes. There's still need to cover it for devices. As a regular | |
| file, devices are manipulated in Windows with both read / write | |
| operations, but also control mechanisms (speed or parity of a serial | |
| line; volume name of a hard disk...). Since, this is also supported | |
| in Linux, there's also a need to open (in a Unix sense) a device | |
| when given a Windows device name. This section applies to DOS device | |
| names, which are seen in NT as nicknames to other devices. | |
| </para> | |
| <para> | |
| Firstly, Wine implements the Win32 to NT mapping as described above, | |
| hence every device path (in NT sense) is of the following form: | |
| <filename>/??/devicename</filename> (or | |
| <filename>/DosDevices/devicename</filename>). As Windows device | |
| names are case insensitive, Wine also converts them to lower case | |
| before any operation. Then, the first operation Wine tries is to | |
| check whether | |
| <filename>$(WINEPREFIX)/dosdevices/devicename</filename> exists. If | |
| so, it's used as the final Unix path for the device. The | |
| configuration process is in charge of creating for example, a | |
| symbolic link between | |
| <filename>$(WINEPREFIX)/dosdevices/PhysicalDrive0</filename> and | |
| <filename>/dev/hda0</filename>. If such a link cannot be found, and | |
| the device name looks like a DOS disk name (like | |
| <filename>C:</filename>), Wine first tries to get the Unix device | |
| from the path <filename>$(WINEPREFIX)/dosdevices/c:</filename> | |
| (i.e. the device which is mounted on the target of the symbol link); | |
| if this doesn't give a Unix device, Wine tries whether | |
| <filename>$(WINEPREFIX)/dosdevices/c::</filename> exists. If so, | |
| it's assumed to be a link to the actual Unix device. For example, | |
| for a CD Rom, <filename>$(WINEPREFIX)/dosdevices/e::</filename> | |
| would be a symbolic link to <filename>/dev/cdrom</filename>. If | |
| this doesn't exist (we're still handling the a device name of the | |
| <filename>C:</filename> form), Wine tries to get the Unix device | |
| from the system information (<filename>/etc/mtab</filename> and | |
| <filename>/etc/fstab</filename> on Linux). We cannot apply this | |
| method in all the cases, because we have no insurance that the | |
| directory can actually be found. One could have, for example, a CD | |
| Rom which he/she want only to use as audio CD player (ie never | |
| mounted), thus not having any information of the device itself. If | |
| all of this doesn't work either, some basic operations are checked: | |
| if the devicename is <filename>NUL</filename>, then | |
| <filename>/dev/null</filename> is returned. If the device name is a | |
| default serial name (<filename>COM1</filename> up to | |
| <filename>COM9</filename>) (resp. printer name | |
| <filename>LPT1</filename> up to <filename>LPT9</filename>), then | |
| Wine tries to open the Nth serial (resp. printer) in the system. | |
| Otherwise, some basic old DOS name support is done | |
| <filename>AUX</filename> is transformed into | |
| <filename>COM1</filename> and <filename>PRN</filename> into | |
| <filename>LPT1</filename>), and the whole process is retried with | |
| those new names. | |
| </para> | |
| <para> | |
| To sum up: | |
| <table> | |
| <title> | |
| Mapping of Windows device names into Unix device names | |
| </title> | |
| <tgroup cols="3" align="left"> | |
| <thead> | |
| <row> | |
| <entry>Windows device name</entry> | |
| <entry>NT device name</entry> | |
| <entry>Mapping to Unix device name</entry> | |
| </row> | |
| </thead> | |
| <tbody> | |
| <row> | |
| <entry><filename><any_path>AUX</filename></entry> | |
| <entry<filename>>\Global??\AUX</filename></entry> | |
| <entry> | |
| Treated as an alias to <filename>COM1</filename> | |
| </entry> | |
| </row> | |
| <row> | |
| <entry><filename><any_path>PRN</filename></entry> | |
| <entry><filename>\Global??\PRN</filename></entry> | |
| <entry>Treated as an alias to <filename>LPT1</filename></entry> | |
| </row> | |
| <row> | |
| <entry><filename><any_path>COM1</filename></entry> | |
| <entry><filename>\Global??\COM1</filename></entry> | |
| <entry> | |
| <filename>$(WINEPREFIX)/dosdevices/com1</filename> | |
| (if the symbol link exists) or the Nth serial | |
| line in the system (on Linux, | |
| <filename>/dev/ttyS0</filename>). | |
| </entry> | |
| </row> | |
| <row> | |
| <entry><filename><any_path>LPT1</filename></entry> | |
| <entry><filename>\Global??\LPT1</filename></entry> | |
| <entry> | |
| <filename>$(WINEPREFIX)/dosdevices/lpt1</filename> | |
| (if the symbol link exists) or the Nth printer | |
| in the system (on Linux, | |
| <filename>/dev/lp0</filename>). | |
| </entry> | |
| </row> | |
| <row> | |
| <entry><filename><any_path>NUL</filename></entry> | |
| <entry><filename>\Global??\NUL</filename></entry> | |
| <entry><filename>/dev/null</filename></entry> | |
| </row> | |
| <row> | |
| <entry><filename>\\.\E:</filename></entry> | |
| <entry><filename>\Global??\E:</filename></entry> | |
| <entry> | |
| <filename>$(WINEPREFIX)/dosdevices/e::</filename> (if the | |
| symbolic link exists) or guessing the device from | |
| <filename>/etc/mtab</filename> or | |
| <filename>/etc/fstab</filename>. | |
| </entry> | |
| </row> | |
| <row> | |
| <entry><filename>\\.\<device_name></filename></entry> | |
| <entry> | |
| <filename>\Global??\<device_name></filename> | |
| </entry> | |
| <entry> | |
| <filename>$(WINEPREFIX)/dosdevices/<device_name></filename> | |
| (if the symbol link exists). | |
| </entry> | |
| </row> | |
| </tbody> | |
| </tgroup> | |
| </table> | |
| </para> | |
| <para> | |
| Now that we know which Unix device to open for a given Windows | |
| device, let's cover the operation on it. Those operations can either | |
| be read / write, io control (and even others). | |
| </para> | |
| <para> | |
| Read and write operations are supported on Real disks & CDROM | |
| devices, under several conditions: | |
| <itemizedlist> | |
| <listitem> | |
| <para> | |
| Foremost, as the <function>ReadFile()</function> and | |
| <function>WriteFile()</function> calls are mapped onto the | |
| Unix <function>read()</function> and | |
| <function>write()</function> calls, the user (from the Unix | |
| perspective of the one running the Wine executable) must have | |
| read (resp. write) access to the device. It wouldn't be wise | |
| to let a user write directly to a hard disk!!! | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| Blocks' size for read and write but be of the size of a | |
| physical block (generally 512 for a hard disk, depends on the | |
| type of CD used), and offsets must also be a multiple of the | |
| block size. | |
| </para> | |
| </listitem> | |
| </itemizedlist> | |
| </para> | |
| <para> | |
| Wine also reads (if the first condition above about access rights is | |
| met) the volume information from a hard disk or a CD ROM to be | |
| displayed to a user. | |
| </para> | |
| <!-- | |
| <para> | |
| Handling of old DOS devices (<filename>COMx</filename>, | |
| <filename>LPTx</filename>, <filename>NUL</filename>...) | |
| </para> | |
| --> | |
| <para> | |
| Wine also recognizes VxD as devices. But those VxD must be the | |
| Wine builtin ones (Wine will never allow to load native VxD). Those | |
| are configured with symbolic links in the | |
| <filename>$(WINEPREFIX)/dosdevices/</filename> directory, and point | |
| to the actual builtin DLL. This DLL exports a single entry point, | |
| that Wine will use when a call to | |
| <function>DeviceIoControl</function> is made, with a handle opened | |
| to this VxD. This allows to provide some kind of compatibility for | |
| old Win9x apps, still talking directly to VxD. This is no longer | |
| supported on Windows NT, newest programs are less likely to make use | |
| of this feature, so we don't expect lots of development in this | |
| area, eventhough the framework is there and working. Note also that | |
| Wine doesn't provide support for native VxDs (as a game, report how | |
| many times this information is written in the documentation; as an | |
| advanced exercice, find how many more occurences we need in order to | |
| stop questions whether it's possible or not). | |
| </para> | |
| </sect3> | |
| </sect2> | |
| </sect1> | |
| <sect1 id="ntdll"> | |
| <title><filename>NTDLL</filename> module</title> | |
| <para> | |
| <filename>NTDLL</filename> provides most of the services you'd expect | |
| from a kernel. In lots of cases, <filename>KERNEL32</filename> APIs are | |
| just wrappers to <filename>NTDLL</filename> APIs. There are however, | |
| some difference in the APIs (the <filename>NTDLL</filename> ones have | |
| quite often a bit wider semantics than their | |
| <filename>KERNEL32</filename> counterparts). All the detailed functions | |
| we've described since the beginning of this chapter are in fact | |
| implemented in <filename>NTDLL</filename>, plus a great numbers of | |
| others we haven's written about yet. | |
| </para> | |
| </sect1> | |
| <sect1> | |
| <title><filename>KERNEL32</filename> Module</title> | |
| <para> | |
| As already explained, <filename>KERNEL32</filename> maps quite a few of | |
| its APIs to <filename>NTDLL</filename>. There are however a couple of | |
| things which are handled directly in | |
| <filename>KERNEL32</filename>. Let's cover a few of them... | |
| </para> | |
| <sect2 id="consoles"> | |
| <title>Console</title> | |
| <sect3> | |
| <title>NT implementation</title> | |
| <para> | |
| Windows implements console solely in the Win32 subsystem. Under NT, | |
| the real implementation uses a dedicated subsystem | |
| <filename>csrss.exe</filename> Client/Server Run-time SubSystem) | |
| which is in charge, amont other things, of animating the consoles. | |
| Animating includes for example handling several processes on the | |
| same console (write operations must be atomic, but also a character | |
| keyed on the console must be read by a single process), or sending | |
| some information back to the processes (changing the size or | |
| attributes of the console, closing the console). Windows NT uses a | |
| dedicated (RPC based) protocol between each process being attached | |
| to a console and the <command>csrss.exe</command> subsystem, which | |
| is in charge of the UI of every console in the system. | |
| </para> | |
| </sect3> | |
| <sect3> | |
| <title>Wine implementation</title> | |
| <para> | |
| Wine tries to integrate as much as possible into the Unix consoles, | |
| but the overall situation isn't perfect yet. Basically, Wine | |
| implements three kinds of consoles: | |
| <itemizedlist> | |
| <listitem> | |
| <para> | |
| the first one is a direct mapping of the Unix console into the | |
| Windows environment. From the windows program point of view, | |
| it won't run in a Windows console, but it will see its | |
| standard input and output streams redirected to files; thoses | |
| files are hooked into the Unix console's output and input | |
| streams respectively. This is handy for running programs from | |
| a Unix command line (and use the result of the program as it | |
| was a Unix programs), but it lacks all the semantics of the | |
| Windows consoles. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| the second and third ones are closer to the NT scheme, albeit | |
| different to what NT does. The <command>wineserver</command> | |
| plays the role of the <filename>csrss.exe</filename> subsystem | |
| (all requests are sent to it), and are then dispatched to a | |
| dedicated wine process, called (surprise!) | |
| <command>wineconsole</command> which manages the UI of the | |
| console. There is a running instance of | |
| <command>wineconsole</command> for every console in the | |
| system. Two flavors of this scheme are actually implemented: | |
| they vary on the backend for the | |
| <command>wineconsole</command>. The first one, dubbed | |
| <constant>user</constant>, creates a real GUI window | |
| (hence the USER name) and renders the console in this window. | |
| The second one uses the <filename>(n)curses</filename> library | |
| to take full control of an existing Unix console; of course, | |
| interaction with other Unix programs will not be as smooth as | |
| the first solution. | |
| </para> | |
| </listitem> | |
| </itemizedlist> | |
| </para> | |
| <para> | |
| The following table describes the main implementation differences | |
| between the three approaches. | |
| <table> | |
| <title>Function consoles implementation comparison</title> | |
| <tgroup cols="4" align="left"> | |
| <thead> | |
| <row> | |
| <entry>Function</entry> | |
| <entry>Bare streams</entry> | |
| <entry> | |
| <command>Wineconsole</command> & user backend | |
| </entry> | |
| <entry> | |
| <command>Wineconsole</command> & curses backend | |
| </entry> | |
| </row> | |
| </thead> | |
| <tbody> | |
| <row> | |
| <entry> | |
| Console as a Win32 Object (and associated handles) | |
| </entry> | |
| <entry> | |
| No specific Win32 object is used in this case. The | |
| handles manipulated for the standard Win32 streams are in | |
| fact "bare handles" to their corresponding Unix streams. | |
| The mode manipulation functions | |
| (<function>GetConsoleMode()</function> / | |
| <function>SetConsoleMode()</function>) are not supported. | |
| </entry> | |
| <entry> | |
| Implemented in server, and a specific Winelib program | |
| (<command>wineconsole</command>) is in charge of the | |
| rendering and user input. The mode manipulation functions | |
| behave as expected. | |
| </entry> | |
| <entry> | |
| Implemented in server, and a specific Winelib program | |
| (<command>wineconsole</command>) is in charge of the | |
| rendering and user input. The mode manipulation functions | |
| behave as expected. | |
| </entry> | |
| </row> | |
| <row> | |
| <entry> | |
| Inheritance (including handling in | |
| <function>CreateProcess()</function> of | |
| <constant>CREATE_DETACHED</constant>, | |
| <constant>CREATE_NEW_CONSOLE</constant> flags). | |
| </entry> | |
| <entry> | |
| Not supported. Every process child of a process will | |
| inherit the Unix streams, so will also inherit the Win32 | |
| standard streams. | |
| </entry> | |
| <entry> | |
| Fully supported (each new console creation will be handled | |
| by the creation of a new <filename>USER32</filename> window) | |
| </entry> | |
| <entry> | |
| Fully supported, except for the creation of a new console, | |
| which will be rendered on the same Unix terminal as the | |
| previous one, leading to unpredictable results. | |
| </entry> | |
| </row> | |
| <row> | |
| <entry> | |
| <function>ReadFile()</function> / | |
| <function>WriteFile()</function> operations | |
| </entry> | |
| <entry>Fully supported</entry> | |
| <entry>Fully supported</entry> | |
| <entry>Fully supported</entry> | |
| </row> | |
| <row> | |
| <entry> | |
| Screen-buffer manipulation (creation, deletion, resizing...) | |
| </entry> | |
| <entry>Not supported</entry> | |
| <entry>Fully supported</entry> | |
| <entry> | |
| Partly supported (this won't work too well as we don't | |
| control (so far) the size of underlying Unix terminal | |
| </entry> | |
| </row> | |
| <row> | |
| <entry> | |
| APIs for reading/writing screen-buffer content, cursor position | |
| </entry> | |
| <entry>Not supported</entry> | |
| <entry>Fully supported</entry> | |
| <entry>Fully supported</entry> | |
| </row> | |
| <row> | |
| <entry>APIs for manipulating the rendering window size</entry> | |
| <entry>Not supported</entry> | |
| <entry>Fully supported</entry> | |
| <entry> | |
| Partly supported (this won't work too well as we don't | |
| control (so far) the size of underlying Unix terminal | |
| </entry> | |
| </row> | |
| <row> | |
| <entry> | |
| Signaling (in particular, Ctrl-C handling) | |
| </entry> | |
| <entry> | |
| Nothing is done, which means that Ctrl-C will generate (as | |
| usual) a <constant>SIGINT</constant> which will terminate | |
| the program. | |
| </entry> | |
| <entry> | |
| Partly supported (Ctrl-C behaves as expected, however the | |
| other Win32 CUI signaling isn't properly implemented). | |
| </entry> | |
| <entry> | |
| Partly supported (Ctrl-C behaves as expected, however the | |
| other Win32 CUI signaling isn't properly implemented). | |
| </entry> | |
| </row> | |
| </tbody> | |
| </tgroup> | |
| </table> | |
| </para> | |
| <para> | |
| The Win32 objects behind a console can be created in several | |
| occasions: | |
| <itemizedlist> | |
| <listitem> | |
| <para> | |
| When the program is started from | |
| <command>wineconsole</command>, a new console object is | |
| created and will be used (inherited) by the process launched | |
| from <command>wineconsole</command>. | |
| </para> | |
| </listitem> | |
| <listitem> | |
| <para> | |
| When a program, which isn't attached to a console, calls | |
| <function>AllocConsole()</function>, Wine then launches | |
| <command>wineconsole</command>, and attaches the current | |
| program to this console. In this mode, the | |
| <filename>USER32</filename> mode is always selected as Wine | |
| cannot tell the current state of the Unix console. | |
| </para> | |
| </listitem> | |
| </itemizedlist> | |
| </para> | |
| <para> | |
| Please also note, that starting a child process with the | |
| <constant>CREATE_NEW_CONSOLE</constant> flag, will end-up calling | |
| <function>AllocConsole()</function> in the child process, hence | |
| creating a <command>wineconsole</command> with the | |
| <filename>USER32</filename> backend. | |
| </para> | |
| <para> | |
| Another interesting point to note is that Windows implements handles | |
| to console objects (input and screen buffers) only in the | |
| <filename>KERNEL32</filename> DLL, and those are not sent nor seen | |
| from the <filename>NTDLL</filename> level, albeit, for example, | |
| console are waitable on input. How is this possible? Well, Windows | |
| NT is a bit tricky here. Regular handles have an interesting | |
| property: their integral value is always a multiple of four (they | |
| are likely to be offsets from the beginning of a table). Console | |
| handles, on the other hand, are not multiple of four, but have the | |
| two lower bit set (being a multiple of four means having the two | |
| lower bits reset). When <filename>KERNEL32</filename> sees a handle | |
| with the two lower bits set, it then knows it's a console handle and | |
| takes appropriate decisions. For example, in the various | |
| <function>kernel32!WaitFor*()</function> functions, it transforms | |
| any console handle (input and <emphasis>output</emphasis> - | |
| strangely enough handles to console's screen buffers are waitable) | |
| into a dedicated wait event for the targetted console. There's an | |
| (undocumented) <filename>KERNEL32</filename> function | |
| <function>GetConsoleInputWaitHandle()</function> which returns the | |
| handle to this event in case you need it. Another interesting | |
| handling of those console's handles is in | |
| <function>ReadFile()</function> | |
| (resp. <function>WriteFile()</function>), which behavior, for | |
| console's handles, is transferred to | |
| <function>ReadConsole()</function> (resp. | |
| <function>WriteConsole()</function>). Note that's always the ANSI | |
| version of | |
| <function>ReadConsole()</function> / | |
| <function>WriteConsole()</function> | |
| which is called, hence using the default console's code page. There | |
| are some other spots affected, but you can look in | |
| <filename>dlls/kernel</filename> to find them all. All of this is | |
| implemented in Wine. | |
| </para> | |
| <para> | |
| Wine also implements the same layout of the registry for storing the | |
| preferences of the console as Windows does. Those settings can | |
| either be defined globally, or on a per process name basis. | |
| <command>wineconsole</command> provides the choice to the user to | |
| pick you which registry part (global, current running program) it | |
| wishes to modify the settings for. | |
| <table> | |
| <title>Console registry settings</title> | |
| <tgroup cols="3" align="left"> | |
| <thead> | |
| <row> | |
| <entry>Name</entry> | |
| <entry>Default value</entry> | |
| <entry>Purpose</entry> | |
| </row> | |
| </thead> | |
| <tbody> | |
| <row> | |
| <entry>CursorSize</entry> | |
| <entry>25</entry> | |
| <entry> | |
| Percentage of cell height to which the cursor extents | |
| </entry> | |
| </row> | |
| <row> | |
| <entry>CursorVisible</entry> | |
| <entry>1</entry> | |
| <entry>Whether the cursor is visible or not</entry> | |
| </row> | |
| <row> | |
| <entry>EditionMode</entry> | |
| <entry>0</entry> | |
| <entry> | |
| The way the edition takes place in the console: 0 is | |
| insertion mode, 1 is overwrite mode. | |
| </entry> | |
| </row> | |
| <row> | |
| <entry>ExitOnDie</entry> | |
| <entry>1</entry> | |
| <entry> | |
| Whether the console should close itself when last running | |
| program attached to it dies | |
| </entry> | |
| </row> | |
| <row> | |
| <entry>FaceName</entry> | |
| <entry>No default</entry> | |
| <entry> | |
| Name of the font to be used for display. When none is | |
| given, <command>wineconsole</command> tries its best to | |
| pick up a decent font | |
| </entry> | |
| </row> | |
| <row> | |
| <entry>FontSize</entry> | |
| <entry>0x0C08</entry> | |
| <entry> | |
| The high word in the font's cell height, and the low word | |
| is the font cell's width. The default value is 12 pixels | |
| in height and 8 pixels in width. | |
| </entry> | |
| </row> | |
| <row> | |
| <entry>FontWeight</entry> | |
| <entry>0</entry> | |
| <entry> | |
| Weigth of the font. If none is given (or 0) | |
| <command>wineconsole</command> picks up a decent font size | |
| </entry> | |
| </row> | |
| <row> | |
| <entry>HistoryBufferSize</entry> | |
| <entry>50</entry> | |
| <entry> | |
| Number of entries in history buffer (not actually used) | |
| </entry> | |
| </row> | |
| <row> | |
| <entry>HistoryNoDup</entry> | |
| <entry>0</entry> | |
| <entry> | |
| Whether the history should store twice the same entry | |
| </entry> | |
| </row> | |
| <row> | |
| <entry>MenuMask</entry> | |
| <entry>0</entry> | |
| <entry> | |
| This mask only exists for Wine console handling. It | |
| allows to know which combination of extra keys are need to | |
| open the configuration window on right click. The mask | |
| can include <constant>MK_CONTROL</constant> or | |
| <constant>MK_SHIFT</constant> bits. This can be needed | |
| when programs actually need the right click to be passed | |
| to them instead of being intercepted by | |
| <command>wineconsole</command>. | |
| </entry> | |
| </row> | |
| <row> | |
| <entry>QuickEdit</entry> | |
| <entry>0</entry> | |
| <entry> | |
| If null, mouse events are sent to the application. If non | |
| null, mouse events are used to select text on the window. | |
| This setting must really be set on a application per | |
| application basis, because it deals with the fact the CUI | |
| application will use or not the mouse events. | |
| </entry> | |
| </row> | |
| <row> | |
| <entry>ScreenBufferSize</entry> | |
| <entry>0x1950</entry> | |
| <entry> | |
| The high word is the number of font cells in the height of | |
| the screen buffer, while the low word is the number of | |
| font cells in the width of the screen buffer. | |
| </entry> | |
| </row> | |
| <row> | |
| <entry>ScreenColors</entry> | |
| <entry>0x000F</entry> | |
| <entry> | |
| Default color attribute for the screen buffer (low char is | |
| the foreground color, and high char is the background | |
| color) | |
| </entry> | |
| </row> | |
| <row> | |
| <entry>WindowSize</entry> | |
| <entry>0x1950</entry> | |
| <entry> | |
| The high word is the number of font cells in the height of | |
| the window, while the low word is the number of font cells | |
| in the width of the window. This window is the visible | |
| part of the screen buffer: this implies that a screen | |
| buffer must always be bigger than its window, and that the | |
| screen buffer can be scrolled so that every cell of the | |
| screen buffer can be seen in the window. | |
| </entry> | |
| </row> | |
| </tbody> | |
| </tgroup> | |
| </table> | |
| </para> | |
| </sect3> | |
| </sect2> | |
| </sect1> | |
| </chapter> | |
| <!-- Keep this comment at the end of the file | |
| Local variables: | |
| mode: sgml | |
| sgml-parent-document:("wine-devel.sgml" "set" "book" "part" "chapter" "") | |
| End: | |
| --> |