| This document should help new developers get started. Like all of Wine, it | |
| is a work in progress. | |
| SOURCE TREE STRUCTURE | |
| ===================== | |
| 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 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: | |
| 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 (that is TRACE_ON(win) is 0 at compile time), the compiler will | |
| eliminate the dead code. | |
| 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". | |
| 4. You might want to check out BYTE from December 1983 as well :-) |