DMHclient - A C++ DMH Client Class


Hume Integration has created a class library for integrating Visual C++ programs into a distributed system using the Distributed Message Hub (DMH) message system.   The DMHclient class provides high-level methods for sending and receiving messages, with either send-and-reply synchronous-style interactions, or higher performance asynchronous-style interactions.    Message exchanges are typically directed to application servers such as the Hume Integration Datahub, or the dmh_SQLsrv persistent database interface.  The DMH message system is remarkably easy to use with these DMH Tcl processes because the messages are typically SQL, Tcl, or VFEI text that is directly interpreted by the receiver.   To extend this ease of use to the C++ client, methods are provided with the control to parse Tcl list text strings,  to create Tcl list text strings from string elements, or to parse VFEI text.   The DMHclient class fully supports peer-to-peer interactions.

Feature Summary


User Guide


The DMHclient class for Visual C++ is provided as the following files:

The files are distributed in a .zip archive named DMHclient.zip. If you received the DMH software on CDROM, this archive is in the subdirectory LAN_IMAGE. The HTML documents in the DMHclient.zip archive are copies of the same documents found in the main online documentation.

The distribution is designed and tested for the Windows 2000 and Windows NT x86 architecture platform.  The class library is designed to successfully interoperate with recent versions of the Tcl/Tk DMH software running on any platform.  The library is designed to integrate into the Windows event loop, and to be used from the main thread of your application.  This is the usual scenario of Visual C++ applications.  If your application requires use of multiple threads for sending and receiving DMH messages, you should not use this library.  Instead, you should use the POSIX C Library which offers similar features but is designed from the ground up as a portable offering for high-performance threaded platforms.

The DMHclient DLL uses only the C++ runtime library and Win32  calls.  It does not require any additional libraries or product installations - not Tcl, not MFC, and not any other source of maintenance or compatibility issues.  Also, the library does not use any files, or the registry, so these are eliminated as a source of configuration management, installation, or runtime problems.  In short, the DMHclient DLL is an ideal component for your integrated software solution, and a model for other vendors.

The VFEI2Map DLL does use the MFC class libraries as a shared DLL.  If you build an application that uses the VFEI2Map class, your application will use the CMapStringToString MFC class, and require that MFC libraries be accessible at runtime.

Installation

Installation consists of extracting the DMHclient.zip distribution archive to a directory of your choice, such as c:\hume. The DMHclient.dll needs to be in the working directory of the executables that you build, or in a directory that is found on the system Path or the user's Path. You may wish to copy or move the DMHclient.dll file to a location such as c:\usr\local\bin.

To develop Visual C++ programs, choose an alternative:

  1. Modify the project settings to point to the DMHclient installation:
  2. Or, include the .h and .lib files as part of the project (menu: Project/Add to project/Files...)

Development

Your design will typically use one instance of the DMHclient class.  You can declare the instance as part of your application class, and then pass pointers to it, or references to it, to your window and dialog classes.   A single instance of the DMHclient can be used for sending and receiving with multiple mailboxes simultaneously.  More than one instance of the DMHclient class is only needed if you wish to communicate directly with multiple DMH servers.  You should not use multiple instances of the class to communicate with a single DMH server.

As a developer, per the licensing terms, you are required to have the Tcl/Tk DMH software installed on your development system.   One reason for this requirement is to insure that you have the online documentation for the DMH system.  A second major reason is so that you can run your own DMH server process to test and debug against without affecting a production system.

If you are not familiar with the DMH message system, you may want to read the mbx document which is usually installed at \usr\local\htm83\mann\mbx.html.  Your C++ application acts a DMH message system client, and attaches to a running DMH server.  Once you are connected to the DMH system, you can exchange messages with other attached processes.

To get started, you only need to know the hostname where the DMH server is running, and the DMH Groupname that has been assigned to the server.   If you click on the "Programs"/"Tcl 8.3 - Tk 8.3 - DMH"/"Datahub" program item, you will start a DMH server running on your host, with the default DMH groupname of "mbx".

