Building a DDE server that uses default processing
To build a DDE server application that uses default processing, do the following:
1. Create a DdeServerManager.
2. Build the default database by sending the addItem:topic:value:format: message to the DdeServerManager for each item that you want to make available to DDE clients.
3. Send the updateItem:topic:value:format: message to the DdeServerManager each time the value of the item changes.
4. When the application is finished, send the free message to the DdeServerManager.
By using default processing, the DdeServerManager (along with the default database) handles all connection requests from DDE clients as well as requests for hotlinks, warmlinks, coldlinks, and data.
By default, data sent from any DDE client to your DdeServerManager (a poke, in DDE terminology) is rejected. Requests from the client for the server to run commands are also rejected. However, both of these callbacks can be hooked, enabling the application to service these requests.
An example DDE server that uses default processing
To build a DDE server application that uses default processing:
This example builds a DDE server that has the time and date in two different formats for a total of four available items. The items are as follows:
•The current time in a String format
•The current time as a Smalltalk object
•The current date in a String format
•The current date as a Smalltalk object
First, create a class called
DdeTimeServer that is a subclass of
Object. Give it the two instance variables described in
Table 43.
Table 43. Instance variables for DdeTimeServer
| |
ddeServerManager | The instance of the DdeServerManager class that you are creating. |
timerOn | A flag indicating whether the timer is on or off. Turning the timer off is important when the server shuts down. |
Your new class looks like this:
Object subclass: #DdeTimeServer
instanceVariableNames: 'ddeServerManager timerOn '
classVariableNames: ''
poolDictionaries: ''
Now create a class method new to create a new server. Send the initialize method to the new object in order to set it up.
new
"Answer a new server after initializing it."
^super new initialize
Before executing the new class method, you need to create the initialize method. In the initialize method, first create the DdeServerManager and name it Timer. Next, build the default database.
Note:
With the default database setup you do not have to hook into any of the callbacks provided by the
DdeServerManager. All you need to do is to update the items when the timer goes off. Notice that for the format of 'String,' you pass a Smalltalk
String for the data. When the format is 'Smalltalk Object,' you use the VAST Swapper to convert the Smalltalk object into a
ByteArray. The method
flatten to perform this function is specified in
Converting Smalltalk objects to a ByteArray and back.
initialize
"Private - Create and initialize a DdeServerManager. Set the name
of the server to 'Timer' and create two items in the item database
under the topic of 'Time'. The two items will be 'date' and 'time.'
Support two formats for the items, a string format and a Smalltalk
object. Support the Smalltalk object format by using the VAST
Swapper to turn a Smalltalk object into a ByteArray."
| currentDate currentTime |
ddeServerManager := DdeServerManager name: 'Timer'.
currentTime := Time now.
currentDate := Date today.
ddeServerManager
addItem: 'time'
topic: 'Time'
value: currentTime printString
format: 'String'.
ddeServerManager
addItem: 'time'
topic: 'Time'
value: (self flatten: currentTime)
format: 'Smalltalk Object'.
ddeServerManager
addItem: 'date'
topic: 'Time'
value: currentDate printString
format: 'String'.
ddeServerManager
addItem: 'date'
topic: 'Time'
value: (self flatten: currentDate)
format: 'Smalltalk Object'.
self timerOn: true.
At the end of initialization the timer is turned on by sending the timerOn: message, which in turn sends the timerSet message. The timer uses the Common Widgets timer functionality so that when the timer goes off, the message timerProc: is sent to the application.
timerOn: aBoolean
"Start/stop the timer depending on aBoolean."
timerOn := aBoolean.
self timerSet.
timerOn
"Answer whether the timer is on or off."
^timerOn.
timerSet
"If the timer is on, reset it to go off in one second."
self timerOn ifTrue: [
CwAppContext default
addTimeout: 1000
receiver: self
selector: #timerProc:
clientData: nil
]
Now all initialization has been completed. The main work of the server is now in the method that is run whenever the timer goes off. When the timer goes off and the timerProc: method is run, all the items in the default database are updated. As the items are updated, the DdeServerManager looks for any hot- or warmlinks to the data and updates the clients that are linked to those items.
timerProc: clientData
"The timer has gone off so save the current date and time and then
update the item database."
| currentDate currentTime |
currentTime := Time now.
currentDate := Date today.
ddeServerManager
updateItem: 'time'
topic: 'Time'
value: currentTime printString
format: 'String'.
ddeServerManager
updateItem: 'date'
topic: 'Time'
value: currentDate printString
format: 'String'.
ddeServerManager
updateItem: 'time'
topic: 'Time'
value: (self flatten: currentTime)
format: 'Smalltalk Object'.
ddeServerManager
updateItem: 'date'
topic: 'Time'
value: (self flatten: currentDate)
format: 'Smalltalk Object'.
self timerSet.
The final method that you need to implement is the free method. This method stops the timer and frees up the DdeServerManager.
free
"Close down by stopping the timer and freeing up the
DdeServerManager."
self timerOn: false.
ddeServerManager free.
You now have a DDE server that not only provides the current time and date to any DDE client but also allows access to the Systems Topics that should be supported by all servers.
In this example server, the time and date are both updated when the timer goes off. An improvement to the code might be to only update the date (and possibly the time) if it has changed since the previous update.