DDE COM Client v1.0

Introduction

This is a COM component to allow scripting of DDE Servers. It is an Automation Server (i.e. it is programmable via IDispatch) that houses two fundamental COM classes. The first is a DDE Client, which is a Singleton style object that can be used to make ad-hoc DDE queries and querying for running DDE servers. The second is for a specific DDE Conversation and can be used as an optimisation when you need to query many values from the same DDE source.

At present it only supports the requesting of data in CF_TEXT format, which is then converted to UNICODE to pass back over the COM interface. Most of the DDE servers I have dealt with were ANSI based and given the nature of scripting I felt this was probably good enough for a first attempt. If there is a need to allow access in other formats (e.g. CF_UNICODETEXT, CF_DIF etc) I will add to the API. It also only supports DDE Requests [XTYP_REQUEST], but could be easily extended to allow Pokes [XTYP_POKE] and Executes [XTYP_EXECUTE].

The other major feature of DDE that is missing is the asynchronous updating of values via advise loops (a.k.a. DDE Links). These have not been implemented as I did not know if it is possible to handle COM events from scripting languages such as VBScript.

The component is implemented using dual interfaces, so also supports early binding. However, if you're using C++ you would be better off using the underlying NCL library/DDE classes directly.


The DDE Client Class

The DDE Client class is essentially a Singleton style class that provides simple access to DDE servers. If all you need to do is query for a few values from a DDE source or two you can do it with repeated calls to RequestTextItem. It also provides access to the Wildcard style request [XTYP_WILDCONNECT] so that you can query for running servers and their topics.

String[] RunningServers()

Finds out which DDE servers are currently running and returns a collection of the server names. The collection is an array of strings.

String[] GetServerTopics(String strService)

Finds out what topics are supported by a DDE server. The return value is an array of strings which are the topic names.

IDDEConversation OpenConversation(String strService, String strTopic)

Open a DDE conversation for a specific Server and Topic.
See the DDE Conversation class for other ways to open a conversation.

IDDEConversations Conversations()

Get the collection of open DDE conversations. This collection is enumerable using the "For Each" idiom or can be indexed directly using the Item method
NB: The Item method follows the VBScript and WMI convention of being 0-based.

String RequestTextItem(BSTR strService, BSTR strTopic, BSTR strItem)

Request the current value for a single item from a named service and topic. The item is requested in CF_TEXT (i.e. ANSI) format and then converted to UNICODE to pass back via COM as a string.

The DDE Conversation Class

The DDE Conversation class is really an optimisation (and an excuse for me to implement a COM collection :-) that avoids the overhead of creating a conversation every time an item is requested. If you have many values to request from a single Service|Topic pair, open an explicit conversation either from the DDE Clients' OpenConversation method, or use the "ddelink:" moniker namespace, then use that to request the items.

Property: String Service

This property is the DDE service name. It can be read at any time, but only modified when the conversation is not open.

Property: String Topic

This property is the DDE topic name. It can be read at any time, but only modified when the conversation is not open.

Open()

Opens the conversation specified by the Service and Topic properties. If the conversation is already open, an error is returned.
This method allows a DDE conversation to be opened by creating an explicit DDE Conversation object, setting the Service and Topic names and then calling Open().

Boolean IsOpen()

Checks if the conversation is currently open. Returns True or False.

Close()

Closes the DDE conversation. If the conversation is not open then the operation has no effect.

String RequestTextItem(String strItem)

Request the current value for a single item. The item is requested in CF_TEXT (i.e. ANSI) format and then converted to UNICODE to pass back via COM as a string.

The DDE Conversation Moniker Namespace

WMI uses a moniker namespace of "winmgmts" to support simpler creation of WMI queries by encoding the query as a moniker item, which in VBScript you pass to GetObject(). You can achieve a similar effect with DDE Conversations by using the "ddelink" namespace. The full moniker consists of the "ddelink:" prefix, a "//" separator and the moniker item is the Service and Topic name in DDE Link format, e.g.

ddelink://SERVICE|TOPIC

This helpfully gives the link a URL like syntax, and when support for true links are added the syntax can be updated to allow a "!Item" style suffix.

Errors

All the COM objects support IErrorInfo, so you will receive textual error messages along with the result code. If the underlying error comes from DDE itself, then the symbolic name for the error code will be included (e.g. DMLERR_BUSY) which you can look up in the DDE SDK.


Examples

The following set of examples should cover the most common scenarios. They are written in VBScript as scripting was the reason I created the components. The initial example shows how to create the DDE Client, which is then assumed in the subsequent code snippets.

Creating the DDE Client
Dim oDDEClient
Set oDDEClient = CreateObject("DDECOMClient.DDEClient")
Listing the Running Servers and Topics
Dim astrServers, astrTopics
Dim i, j

astrServers = oDDEClient.RunningServers()

For i = LBound(astrServers) To UBound(astrServers)

    WScript.Echo "Server: " & astrServers(i)

    astrTopics = oDDEClient.GetServerTopics(astrServers(i))

    For j = LBound(astrTopics) To UBound(astrTopics)

        WScript.Echo "    Topic: " & astrTopics(j)

    Next

Next
Requesting a Single Item
Dim strValue
strValue = oDDEClient.RequestTextItem("PROGMAN", "PROGMAN", "Accessories")
Opening a Conversation
Dim oDDEConv
Set oDDEConv = oDDEClient.OpenConversation("PROGMAN", "PROGMAN")

or

Dim oDDEConv
Set oDDEConv = GetObject("ddelink://PROGMAN|PROGMAN")

or

Dim oDDEConv
Set oDDEConv = CreateObject("DDECOMClient.DDEConversation")

With oDDEConv
    .Service = "PROGMAN"
    .Topic   = "PROGMAN"
End With
Requesting Items From One Conversation
Dim oDDEConv
Set oDDEConv = GetObject("ddelink://PROGMAN|PROGMAN")

Dim strValue1, strValue2, strValue3
strValue1 = oDDEClient.RequestTextItem("Accessories")
strValue2 = oDDEClient.RequestTextItem("Games")
strValue3 = oDDEClient.RequestTextItem("Startup")

License & Warranty

This COM component is freeware - you get what you pay for, nothing more, nothing less.

Source Code

The full source code (C++) is available from my web site listed below.

Contact Details

Email: gort@cix.co.uk
Web: www.cix.co.uk/~gort

Chris Oldwood
19th July 2007