The usual application design, and the one that provides the best performance,  is to connect to the DMH server during initialization, and to use this connection during the life of the application.  The Init( ) method is used to connect to the server.  The server's hostname and groupname are provided as arguments to the Init( ) method.  If the application disconnects from the server, the Init( )
command can be used again to restore the connection.

Error Handling

A long running program such as a user interface or automation application needs to handle intermittent errors with network outages or server shutdowns.  There are two styles of handling errors; you can mix both styles in your application as you see fit.

The first style of error handling is to avoid them by disabling buttons and window controls that make use of DMH features when there is not a server connection.  You write the statements that enable your buttons in the "Connected" event handler, and you write statements that disable the buttons in your "Disconnected" event handler.  During initialization, before you have a connection, call the Disconnected event handler yourself to disable the buttons.  Also during initialization, call the Init( ) method.  When the Init( ) succeeds, a "Connected" event occurs and your buttons become enabled.  This technique requires less coding than the method described next.

The second style of error handling is to add explicit error checking to your procedures.   Many of the method calls return NULL for the usual successful invocation, or an error message that could be logged or displayed to the user.  The most common error message is "No DMH server connection".  This message occurs when using a method that requires a connection and Init( ) has not been called successfully, or the DMH connection has been lost.  The methods do not throw exceptions, and you do not need to use try and catch.

Here is a summary of the kinds of errors that the DMH control will report.  When you make a method call that requires a DMH server connection, and you do not have one, the method call will return "No DMH server connection".  If you use an improper mailbox name such as one with whitespace in it, the method call will return a string such as, "mailbox name must contain only ASCII letters, digits, -, _, ., !, :, or @".   These are the two main errors when initiating a method call.   Most of the DMH  method calls are then processed asynchronously.  In other words, your method call returns, and the message communication you initiated happens as events are processed.  An error that occurs during event processing results in the DMHclient Error( ) event occurring.  You do not need to write an Error( ) event handler,  but you probably should to communicate to the users of your program if an error occurs.  When the Error( ) event occurs, the Disconnected( ) event will also occur.  You can place logic in your Disconnected( ) event handler to initiate recovery and resume logic, exit the program, etc.

Child Windows

Here is the recommended technique to use a single DMH control with all of the class code of your application.  If you have a child window class,  include a variable for use in referencing the application's DMHclient instance.  So in the child class declarations, you include something like:

// Child Header code
// Child class declaration
public:
    DMHclient *dmh;
 

// Child class code
    // constructor code
    dmh = &theApp.dmh

    // button code
    //...
    CString reply = dmh->DoXact("DATAHUB", "eval localtime 16");
    // ...
 

// Application header
// class declaration
...
public:
    DMHclient dmh;
...
// declare a visible pointer to the application instance
extern MyTypeOfApp theApp;
 
 
 

Sending and Receiving - Basics

The programming model of the DMH message system is that you send a plain text message to a destination mailbox.  When sending the message, you can optionally specify the name of a second mailbox for the recipient to send a reply message to.  Usually you send a message to an application logic server such as a Datahub.  The message is usually SQL,  Tcl, or VFEI code that the recipient executes.  If the sender has designated a reply mailbox, the result of executing the command is sent to the reply mailbox.

Lets discuss sending without asking for replies using the Send( ) method  or its equivalent, the Put( ) method .  For example,  suppose you are integrating a barcode reader.  When data is read from the barcode reader device, your code is supposed to update a record in a Datahub table.  You will send messages without asking for reply messages - if there is a system shutdown or communication failure, your application will know from the Disconnected( ) event.  This is more efficient than asking for a reply message at every barcode read.

// update latest read record in table barcode_reader at the Datahub
CString message;
message.Format("update barcode_reader set data_in='%s' where device_id='%s'",
               newdata, myID);
dmh->Send(Hub, message)

When you send a message without waiting for a reply, it is referred to as an asynchronous send.

