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:


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.


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:

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

  1. Download windex-1.06.zip to a temporary directory.
  2. Extract to the directory of your choice (herinafter called "the root directory"). This will create two top-level directories in the root directory:

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.

  1. Download as above.
  2. Delete directories Makerules and Windex/Build
  3. 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

  1. Download as above.
  2. 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.
  3. From directory Windex/Build, run make build. This will build the library, in directory Windex/Lib/Gnat_Release.
  4. To use the library with GNAT, add -I$(STEPHE_ADA_ROOT)/Windex/Lib/Gnat_Release to your INCLUDE list.
  5. 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.
  6. To build a debug version: From directory Windex/Build/Gnat_Debug, run make lib.

Installation instructions - DOS way

  1. Download as above.
  2. Define WINDEX_DRIVE and WINDEX_DIR at the top of file Windex/Build/build_dos.bat.
  3. From directory Windex/Build, run build_dos.bat. This will build the library, in directory Windex/Lib/Gnat_Release.
  4. To use the library: add -I%WINDEX_DRIVE%%WINDEX_DIR%\Lib\Gnat_Release to your INCLUDE list.

Known Bugs


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
Version 1.02 18 April 1999
Version 1.00 20 December, 1998
First release.

email me with any suggestions, bugs, additions, or demo applications!
my home page.


Author : Stephen Leake

Valid HTML 4.0! Created with Emacs Last modified: Wed Apr 16 22:29:08 Eastern Daylight Time 2003