mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-31 11:43:31 +00:00
505 lines
16 KiB
Text
505 lines
16 KiB
Text
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 :-)
|