Often, you will want to send a message to obtain reply data.  The most convenient method to use is the DoXact( ) method.  This method will take care of specifying and using a unique mailbox for your reply message, and it will take care of managing a timer in case a reply message is not forthcoming.  Suppose you want to query a database table, and the DB variable is assigned the mailbox name of the dmh_SQLsrv process.   The online documentation shows that the SQL standard "select" command sends multiple reply messages, but the "telect" command sends a single reply message with all of the requested data formatted as a Tcl list.  The DoXact( ) method is designed for a single reply message, so your code looks like:

const char *reply;
CString msg;
CString device_id;
msg.Format("telect device_id from barcode_config where display='%s'", dmh->Hostname());
reply = dmh->DoXact(DB, msg);
if (!strcmp(reply, "TIMEOUT")) {
    // timeout or error
    return reply;
}
// Parse the result- a Tcl List
// element(6) = rows of data, then (0) = first row, then (0) = first item in row
device_id  = dmh->ListElement(reply, 6, 0, 0);
// success
return NULL;
 

Sending and Receiving - Advanced

If your application needs to receive unsolicited messages from other processes, you use the Whenever( ) method to setup asynchronous receiving.  When an unsolicited message is received, your specified Whenmsg( ) event handler is called.    By convention you should use mailbox names for receiving that end in _SQL if SQL messages are expected, _VFEI if VFEI messages are expected, and _RPC if Tcl messages are expected.   There is no limit to the number of mailboxes that you use for receiving, but the design convention is that you use unique names based on the server function(s) provided.  There should be only one receiving process per mailbox name in a DMH group.  You may wish to create a unique mailbox name for receiving by basing the name on your hostname - see the DMH method Hostname( ).

The Whenever( ) method is used for ongoing receiving - your application will continue to receive the messages that are sent to your specified mailbox.  The Disarm( ) method can be used to stop asynchronous receiving.

The Whenmsg( ) method is similar to Whenever( ) except that it functions to receive only one message.  If WhenmsgAgain( ) is executed from your receiving event handler, then the control is re-armed to receive the next message.  So the combination of Whenmsg( ) and WhenmsgAgain( ) are equivalent to the Whenever( ) method.

Lets revisit the DoXact( ) method.  In some situations, you may want higher performance by sending messages and collecting the replies asynchronously, instead of waiting for each reply before sending the next message.  You do this by setting up one or more reply mailboxes and arming them for receiving using the Whenmsg( ) or Whenever( ) methods.  Instead of using DoXact( ) use the Send( ) command and specify the reply mailbox argument.  Typically a high  performance application will create a small number of unique mailbox names for replies, and re-use them.  If you are creating unique mailboxes for each reply message, use the CloseMailbox( ) method when you are done with each one, to recover resource usage.

Event Handling Notes

Your application should not "live" inside of your event handling code.  Be sure to return in due course.  Avoid performing long running computations.

Be careful with the Trace( ) event.  If you turn on a lot of tracing and are exchanging long messages, your application will be manipulating huge amounts of string data.

Do not use modal dialogs that block the dispatching of events to other windows.

International Character Sets

Multibyte UTF-8 character sequences are used by Tcl and DMH to represent International characters.  The API for the DMHclient uses these character sequences since they are compatible with the usual single character ASCII strings used by most applications.  UTF-8 strings can be manipulated with all the usual C language functions because they do not use the null character as data.  If you are using International characters in C++ and displaying text to the user, you are probably using Unicode strings, and you probably need to convert the UTF-8 strings used by the DMHclient DLL to and from Unicode.  This can be done using the Win32 calls MultiByteToWideChar( ) and WideCharToMultiByte( ).  If you are developing International applications, you may find it easier to use Visual Basic and the DMHocx Active-X control.  The DMHocx control converts Tcl/DMH UTF-8 sequences to and from Unicode transparently.

When declaring database tables to hold international text, base the VARCHAR( ) sizes on UTF-8 byte counts, not on the number of characters.  In the most conservative case,  you need to allow 3 bytes per displayed character.

To be successful with International applications you need to make sure that you have installed fonts and chosen fonts in your application that are capable of displaying the characters you require.

Termination

