MORE INFORMATION
In DDEML-based applications, while transactions can be either
synchronous or asynchronous, only DDEML client applications may choose
to establish either type of transaction when requesting data from a
server application. DDEML server applications do not distinguish
between synchronous and asynchronous transactions.
Asynchronous transactions can be very useful when client applications
know that the partner server application will take some time to gather
data. This type of transaction frees up the client to do other things
while waiting for a notification from the server of data availability.
Server applications have no way of determining whether the client
application has requested data synchronously or asynchronously.
Request transactions on the server's side are always synchronous. When
a client requests data, the server's callback receives an XTYP_REQUEST
transaction, where the expected return value is a data handle. If the
server application has to wait for data from a serial port, for
example, access to the CPU by other applications will be delayed,
thereby freezing the system until data arrives.
There are a couple of ways one can enable the server to gather data in
an asynchronous manner, thereby allowing it to yield to other
applications on the system while it gathers data. One method is to
use CBR_BLOCK; another is to change the request transaction to a
one-time ADVISE loop.
Method 1
Given that DDEML callbacks are not re-entrant, and that DDEML expects
a data handle as a return value from the XTYP_REQUEST transaction (and
transactions of XCLASS_DATA class), the server application can block
the callback momentarily. It can do this by returning a CBR_BLOCK
value after posting itself a user-defined message.
This way, the server application can gather data in the background
while DDEML queues up any further transactions. The server can start
gathering data when its window procedure gets the user defined message
that was posted by its DDE callback function.
When a server application returns CBR_BLOCK for a request transaction,
DDEML disables the server's callback function. It also queues
transactions that are sent by DDEML after its callback has been
disabled. This feature gives the server an opportunity to gather data
while allowing other applications to run in the system.
As soon as data becomes available, then the server application can
call DdeEnableCallBack() to re-enable the server callback function.
Once the callback is re-enabled, DDEML will resend the same request
transaction to the server's callback and this time, because data is
ready, the server application can return the appropriate data handle
to the client.
Transactions that were queued up because of an earlier block are sent
to the server's callback function in the order they were received by
DDEML.
The pseudo code to implement method 1 might resemble the following:
BOOL gbGatheringData = TRUE; // Defined GLOBAlly.
HDDEDATA ghData = NULL;
HDDEDATA CALLBACK DdeServerCallBack(...)
{
switch(txnType)
{
case XTYP_REQUEST:
// If the server takes a long time to gather data...
// for this topic/item pair, then
// post a user-defined message to the server app's wndproc
// and return CBR_BLOCK... DDEML will block the callback
// and queue transactions.
if(bGatheringData) {
PostMessage(hSrvWnd, WM_GATHERDATA, .....) ;
return CBR_BLOCK;
}
else // Data is ready, send back handle.
return ghData;
default:
return DDE_FNOTPROCESSED;
}
}
LRESULT CALLBACK SrvWndProc(...)
{
switch (wMessage)
{
case WM_GATHERDATA:
while (bGatheringData)
{
// Gather data here while yielding to others
// at the same time!
if(!PeekMessage(..))
bGatheringData = GoGetDataFromSource (&ghData);
else {
TranslateMessage() ;
DispatchMessage ();
}
}
DdeEnableCallback (idInst, ghConv, EC_ENABLEALL);
break ;
default:
return DefWndProc();
}
}
Method 2
Advise transactions in DDEML (or DDE) are just a continuous request
link. Changing the transaction from a REQUEST to a "one time only"
ADVISE loop on the client side allows the server to gather data
asynchronously.
The client application can start an ADVISE transaction from its side
and when the server receives a XTYP_ADVSTART transaction, return TRUE
so that an ADVISE link is established. Once the link is established,
the server can start gathering data, and as soon as it becomes
available, notify the client of its availability.
This can be done by calling DdePostAdvise(). The server can use
PeekMessage() to gather data if the data gathering process is a
lengthy one, so that other applications on the system will get a
chance to run. Once the client receives the data from the server in
its callback (in its XTYP_ADVDATA transaction), it can disconnect the
the ADVISE link from the server by specifying an XTYP_ADVSTOP
transaction.