-This is intend to be a document to help new developers get started.
-Existing developers should feel free to add there comments.
+This document should help new developers get started. Like all of Wine, it
+is a work in progress.
-SUBMITTING YOUR WORK:
-Submissions of code for inclussion into Wine should be sent to
-wine-new@amscons.com (Bob Amstadt). You MUST provide a suitable
-ChangeLog entry for any work that you submit. I prefer new code
-to be submitted as unified diffs (diff -u) off of the latest release.
-Releases are every Tuesday evening (approximately 17:00 PST or
-Wednesday 01:00 GMT).
+SOURCE TREE STRUCTURE
+=====================
-MEMORY AND SEGMENTS:
+The Wine source tree is loosely based on the original Windows modules.
+Most of the source is concerned with implementing the Wine API, although
+there are also various tools, documentation, sample Winelib code, and
+code specific to the binary loader.
+
+DLLs:
+-----
+ dlls/ - All the DLLs implemented by Wine
+
+ advapi32/ - crypto, systeminfo, security, eventlogging
+ avicap32/
+ avifil32/ - COM object to play AVI files
+ comctl32/ - common controls
+ commdlg/ - common dialog boxes (both 16 & 32 bit)
+ crtdll/ - Old C runtime library
+ crypt32/
+ dciman32/
+ ddraw/ - DirectX ddraw
+ dinput/ - DirectX dinput
+ dplay/ - DirectX dplay
+ dplayx/ - DirectX dplayx
+ dsound/ - DirectX dsound
+ gdi/ - GDI (graphics calls)
+ enhmetafiledrv/ - enhanced metafile driver
+ metafiledrv/ - metafile driver
+ win16drv/ - support for Win16 printer drivers
+ glu32/
+ icmp/
+ imagehlp/ - PE (Portable Executable) Image Helper lib
+ imm32/
+ kernel/ - The Windows kernel
+ lzexpand/ - Liv-Zempel compression/decompression
+ mpr/ - Multi-Protocol Router (interface to various
+ network transport protocols)
+ msacm/ - audio compression manager (multimedia) (16 bit)
+ msacm32/ - audio compression manager (multimedia) (32 bit)
+ msdmo/
+ msimg32/
+ msisys/
+ msnet/
+ msrle32
+ msvcrt/ - 16 bit C runtime library
+ msvcrt20/ - 32 bit C runtime library
+ msvideo/ - 16 bit video manager
+ netapi32/
+ ntdll/ - NT implementation of kernel calls
+ odbc32/
+ ole32/ - 32 bit OLE 2.0 libraries
+ oleaut32/ - 32 bit OLE 2.0 automation
+ olecli/ - 16 bit OLE client
+ oledlg/ - OLE 2.0 user interface support
+ olepro32/ - 32 bit OLE 2.0 automation
+ olesvr/ - 16 bit OLE server
+ opengl32/ - OpenGL implementation
+ psapi/ - process status API
+ qcap/
+ quartz/
+ rasapi32/ - remote access server API
+ richedit/
+ rpcrt4/
+ serialui/
+ setupapi/
+ shdocvw/
+ shfolder/
+ shell32/ - COM object implementing shell views
+ shlwapi/
+ sti/
+ tapi32/ - telephone API
+ ttydrv/ - TTY display driver (Wine specific)
+ url
+ urlmon
+ user/ - Window management, standard controls, etc.
+ ver/ - File Installation Library (16 bit)
+ version/ - File Installation Library (32 bit)
+ win32s/
+ win87em/ - 80387 math-emulation
+ winaspi/ - 16 bit Advanced SCSI Peripheral Interface
+ winedos/ - DOS features and BIOS calls (interrupts)
+ wineps/ - Postscript driver (Wine specific)
+ winmm/ - multimedia (16 & 32 bit)
+ mciXXX/ - various MCI drivers
+ midimap/- midi mapper
+ wavemap/- audio mapper
+ winearts/ - ARTS audio driver
+ wineoss/- MM driver for OSS systems
+ winnls/ - National Language Support
+ winsock/
+ wsock32/
+ winspool/ - Printing & Print Spooler
+ wintrust/
+ wnaspi32/ - 32 bit ASPI
+ x11drv/ - X11 display driver (Wine specific)
+
+Winelib programs:
+-----------------
+
+ programs/ - All the Winelib programs
+ avitools/
+ clock/
+ cmdlgtst/
+ control/
+ expand/
+ notepad/
+ osversioncheck/
+ progman/
+ regapi/
+ regedit/
+ regsvr32/
+ regtest/
+ uninstaller/
+ view/
+ wcmd/
+ wineconsole/
+ winedbg/
+ winefile/
+ winemine/
+ winepath/
+ winetest/
+ winhelp/
+ winver/
+
+
+Support programs, libraries, etc:
+---------------------------------
+
+ documentation/ - some documentation
+ include/ - Windows standard includes
+ library/ - the Wine portability library
+ miscemu/ - the main Wine program
+ ole/ - global UUIDs static library
+ server/ - the Wine server
+ tools/ - relay code builder, new rc, bugreport
+ generator, wineconfigurator, etc.
+ unicode/ - Unicode support shared
+
+
+Miscellaneous:
+--------------
+
+Note: these directories will ultimately get moved into their
+respective dlls.
+
+ files/ - KERNEL file I/O
+ if1632/ - KERNEL relay code
+ loader/ - KERNEL loader code
+ memory/ - KERNEL memory management
+ misc/ - KERNEL shell, registry, winsock, etc.
+ msdos/ - KERNEL DOS support
+ relay32/ - KERNEL 32-bit relay code
+ scheduler/ - KERNEL process and thread management
+ win32/ - KERNEL misc Win32 functions
+
+ graphics/ - GDI graphics drivers
+ objects/ - GDI logical objects
+
+ controls/ - USER built-in widgets
+ windows/ - USER window management
+
+ tsx11/ - thread-safe X11 wrappers (auto generated)
+
+
+
+IMPLEMENTING NEW API CALLS
+==========================
+
+This is the simple version, and covers only Win32. Win16 is slightly
+uglier, because of the Pascal heritage and the segmented memory model.
+
+All of the Win32 APIs known to Wine are listed in the .spec file of
+their corresponding dll. An unimplemented call will look like (from
+gdi32.spec)
+ 269 stub PolyBezierTo
+To implement this call, you need to do the following four things.
+
+1. Find the appropriate parameters for the call, and add a prototype to
+the correct header file. In this case, that means [include/wingdi.h],
+and it might look like
+ BOOL WINAPI PolyBezierTo(HDC, LPCVOID, DWORD);
+If the function has both an ASCII and a Unicode version, you need to
+define both and add a #define WINELIB_NAME_AW declaration. See below
+for discussion of function naming conventions.
+
+2. Modify the .spec file to tell Wine that the function has an
+implementation, what the parameters look like and what Wine function
+to use for the implementation. In Win32, things are simple--everything
+is 32-bits. However, the relay code handles pointers and pointers to
+strings slightly differently, so you should use 'str' and 'wstr' for
+strings, 'ptr' for other pointer types, and 'long' for everything else.
+ 269 stdcall PolyBezierTo(long ptr long) PolyBezierTo
+The 'PolyBezierTo' at the end of the line is which Wine function to use
+for the implementation.
+
+3. Implement the function as a stub. Once you add the function to the .spec
+file, you must add the function to the Wine source before it will link.
+Add a function called 'PolyBezierTo' somewhere. Good things to put
+into a stub:
+ o a correct prototype, including the WINAPI
+ o header comments, including full documentation for the function and
+ arguments (see documentation/README.documentation)
+ o A FIXME message and an appropriate return value are good things to
+ put in a stub.
+
+ /************************************************************
+ * PolyBezierTo (GDI32.269)
+ *
+ * Draw many Bezier curves
+ *
+ * RETURNS
+ * nonzero on success or zero on faillure
+ *
+ * BUGS
+ * Unimplemented
+ */
+ BOOL WINAPI PolyBezierTo(HDC hdc, /* handle to device context */
+ LPCVOID p, /* ptr to array of Point structs */
+ DWORD count /* nr of points in array */
+ )
+ {
+ /* tell the user they've got a substandard implementation */
+ FIXME(gdi, ":(%x,%p,%d): stub\n", hdc, p, count);
+
+ /* some programs may be able to compensate,
+ * if they know what happened
+ */
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return FALSE; /* error value */
+ }
+
+4. Implement and test the rest of the function.
+
+
+IMPLEMENTING A NEW DLL
+======================
+
+Generic directions
+------------------
+
+Apart from writing the set of needed .c files, you also need to do the
+following:
+
+1. Create a directory <MyDll> where to store the implementation of
+ the DLL. This directory has to be put under the dlls/ directory.
+ If the DLL exists under Windows as both 16 and 32 bit DLL, you
+ should have a single directory with both implementations.
+
+2. Create the Makefile.in in the ./dlls/<MyDll>/ directory. You can
+ copy an existing Makefile.in from another ./dlls/ subdirectory.
+ You need at least to change the MODULE and C_SRCS macros.
+
+3. Add the directory in ./configure.ac (in AC_OUTPUT macro at the end
+ of the file to trigger the Makefile generation)
+
+4. Run ./make_dlls in the dlls directory to update Makefile.in in
+ that directory.
+
+5. You can now regenerate ./configure file (with 'make configure')
+ and the various Makefiles (with 'configure; make depend') (run
+ from the top of Wine's tree).
+ You should now have a Makefile file in ./dlls/<MyDll>/
+
+6. Create the .spec file for the DLL exported functions in your
+ directory. Refer to 'Implementation of new API calls' earlier in
+ this document for more information on this part.
+
+7. You can now start adding .c files. For the .h files, if they are
+ standard Windows one, put them in include/. If they are linked to
+ *your* implementation of the dll, put them in your newly created
+ directory.
+
+Debug channels
+--------------
+
+If you need to create a new debug channel, just add the
+WINE_DEFAULT_DEBUG_CHANNEL to your .c file(s), and use them.
+All the housekeeping will happen automatically.
+
+Resources
+---------
+
+If you also need to add resources to your DLL, the create the .rc
+file. Add to your ./dlls/<MyDll>/Makefile.in, in the RC_SRCS macro,
+the list of .rc files to add to the DLL. See dlls/comctl32/ for an
+example of this.
+
+Thunking
+--------
+
+If you're building a 16 & 32 bit DLLs pair, then from the 32 bit code
+you might need to call 16 bit routine. The way to do it to add in the
+code, fragments like:
+/* ### Start build ### */
+extern WORD CALLBACK <PREFIX>_CallTo16_word_wwlll(FARPROC16,WORD,WORD,LONG,LONG,LONG);
+/* ### stop build ### */
+Where <PREFIX>_ is an internal prefix for your module. The first
+parameter is always of type FARPROC16. Then, you can get the regular
+list of parameters. The _word_wwlll indicates the type of return (long
+or word) and the size of the parameters (here l=>long, w=>word; which
+maps to WORD,WORD,LONG,LONG,LONG.
+You can put several functions between the Start/Stop build pair.
+
+You can also read the winebuild manpage for more details on this.
+
+Then, add to ./dlls/<MyDll>/Makefile.in a line like:
+
+EXTRA_OBJS = $(MODULE).glue.o
+
+See dlls/winmm/ for an example of this.
+
+MEMORY AND SEGMENTS
+===================
NE (Win16) executables consist of multiple segments. The Wine loader
-loads each segment into a unique location the Wine processes memory
-and assigns a selector to that segment. To make address conversion
-simpler, Wine loads the segments in such a way that the segmented
-address (16:16) is stored in memory the same way as the 32-bit linear
-address. For example, the segmented address 1237:89AB can be at the
-address 0x123789AB in the Wine process space.
-
-This also implies that a Win16 program cannot access any arbitrary
-memory location. If a pointer needs to be returned to a Win16 program,
-then the memory block must be allocated using either GlobalAlloc()
-or HEAP_Alloc(). The HEAP_* functions are faster than the Global*
-functions but are only capable of managing a 64k memory block. The
-HEAP_* functions are used to implement local heaps. Wine should
-never call Local* functions. These functions are reserved for use
-by Win16 programs only!
-
-The following code fragment should be used to establish a new Wine
-local heap:
-
- #include "heap.h"
-
- #define MY_HEAP_SIZE 0x10000 /* Must be <= 64k */
-
- int MyHeapHandle;
- void *MyHeapBase;
- MDESC *MyHeap;
-
- ...
-
- int InitMyHeap()
- {
- MyHeapHandle = GlobalAlloc(GMEM_FIXED, MY_HEAP_SIZE);
- if (MyHeapHandle == 0)
- return -1;
- MyHeapBase = GlobalLock(MyHeapHandle);
- HEAP_Init(&MyHeap, MyHeapBase, MY_HEAP_SIZE);
- return 0;
- }
-
-Memory blocks greater than 64 kilobytes in length must be allocated
-using GlobalAlloc(). Because of our special memory mapping, GlobalLock()
-cannot be used to obtain the address of a linearly accessible memory
-block that is greater than 64kB in length. Instead GlobalLinearLock()
-should be used. The inverse function GlobalLinearUnlock() must be
-called before the block can be freed with GlobalFree().
-
-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 dll_*.s and dll_tab_*.c. The dll_*.s
-files contain the entry point code for each API call, and the dll_tab_*.s
-files contain tables used by relay.c to translate arguments and transfer
-control to the proper handler. The format of the *.spec files is
-documented in the file "tools/build-spec.txt".
-
-REGISTER FUNCTIONS:
-
-Some functions are defined as type "register" in the DLL specification files.
-Inorder to return values in the registers to the WIN16 program, the handler
-function must exit by calling ReturnFromRegisterFunc(). Look at the function
-DOS3Call() for an example of how this works.
-
-DEBUG MESSAGES:
+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:
+ - Using the MapLS function (recommended).
+ - Allocate a block of memory from the global heap and use
+ WIN16_GlobalLock to get its segmented address.
+ - 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 MapSL function. 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 embed the struct within two special
+#include's which will take care of the packing for you:
+
+#include "pshpack1.h"
+struct { BYTE x; WORD y; };
+#include "poppack1.h"
+
+For alignment on a 2-byte boundary, there is a "pshpack2.h", etc.
+
+The use of the WINE_PACKED attribute is obsolete. Please remove these
+in favour of the above solution.
+Using WINE_PACKED, you would declare the above structure like this:
+
+struct { BYTE x; WORD y WINE_PACKED; };
+
+You had 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 was 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, 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 Win16 version,
+ - 'xxx' for the Win32 version when no ASCII/Unicode strings are
+ involved,
+ - 'xxxA' for the Win32 version with ASCII strings,
+ - 'xxxW' for the Win32 version with Unicode strings.
+
+If the function has both ASCII and Unicode version, you should then
+use the macros WINELIB_NAME_AW(xxx) or DECL_WINELIB_TYPE_AW(xxx)
+(defined in include/windef.h) to define the correct 'xxx' function
+or type for Winelib. When compiling Wine itself, 'xxx' is _not_
+defined, meaning that code inside of Wine must always specify
+explicitly the ASCII or Unicode version.
+
+If 'xxx' is the same in Win16 and Win32, you can simply use the same
+name as Windows, i.e. just 'xxx'. If 'xxx' is Win16 only, you could
+use the name as is, but it's preferable to use 'xxx16' to make it
+clear it is a Win16 function.
+
+Examples:
+
+typedef struct { /* Win32 ASCII data structure */ } WNDCLASSA;
+typedef struct { /* Win32 Unicode data structure */ } WNDCLASSW;
+typedef struct { /* Win16 data structure */ } WNDCLASS16;
+DECL_WINELIB_TYPE_AW(WNDCLASS);
+
+ATOM RegisterClass16( WNDCLASS16 * );
+ATOM RegisterClassA( WNDCLASSA * );
+ATOM RegisterClassW( WNDCLASSW * );
+#define RegisterClass WINELIB_NAME_AW(RegisterClass)
+
+The Winelib user can then say:
+
+ WNDCLASS wc = { ... };
+ RegisterClass( &wc );
+
+and this will use the correct declaration depending on the definition
+of the UNICODE symbol.
+
+
+NAMING CONVENTIONS FOR NON-API FUNCTIONS AND TYPES
+==================================================
+
+Functions and data which are internal to your code (or at least shouldn't be
+visible to any Winelib or Windows program) should be preceded by
+an identifier to the module:
+
+Examples:
+
+ENUMPRINTERS_GetDWORDFromRegistryA() (in dlls/winspool/info.c)
+IAVIFile_fnRelease() (in dlls/avifil32/avifile.c)
+X11DRV_CreateDC() (in graphics/x11drv/init.c)
+
+if you need prototypes for these, there are a few possibilities:
+- within same source file only:
+ put the prototypes at the top of your file and mark them as prototypes.
+- within the same module:
+ create a header file within the subdirectory where that module resides,
+ e.g. graphics/ddraw_private.h
+- from a totally different module, or for use in winelib:
+ you should never do that. Only exported APIs can be called across
+ module boundaries.
+
+
+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);
+ TRACE("abc..."); or
+ FIXME("abc..."); or
+ WARN("abc..."); or
+ ERR("abc...");
+
+depending on the seriousness of the problem. (documentation/degug-msgs
+explains when it is appropriate to use each of them). You need to declare
+the debug channel name at the top of the file (after the includes) using
+the WINE_DEFAULT_DEBUG_CHANNEL macro, like so:
+
+ WINE_DEFAULT_DEBUG_CHANNEL(win);
+
+If your debugging code is more complex than just printf, you can use
+the macros:
+
+ TRACE_ON(xxx), WARN_ON(xxx), ERR_ON(xxx) and FIXME_ON(xxx)
+
+to test if the given channel is enabled. Thus, you can write:
+
+ if (TRACE_ON(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
+disabled (that is TRACE_ON(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.
+For more info about debugging messages, read:
+
+documentation/debug-msgs
+
+
+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".
-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.
+4. You might want to check out BYTE from December 1983 as well :-)