When your application is shutting down, you should call the Disconnect( ) method to disconnect gracefully from the DMH server.  Practically speaking the DMH server routinely takes care of situations where clients leave ungracefully, but proper software manners are encouraged.

 

Miscellaneous Notes

An actual network connection is not attempted until Init() is called.

The programming model is that you will not have more than one connection to a particular DMH server.  It is typical to have only one DMH connection per application process.  Communication across DMH groups can be accomplished by sending to mailbox@groupname.  It is also possible to use multiple controls, each connected to a different DMH Group.

There should be only one reader per mailbox name in a given DMH group.

The  DMHclient class is able to use and resolve DMH groupname aliases as described in the online Tcl documentation.  Groupname aliases are resolved at the DMH server and not at the client.

Mailbox Naming rules:



DMHclient Class Reference

 DMHclient "Properties"
Property Access Description
const char *getClientID() The DMH server assigns a unique string to each client for identification purposes. This value is a read-only runtime value providing the server's ID string or an empty string if a connection has not been established. 
int getDefaultTimeout( )
int setDefaultTimeout(int)
The default timeout interval for send and reply transactions, or timed receive invocations.   In seconds - the default value is 30.  Settable range: 1 - 86399.
const char *getDescription( )

void setDescription(char *)

One of the features of the Tcl/Tk DMH Status Window is an action to identify connected clients.  The default description provided for a Visual C++ client is similar to "hostname:VC DMH client".  You are able to provide your own description string for your application.
int getState( )
 
 
 
 
 
 
 
 

 

The state property is a read-only value available at runtime.  The value can be read to determine if a healthy communication connection exists, etc.    Applications will ordinarily use event methods and not poll the state property value.  The transient and error states do not last long, so testing for the values 0 or 7 is the most common scenario. 
  0       disconnected
  4       hostname is being resolved
  6       connection setup in progress 
  7       healthy connection exists
  8       connection close in progress
  9       a communication error has occurred  
519       DMH protocol setup in progress (519 = &H100 Or 7)
int getTracebits( )
int setTracebits( )
The Tracebits property controls output of diagnostic data to the Trace event.  This value is used as a bitfield with the bit values controlling the following categories of output:

01 data reads
02 data writes
04 message receiving
08 message sending
16 logic tracing

const char *getmhgroup() The mhgroup property is a readonly runtime value indicating the hostname:port  of the DMH server when connected, else NULL.  Hostname is the server's idea of his hostname which may be different from the hostname that was specified at the client.


 
DMHclient Callback Events
Event Callback  and Set Method  Description
All callback methods - NOTES
 
 
 
 
 

 

You write your own callback function consistent with the typedef of the callback.

void MyConnectedCallback(DMHclient *dmh) { ... }

Then you register it with the DMHclient:

dmh->setConnectedProc(MyConnectedCallback);

When the event happens, your callback function is called.  A pointer to the DMHclient is provided as an argument, in case you are using the same callback with multiple instances of the DMHclient class. 

When registering the callback, the previous value is returned.  This lets you chain, or swap and restore callbacks.  These are not recommended techniques.

void (DMHConnectedProc) (DMHclient *)

DMHConnectedProc * setConnectedProc(DMHConnectedProc *);

The Connected event happens after successfully connecting to the DMH server in the wake of the Init method invocation. 
void (DMHDisconnectedProc) (DMHclient *)

DMHDisconnectedProc * setDisconnectedProc(DMHDisconnectedProc *)

The Disconnected event happens when the DMH connection has been closed from any circumstance such as remote closure, communication failure, error, or invocation of the Disconnect method.  This event is similar to the Tcl lostserver procedure invocation.  The event may happen more than once if multiple errors are being processed.
void (DMHDoOneEventProc)(void)
 

DMHDoOneEventProc * setDoOneEventProc(DMHDoOneEventProc *)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

 

The DoOneEvent callback:
When the DMHclient does a modal receive for Init( ) or DoXact( ) it dispatches events on behalf of the application.  The default event dispatcher is the usual GetMessage( ) , TranslateMessage( ), DispatchMessage( ).  If you need a custom event loop, replace the DoOneEvent( ) with your own code - just 
process one message and return.

