msi: Move some registry helper functions to registry.c.
[wine] / DEVELOPERS-HINTS
1 This document should help new developers get started. Like all of Wine, it
2 is a work in progress.
3
4
5 SOURCE TREE STRUCTURE
6 =====================
7
8 The Wine source tree is loosely based on the original Windows modules. 
9 Most of the source is concerned with implementing the Wine API, although
10 there are also various tools, documentation, sample Winelib code, and
11 code specific to the binary loader.  Note that several of the libraries
12 listed here are "stubbed out", meaning they still need to be implemented.
13
14 DLLs (under dlls/):
15 -------------------
16
17         activeds/               - Active Directory Service Interface
18         advapi32/               - Crypto, systeminfo, security, eventlogging
19         advpack/                - Reads and verifies .INF files
20         amstream/               - MultiMedia Streams
21         atl/                    - Active Template Library
22         avicap32/               - AVI capture window class
23         avifil32/               - COM object to play AVI files
24         cabinet/                - Cabinet file interface
25         capi2032/               - Wrapper library for CAPI4Linux access
26         cards/                  - Card graphics
27         cfgmgr32/               - Config manager
28         comcat/                 - Component category manager
29         comctl32/               - Common controls
30         comdlg32/               - Common dialog boxes (both 16 & 32 bit)
31         compstui/               - Common Property Sheet User Interface
32         crtdll/                 - Old C runtime library
33         crypt32/                - Cryptography
34         cryptdll/               - Cryptography Manager
35         ctl3d32/                - 3D Effects for Common GUI Components
36         d3d8/                   - Direct3D (3D graphics)
37         d3d9/                   - Direct3D (3D graphics)
38         d3dim/                  - Direct3D Immediate Mode
39         d3drm/                  - Direct3D Retained Mode
40         d3dx8/                  - Direct3D (3D graphics)
41         d3dxof/                 - DirectX Files Functions
42         dbghelp/                - Engine for symbol and module enumeration
43         dciman32/               - DCI Manager (graphics)
44         ddraw/                  - DirectDraw (graphics)
45         devenum/                - Device enumeration (part of DirectShow)
46         dinput/                 - DirectInput (device input)
47         dinput8/                - DirectInput (device input)
48         dmband/                 - DirectMusic Band
49         dmcompos/               - DirectMusic Composer
50         dmime/                  - DirectMusic Interactive Engine
51         dmloader/               - DirectMusic Loader
52         dmscript/               - DirectMusic Scripting
53         dmstyle/                - DirectMusic Style Engine
54         dmsynth/                - DirectMusic Software Synthesizer
55         dmusic/                 - DirectMusic Core Services
56         dmusic32/               - DirectMusic Legacy Port
57         dnsapi/                 - DNS support
58         dplay/                  - DirectPlay (networking)
59         dplayx/                 - DirectPlay (networking)
60         dpnet/                  - DirectPlay (networking)
61         dpnhpast/               - DirectPlay NAT Helper PAST
62         dsound/                 - DirectSound (audio)
63         dswave/                 - DirectMusic Wave
64         dxdiagn/                - DirectX Diagnostic Tool 
65         gdi/                    - GDI (graphics)
66         glu32/                  - OpenGL Utility library (graphics)
67         glut32/                 - OpenGL Utility Toolkit
68         gphoto2.ds/             - Contains libgphoto2 based TWAIN datasource driver
69         hhctrl.ocx/             - HHCTRL OCX implementation
70         hlink/                  - Microsoft Hyperlink Library
71         iccvid/                 - Radius Cinepak Video Decoder
72         icmp/                   - ICMP protocol (networking)
73         ifsmgr.vxd/             - IFSMGR VxD implementation
74         imaadp32.acm/           - IMA ADPCM Audio Codec
75         imagehlp/               - PE (Portable Executable) Image Helper lib
76         imm32/                  - Input Method Manager
77         inseng/                 - Install engine
78         iphlpapi/               - IP Helper API
79         itss/                   - Infotech Structured Storage (HTML Help)
80         kernel/                 - The Windows kernel
81         lz32/                   - Lempel-Ziv compression/decompression
82         mapi32/                 - Mail interface
83         mciavi32/               - MCI video driver
84         mcicda/                 - MCI audio CD driver
85         mciseq/                 - MCI MIDI driver
86         mciwave/                - MCI wave driver
87         midimap/                - MIDI mapper
88         mlang/                  - Multi Language Support
89         mmdevldr.vxd/           - MMDEVLDR VxD implementation
90         monodebg.vxd/           - MONODEBG VxD implementation
91         mpr/                    - Multi-Protocol Router (networking)
92         mprapi/                 - Multi-Protocol Router Administration
93         msacm32/                - Audio Compression Manager (multimedia)
94         msacm32.drv/            - Audio mapper
95         msadp32.acm/            - MS ADPCM Audio Codec
96         mscms/                  - Color Management System
97         msdmo/                  - DirectX Media Objects
98         msftedit/               - Rich text editing control (Version 4.1)
99         msg711.acm/             - MS G711 Audio Codec (includes A-Law & MU-Law)
100         mshtml/                 - MS HTML component
101         msi/                    - Microsoft Installer
102         msimg32/                - Gradient and transparency (graphics)
103         msisys.ocx/             - System information
104         msnet32/                - Network interface
105         msrle32/                - Video codecs
106         msvcrt/                 - C runtime library 
107         msvcrt20/               - C runtime library version 2.0
108         msvcrt40/               - C runtime library version 4.0
109         msvcrtd/                - C runtime library debugging
110         msvfw32/                - 16 bit video manager
111         msvidc32/               - Microsoft Video-1 Decoder
112         mswsock/                - Misc networking
113         msxml3/                 - MSXML Class Factory
114         netapi32/               - Network interface
115         newdev/                 - New Hardware Device Library
116         ntdll/                  - NT implementation of kernel calls
117         ntdsapi/                - NT Directory Service Provider
118         objsel/                 - Object Picker Dialog
119         odbc32/                 - Open DataBase Connectivity driver manager
120         odbccp32/               - Open DataBase Connectivity driver installer
121         ole32/                  - 32 bit OLE 2.0 libraries
122         oleacc/                 - OLE accessibility support
123         oleaut32/               - 32 bit OLE 2.0 automation
124         olecli32/               - 16 bit OLE client
125         oledlg/                 - OLE 2.0 user interface support
126         olepro32/               - 32 bit OLE 2.0 automation
127         olesvr32/               - 16 bit OLE server
128         opengl32/               - OpenGL implementation (graphics)
129         powrprof/               - Power Management and Profiling
130         psapi/                  - Process Status interface
131         qcap/                   - DirectShow runtime
132         quartz/                 - DirectShow runtime
133         rasapi32/               - Remote Access Server interface
134         riched20/               - Rich text editing control (Version 2.0 and 3.0)
135         riched32/               - Rich text editing control
136         rpcrt4/                 - Remote Procedure Call runtime
137         rsabase/                - RSA encryption
138         rsaenh/                 - Crypto API (DES, 3DES, RSA, etc.)
139         sane.ds/                - Contains sane based TWAIN datasource driver
140         secur32/                - Contains Windows Security functions
141         security/               - Security Support Provider Interface
142         sensapi/                - System Event Notification Service
143         serialui/               - Serial port property pages
144         setupapi/               - Setup interface
145         sfc/                    - System File Checker (Windows File Protection)
146         shdocvw/                - Shell document object and control
147         shell32/                - COM object implementing shell views
148         shfolder/               - Shell folder service
149         shlwapi/                - Shell Light-Weight interface
150         snmpapi/                - SNMP protocol interface (networking)
151         spoolss/                - Spooler Subsystem Library ("spooler" - Service)
152         stdole2.tlb/            - OLE Automation typelib
153         stdole32.tlb/           - Standard OLE typelib
154         sti/                    - Still Image service
155         tapi32/                 - Telephone interface
156         twain_32/               - TWAIN Imaging device communications
157         unicows/                - Unicows replacement (Unicode layer for Win9x)
158         url/                    - Internet shortcut shell extension
159         urlmon/                 - URL Moniker allows binding to a URL
160         user/                   - Window management, standard controls, etc.
161         userenv/                - User - Environment and Policy Management
162         usp10/                  - Uniscribe Script Processor
163         uxtheme/                - Theme library
164         vdhcp.vxd/              - VDHCP VxD implementation
165         vdmdbg/                 - Virtual DOS machine debug library
166         version/                - File installation library
167         vmm.vxd/                - VMM VxD implementation
168         vnbt.vxd/               - VNBT VxD implementation
169         vnetbios.vxd/           - VNETBIOS VxD implementation
170         vtdapi.vxd/             - VTDAPI VxD implementation
171         vwin32.vxd/             - VWIN32 VxD implementation
172         win32skrnl/             - 32-bit function access for 16-bit systems
173         wined3d/                - Wine internal Direct3D helper
174         winedos/                - DOS features and BIOS calls (Wine specific)
175         winemp3.acm/            - Mpeg Layer 3 Audio Codec
176         wineps.drv/             - Postscript driver (Wine specific)
177         winex11.drv/            - X11 display driver (Wine specific)
178         wininet/                - Internet extensions
179         winmm/                  - Multimedia (16 & 32 bit)
180         winmm/joystick/         - Joystick driver
181         winmm/winealsa/         - ALSA audio driver
182         winmm/winearts/         - aRts audio driver
183         winmm/wineaudioio/      - audioio audio driver
184         winmm/winecoreaudio/    - CoreAudio audio driver (MacOS)
185         winmm/winejack/         - JACK audio server driver
186         winmm/winenas/          - NAS audio driver
187         winmm/wineoss/          - OSS audio driver
188         winnls32/               - National Language Support
189         winspool.drv/           - Printing & Print Spooler
190         wintab32/               - Tablet device interface
191         wintrust/               - Trust verification interface
192         wldap32/                - LDAP support
193         wnaspi32/               - 16 bit Advanced SCSI Peripheral Interface
194         wow32/                  - WOW subsystem
195         ws2_32/                 - Sockets 2.0 (networking)
196         wsock32/                - Sockets 1.1 (networking)
197         wtsapi32/               - Terminal Services
198
199 Winelib programs (under programs/):
200 -----------------------------------
201
202         clock/                  - Graphical clock
203         cmdlgtst/               - Common dialog tests
204         control/                - Control panel
205         eject/                  - Unmount and eject removable Media
206         expand/                 - Decompress Lempel-Ziv compressed archive
207         explorer/               - Desktop/Systray/HAL-Manager, Winefile-wrapper
208         hh/                     - HTML Help viewer
209         icinfo/                 - List/Configure installed Video Compressors
210         iexplore/               - Internet Explorer replacement 
211         msiexec/                - Microsoft Installer frontend
212         notepad/                - Notepad replacement 
213         oleview/                - OLE/COM Object Viewer
214         progman/                - Program manager
215         regedit/                - Registry editor
216         regsvr32/               - Register COM server
217         rpcss/                  - RPC services
218         rundll32/               - Execute DLL functions directly
219         start/                  - Replacement for start.exe
220         taskmgr/                - Manage running Windows/Winelib applications
221         uninstaller/            - Remove installed programs
222         view/                   - Metafile viewer
223         wcmd/                   - Command line interface
224         wineboot/               - Wine bootstrap process
225         winebrowser/            - Frontend for Webbrowsers on the Host
226         winecfg/                - Wine configuration utility
227         wineconsole/            - Console
228         winedbg/                - Debugger
229         winefile/               - File manager
230         winemenubuilder/        - Helper program for building Unix menu entries
231         winemine/               - Mine game
232         winepath/               - Translate between Wine and Unix paths
233         winetest/               - Wine testing shell
234         winevdm/                - Wine virtual DOS machine
235         winhelp/                - Help viewer
236         winver/                 - Windows Version Program
237         wordpad/                - Wordpad replacement skeleton
238
239
240 Support programs, libraries, etc:
241 ---------------------------------
242
243         dlls/dxerr8/            - DirectX 8 error import lib
244         dlls/dxerr9/            - DirectX 9 error import lib
245         dlls/dxguid/            - DirectX UUID import lib
246         dlls/strmiids/          - Exports class CLSIDs and interface IIDs
247         dlls/uuid/              - Windows-compatible UUID import lib
248         documentation/          - some documentation
249         include/                - Windows standard includes
250         include/ddk/            - Windows DDK compatible headers
251         include/msvcrt/         - MSVC compatible libc headers
252         include/wine/           - Wine specific headers
253         libs/                   - the Wine libraries
254         libs/port/              - portability library
255         libs/unicode/           - Unicode support shared
256         libs/wine/              - Wine bootstrap library
257         libs/wpp/               - C preprocessor
258         loader/                 - the main Wine loader
259         server/                 - the Wine server
260         tools/                  - various tools used to build/check Wine
261         tools/widl/             - the IDL compiler
262         tools/winapi/   - A Win32 API checker
263         tools/winebuild/        - Wine build tool
264         tools/winedump/         - a .DLL dump utility
265         tools/winegcc/          - a MinGW command line compatible gcc wrapper
266         tools/wmc/              - the message compiler
267         tools/wrc/              - the resource compiler
268
269
270
271 IMPLEMENTING NEW API CALLS
272 ==========================
273
274 This is the simple version, and covers only Win32. Win16 is slightly
275 uglier, because of the Pascal heritage and the segmented memory model.
276
277 All of the Win32 APIs known to Wine are listed in the .spec file of
278 their corresponding dll. An unimplemented call will look like (from
279 gdi32.spec)
280   269 stub PolyBezierTo
281 To implement this call, you need to do the following four things.
282
283 1. Find the appropriate parameters for the call, and add a prototype to
284 the correct header file. In this case, that means [include/wingdi.h],
285 and it might look like
286   BOOL WINAPI PolyBezierTo(HDC, LPCVOID, DWORD);
287 If the function has both an ASCII and a Unicode version, you need to
288 define both and add a #define WINELIB_NAME_AW declaration. See below
289 for discussion of function naming conventions.
290   
291 2. Modify the .spec file to tell Wine that the function has an
292 implementation, what the parameters look like and what Wine function
293 to use for the implementation. In Win32, things are simple--everything
294 is 32-bits. However, the relay code handles pointers and pointers to
295 strings slightly differently, so you should use 'str' and 'wstr' for
296 strings, 'ptr' for other pointer types, and 'long' for everything else.
297   269 stdcall PolyBezierTo(long ptr long) PolyBezierTo
298 The 'PolyBezierTo' at the end of the line is which Wine function to use
299 for the implementation.
300
301 3. Implement the function as a stub. Once you add the function to the .spec
302 file, you must add the function to the Wine source before it will link.
303 Add a function called 'PolyBezierTo' somewhere. Good things to put
304 into a stub:
305   o a correct prototype, including the WINAPI
306   o header comments, including full documentation for the function and
307     arguments (see documentation/README.documentation)
308   o A FIXME message and an appropriate return value are good things to
309     put in a stub.
310
311   /************************************************************
312    *                    PolyBezierTo   (GDI32.269)  
313    *  
314    * Draw many Bezier curves.
315    *
316    * PARAMS
317    *   hdc   [I] Device context to draw to
318    *   p     [I] Array of POINT structs
319    *   count [I] Number of points in p
320    *
321    * RETURNS
322    *   Success: Non-zero.
323    *   Failure: FALSE. Use GetLastError() to find the error cause.
324    *
325    * BUGS
326    *   Unimplemented
327    */
328    BOOL WINAPI PolyBezierTo(HDC hdc, LPCVOID p, DWORD count) 
329    {
330        /* tell the user they've got a substandard implementation */
331        FIXME("(%x,%p,%d): stub\n", hdc, p, count);
332
333        /* some programs may be able to compensate, 
334         * if they know what happened 
335         */
336        SetLastError(ERROR_CALL_NOT_IMPLEMENTED);  
337        return FALSE;    /* error value */
338    }
339
340 4. Implement and test the rest of the function.
341
342
343 IMPLEMENTING A NEW DLL
344 ======================
345
346 Generic directions
347 ------------------
348
349 Apart from writing the set of needed .c files, you also need to do the 
350 following:
351
352 1.  Create a directory <MyDll> where to store the implementation of
353     the DLL. This directory has to be put under the dlls/ directory.
354     If the DLL exists under Windows as both 16 and 32 bit DLL, you
355     should have a single directory with both implementations.
356
357 2.  Create the Makefile.in in the ./dlls/<MyDll>/ directory. You can
358     copy an existing Makefile.in from another ./dlls/ subdirectory.
359     You need at least to change the MODULE and C_SRCS macros. 
360
361 3.  Add the directory in ./configure.ac (in AC_OUTPUT macro at the end
362     of the file to trigger the Makefile generation)
363
364 4.  Run ./make_dlls in the dlls directory to update Makefile.in in
365     that directory.
366
367 5.  You can now regenerate ./configure file (with 'autoconf')
368     and the various Makefiles (with 'configure; make depend') (run
369     from the top of Wine's tree).
370     You should now have a Makefile file in ./dlls/<MyDll>/
371
372 6.  Create the .spec file for the DLL exported functions in your
373     directory. Refer to 'Implementation of new API calls' earlier in
374     this document for more information on this part.
375
376 7.  You can now start adding .c files. For the .h files, if they are
377     standard Windows one, put them in include/. If they are linked to
378     *your* implementation of the dll, put them in your newly created
379     directory.
380
381 Debug channels
382 --------------
383
384 If you need to create a new debug channel, just add the
385 WINE_DEFAULT_DEBUG_CHANNEL to your .c file(s), and use them. 
386 All the housekeeping will happen automatically.
387
388 Resources
389 ---------
390
391 If you also need to add resources to your DLL, then create the .rc
392 file. Add to your ./dlls/<MyDll>/Makefile.in, in the RC_SRCS macro,
393 the list of .rc files to add to the DLL. See dlls/comctl32/ for an
394 example of this.
395
396 Thunking
397 --------
398
399 If you're building a 16 & 32 bit DLLs pair, then from the 32 bit code
400 you might need to call 16 bit routine. The way to do it to add in the
401 code, fragments like:
402 /* ### Start build ### */
403 extern WORD CALLBACK <PREFIX>_CallTo16_word_wwlll(FARPROC16,WORD,WORD,LONG,LONG,LONG);
404 /* ### stop build ### */
405 Where <PREFIX>_ is an internal prefix for your module. The first
406 parameter is always of type FARPROC16. Then, you can get the regular
407 list of parameters. The _word_wwlll indicates the type of return (long
408 or word) and the size of the parameters (here l=>long, w=>word; which
409 maps to WORD,WORD,LONG,LONG,LONG.
410 You can put several functions between the Start/Stop build pair.
411
412 You can also read the winebuild manpage for more details on this.
413
414 Then, add to ./dlls/<MyDll>/Makefile.in a line like:
415
416 EXTRA_OBJS = $(MODULE).glue.o
417
418 See dlls/winmm/ for an example of this.
419
420 MEMORY AND SEGMENTS
421 ===================
422
423 NE (Win16) executables consist of multiple segments.  The Wine loader
424 loads each segment into a unique location in the Wine processes memory
425 and assigns a selector to that segment.  Because of this, it's not
426 possible to exchange addresses freely between 16-bit and 32-bit code.
427 Addresses used by 16-bit code are segmented addresses (16:16), formed
428 by a 16-bit selector and a 16-bit offset.  Those used by the Wine code
429 are regular 32-bit linear addresses.
430
431 There are four ways to obtain a segmented pointer:
432   - Using the MapLS function (recommended).
433   - Allocate a block of memory from the global heap and use
434     WIN16_GlobalLock to get its segmented address.
435   - Declare the argument as 'segptr' instead of 'ptr' in the spec file
436     for a given API function.
437
438 Once you have a segmented pointer, it must be converted to a linear
439 pointer before you can use it from 32-bit code.  This can be done with
440 the MapSL function.  The linear pointer can then be used freely with
441 standard Unix functions like memcpy() etc. without worrying about 64k
442 boundaries.  Note: there's no easy way to convert back from a linear
443 to a segmented address.
444
445 In most cases, you don't need to worry about segmented address, as the
446 conversion is made automatically by the callback code and the API
447 functions only see linear addresses. However, in some cases it is
448 necessary to manipulate segmented addresses; the most frequent cases
449 are:
450   - API functions that return a pointer
451   - lParam of Windows messages that point to a structure
452   - Pointers contained inside structures accessed by 16-bit code.
453
454 It is usually a good practice to used the type 'SEGPTR' for segmented
455 pointers, instead of something like 'LPSTR' or 'char *'.  As SEGPTR is
456 defined as a DWORD, you'll get a compilation warning if you mistakenly
457 use it as a regular 32-bit pointer.
458
459
460 STRUCTURE PACKING
461 =================
462
463 Under Windows, data structures are tightly packed, i.e. there is no
464 padding between structure members. On the other hand, by default gcc
465 aligns structure members (e.g. WORDs are on a WORD boundary, etc.).
466 This means that a structure like
467
468 struct { BYTE x; WORD y; };
469
470 will take 3 bytes under Windows, but 4 with gcc, because gcc will add a
471 dummy byte between x and y. To have the correct layout for structures
472 used by Windows code, you need to embed the struct within two special
473 #include's which will take care of the packing for you:
474
475 #include "pshpack1.h"
476 struct { BYTE x; WORD y; };
477 #include "poppack1.h"
478
479 For alignment on a 2-byte boundary, there is a "pshpack2.h", etc.
480
481
482 NAMING CONVENTIONS FOR API FUNCTIONS AND TYPES
483 ==============================================
484
485 In order to support both Win16 and Win32 APIs within the same source
486 code, the following convention must be used in naming all API
487 functions and types. If the Windows API uses the name 'xxx', the Wine
488 code must use:
489
490  - 'xxx16' for the Win16 version,
491  - 'xxx'   for the Win32 version when no strings are involved,
492  - 'xxxA'  for the Win32 version with ASCII strings,
493  - 'xxxW'  for the Win32 version with Unicode strings.
494
495 If the function has both ASCII and Unicode version, you should then
496 use the macros WINELIB_NAME_AW(xxx) or DECL_WINELIB_TYPE_AW(xxx)
497 (defined in include/windef.h) to define the correct 'xxx' function
498 or type for Winelib. When compiling Wine itself, 'xxx' is _not_
499 defined, meaning that code inside of Wine must always specify
500 explicitly the ASCII or Unicode version.
501
502 If 'xxx' is the same in Win16 and Win32, you can simply use the same
503 name as Windows, i.e. just 'xxx'.  If 'xxx' is Win16 only, you could
504 use the name as is, but it's preferable to use 'xxx16' to make it
505 clear it is a Win16 function.
506
507 Examples:
508
509 typedef struct { /* Win32 ASCII data structure */ } WNDCLASSA;
510 typedef struct { /* Win32 Unicode data structure */ } WNDCLASSW;
511 typedef struct { /* Win16 data structure */ } WNDCLASS16;
512 DECL_WINELIB_TYPE_AW(WNDCLASS);
513
514 ATOM RegisterClass16( WNDCLASS16 * );
515 ATOM RegisterClassA( WNDCLASSA * );
516 ATOM RegisterClassW( WNDCLASSW * );
517 #define RegisterClass WINELIB_NAME_AW(RegisterClass)
518
519 The Winelib user can then say:
520
521     WNDCLASS wc = { ... };
522     RegisterClass( &wc );
523
524 and this will use the correct declaration depending on the definition
525 of the UNICODE symbol.
526
527
528 DEBUG MESSAGES
529 ==============
530
531 To display a message only during debugging, you normally write something
532 like this:
533
534         TRACE("abc...");  or
535         FIXME("abc...");  or
536         WARN("abc...");   or
537         ERR("abc...");
538
539 depending on the seriousness of the problem. (documentation/debugging.sgml
540 explains when it is appropriate to use each of them). You need to declare
541 the debug channel name at the top of the file (after the includes) using
542 the WINE_DEFAULT_DEBUG_CHANNEL macro, like so:
543
544         WINE_DEFAULT_DEBUG_CHANNEL(win);
545
546 If your debugging code is more complex than just printf, you can use 
547 the macros:
548
549         TRACE_ON(xxx), WARN_ON(xxx), ERR_ON(xxx) and FIXME_ON(xxx) 
550
551 to test if the given channel is enabled. Thus, you can write:
552
553         if (TRACE_ON(win)) DumpSomeStructure(&str);
554
555 Don't worry about the inefficiency of the test. If it is permanently 
556 disabled (that is TRACE_ON(win) is 0 at compile time), the compiler will 
557 eliminate the dead code.
558
559 For more info about debugging messages, read:
560
561 http://www.winehq.org/site/docs/wine-devel/debugging
562
563
564 MORE INFO
565 =========
566
567 1. There is a FREE online version of the MSDN library (including
568    documentation for the Win32 API) on http://msdn.microsoft.com/
569    or http://www.msdn.com/
570
571 2. Windows apilist:  http://www.mentalis.org/apilist/apilist.php
572
573 3. http://www.sonic.net/~undoc/bookstore.html
574
575 4. In 1993 Dr. Dobbs Journal published a column called "Undocumented Corner".
576
577 5. www.geocities.com/SiliconValley/4942/