Windex
current release : 1.06
Windex is an object-oriented thick binding of Ada to a subset of the
Microsoft Win32 API, along with extensions to make it easier to use. It takes
advantage of Ada controlled types to provide safe access to Win32 handles, and
uses dispatching to let the user customize a window's response to Win32
messages.
Browse
the package specs. Each spec contains comments detailing the design
decisions concerning that package (suggestions for improved comments are always
welcome).
Download
the source in zip format. Included with the source are makefiles for
building with GNAT. Then follow the simple installation
instructions.
Review the known
bugs list, or the release
history. Warning: there is a change in Windex.Menus.Add_Sub_Menu between
Windex 1.05 and Windex 1.06, that the compiler will not catch for you!
Example applications:
Windex compared to
other GUI and Win32 bindings.
Windex is Copyright (C) 2000 - 2002 by Stephen Leake, released under the Modified Gnu Public
License (the same one that covers the GNAT run time libraries).
Overview
Windex grew out of my frustrations with the currently
available Win32 bindings; they are too thin, don't work, or are not free
software. Partly as a way to better understand Win32, and partly as a way to
learn the object-oriented features of Ada 95, I started writing a thick binding,
for use in my own applications. So only the parts of Win32 that I have needed so
far, or that others have contributed, are present in Windex. I hope others can
extend Windex to the areas they need.
However, recently GtkAda has gotten much better, and is now officially
supported by Ada Core Technologies. So I'm
not working on Windex anymore; I'm switching to GtkAda.
See the
source for complete details on the areas currently covered.
In addition to Win32 API functionality, there are packages that provide more
structure:
Win32 Menus
and List_Boxes
can store pointers to user data; Windex provides facilities to do this in a
structured, type-safe and memory-safe way.
Many packages provide a Profiles child, which provide ini file Read
and Write subprograms for the package's types.
I've started writing new controls entirely in Ada; see Windows.Date_Time_Controls.Edit
and Windows.Duration_Controls.Edit.
These still need work, particularly in the area of text cursors and navigation
keys.
Windows.Combo_Boxes.Gen_Enumeral
is an example of an Ada generic control; it lets you create a combo box to
select from an enumeration type.
Finding things in Windex
If you want to find how to do something using Windex, there are a couple
strategies:
- If you know the Win32 function you need to use, search the Windex
Source_Common directory for that function (use grep from the Cygwin tools, or
Windows Explorer Find (you can search for files containing text on the
Advanced tab)). I always spell the imported function exactly as in the Win32
documentation, so you can search for it.
- Look thru the list of packages at the
source to see if there's one that might match.
- Look thru the tests in Windex/Source_Common/Tests for one that does what
you want.
User Windows
The core of any Windows application is the window procedure, which processes
windows messages. In Windex, each message is handled by a dispatching routine.
Where it makes sense (such as for the mouse messages), one routine handles more
than one message. There are about 170 messages defined in the Win32 API; Windex
currently provides handlers for about 30 of them (the most common, and/or the
ones I've needed). There are two ways for a user to handle other messages;
overload Other_Handler, or add a new handler to the package Windex.Windows.User.
The main windows procedure in Windex.Windows.User provides default exception
handling, and provides hooks for previewing the message and the returned
result.
Design standards
Miscellaneous design decisions that should be uniformly applied.
Threads / Tasks
Ada tasks are mapped to Win32 threads (at least by GNAT). In general, a
window can only be manipulated by the thread that created it. That means any
functions defined in Windex.Windows and its children. One exception is
Win32_PostMessage (not visible to users); this posts messages to the correct
thread for the window. Windex does not currently do a good job of protecting the
user against attempting to manipulate windows from the wrong thread; you don't
even get good error messages, just incorrect behavior or crashes. I'm working on
a tasking version of Mandelplot, to explore these issues. CLAW (a non-open
source Windex competitor) uses a hidden task to enforce this, at the expense of
forcing one task to manage all windows in an application. This is probably the
best design, but I hope to allow users a choice of tasking designs.
Extending Windex
Win32 API documentation
If you want to add to the functionality of Windex, it is crucial that you
have good documentation on the Win32 API. I recommend three sources:
- Microsoft Win32 API documentation
- This is available as a Windows Help file with most Windows compilers, or
on the web in the Microsoft Developers
Network library
- "Programming Windows 95", Charles Petzold, Microsoft Press 1996
- Gives a good basic introduction to how Windows works; the windows
procedure, message processing, basic user interface controls. Includes
examples in straight C (no C++); easy to translate to Ada.
- "Win32 Programming", Brent E. Rector, Joseph M. Newcomer, Addison-Wesley,
1997
- Gives nitty-gritty detail on all Win32 functions, including how to use the
controls correctly. Includes a CD with excellent demonstration code for all
controls. Uses straight C syntax for the Win32 calls, with extensive C++
wrappers. Sometimes it's hard to separate the Win32 calls from the wrappers,
but the information in the book is worth it even without the sample code.
Low level Win32 binding issues
Here are some guidelines on how I write the low-level bindings to the Win32
API. Note that the Windex code that I wrote first may not follow these
guidelines; they have evolved over time.
- I don't use the Win32Ada binding distributed with GNAT, for a couple of
reasons:
- It is copyrighted by Microsoft, and has a restrictive license; you must
have an MS SDK license (or equivalent) to use Win32Ada. I suspect a lot of
people ignore this, but I don't want to encourage that. Note that you
don't need an MS SDK license to use the DLL interface libraries with
Windex; see the installation
instructions.
- It brings in a lot of stuff I don't want in a thick binding, like all
the subtypes for DWORD etc, and the variable parameter list stuff. I don't
like wasting compilation time reading all those specs.
- There are often better ways to define things, even in a thin binding.
See Windex.Windows.Window_Style_Type for a good example of this. Win32Ada
was generated by an automatic tool, which can't translate #defines into
bitmapped records.
- I use types from Interfaces, Interfaces.C, or Interfaces_More (my own
package). I don't use subtypes just for renaming. Here's my mapping of the
most common Win32 scalar types:
ATOM |
Interfaces.C.unsigned_short |
BOOL |
Interfaces.C.int |
BYTE |
Interfaces.C.unsigned_char |
DWORD |
Interfaces.C.unsigned_long |
HINSTANCE |
System.Address |
HWND |
System.Address |
LONG |
Interfaces.C.long |
LPARAM |
Interfaces.c.long |
LPCSTR, LPSTR, etc |
System.Address (see below) |
LPVOID |
System.Address |
LRESULT |
Interfaces.C.long |
UINT |
Interfaces.C.unsigned |
WORD |
Interfaces.C.unsigned_short |
WPARAM |
Interfaces.C.unsigned |
- Strings are passed by address, after appending an Ascii.nul. This is
equivalent to using Interfaces.C.Strings, and much simpler.
C_Name :
constant String := Name & Ascii.nul;
Win32_Create (Name =>
C_Name'address ...);
- Win32 defines many parameters, especially style parameters, using bit
masks. In general, I define the equivalent record, with Boolean or enumerated
fields, and use a representation clause to match the bits. This usually makes
things easier to understand. Where there are undefined bits, I define one
record in the spec for users, with no "undefined" fields, and define another
record in the body, with undefined fields and a rep clause. This involves a
small amount of conversion overhead, but the gain in clarity is worth it.
- I define generally useful low-level stuff in Windex.Ops (splitting
unsigned_32 into two unsigned_16, etc); check there first before defining new
low-level stuff.
- There are many functions in Win32 that have been superceded by newer
functions with more parameters. In such cases, I only use the newer function;
fewer Import pragmas to write!
Test code
There is at least some test code for each Windex package; the major functions
are tested, but full path coverage is not provided. Some tests generate mouse
and keyboard events to drive the user interface element under test; they can
also be run in a debug mode to let the tester experiment, and see what Windows
messages are sent.
If you find a bug in Windex, let me know. If you are up to it, please try
to enhance the appropriate test to pinpoint the bug.
Installation
Development tools
Windex is distributed in source form only. One way for you to use it is
simply to incorporate it in your Ada code just like code you write; you don't
need to use my development environment.
Earlier versions of Windex could be compiled by ObjectAda 7.1.2a. However,
recent additions to Windex cannot be compiled by ObjectAda. Since I like GNAT
better anyway, and ObjectAda is not open source, I have dropped support for
ObjectAda.
If you'd like to compile Windex the way I do, here's the list of tools I
use:
Installation instructions - Cygwin
You don't need all of Cygwin. It has a nice installer that lets you choose
what packages you want. I use the following packages:
- Base
- Devel
- Doc | texinfo
- cvs
Installation instructions - GNAT Win32 DLL interface libraries
If you are using GNAT, you must install the Win32 DLL interface libraries. To
do this, you have to answer "yes" to the MS SDK license query in the install
process, even though the libraries are not covered by the SDK license.
For other compilers, you are on your own.
Installation instructions - download Windex
- Download windex-1.06.zip
to a temporary directory.
- Extract to the directory of your choice (herinafter called "the root
directory"). This will create two top-level directories in the root directory:
- Windex contains the source code, test code, and makefiles,
totalling about 2.3 Mb.
- Makerules contains rules for the makefiles (shared among all my
projects).
Compile the code your way, my way, or the DOS way (choose from below).
Installation instructions - your way
You can just compile the Windex source as if it were your code.
- Download as above.
- Delete directories Makerules and Windex/Build
- Add Windex/Source_Common to your development environment's list
of source directories, and have fun!
Installation instructions - my way
This is how I compile Windex source
- Download as above.
- Define STEPHE_ADA_ROOT, either as an environment variable, or at
the top of file Windex/Build/common.make. In either case, its value
must be an absolute path to the root directory. GNAT can handle either forward
or back slashes.
- From directory Windex/Build, run make build. This will
build the library, in directory Windex/Lib/Gnat_Release.
- To use the library with GNAT, add
-I$(STEPHE_ADA_ROOT)/Windex/Lib/Gnat_Release to your INCLUDE list.
- If you'd like to run all the tests: From directory Windex/Build,
run make test. Most tests run to completion without user
intervention, and compare the output with known good output. But some require
user actions - you should read the source of each test (in
Windex/Source_Common/Test) to see how you should respond to tests.
- To build a debug version: From directory Windex/Build/Gnat_Debug,
run make lib.
Installation instructions - DOS way
- Download as above.
- Define WINDEX_DRIVE and WINDEX_DIR at the top of file
Windex/Build/build_dos.bat.
- From directory Windex/Build, run build_dos.bat. This
will build the library, in directory Windex/Lib/Gnat_Release.
- To use the library: add
-I%WINDEX_DRIVE%%WINDEX_DIR%\Lib\Gnat_Release to your INCLUDE list.
Known Bugs
- Under Windows 2000 (and probably Windows XP), the Windex menus package is
broken. I may fix this sometime, but probably not.
- In Windex.Graphics_Devices.Images.IO, reading and writing 16 and 24 bit
color images works fine on at least a 16 bit display. Reading 4 and 8 bit
color also works fine on a 16 bit display, but writing to less than 16 bits
uses a very bad palette, despite my efforts to tell Win32 to use a good
palette. Displaying anything on an 8 bit display also uses a bad palette.
- GNAT 3.14p doesn't build the resources_dll.dll correctly, so test_dialogs
fails. I'm not working on it!
History
- Version 1.06 15 Feb 2002
-
- Upward-compatible changes
-
- Compiles with GNAT 3.14p.
- Document use of window extended style Client Edge to get 3D look on
controls. Set defaults on controls to normally get 3D look.
- Add support for printing stack trace to standard output on exception.
- In windex-windows-duration_controls-edit.adb, don't rely on
Constraint_Error; Windex release library is compiled without them!
- In windex-graphics_devices, add several useful functions.
- Non-upward-compatible changes
-
- Change the way windex-windows-thread_safe works, to make it safer.
- In windex-graphics_devices, fix usage of DC vs Image parameter names.
Rename Size_Bitmap to Size.
- Non-upward-compatible silent changes
- These changes require changes to your existing code, and are _not_
reported by the compiler! But they are caught by run-time exceptions.
- Windex.Menus.Add_Sub_Menu (Menu_type, Menu_Type), was _not_ nulling
the sub_menu, as the description says. Now it does. This means you _must_
use Add_Sub_Menu (Menu_type, Menu_Access_Type) to add sub menus that you
want to retain access to. If you have used the wrong Add_Sub_Menu, you
will now get a NOT_CREATED error when you try to access it. Unfortunately,
symbolic tracebacks are broken when called from window procedures, so
these errors are hard to find.
- Version 1.05 4 Sept 2000
-
- Non-upward-compatible silent changes
- These changes require changes to your existing code, and are _not_
reported by the compiler! There is a proposal to fix this with pragmas.
- In Windex.Windows.User.Create_Handler, change Window from "in out" to
"access". This allows creating subclassed child windows using
Windex.Windows.Subclass.
- Non-upward-compatible changes
- These changes may require changes to your existing code, but are
reported by the compiler.
- Changed Lparam parameter in all Windex.Windows.User subprograms to
type Interfaces.C.long, as they should have been in the first place.
- Moved all Create routines to nested Creators packages. This makes them
not inherited, without making them class-wide. You are now forced to be
more precise about which Create to call.
- Changed Windex.Keyboard.Key_Event (String) to Key_Stroke (String), to
be more consistent with Key_Stroke (Character). Enhance to handle all
ASCII characters.
- Changed Windex.Time.File_Time_Type to 64 bit fixed point, to allow
user addition, subtraction. Since ObjectAda doesn't support 64 bit six
point, and for other reasons, support for ObjectAda is dropped.
- Redesigned Windex.Windows.Subclasses; Subclass_Type did not need to be
a window.
- Split Windex.Windows.User Notify_Handler function into two handlers,
one for Windex objects, and one for non-Windex objects. The non-Windex
version is now called for Windex objects before they are completely
created, avoiding the need to check for this in user handlers. Also, drop
the 'Handled' parameter; it has no effect.
- In Windex.Graphics_Devices, reorder parameters to Text_Out to allow
easier use of defaults.
- In Windex.Windows.Static_Text, change Create parameter from
Text_Control to Control (should have been done in Windex 1.04).
- Upward-compatible changes
- These changes should not require changes to your existing code, unless
you get a name collision with a new Windex name.
- Added Windex.Windows.Get_Enabled.
- Added Windex.Windows.Parent_Rectangle.
- Added Windex.Windows.Notify_Parent.
- Added Windex.Common_Dialogs.Print, with support for the default
printer only.
- Added Windex.Graphics_Devices.Printers (minimal support).
- Added formatting for Duration types to Windex.Time.
- Added Windex.Keyboard.Alt_Key_Stroke, for easier testing.
- Added Windex.Windows.Edit_Text.Gen_Integer, a generic control for
editing integer values.
- Added default values of (0, 0) to all Left_Top and Size parameters in
Create routines. This is useful when the size will be automatically reset
later.
- Version 1.04 4 Dec 1999
-
- Non-upward-compatible changes
- These changes may require changes to your existing code.
- Change object parameter type of all Create routines to 'class
- Change object parameter name of all Windex.Windows.*.Create routines
to Control
- Change Windex.Windows.User.Notify_Handler to pass Control as "access
Windows.Handle_Type'class" (was "in"), and store pointer to actual Windex
object in Windex interfaces to standard Win32 controls. This allows access
to the Windex object for the control when handling messages from the
control. Note that current overrides of Notify_Handler will silently stop
working; this is one feature of Ada 95 that is truly bad.
- Change Menu operations in Windex.Windows.User from class-wide to
dispatching.
- In Windex.MessageBoxes.Message_Box, change Window argument to Parent
- Add Windex.Graphics_Devices.Set_Text_Align, Set_Text_Color,
Set_Background_Color. This required changing
Windex.Graphics_Devices.Images.Set_Background_Color to
Set_Background_Brush.
- Move Windex.Graphics_Devices.Drawing.Text_Out, Set_Background_Mode to
Windex.Graphics_Devices. This puts text operations at the same level as
bitmap operations.
- Delete Windex.Windows.Destroy; replace with Windex.Windows.Close.
Calling Close instead of Destroy allows user windows to clean up by
handling only the WM_CLOSE message.
- Upward-compatible changes
- These changes should not require changes to your existing code, unless
you get a name collision with a new Windex name.
- Fixed bug in Windex.Windows.Subclass, thanks to Jeff Loh. Can now
subclass edit controls, although ObjectAda seems to have trouble with
this.
- Add automatic caret handling, mouse activation handling to
Windex.Windows.User.
- Add Windex.Graphics_Devices.Text_Size, Windex.Windows.System_Text_Size
- Add private package Windex.Stock_Objects
- Add Read, Write for Boolean to Windex.Profiles.Common
- Add Windex.Locales with default constants
- Add Windex.Time with Win32 time formatting
- Add Windex.Time.Profiles for storing time in files
- Add Windex.Windows.Date_Time_Controls, Windex.Date_Time_Controls.Edit;
pure Ada controls for displaying and editing date and time. The Edit
control needs more work, to support keyboard editing.
- Add Windex.Windows.Combo_Boxes,
Windex.Windows.Combo_Boxes.Gen_Enumeral
- Add Windex.Windows.Buttons.Check
- Add handlers for WM_PARENTNOTIFY
- Fixed bug to allow null menus when destroying user windows
- Don't require user to override Create_Handler
- Add space for terminating nul in Windex.Profiles.Read_String.
- Move Win32_SendMessage, Win32_PostMessage to
Windex.Windows.Win32_Messages.
- In Windex.File_Parsing, allow '\' and '/' directory characters. Also
add Length and With_Default.
- Version 1.03 12 June 1999
-
- Defined a new Coordinate_Type in Windex.Points, used in
Windex.Points.Point_Type. Now the Windex user does not have to with and use
Interfaces.c.int.
- Added support for 1 bit color bitmaps, thanks to Herve Bitteur.
- Added all Win32 defined system metrics.
- Added standard window scroll bars to Windex.Windows.User.
- Added handlers for WM_ENTERSIZEMOVE, WM_EXITSIZEMOVE, WM_SIZING.
- Added handlers for WM_CLOSE, WM_QUERYENDSESSION, WM_ENDSESSION.
- Switched to using FSF Gnu make 3.77 instead of Cygwin Gnu make.
- Version 1.02 18 April 1999
-
- Updated for GNAT 3.11p, ObjectAda 7.1.2a, Cygwin 20.1. This fixed a
couple bugs, created a couple more.
- Moved Images from Windex.Images to Windex.Graphics_Devices.Images. Also
made most Graphics_Devices.Device_Context_Type operations dispatching. This
allows using an Image whereever a Device_Context is needed. I wrote the
first version of Images in Ada 83, and didn't really think about where it
belonged in a child package hierarchy when I upgraded to Ada 95.
- Added a Flags field to Windex.Colors.Color_Type.
- Added Windex.Graphics_Devices.Drawing, .Drawing.Turtle
- Changed Windex.Menus.Create to Create_Root and Create_Popup. This was
the problem with Popup menus - I was calling Win32 CreateMenu, not Win32
CreatePopupMenu. Also I was calling Windex.Windows.Users.Popup from a
different task than the main message loop.
- Added Windex.Windows.Edit_Text, for edit text boxes.
- Added Windex.Keyboard, for generating keyboard events in testing.
- Added Windex.Windows.Buttons.Push, for push buttons.
- Fixed a bug in Windex.Windows.User that prevented Notification_Handler
seeing SELECT_CHANGE notifications from list boxes.
- Changed Windex.Windows.Style to be a record type, with Control_Style
separate. Now it makes much more sense! A good example of the expressive
power of Ada.
- Enhanced error messages with Not_Created exception.
- Added DOS build files.
- Version 1.00 20 December, 1998
- First release.
email me with any suggestions,
bugs, additions, or demo applications!
my home page.
Author : Stephen Leake
Last modified: Wed Apr 16 22:29:08 Eastern
Daylight Time 2003