static void DoOneEvent(void) {
    MSG msg;
    if ( GetMessage(&msg, NULL, 0, 0) ) {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
    }
}

A Special Note for MFC applications:

MFC is designed to call PreTranslateMessage() in its event loop, so you should provide a custom DoOneEvent callback.  This cannot be coded in the DMHclient class without forcing everybody to link with MFC.
 

void MFCDoOneEvent () {
 MSG msg;
 if ( GetMessage(&msg, NULL, 0, 0) ) {
  if ( !AfxGetApp()->PreTranslateMessage(&msg) )  {
   TranslateMessage(&msg);
   DispatchMessage(&msg);
  }
 }
}
 

void (DMHErrorProc) (DMHclient *, int errnum, const char *text)
 
 

DMHErrorProc * setErrorProc(DMHErrorProc *)
 
 
 
 

 

The Error event happens when the Init method fails, or there has been communication failure.  In most cases when the Error event happens, the control state will transition to the disconnected state, and the Disconnected( ) event will occur shortly.
 


Broken connection errors include:

10051  the network is unreachable
10060  Connection has timed out
11053  Connection is aborted due to timeout or other failure
10054  Connection is reset by remote system
10058  Connection has been shutdown
50001  DMH Protocol error - missing data.  You should never see this error.
50002  DMH Protocol error - improper packet.  You should never see this error.
void (DMHShutdownProc) (DMHclient *, int *StayAlive)

DMHShutdownProc * setShutdownProc(DMHShutdownProc *)

A remote request has been received to terminate the process.  If you do not set the StayAlive flag true, the software will cause the application to exit. 
void (DMHTraceProc) (DMHclient *, const char *text)

DMHTraceProc * setTraceProc(DMHTraceProc *)

This event provides diagnostic and debug information per the Tracebit property setting.  Your application needs to avoid creating new DMH activity in the Trace event callback, that in return causes Trace events.  A cycle of positive feedback is possible which will cause a software fission reaction.
void (DMHWhenmsgProc) (DMHclient *, const char *DestinationMailbox,  const char *ReplyMailbox, const char *Data, void *ClientData)
 
 
 
 
 
 
 

 

The Whenmsg callback is executed when a message has arrived.  You can register different callback functions for each destination mailbox using the Whenmsg or Whenever methods, described in the next table. 

The DestinationMailbox parameter is a mailbox name that your application has specified when initiating receiving.  If the sender of the message indicated a reply mailbox, it is passed as the second argument, ReplyMailbox.  If no reply mailbox has been specified, the ReplyMailbox argument is an empty string.  The Data argument is the text of the sent message.  The DMHclient  logic protects you from receiving another message for the DestinationMailbox, and re-entering your handler logic until you have returned from the current callback execution. 

When you call the Whenmsg() method or Whenever( ) method to setup receiving,  you can optionally specify the ClientData argument to be saved and passed  to your callback at the time a message arrives.  A typical use would be to  pass a pointer to a C++ object, so your receive callback can use the pointer  to call a class method. 

DMHclient Methods
METHOD DESCRIPTION
General Comments
 
 
 
 
 
 
 
 
 

 

Most of the information in this table cell is copied from the User Guide.

Many of the method calls return NULL for the usual successful invocation, or an error message that could be logged or displayed to the user.  The most common error message is "No DMH server connection".  This message occurs when using a method that requires a connection and Init( ) has not been called successfully, or the DMH connection has been lost.  The methods do not throw exceptions, and you do not need to use try and catch. 

If you use an improper mailbox name such as one with whitespace in it, the method call will return a string such as, "mailbox name must contain only ASCII letters, digits, -, _, ., !, :, or @".   Most of the DMH  method calls are then processed asynchronously.  In other words, your method call returns, and the message communication you initiated happens as events are processed.  An error that occurs during event processing results in the DMHclient Error( ) event occurring.

We use a lot of "const char *" declarations because they interoperate very well with the MFC CString string class, and they show that you should not tamper with the returned values - copy to save, copy to modify, etc.

