You are, I trust, beginning to recognize some of the complexities involved in DDE. It gets a little more complex with WM_DDE_ADVISE and the hot link.
The WM_DDE_REQUEST message I've just discussed allows the client to obtain data from the server. But if this data changes (as the instantaneous population will), then the client has no way to know that. Allowing the client to know when data has been updated is the purpose of the WM_DDE_ADVISE message. On receipt of this message, a server is responsible for notifying the client when the data has changed. (This notification is accomplished by the server posting WM_DDE_DATA messages to the client.) This can be tricky because the server must ”remember“ which items the client has asked to be advised on. Moreover, the client will ask that this data be posted in particular ways.
In a WM_DDE_ADVISE message, the low word of lParam is a handle to a global memory block containing a DDEADVISE structure as defined in DDE.H. The high word of lParam is the atom identifying the data item.
When processing WM_DDE_ADVISE, ServerProc first checks that the cfFormat field of the DDEADVISE structure is CF_TEXT. It then obtains the text string referenced by the atom and checks it against the szState field of the pop structure.
If there's a match, then ServerProc gets a pointer to the array of POPADVISE structures that it allocated during the WM_CREATE message. This array has a POPADVISE structure for each state, and there is a different array for each window carrying on a DDE conversation. This array is used to store all information ServerProc will need to update items to the client.
The fields of the POPADVISE structure for the selected state are set as follows:
The fAdvise field is set to TRUE. This is simply a flag that indicates that the client wants updated information on this state.
The fDeferUpd (”deferred update“) field is set to the value of the same field in the DDEADVISE structure. A FALSE value indicates that the client wants to establish a warm link rather than a hot link. The client will be
advised of a change in data without getting the data immediately. (In this case, the server posts a WM_DDE_DATA message with a NULL value rather than a handle to the global memory block containing a DDEDATA structure. The client will later post a normal WM_DDE_REQUEST message to obtain the actual data.) A TRUE value indicates that the client wants the data in the WM_DDE_DATA message.
The fAckReq (”acknowledgment requested“) field is set to the value of the same field in the DDEADVISE structure. This is a very tricky value. A TRUE value instructs the server to post the WM_DDE_DATA with the fAckReq field of the DDEDATA structure set to TRUE so that the client is required to acknowledge the WM_DDE_DATA message with a WM_DDE_ACK message. A TRUE value does not mean that the client is requesting a WM_DDE_ACK message from the server; it's requiring that the server require a WM_DDE_ACK message from the client when later posting the WM_DDE_DATA message.
The lPopPrev field is set to the current population of the state. ServerProc uses this field to determine if the client needs notification that the population has changed.
ServerProc is now finished with the DDEADVISE structure and frees the memory block as the documentation for WM_DDE_ADVISE instructs. ServerProc must now acknowledge the WM_DDE_ADVISE message by posting a positive WM_DDE_SBACK message. The fAck field of the DDEACK structure is set to TRUE. If PostMessage fails, then ServerProc deletes the atom.
If the data format was not CF_TEXT, or if there was no match for the state, then ServerProc posts a negative WM_DDE_BACK message. In this case, if the PostMessage call fails, ServerProc both deletes the atom and frees the DDEADVISE memory block.
In theory, handling of the WM_DDE_ADVISE message is now complete. However, the client has asked that it be notified whenever a data item changes. Given that the client doesn't know any value of the data item, it is necessary for ServerProc to post a WM_DDE_DATA message to the client.
It does this using the PostDataMessage function, but with the third parameter set to the fDeferUpd field of the POPADVISE structure, the fourth parameter set to the fAckReq field of the POPADVISE structure, and the last parameter set to FALSE (indicating a WM_DDE_DATA message posted in response to WM_DDE_ADVISE rather than WM_DDE_REQUEST).
It's time for another look at PostDataMessage. Toward the beginning of the function, note that if the fDeferUpd parameter is TRUE, then the function simply sets hDdeData to NULL rather than allocating memory for it.
If the fAckReq parameter is TRUE, then PostDataMessage waits for a WM_DDE_ACK message from the client after posting the WM_DDE_DATA message. It does this by calling PeekMessage. PostDataMessage deletes the atom in the WM_DDE_ACK message. If the WM_DDE_ACK message does not arrive within three seconds—or if the message is a negative acknowledgment—then PostDataMessage frees the global data block containing the DDEDATA structure.
If you think that you can skip over part of this work by assuming that a client will never post a WM_DDE_ADVISE message with the deferred update or acknowledgment requested fields set to TRUE, guess again. Microsoft Excel does precisely that, establishing a warm link with acknowledgments to the WM_DDE_DATA messages.