1. General concepts
2. Support of multiple objects
3. Dispose
4. Address of callback feature
5. Specifying callbacks
Visual Eiffel allows its users to generate special type of features called 'callbacks'. The term is widely used in programming under Win32 platform. Callback is a feature that can be called from the side of operating system at any time. All callbacks have to support special calling and naming conventions that are not identical to the corresponding conventions supported by Visual Eiffel. To resolve the problem Visual Eiffel generates special code stub for every feature described as a callback. In fact the stub is used as a gate between Visual Eiffel and Win32: all invocations of the callback are transferred to the stub and all results are getting from the stub. Due to such implementation operating system can work with Eiffel features as it does with any other languages without assuming something about special nature of the Eiffel.
The technique described below is related to the callbacks which have a handle as their first parameter. The technique of using callbacks which do not provide a handle as the first parameter to the callback is described in the next section.
Both Eiffel program and Win32 API operate with 'objects'. In Eiffel such objects can be obtained as results of creation instructions. In Win32 the objects are windows, buttons, timers, etc. To distinguish between two objects both Eiffel and Win32 use some type of unique identifier. In Eiffel it's called 'Current' , in Win32 - 'handle'.
Most callbacks described in Win32 API Reference has one argument that is the handle mentioned above. So if we could associate one handle with exactly one Eiffel object then we could use the same callback routine for any number of Eiffel objects. Visual Eiffel automatically supports such association. When user creates an instance of a class including callback(s), run-time system inserts one line in the special internal table(s). This line keeps the Current, the address of the callback and special value indicating that this object has no corresponding handle yet (run-time supports one such table per one callback routine in the program). After that control returns to the user program which in turn must immediately register the object as Win32 object (before any new creation of the object of the same or conforming class). As a response for such registration Win32 would invoke the callback(s) with some new handle(s) as its argument. The run-time system catches the invocation in the stub entry point and fills the empty line in the above internal table. From now the Eiffel object is associated with the Win32 object and can be safely used: all what we need is just substitute an appropriate current instead of the handle.
Visual Eiffel provides a limited support of callbacks for which Win32 does not pass any handle as the first parameter. This limitation is described by the following rules depending on how many objects with this callback will be created in your program:
If the program creates a lot of objects with callbacks then the internal tables used to support them can overflow. To remove from the tables all the lines corresponding to the dead objects, Visual Eiffel delivers a special class CALLBACKABLE. The class inherits from the class MEMORY and redefines its feature 'dispose'. So if Garbage Collector encounters such an object then the special internal routine will be called and the callback' table(s) will be elaborated.
It is not necessary to inherit from CALLBACKABLE if you want to use some callback routine. However, it's strongly recommended.
There is one special trick in maintenance of callbacks in Visual Eiffel. The address operator ($) has a special meaning for the callback features. It returns the address of the stub rather then the real feature address. Due to that you can introduce some feature of some class as a callback; then you can inherit from the class and redefine the feature as many times as you want. After that you can create and register several objects of the above classes as described in section 2. You can be sure that an appropriate version of the callback feature will be called for every object.
To specify the callback feature you need to insert in Eiffel System Description file the list list of all classes and the corresponding features which you want to use as callbacks (after keyword 'CALLBACK') like here:
.... callback SOME_CLASS some_callback1 some_callback2 end SOME_OTHER_CLASS some_other_callback end ....
Please remember that status 'callbackable' is inherited so you have not to inherit class CALLBACKABLE again if the parent already does.