void Abort(void) Any in-progress send-and-reply or modal wait transactions such as the Init( ) method or DoXact( ) calls are aborted with return values indicating TIMEOUT.  Invoking the Abort method does not affect asynchronous receiving that is setup using the Whenmsg( ) or Whenever( ) methods.  Has no effect if not connected.
const char *CloseMailbox(const char *boxname) Stop using a mailbox - Disarm receiving if listening, Flush if not empty,  and remove from existence if it exists.  The Tcl version of this call, differs because it will not flush existing messages.

Returns NULL on success, or an error message.  You must be connected to use this call.

const char *Count(const char *boxname, long *ctsent, long *ctread, long *ctpending)
Returns three numbers, the total count of messages that have been sent to the mailbox, the total count of messages that have been consumed from the mailbox, and last, the current count of pending messages.  A pending message is one that exists in the queue associated with the mailbox, and has not been consumed by reading or flushing.

Returns NULL on success, or an error message.  You must be connected to use this call.

void Disarm(const char *boxname = NULL) Un-register the listener from a specified  mailbox.  This call may be used to cancel an earlier whenever( ) or whenmsg( ) call.  If called with no arguments, all Whenever( ) and Whenmsg( ) receiving registrations are canceled.  The Abort( ) method will cancel in-progress DoXact( ) calls.  Has no effect if not connected.
void Disconnect(void) The counterpart of Init( ); disconnects from the DMH server.  The Abort( ) method gets called to end any in-progress transactions.  The Disarm( ) method gets called with no arguments to cancel all receiving.  Has no effect if not connected.
const char *DoXact(const char *DestinationMailbox, const char *Message, int TimeoutSeconds = 0,
  const char *ReplyMailbox = NULL)
 
 
 
 
 

 

Performs a complete send and reply transaction with timeout management.  Creates and manages a unique reply mailbox for the send and reply transaction if the replybox argument is defaulted.  If the timeout is not specified, the DefaultTimeout value is used.  The usual reply is the text of the reply message. The String literal TIMEOUT is returned in case of failure.  You can have multiple instances of DoXact( ) or TimedReceive( ) active at a time but not more than one instance for a specified reply mailbox.  (You can wind up with multiple instances by letting a user interface initiate them before completing an earlier invocation.)  Memory used for the reply result is freed and re-used with the next call to DoXact() or TimedReceive() so copy the reply to your own data structure when persistence is needed.

If you specify a ReplyMailbox, you need to insure that the name you specify is only used by your application.  It is usual to create a unique reply mailbox name, perhaps based on the hostname, assign it to a variable, and use it repeatedly.

If you are not connected when using this call, the TIMEOUT string is returned immediately.  Trace event information can be used to show the cause.

const char *Flush(const char *boxname)

 

Empty a mailbox of any pending messages.  A pending message is one that has been sent to the mailbox but has not been consumed.  In other words, a pending message is waiting in a queue associated with the  mailbox name.  Messages are consumed by reading or flushing.

Returns NULL on success, or an error message.  You must be connected to use this call.

int GroupnamePort(const char *Groupname)
Used to determine the TCP/IP port number that is used by the DMH server to listen for client connections.  The method is equivalent to the mh_name_to_socket Tcl procedure.  Most applications will not have a use for this method since the server socket port is managed by the DMH software. 
const char *Hostname(void)
Returns the TCP/IP hostname of the computer that the control is executing on.  The name is guaranteed to be stripped of domain information, and imbedded white spaces which are not valid in hostnames, are seen as delimiters of the first token.
const char *Init(const char *DMHGroupname = "mbx", const char *DMHServerHostname = "localhost")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

 

Performs the initial connection to the DMH message server. The connection will be setup or an error result will be obtained before returning.

Init errors include

