To build a DDE server application that uses default processing, do the following:
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.
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:
First, create a class called DdeTimeServer that is a subclass of
Object. Give it the two instance variables described in Table 42.
Table 42. Instance variables for DdeTimeServer
Instance variable | Description |
---|---|
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 IBM Smalltalk 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 IBM Smalltalk 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.