DosLibrary sleep: 10000This will cause your entire workstation to hang for the 10 seconds it takes DosSleep to return control. Clearly, if you can't guarantee the DLL call will return control quickly, another implementation must be found. This causes particular problems for communications packages, since the time it takes to return control depends on the network and the partner program! In fact, all of the research for this article was done while developing an APPC interface for VPM.
The first thing to understand is how VPM uses OS/2 threads. In VPM 1.3, two OS/2 threads execute when the environment is running: a Presentation Manager (PM) processing thread and a Smalltalk code executor thread. this design is based on a PM requirement that an application return control to it quickly after processing a message. Since a PM message might (and usually does) cause Smalltalk code to be executed, this PM requirement could not be guaranteed using a single OS/2 thread.
In the two-thread implementation, a PM message is processed by adding it to a global OrderedCollection named CurrentEvents by the PM message processing thread. This thread immediately returns control to PM, allowing other applications to process their PM messages. Some (typically very short) time later, the Smalltalk code executor thread checks the CurrentEvents collection to see if there are any messages. If any are pending, they are routed to their respective window objects. Class NotificationManager performs this service for the code executor thread. See its instance method #run for more details.
Since PM messages are identified by a unique message number, VPM must
have a way to translate between messages numbers and method names.
This translation is done by using two global objects, PMEvents and PMExtraEvents.
PMEvents is an array of symbols, indexed by PM message number. that
is, (PMEvents at: 7) contains the value #wmSize:with:. Seven is the
message number assigned to the WM_SIZE message by PM. The PMEvents
array is not large enough to map every possible PM message. Due to
memory considerations, only about the first 478 are mapped here.
Any message numbers received that are greater than the size of PMEvents
are looked up in the global Dictionary PMEventsExtra. the PM message
number (558, for example) is the ky for this dictionary, and the method
name symbol is its value (#wmerror:with:). Once the PM message has
been mapped to a method name via either PMEvents or PMEventsExtra, the
PM message processing thread sends a Smalltalk message to the appropriate
window object using the two arguments provided by PM. For more details
look at any of the #wm... instance methods in the Window class.
The first issue to be addressed is the selection of message numbers for communications with the thread. A consecutive block of message numbers should be chosen for each application, avoiding conflicts. Message numbers must be unique within one VPM image. User-defined message numbers must be greater than 4,096 to avoid conflicts with Pm messages. For the APPC interface, message numbers range from 29,500 to 29,505. Each message number must have an entry in PMEventsExtra that specifies the method name associated with it. For example, message number 29,501 is associated with the #vpmAppcVerbDone:with: method. the message definitions used in the APPC interface are:
PMEventsExtraTo create an additional thread from the VPM environment, a DLL must be created to issue the DosCreateThread OS/2 call and to contain the code to be executed by the thread. In Listing 1, the CreateThread function performs this action. Parameters to CreateThread are the stack area to be used by the new thread, the size of the stack area, and the window handle to be notified when the thread is created and ready for work. The stack is passed to the thread from the VPM environment to ensure that it is properly freed after thread termination. The code in the Thread function initializes PM and creates a message queue. It then posts the VPM_APPC_THREAD_QUEUE message to the AppcNotifierWindow instance, passing the queue handle as a message parameter. The Thread function then loops until a VPM_APPC_STOP_THREAD is received, processing messages. After each message is processed, a VPM_APPC_VERB_DONE message is posted to the AppcNotifierWindow instance. After the VPM_APPC_STOP_THREAD message is received, the Thread function stops looping and posts the VPM_APPC_THREAD_STOPPED message, which allows us to be absolutely sure the thread has stopped before freeing the stack area. A subclass of DynamicLinkLibrary must be created to allow the CreateThread function to be called. The AppcDLL class is shown in Listing 2.
at: 29501 put: #vpmAppcVerbDone:with:
at: 29503 put: #vpmAppcThreadQueue:with:.
To communicate with the thread using PM messages, there must be a PM window to receive them. Since this window will not perform any other functions, it should not be visible. this may be accomplished by making it a subclass of DDEAuxWindow. To facilitate reuse, an abstract superclass named InvisibleNotifierWindow has been created as a subclass of DDEAuxWindow. Notifier windows for various functions are subclasses of this class. InvisibleNotifierWindow implements the same #when:perform: interface as SubPane, allowing notifier windows to send messages to their owners when important events occur. Listing 3 shows some of the methods defined for the AppcNotifierWindow. as you can see, there is a method corresponding to each PM message number defined in PMEventsExtra. Companion methods are also defined for each. The #vpmAppc... methods are executed on behalf of the PM message processing thread. they copy the message parameters to instance variables if necessary and add the message event to CurrentEvents via the #sendInputEvent: method. The return from a #vpmAppc... method causes VM to return control to PM, allowing other applications to perform window operations.