10051  the network is unreachable
10060  Connection has timed out. This error indicates that the remote host may not be online.
10061  Connection attempt is refused. 
10061  Connection is forcefully rejected.
The remote host is online and reachable, but there is not a DMH server at the specified group or port.  We have improperly seen this error when using the hostname "localhost" on Windows 2000, and have worked around it using the actual hostname.  This seems to be a buggy behavior that is being investigated.
11001  Hostname not found (DNS authoritative).  This error may indicate an improperly spelled hostname, or a hostname that is not known to your name server.
11002  Hostname not found (non-authoritative name resolution).  This error may indicate that your name server is down.
50003  DMH Server refuses our client connection
This error indicates that customer modified software running in the DMH server has rejected the connection.  It is likely that you are in violation of your site's security policy.
50004  DMH Protocol error - improper setup reply.
You should never see this error.
If no DMHGroupname or RemoteHostname is specified, the default values, "mbx" and "localhost" are used.  See the above note on "localhost" not always working.

If the connection succeeds, the return value is NULL, otherwise an error message is returned  indicating why the initialization failed. 

When the initialization is successfully completed, the Connected( ) event is fired.  If it fails, depending on how the Init call fails, the Error( ) event may fire. 

If the connection to the DMH server is ever lost, the Disconnected( ) event is fired.

Returns NULL on success, or an error message. 

const char *ListElement(const char *TclList, int index1, int index2 = -1, int index3 = -1); This method is similar to the lindex method of Tcl.  It will parse text formatted as a Tcl list and return the specified element.  Additional indexes may be specified to parse lists that are nested inside of  lists.  If a specified index is out of bounds, an empty string is returned.  If an invalid list is parsed, NULL is returned.   Memory is allocated from the heap for the result, and it is freed and re-used with the next call.
const char *ListJoin(int argc, const char *argv[]); Joins together strings as Tcl list elements forming a result string that is a Tcl list.  Braces are added as needed to delimit empty elements, or to delimit special Tcl character sequences involving backslashes , square brackets, etc.  Memory is allocated from the heap for the result, and it is freed and re-used with the next call to ListJoin().
int ListSplit(const char *TclList, int *argc, char **argv[]) ListSplit( ) parses a string formatted as a Tcl list into an array of string elements.  The method understands the Tcl usage of quotes, braces and backslash sequences.  Not all strings are valid Tcl lists.  The return value is 0 on success.  Failure occurs when there are unmatched braces, unmatched quotes, or non-whitespace following braces or quotes.  Memory is allocated from the heap for the resulting argv[] stack and the elements that the stack points to. These values are safe until the next call to ListSplit, when the memory is freed and re-used.  The TclList passed in is treated as const - it is read, but not changed.
const char *Product() { return "DMH"; } The idea here is that if this interface is implemented for another product, a different Product() string should be returned in case the using software needs to know the difference.
const char *Put(const char *DestinationMailbox, const char *Message) The Put( ) method is equivalent to Send( ) without specifying a ReplyMailbox. 
Returns NULL on success, or an error message. 
const char *Putr(const char *DestinationMailbox, const char *ReplyMailbox, const char *Message) The Putr( ) method is equivalent to Send( ) with specifying a ReplyMailbox.
Returns NULL on success, or an error message. 
const char *ReceiveList(void) Returns a list of the mailboxes you are listening for messages on.  Does not show mailbox names that have in-progress Whenmsg( ) callbacks.  This command may be useful for debugging, and it is not used in a typical application.  The result is an empty string when you are not connected.
const char *Send(const char *DestinationMailbox, const char *Message, const char *ReplyMailbox = NULL);
 
 
 
 

 

Send a message to a mailbox, optionally with a reply mailbox indicated.   By convention, when a reply mailbox is indicated for a command message sent to a Datahub mailbox or equipment interface mailbox, the command is processed, and a reply message is sent to the reply mailbox. 

Specifying the reply mailbox as a NULL pointer, an empty string, or as the literal text "NULL" is equivalent to not specifying a reply mailbox.

Sending to the mailbox name "TRACE" sends the message to the DMH Server Trace Facility.

The Send method corresponds to the Tcl mbx put and mbx putr commands. 

Returns NULL on success, or an error message.  You must be connected to use this call.

const char *ServerStatus()
 
 
 
 
 

 

