| This is intended to be a document to help new developers get started. | |
| Existing developers should feel free to add their comments. | |
| SOURCE TREE STRUCTURE | |
| ===================== | |
| Source tree is loosely based on the original Windows modules. Most | |
| directories are shared between the binary emulator and the library. | |
| Shared directories: | |
| ------------------- | |
| KERNEL: | |
| files/ - file I/O | |
| loader/ - Win16-, Win32-binary loader | |
| memory/ - memory management | |
| msdos/ - DOS and BIOS emulation | |
| scheduler/ - process and thread management | |
| GDI: | |
| graphics/ - graphics drivers | |
| graphics/x11drv/ - X11 display driver | |
| graphics/metafiledrv/ - metafile driver | |
| objects/ - logical objects | |
| USER: | |
| controls/ - built-in widgets | |
| resources/ - built-in dialog resources | |
| windows/ - window management | |
| Miscellaneous: | |
| misc/ - shell, registry, winsock, etc... | |
| multimedia/ - multimedia driver | |
| ipc/ - SysV IPC management | |
| win32/ - misc Win32 functions | |
| Tools: | |
| rc/ - resource compiler | |
| tools/ - relay code builder + misc tools | |
| documentation/ - some documentation | |
| Emulator-specific directories: | |
| ------------------------------ | |
| debugger/ - built-in debugger | |
| if1632/ - relay code | |
| miscemu/ - hardware instruction emulation | |
| graphics/win16drv/ - Win16 printer driver | |
| Winelib-specific directories: | |
| ----------------------------- | |
| library/ - Winelib-specific routines (should disappear) | |
| programs/ - utilities (Progman, WinHelp) | |
| libtest/ - Winelib test samples | |
| MEMORY AND SEGMENTS | |
| =================== | |
| NE (Win16) executables consist of multiple segments. The Wine loader | |
| loads each segment into a unique location in the Wine processes memory | |
| and assigns a selector to that segment. Because of this, it's not | |
| possible to exchange addresses freely between 16-bit and 32-bit code. | |
| Addresses used by 16-bit code are segmented addresses (16:16), formed | |
| by a 16-bit selector and a 16-bit offset. Those used by the Wine code | |
| are regular 32-bit linear addresses. | |
| There are four ways to obtain a segmented pointer: | |
| - Use the SEGPTR_* macros in include/heap.h (recommended). | |
| - Allocate a block of memory from the global heap and use | |
| WIN16_GlobalLock to get its segmented address. | |
| - Allocate a block of memory from a local heap, and build the | |
| segmented address from the local heap selector (see the | |
| USER_HEAP_* macros for an example of this). | |
| - Declare the argument as 'segptr' instead of 'ptr' in the spec file | |
| for a given API function. | |
| Once you have a segmented pointer, it must be converted to a linear | |
| pointer before you can use it from 32-bit code. This can be done with | |
| the PTR_SEG_TO_LIN() and PTR_SEG_OFF_TO_LIN() macros. The linear | |
| pointer can then be used freely with standard Unix functions like | |
| memcpy() etc. without worrying about 64k boundaries. Note: there's no | |
| easy way to convert back from a linear to a segmented address. | |
| In most cases, you don't need to worry about segmented address, as the | |
| conversion is made automatically by the callback code and the API | |
| functions only see linear addresses. However, in some cases it is | |
| necessary to manipulate segmented addresses; the most frequent cases | |
| are: | |
| - API functions that return a pointer | |
| - lParam of Windows messages that point to a structure | |
| - Pointers contained inside structures accessed by 16-bit code. | |
| It is usually a good practice to used the type 'SEGPTR' for segmented | |
| pointers, instead of something like 'LPSTR' or 'char *'. As SEGPTR is | |
| defined as a DWORD, you'll get a compilation warning if you mistakenly | |
| use it as a regular 32-bit pointer. | |
| STRUCTURE PACKING | |
| ================= | |
| Under Windows, data structures are tightly packed, i.e. there is no | |
| padding between structure members. On the other hand, by default gcc | |
| aligns structure members (e.g. WORDs are on a WORD boundary, etc.). | |
| This means that a structure like | |
| struct { BYTE x; WORD y; }; | |
| will take 3 bytes under Windows, but 4 with gcc, because gcc will add a | |
| dummy byte between x and y. To have the correct layout for structures | |
| used by Windows code, you need to use the WINE_PACKED attribute; so you | |
| would declare the above structure like this: | |
| struct { BYTE x; WORD y WINE_PACKED; }; | |
| You have to do this every time a structure member is not aligned | |
| correctly under Windows (i.e. a WORD not on an even address, or a | |
| DWORD on a address that is not a multiple of 4). | |
| NAMING CONVENTIONS FOR API FUNCTIONS AND TYPES | |
| ============================================== | |
| In order to support both Win16 and Win32 APIs within the same source | |
| code, as well as share the include files between the emulator and the | |
| library, the following convention must be used in naming all API | |
| functions and types. If the Windows API uses the name 'xxx', the Wine | |
| code must use: | |
| - 'xxx16' for the 16-bit version, | |
| - 'xxx32' for the 32-bit version when no ASCII/Unicode strings are | |
| involved, | |
| - 'xxx32A' for the 32-bit version with ASCII strings, | |
| - 'xxx32W' for the 32-bit version with Unicode strings. | |
| You should then use the macros WINELIB_NAME[_AW](xxx) or | |
| DECL_WINELIB_TYPE[_AW](xxx) (defined in include/wintypes.h) to define | |
| the correct 'xxx' function or type for Winelib. When compiling the | |
| emulator, 'xxx' is _not_ defined, meaning that you must always specify | |
| explicitly whether you want the 16-bit or 32-bit version. | |
| Note: if 'xxx' is the same in Win16 and Win32, you can simply use the | |
| same name as Windows. | |
| Examples: | |
| typedef short INT16; | |
| typedef int INT32; | |
| DECL_WINELIB_TYPE(INT); | |
| typedef struct { /* Win32 ASCII data structure */ } WNDCLASS32A; | |
| typedef struct { /* Win32 Unicode data structure */ } WNDCLASS32W; | |
| typedef struct { /* Win16 data structure */ } WNDCLASS16; | |
| DECL_WINELIB_TYPE_AW(WNDCLASS); | |
| ATOM RegisterClass16( WNDCLASS16 * ); | |
| ATOM RegisterClass32A( WNDCLASS32A * ); | |
| ATOM RegisterClass32W( WNDCLASS32W * ); | |
| #define RegisterClass WINELIB_NAME_AW(RegisterClass) | |
| The Winelib user can then say: | |
| INT i; | |
| WNDCLASS wc = { ... }; | |
| RegisterClass( &wc ); | |
| and this will use the correct declaration depending on the definition | |
| of the symbols WINELIB16, WINELIB32 and UNICODE. | |
| API ENTRY POINTS | |
| ================ | |
| Because Win16 programs use a 16-bit stack and because they can only | |
| call 16:16 addressed functions, all API entry points must be at low | |
| address offsets and must have the arguments translated and moved to | |
| Wines 32-bit stack. This task is handled by the code in the "if1632" | |
| directory. To define a new API entry point handler you must place a | |
| new entry in the appropriate API specification file. These files are | |
| named *.spec. For example, the API specification file for the USER | |
| DLL is contained in the file user.spec. These entries are processed | |
| by the "build" program to create an assembly file containing the entry | |
| point code for each API call. The format of the *.spec files is | |
| documented in the file "tools/build-spec.txt". | |
| DEBUG MESSAGES | |
| ============== | |
| To display a message only during debugging, you normally write something | |
| like this: | |
| #ifdef DEBUG_WIN | |
| printf("abc..."); | |
| #endif | |
| You can write this shorter (and better) in this way: | |
| dprintf_win(stddeb,"abc..."); | |
| All symbols of the form dprintf_xxxx are macros defined in include/debug.h . | |
| The macro-definitions are generated by the shell-script tools/make_debug. It | |
| scans the source code for symbols of this forms and puts the necessary | |
| macro definitions in include/debug.h and include/stddebug.h . These macros | |
| test for the symbol DEBUG_XXXX (e.g. dprintf_win refers to DEBUG_WIN) being | |
| defined and thus decided whether to actually display the text. If you want | |
| to enable specific types of messages, simply put the corresponding | |
| #define DEBUG_XXXX in include/stddebug.h . If you want to enable or disable | |
| a specific type of message in just one c-source-file, put the corresponding | |
| #define DEBUG_XXXX or #undefine DEBUG_XXXX between #include<stddebug.h> and | |
| #include <debug.h> in that specific file. In addition you can change the | |
| types of displayed messages by supplying the "-debugmsg" option to Wine. | |
| If your debugging code is more complex than just printf, you can use the | |
| symbols debugging_XXX as well. These are true when XXX is enabled, either | |
| permanent or in the command line. So instead of writing | |
| #ifdef DEBUG_WIN | |
| DumpSomeStructure(&str); | |
| #endif | |
| write | |
| if(debugging_win)DumpSomeStructure(&str); | |
| Don't worry about the inefficiency of the test. If it is permanently | |
| disabled (thus debugging_win is 0 at compile time), the compiler will | |
| eliminate the dead code. | |
| The file handle "stddeb" is intended for displaying standard informational | |
| messages, whereas "stdnimp" is intended for displaying messages concerning | |
| not yet implemented functions. | |
| You have to start tools/make_debug only if you introduced a new macro, | |
| e.g. dprintf_win32s - not if you just changed one of the #define | |
| DEBUG_XXX's in include/stddebug.h or in a specific file. | |
| MORE INFO | |
| ========= | |
| 1. There is a FREE online version of the MSDN library (including | |
| documentation for the Win32 API) on http://www.microsoft.com/msdn/ | |
| 2. http://www.sonic.net/~undoc/bookstore.html | |
| 3. In 1993 Dr. Dobbs Journal published a column called "Undocumented Corner". | |
| 4. You might want to check out BYTE from December 1983 as well :-) | |