The Win32 API Libraries¶
This chapter is about Open Dylan’s set of Win32 API interface libraries. These libraries provide a low-level Dylan interface to the Win32 API in Microsoft Windows and Microsoft Windows NT.
Each Dylan library is a simple translation of Win32 API header files into a set of interface declarations from Open Dylan’s C-FFI library. So you can write Windows applications in Dylan by using the same functions and types as you would in C, albeit with slightly modified names so that they conform to Dylan naming conventions and requirements.
The Open Dylan Win32 API has been constructed from several Dylan libraries. Win32 functionality is divided among these libraries, matching the contents of Microsoft’s DLLs, allowing Dylan applications to avoid references to DLLs they do not need to use.
With the exception of changes necessitated by Dylan naming conventions and requirements, the names of C items have been preserved in the Open Dylan Win32 API libraries. Hence this chapter does not provide an exhaustive list of the items available in the libraries. Instead, it explains the name mapping scheme we used in the conversion, and provides a collection of tips for writing Dylan applications with the libraries. Finally, there is a list of items not supported in our versions of these libraries.
Supported Win32 libraries¶
Each Dylan library representing a portion of the Win32 API has a single module of the same name as the library itself. For example, the library Win32-Common has a module also called Win32-Common. An exception to this rule is Win32-User, which also exports the module Win32-Default-Handler.
The libraries are:
- Data types, constants (including error codes), and structure accessors that are shared by the other modules.
- Most of these come from the Win32 header files WINDEF.H, WINNT.H, and WINERROR.H. (There is no DLL file supplied as standard with Windows that corresponds with this library, because there are no C functions in the header files to which it forms an interface.)
- Win32-Kernel Non-GUI system services, as implemented in KERNEL32.DLL and declared in WINBASE.H (files, pipes, semaphores, atoms, time, and so on) and WINNLS.H (National Language Support).
- Note: This library does not provide thread support. Thread support is being handled at a higher level by Dylan’s own Threads library. See the Core Features manual for details.
- Win32-GDI Graphics Device Interface, drawing graphics and text, and printing. Corresponds to WINGDI.H and GDI32.DLL.
- Win32-User Other windowing functions. Corresponds to WINUSER.H and
USER32.DLL. Also contains
win32-last-handlerwhich can handle conditions and display them to the application user a simply Win32 dialog. That function is exported from the module Win32-Default-Handler.
- Win32-Version Version management. Corresponds to WINVER.H and VERSION.DLL.
- Win32-Dialog Common dialog boxes, as implemented in COMDLG32.DLL and declared in COMMDLG.H, DLGS.H, and CDERR.H.
- “Common controls”, including list view, tree view, property sheets, and so on (COMMCTRL.H and COMCTL32.DLL).
- Registry (WINREG.H and ADVAPI32.DLL).
- “Rich edit” controls (RICHEDIT.H and RICHED32.DLL).
- Win32-DDE Dynamic Data Exchange (DDE.H and DDEML.H).
- Win32-Shell API for querying and extending the Windows Shell. Corresponds to SHELLAPI.H and SHELL32.DLL.
- Winsock2 Corresponds to WINSOCK2.H, QOS.H, and MSWSOCK.H.
Content and organization of the Win32 API libraries¶
The Open Dylan Win32 API libraries are modeled closely upon Microsoft’s Win32 C libraries. Most names available in the Dylan libraries are the same as those available in the C libraries, though of course to conform to Dylan naming conventions and restrictions, many of the C names have been translated.
Look at the library.dylan file in each library to see what each library provides. (Look in comlib.dylan for Win32-Common.) The libraries generally include only features that apply to both Windows NT and Windows 95/98.
If there is an additional area of Win32 you would like to see these libraries support, please inform the Open Dylan support team.
Notes on the translations¶
The Win32-Common module re-exports some names from the C-FFI module that
its user may need to use directly, without needing to use (or know
about) the C-FFI module itself. These names are: null-pointer,
<C-unicode-string>, destroy, and with-stack-structure.
Names that are documented as being obsolete and/or included in Win32 only for compatibility with Win16, are generally not defined in the Dylan libraries. The names excluded are listed in Index of Win32 names excluded from the Dylan libraries.
The extended API macros, defined in the optional C header file WINDOWSX.H, are not supported.
Naming and mapping conventions¶
A Dylan application using the Win32 API will generally use the same API names as a C program would, with the following modifications for consistency with Dylan conventions.
Simple naming conventions¶
Type names are enclosed in angle brackets. For example, HANDLE becomes
Names of constants are prefixed by $. For example, OPAQUE becomes $OPAQUE.
Underscores are replaced by hyphens. Thus, a constant called NO_ERROR
becomes $NO-ERROR and a class called LIST_ENTRY becomes
Hyphens will not be inserted between capitalized words (for example, CreateWindow does not become Create-Window) since that is a less obvious mapping that is more likely to cause confusion when switching between Dylan code and Windows documentation.
Mapping the null value¶
In place of
NULL, there are several constants providing null values
for frequently used types, such as $NULL-HANDLE, $NULL-RECT, and
$NULL-STRING. Null values for other pointer types may be designated
by the expression null-pointer(<FOO>). Use the function
null-pointer? to test whether a value is null. Do not use the
expression if(ptr)... as is often done in C, since a null pointer is
not the same as
#f. There are also functions null-handle and
null-handle? for creating and testing handles, since conceptually they
are not necessarily pointers.
Mapping C types onto Dylan classes¶
The multitude of integer data types in C code (
LRESULT, and so on) are all
<integer> (or some appropriate subrange thereof) in
Dylan method argument types. However, a
<machine-word> needs to be
used to represent values that do not fit in the signed 30-bit
representation of an integer.
Names such as
<DWORD> should not be used in application code because
they refer to the FFI designation of the C value representation, not to
a Dylan data type.
The C types
BOOLEAN are both mapped to
#f instead of
Beware that some functions, such as TranslateAccelerator,
though documented to return
FALSE, actually return
BOOL ; in such a case, you will have to compare the result
Similarly, watch out for cases where C code passes
an integer argument. To handle one common case, the Dylan implementation
of MAKELPARAM accepts either an
<boolean> as the
Most of the pointer types in the Windows API have several names; for example: PRECT, NPRECT, and LPRECT. In 16-bit code, these distinguished between “near” and “far” pointers, but in 32-bit code there is no difference. Rather than carry the duplicate names over into Dylan, it would be simpler to use only the basic P... prefix names. However, the LP... names seem to be used much more often, and hence may be more familiar, and the Microsoft documentation still tends to use the LP... names in most places. So the Dylan interface defines both the <P...> and <LP...> names even though they have identical values. The NP... names are not defined in Dylan since they are not as commonly used.
Values of type
char* in C are represented as instances of class
<C-string> in Dylan. This is a subclass of
<string>, so all of the
normal string operations can be used directly. C function parameters of
type char* will also accept an instance of
<byte-string> ; a C
pointer is created to point to the characters of the Dylan data, so the
string does not need to be copied. (Dylan byte strings maintain a NUL
character at the end in order to allow them to be used directly by C.)
in the current implementation, that involves automatically copying the string at run time, but the need for copying is intended to be removed later.
The TEXT function can also be used to coerce a string literal to a
<C-string>. This usage is consistent with the Win32 TEXT macro,
although the current purpose is different.
The Dylan declarations for C types will generally follow the strict
alternative versions of the C declarations. This means, for example,
that the various handle types such as
disjoint subclasses of
<handle>, instead of all being equivalent.
Creating methods from Windows alias functions¶
Consider a Windows function called Foo which is an alias for either
FooA (an 8-bit character version) or FooW (a 16-bit character
version). In Dylan, only the name Foo will be defined, but it will be
a generic function with separate methods for arguments of types
<unicode-string>. (Only the 8-bit versions will be supported in the
initial implementation, both because the compiler is not ready to handle
Unicode and because it will not work on Windows 95.)
Mapping C structure fields onto Dylan slot names¶
Because slot names are not in a separate name space in Dylan, the names of C structure fields will have the suffix -value added to form the name of the Dylan accessor function. For example, the C statement:
pt->x = x;
becomes in Dylan:
pt.x-value := x;
There is not any attempt to append ? to the names of predicate functions since it is not obvious exactly which functions that should apply to. The Dylan convention of *...* for global variables is not relevant since there are no global variables involved.
Handling return of multiple values¶
In cases where the C library function takes a pointer argument as a place to store a pointer, integer, or boolean value, the corresponding Dylan function uses multiple return values to return such output parameters following the original function return value. For example, where C code does:
BOOL ok; DWORD NumberRead; ok = ReadConsoleInput(handle, buffer, length, & NumberRead);
in Dylan it would be:
let ( ok :: <boolean>, NumberRead :: <integer> ) = ReadConsoleInput(handle, buffer, length);
Similarly, this function returns multiple values instead of a structure:
let ( x, y ) = GetLargestConsoleWindowSize(handle);
Defining callback functions¶
The Win32-common library provides a
define callback macro to make it
easy to define callback functions without the application programmer
needing to use the FFI
define c-callable-wrapper macro directly. It is
used like this:
define callback WndProc :: <WNDPROC> = my-window-function;
This says that
WndProc is being defined as a C function pointer of
<WNDPROC>, which when called from C causes the Dylan function
my-window-function to be run. The Dylan function will be defined
define method or
define function, and it is the
responsibility of the programmer to ensure that its argument signature
is consistent with what
<WNDPROC> requires. For example:
define method my-window-function( hWnd :: <HWND>, // window handle message :: <integer>, // type of message uParam, // additional information lParam) // additional information => return :: <integer>; ...
Note that the uParam and lParam arguments might receive values of
<machine-word>, so it may be best not to
specialize them. Often these values are not used directly anyway, but
are passed to other functions (such as LOWORD and HIWORD) which
have methods for handling either representation.
The other types of function supported by
define callback are dialog
<DLGPROC>) and dialog hooks (<LP...HOOKPROC>), both of
which have the same argument types as a window function, but return a
<boolean>. (The dialog hook functions are actually declared in
COMMDLG.H as returning a UINT, but the value is always supposed to
FALSE, so the Dylan callback interface has been
The Win32-Kernel library provides the following utility functions.
win32-error-message error-code => message
The error-code is an instance of
The error-code argument is either a Windows a Windows error code (such as returned by
GetLastError) or an
SCODE(also known as an
HRESULT) value (such as returned by most OLE/COM functions).
The function returns a text message (in a string) corresponding to the error code,
#fif the code is not recognized. The returned string might have more than one line but does not have a newline at the end.
win32-error-message(5) => "Access is denied."
Signature: report-win32-error name #key error Discussion: Signals a Dylan error if the Win 32 error code specified is not
NO_ERROR. If no code is specified, the value returned by the Win32 API
GetLastErroris used. The error that is signaled includes both the error code and the error message, as computed by the function
check-win32-result name result
Many Windows functions return
NULLto mean failure. The function
check-win32-resultchecks the result to see if it indicates failure, and if so it calls
check-win32-result("SetWindowText", SetWindowText(handle, label))
Handling Dylan conditions in a Win32 application¶
Discussion: Displays a rudimentary Win32 dialog to allow the user to decide what to do with the Dylan condition that has been signalled.
It is a handler utility function that can be by bound dynamically around a computation via
let handleror installed globally via
last-handler-definer. It is automatically installed as the last handler simply by using the Win32-User library.
The function has the following call syntax:
win32-last-handler (serious-condition, next-handler)
The serious-condition argument is an object of class serious condition. The next-handler argument is a function. The win32-last-handler function returns no values.
The following form defines a dynamic handler around some body:
let handler <serious-condition> = win32-last-handler;
while the following form installs a globally visible last-handler:
define last-handler <serious-condition> = win32-last-handler;
seealso: last-handler-definer and default-last-handler, exported from the Functional Dylan-Extensions library and module, in the Core Features reference manual.
Dealing with the C function WinMain¶
In C, the programmer has to supply a WinMain function as the main program for a GUI application, but in Dylan there is no main program as such. The beginning of execution is indicated simply by a top-level function call expression; this needs to be at the bottom of the last file listed in the project file. The Win32-Kernel and Win32-User libraries export functions to obtain the values which would have been the arguments to WinMain:
application-instance-handle() => <HINSTANCE> application-command-line() => <string> // arguments without program name application-show-window() => <integer> // one of $SW-...
There is no accessor provided for the WinMain previous instance parameter because on Win32, that parameter is always null, even for Win32s as well as NT and Windows 95.
The program can be terminated, with an exit code, by calling either the
ExitProcess function or the
exit-application function in
Open Dylan’s System library. The latter method is preferred if the
application might actually be run as part of another process.
The start of an application program might look something like this:
define method my-main () let hInstance :: <HINSTANCE> = application-instance-handle(); let wc :: <PWNDCLASS> = make(<PWNDCLASS>); wc.style-value := 0; wc.lpfnWndProc-value := MainWndProc; ... RegisterClass(wc); let hWnd = CreateWindow( ... ); ShowWindow(hWnd, application-show-window()); UpdateWindow(hWnd); let msg :: <PMSG> = make(<PMSG>); while ( GetMessage(msg, $NULL-HWND, 0, 0) ) TranslateMessage(msg); DispatchMessage(msg); end; ExitProcess(msg.wParam-value); end method my-main; my-main(); // this is what initiates execution.
For a complete example program, see
in the Open Dylan installation directory.
Combining bit mask constants¶
Where C code would use the | operator to combine bit mask constants,
Dylan code usually uses the logior function. However, a few such
constants have values of type
<machine-word> when they will not fit in
a small integer, and logior only works on instances of
Because of this, the win32-common library exports a %logior function
which is used like logior except that it accepts values of either type
<machine-word> and returns a
It can be used in most places that accept a bit mask (C types DWORD,
ULONG, LPARAM, and so on), but must be used if any of the
arguments are a
<machine-word>. The contexts where this is likely to
- Window style parameter of CreateWindow ($WS-...)
- Flags value for CreateFile or CreateNamedPipe ($FILE-FLAG-...)
- $LOCALE-NOUSEROVERRIDE for LCTYPE parameters for GetLocaleInfoA, GetLocaleInfo, and possibly others, or dwFlags parameter of GetTimeFormat, GetNumberFormat, GetCurrencyFormat, or GetDateFormat.
- Mask and effects values in CHARFORMAT structure for “rich edit” controls ($CFM-... and $CFE-...)
- Mask value in PARAFORMAT structure for “rich edit” controls ($PFM-...)
Other minor details¶
<PROC> are defined as equivalent to
<C-function-pointer>, so any C function wrapper object can be passed
to a routine taking a
<FARPROC> without needing to do any type
conversion like that needed in C.
Type casts between handles and integers (
<machine-word>) can be done by using as. For example:
window-class.hbrBackground-value := as(<HBRUSH>, $COLOR-WINDOW + 1);
Note that pointers and handles must be compared using =, not ==, in order to compare the C address instead of the Dylan wrapper objects.
For type casts from one pointer type to another, use the function
pointer-cast instead of
as. Think of
as as converting
the data structure pointed to, while
pointer-cast operates on just
the pointer itself.
The Dylan function
pointer-value can be used to convert between a
Dylan integer and a LARGE-INTEGER or ULARGE-INTEGER. For example:
let li :: make( <PLARGE-INTEGER> ); pointer-value(li) := 0;
allocates a LARGE-INTEGER and sets its value to 0, without needing to be concerned with the individual fields of the internal representation. Alternatively, you can use an initialization keyword:
let li :: make( <PLARGE-INTEGER>, value: 0 );
The C macros MAKEPOINT, MAKEPOINTS, and LONG2POINT do not easily translate to Dylan. Instead, use the Dylan function lparam-to-xy to split a parameter into two signed numbers. For example:
let ( x, y ) = LPARAM-TO-XY(lParam);
<RECTL> is an alias of
<RECT> instead of being a distinct
type. (In Win32, they are structurally equivalent but were separate
types for the sake of source code compatibility with Win16; there is no
need to maintain that artificial distinction in Dylan.)
Windows resource files (.rc files) can be included by using the LID file field RC-Files:.
Index of Win32 names excluded from the Dylan libraries¶
The names listed in the index below are excluded from the Open Dylan Win32 API libraries because they are obsolete.
Functions for old-style metafiles (CreateMetaFile, CloseMetaFile, and so on) are described in the Win32 API as being obsolete, but they are being supported because they are needed for OLE applications to exchange data with 16-bit applications.
Functions wsprintf and wvsprintf are not supported because the Dylan function format-to-string serves the same purpose. Also, the FFI doesn’t currently support C functions with a variable number of arguments.
The extended API macros defined in optional C header file windowsx.h will not be supported by the Dylan interface.
The 64-bit utility macros Int32x32To64, Int64ShllMod32, Int64ShraMod32, Int64ShrlMod32, and UInt32x32To64 are not planned to be supported since there is no clear need for them and the functionality can be obtained by using Dylan extended integers. However, an interface to function MulDiv is provided, since it is an ordinary C function that is commonly used.
_hread, _hwrite, _lclose, _lcreat, _llseek, _lopen, _lread, _lwrite
AccessResource, AllocDSToCSAlias, AllocResource, AllocSelector, AnsiLowerBuff, AnsiNext, AnsiPrev, AnsiToOem, AnsiToOemBuff, AnsiUpper, AnsiUpperBuff
BN_DBLCLK, BN_DISABLE, BN_DOUBLECLICKED, BN_HILITE, BN_PAINT, BN_PUSHED, BN_UNPUSHED, BS_USERBUTTON
CPL_INQUIRE, ChangeSelector, CloseComm, CloseSound, CopyLZFile, CountVoiceNotes
DOS3Call, DefHookProc, DefineHandleTable, DeviceMode, DlgDirSelect, DlgDirSelectComboBox
EnumFonts, ERR_..., ExtDeviceMode
FixBrushOrgEx, FlushComm, FreeModule, FreeProcInstance, FreeSelector
GCW_HBRBACKGROUND, GCW_HCURSOR, GCW_HICON, GWW_HINSTANCE, GWW_HWNDPARENT, GWW_ID, GWW_USERDATA, GetAspectRatioFilter, GetAtomHandle, GetBitmapBits, GetBitmapDimension, GetBrushOrg, GetCharWidth, GetCodeHandle, GetCodeInfo, GetCommError, GetCurrentPDB, GetCurrentPosition, GetEnvironment, GetFreeSpace, GetFreeSystemResources, GetInstanceData, GetKBCodePage, GetMetaFile, GetMetaFileBits, GetPrivateProfileInt GetPrivateProfileSection, GetPrivateProfileSectionNames, GetPrivateProfileString, GetPrivateProfileStruct, GetProfileInt, GetProfileSection, GetProfileString, GetStringTypeA, GetStringTypeW, GetTempDrive, GetTextExtent, GetTextExtentEx, GetTextExtentPoint, GetThresholdEvent, GetThresholdStatus, GetViewportExt, GetViewportOrg, GetWindowExt, GetWindowOrg, GlobalCompact, GlobalDosAlloc, GlobalDosFree, GlobalFix, GlobalLRUNewest, GlobalLRUOldest, GlobalNotify, GlobalPageLock, GlobalPageUnlock, GlobalUnWire, GlobalUnfix, GlobalUnwire, GlobalWire
LZDone, LZStart, LimitEmsPages, LocalCompact, LocalInit, LocalNotify, LocalShrink, LockSegment
MAKEPOINT, MakeProcInstance, MoveTo
OemToAnsi, OemToAnsiBuff, OffsetViewportOrg, OffsetWindowOrg, OpenComm, OpenFile, OpenSound
PM_NOYIELD, ProfClear, ProfFinish, ProfFlush, ProfInsChk, ProfSampRate, ProfSetup, ProfStart, ProfStop
READ, READ_WRITE, ReadComm, RegCreateKey, RegEnumKey, RegOpenKey, RegQueryValue, RegSetValue
SYSTEM_FIXED_FONT, ScaleViewportExt, ScaleWindowExt, SetBitmapDimension, SetCommEventMask, SetEnvironment, SetMetaFileBits, SetResourceHandler, SetScrollPos, SetScrollRange, SetSoundNoise, SetSwapAreaSize, SetViewportExt, SetViewportOrg, SetVoiceAccent, SetVoiceEnvelope, SetVoiceNote, SetVoiceQueueSize, SetVoiceSound, SetVoiceThreshold, SetWindowExt, SetWindowOrg, SetWindowsHook, StartSound, StopSound, SwitchStackBack, SwitchStackTo, SyncAllVoices
UngetCommChar, UnhookWindowsHook, UnlockSegment
WM_CTLCOLOR, WNetAddConnection, WNetCancelConnection, WRITE, WaitSoundState, WriteComm, WritePrivateProfileSection, WritePrivateProfileString, WritePrivateProfileStruct, WriteProfileSection, WriteProfileString