Returns a Tcl list containing the information presented in the Tcl DMH status window.  The information can be parsed by the application to determine  status information on every mailbox that is currently in use.  This command may be useful for debugging, and is not used by ordinary applications.

The first element of the list is a list of 5 elements:
{ hostname:port messages_received messages_sent messages_queued tcl_version }

Subsequent elements in the list are lists of four or five elements:
{ mailboxname count_in count_out count_pending [reader_handle] }

Additional elements may exist in the list if there are DMH clients that are not currently waiting to receive messages.  These elements are formatted as:
{{{no whenmsg pending}} - - - reader_handle}

You must be connected to use this call.

const char *TimedReceive(const char *ReceiveMailbox, int TimeoutSeconds = 0);
g
Waits for a message to be received in the specified mailbox.  If the call succeeds,  the return value is the message data.  If the call fails, the return value is the literal string "TIMEOUT".   If you are not connected, the call fails immediately with the return value "TIMEOUT".  Trace event information can be used to show the TIMEOUT cause.  Memory used for the reply result is freed and re-used with the next call to TimedReceive( ) or DoXact( ) so copy the reply to your own data structure when persistence is needed.
const char *Version(void) { return "1.1"; } Current software returns the string "1.1" to  indicate compatibility with DMH protocol version 1.1.
const char *Whenever(const char *ReceiveMailbox, DMHWhenmsgProc *, void *ClientData = NULL)
Registers to receive all messages directed to the specified mailbox.  When the MessageArrival( ) event handler returns, the control re-arms for receiving the next message directed to the specified mailbox.  The Disarm( ) method is used to stop receiving. 

You can optionally specify the ClientData argument to be saved and passed  to your callback at the time a message arrives.  A typical use would be to  pass a pointer to a C++ object, so your receive callback can use the pointer  to call a class method. 

You must be connected to use this call.

const char *Whenmsg(const char *ReceiveMailbox, DMHWhenmsgProc *, void *ClientData = NULL);
Register for receiving the next available message directed to the specified mailbox.  Calling WhenmsgAgain( ) in the MessageArrival( ) event handling code re-arms the receive registration for the next message.

You can optionally specify the ClientData argument to be saved and passed  to your callback at the time a message arrives.  A typical use would be to  pass a pointer to a C++ object, so your receive callback can use the pointer  to call a class method. 

Returns NULL on success, or an error message.  You must be connected to use this call.

const char *WhenmsgAgain(void) The Whenmsg( ) method functions as a one-shot.  In other words, receiving is stopped after receiving one message.  Calling the WhenmsgAgain method from the receive handler re-registers to receive the next message.

Returns NULL on success, or an error message.  You must be connected to use this call.

VFEI2Map Class Reference

The VFEI2Map class is used to parse text that is formatted according to the SEMATECH VFEI Specification #95113016A-TR.
 
 
Method Description
static const char *lastError() Returns a diagnostic message indicating the reason for not being able to successfully parse a text string.  If the previous invocation of parse() was without error, an empty string is returned.
static int parse(const char *vfei_string, CMapStringToString& map); The parse method is static which means that no instances of the class are needed to call the method. 

The return value is the count of new entries that were added to the Map table.  If the input text cannot be parsed, the return value is -1 and an error diagnostic message is available by calling lastError().

Backslashes can be used per the string conventions of Tcl.  The parsing is equivalent to the Hume developed Tcl vfei_2_array command. 

See the VFEI2MapTest utility program source code for example code that uses this class.


 
 


License Terms

Subject to Change Without Notice

The Hume DMHclient C++ software is licensed for development and runtime use at no additional charge for computers that are licensed for development use of the Hume Integration Datahub SDK.  We ask that developers install the Tcl executables and actively use the Tcl executables for testing and development, instead of developing against production servers.  Also, we ask that developers install the Tcl online documentation and use it to supplement the material presented in this document.

Hume Integration is also pleased to offer separate runtime licenses for using the DMHclient software on systems that are not licensed as development systems. Runtime usage of the DMH client software is licensed separately from the Datahub SDK runtime license.


Document Version

Date of last revision: $Date: 2017/08/10 18:22:08 $