1
Vote

DdemlServer and CADV_LATEACK

description

First off, thank you for this valuable contribution to the community.
 
I am using NDde as a DDE server implementation. My objective is to serve data to Excel documents via DDE (for backward compatibility). Many of those Excel files contain over 2,800 links.
 
Behavior:
After advising a big amount of links (more than 2,500) with Advise("", "") on MS Excel as a DDE client, subsequent calls to Advise() do not cause the OnAdvise overriden method to raise.
 
Reason:
After poking around the source code I discovered that the problem originates from the callback function of the DdemlServer class. When an XTYP_ADVREQ is issued by the client the low-order word of dwData1 contains the number of transactions pending for advisory; thus, NDde raises the OnAdvise once, caches the result data and does not raise the OnAdvise event again until the aforementioned count reaches zero. This, since the context is synchronized to a single thread, happens synchronously.
However, there is a special case, which MS Excel exploits, in which the low-order word of dwData1 contains the value of 0xFFFF aka CADV_LATEACK and NOT the pending transactions. Excel sends this when there is a big amount of links that take time (like the 2,800 links in my case) and it doesn't actually care if it gets response a after the Advise() has been called (asynchronously). The code in DdemlServer.ProcessCallback thinks that there are 65535 remaining transactions that never reach zero, does not remove the cached results, thus never raising the OnAdvise event again. Further details on this can be seen on http://support.microsoft.com/kb/92540.
 
Workaround:
In my case, I modified the following line of code to work around this issue.
 
File:
{root}\Internal\DdemlServer.cs, line 495
Original:
if (remaining == 0)
Modified:
if (remaining == 0 || remaining == 0xFFFF)

comments