windows-nt/Source/XPSP1/NT/base/mvdm/wow16/ddeml/stdptcl.c
2020-09-26 16:20:57 +08:00

823 lines
26 KiB
C

/****************************** Module Header ******************************\
* Module Name: STDPTCL.C
*
* This module contains functions that implement the standard DDE protocol
*
* Created: 4/2/91 Sanfords
*
* Copyright (c) 1991 Microsoft Corporation
\***************************************************************************/
#include <string.h>
#include <memory.h>
#include "ddemlp.h"
VOID FreeDdeMsgData(
WORD msg,
LPARAM lParam)
{
WORD fmt;
switch (msg) {
case WM_DDE_DATA:
case WM_DDE_POKE:
/*
* Only free if fRelease is set!
*/
{
DDEDATA FAR *pDdeData = (DDEDATA FAR *)GLOBALLOCK(LOWORD(lParam));
if (pDdeData != NULL) {
if (pDdeData->fRelease) {
fmt = pDdeData->cfFormat;
GlobalUnlock(LOWORD(lParam));
FreeDDEData(LOWORD(lParam), fmt);
} else {
GlobalUnlock(LOWORD(lParam));
}
}
}
break;
case WM_DDE_ADVISE:
GLOBALFREE(LOWORD(lParam));
break;
case WM_DDE_EXECUTE:
GLOBALFREE(HIWORD(lParam));
break;
}
}
/***************************** Private Function ****************************\
* Processes a client transfer request issued by DdeClientTransaction
* function. This may be synchronous or asynchronous.
*
* This function is responsible for properly filling in pXferInfo->pulResult.
*
* History:
* Created 9/1/89 Sanfords
\***************************************************************************/
long ClientXferReq(
PXFERINFO pXferInfo,
HWND hwnd,
PCLIENTINFO pci)
{
PCQDATA pcqd;
LAP myLostAck;
long retVal;
if (pci->ci.xad.state != XST_CONNECTED) {
SETLASTERROR(pci->ci.pai, DMLERR_SERVER_DIED);
return(0);
}
if (pXferInfo->ulTimeout == TIMEOUT_ASYNC) {
/*
* Create a client async queue if needed.
*/
if (pci->pQ == NULL)
pci->pQ = CreateQ(sizeof(CQDATA));
if (pci->pQ == NULL) {
SETLASTERROR(pci->ci.pai, DMLERR_MEMORY_ERROR);
return(0);
}
/*
* add a client queue item to track this transaction and return
* the ID.
*/
pcqd = (PCQDATA)Addqi(pci->pQ);
if (pcqd == NULL) {
SETLASTERROR(pci->ci.pai, DMLERR_MEMORY_ERROR);
return(0);
}
IncHszCount(LOWORD(pXferInfo->hszItem)); // structure copy
hmemcpy((LPBYTE)&pcqd->XferInfo, (LPBYTE)pXferInfo, sizeof(XFERINFO));
pcqd->xad.state = XST_CONNECTED;
pcqd->xad.pdata = 0L;
pcqd->xad.LastError = DMLERR_NO_ERROR;
pcqd->xad.pXferInfo = &pcqd->XferInfo;
pcqd->xad.DDEflags = 0;
/*
* point pulResult to a safe place
*/
pcqd->XferInfo.pulResult = (LPDWORD)&pcqd->xad.DDEflags;
/*
* Get transaction started - if it fails, quit now.
*/
if ((pcqd->xad.LastError = SendClientReq(pci->ci.pai, &pcqd->xad,
(HWND)pci->ci.hConvPartner, hwnd)) == DMLERR_SERVER_DIED) {
pci->ci.fs = pci->ci.fs & ~ST_CONNECTED;
FreeHsz(LOWORD(pcqd->XferInfo.hszItem));
Deleteqi(pci->pQ, MAKEID(pcqd));
/*
* RARE case of server dyeing in the middle of transaction
* initiation.
*/
SETLASTERROR(pci->ci.pai, DMLERR_SERVER_DIED);
return(0);
}
if (pXferInfo->pulResult != NULL) {
*pXferInfo->pulResult = MAKEID(pcqd);
}
return(1);
}
/*
* Set this so messages comming in during the conversation know whats up
*/
pci->ci.xad.pXferInfo = pXferInfo;
if (SETLASTERROR(pci->ci.pai,
SendClientReq(pci->ci.pai, &pci->ci.xad, (HWND)pci->ci.hConvPartner, hwnd)) ==
DMLERR_SERVER_DIED) {
return(0);
}
// HACK
// If this is an EXEC and the timeout is 1 sec then this
// is probably PC Tools 2.0 trying to add items to the shell so
// crank up the timout.
if ((pXferInfo->wType == XTYP_EXECUTE) && (pXferInfo->ulTimeout == 1*1000))
{
pXferInfo->ulTimeout = 10*1000;
}
timeout(pci->ci.pai, pXferInfo->ulTimeout, hwnd);
retVal = ClientXferRespond(hwnd, &pci->ci.xad, &pci->ci.pai->LastError);
switch (pci->ci.xad.state) {
case XST_INCOMPLETE:
/* now add a record of the ack we expect to eventually get
* to the lost ack pile. When it arrives we'll know what to
* free up -- either a memory handle or an atom.
*/
myLostAck.type = pXferInfo->wType;
if (pXferInfo->wType == XTYP_EXECUTE)
myLostAck.object = HIWORD(pXferInfo->hDataClient);
else
myLostAck.object = LOWORD(pXferInfo->hszItem);
AddPileItem(pLostAckPile, (LPBYTE)&myLostAck, NULL);
pci->ci.xad.state = XST_CONNECTED;
}
if (pci->ci.fs & ST_DISC_ATTEMPTED) {
/*
* During this transaction a call to DdeDisconnect was attempted.
* complete the call now.
*/
Disconnect(hwnd, ST_PERM2DIE, pci);
}
return(retVal);
}
/***************************** Private Function ****************************\
* This routine sends the apropriate initiation messages for starting a
* client request according to the transaction data given.
*
* returns any appropriate DMLERR_
*
* History:
* Created 9/1/89 Sanfords
\***************************************************************************/
WORD SendClientReq(
PAPPINFO pai,
PXADATA pXad,
HWND hwndServer,
HWND hwnd)
{
WORD fsStatus = 0;
WORD msg;
WORD lo, hi;
HANDLE hData;
hi = LOWORD(pXad->pXferInfo->hszItem); /* all but exec need this */
switch (pXad->pXferInfo->wType) {
case XTYP_REQUEST:
msg = WM_DDE_REQUEST;
IncHszCount(hi); // message copy
#ifdef DEBUG
cAtoms--; // don't count this
#endif
lo = pXad->pXferInfo->wFmt;
pXad->state = XST_REQSENT;
break;
case XTYP_POKE:
msg = WM_DDE_POKE;
lo = HIWORD(pXad->pXferInfo->hDataClient);
if (!LOWORD(pXad->pXferInfo->hDataClient & HDATA_APPOWNED))
hData = lo; // need to free this on failed post.
pXad->state = XST_POKESENT;
XmitPrep(pXad->pXferInfo->hDataClient, pai);
break;
case XTYP_EXECUTE:
msg = WM_DDE_EXECUTE;
hi = HIWORD(pXad->pXferInfo->hDataClient);
if (!LOWORD(pXad->pXferInfo->hDataClient & HDATA_APPOWNED))
hData = hi; // need to free this on failed post.
lo = 0;
pXad->state = XST_EXECSENT;
// we DONT XmitPrep() because we retain responsibility over the
// data handle during the execute transaction regardless of
// the server's response.
// XmitPrep(pXad->pXferInfo->hDataClient, pai);
break;
case XTYP_ADVSTART:
case XTYP_ADVSTART | XTYPF_NODATA:
case XTYP_ADVSTART | XTYPF_ACKREQ:
case XTYP_ADVSTART | XTYPF_NODATA | XTYPF_ACKREQ:
fsStatus = DDE_FRELEASE | ((pXad->pXferInfo->wType &
(XTYPF_ACKREQ | XTYPF_NODATA)) << 12);
msg = WM_DDE_ADVISE;
if ((hData = AllocDDESel(fsStatus, pXad->pXferInfo->wFmt,
(DWORD)sizeof(DWORD))) == 0) {
pXad->state = XST_CONNECTED;
return(DMLERR_MEMORY_ERROR);
}
lo = hData;
pXad->pXferInfo->hDataClient = (HDDEDATA)MAKELONG(0, hData);
/* free later if we get nack */
pXad->state = XST_ADVSENT;
break;
case XTYP_ADVSTOP:
msg = WM_DDE_UNADVISE;
lo = pXad->pXferInfo->wFmt;
pXad->state = XST_UNADVSENT;
break;
default:
return(DMLERR_INVALIDPARAMETER);
break;
}
/*
* Send transfer
*/
if (IsWindow(hwndServer)) {
PCLIENTINFO pci;
pci = (PCLIENTINFO)GetWindowLong(hwnd, GWL_PCI);
if (!PostDdeMessage(&pci->ci, msg, hwnd, MAKELONG(lo,hi), 0, 0)) {
pXad->state = XST_CONNECTED;
if (hData)
FreeDDEData(hData, pXad->pXferInfo->wFmt);
return(DMLERR_POSTMSG_FAILED);
}
} else {
/*
* We lost the server, we are TERMINATED arnold!
*/
pXad->state = XST_NULL;
if (hData)
FreeDDEData(hData, pXad->pXferInfo->wFmt);
return(DMLERR_SERVER_DIED);
}
return(DMLERR_NO_ERROR);
}
VOID ServerProcessDDEMsg(
PSERVERINFO psi,
WORD msg,
HWND hwndServer,
HWND hwndClient,
WORD lo,
WORD hi)
{
PADVLI pAdviseItem;
WORD wType;
DWORD dwData1 = 0;
HDDEDATA hData = 0L;
WORD wFmt = 0;
WORD wStat = 0;
LPSTR pMem;
HANDLE hMemFree = 0;
BOOL fQueueOnly = FALSE;
/*
* only respond if this is for us.
*/
if (hwndClient != (HWND)psi->ci.hConvPartner)
return;
if (!(psi->ci.fs & ST_CONNECTED)) {
/*
* Dde messages have been received AFTER we have terminated. Free up
* the information if appropriate.
* BUG: This doesn't handle NACK freeing of associated data.
*/
FreeDdeMsgData(msg, MAKELPARAM(lo, hi));
}
switch (msg) {
case WM_DDE_REQUEST:
wType = XTYP_REQUEST;
wFmt = lo;
break;
case WM_DDE_EXECUTE:
wType = XTYP_EXECUTE;
/* stuff a special flag into the low word to mark as exec data */
// We don't call RecvPrep() because we never have responsability for
// freeing this data.
hData = (HDDEDATA)MAKELONG(HDATA_EXEC | HDATA_NOAPPFREE | HDATA_READONLY, hi);
break;
case WM_DDE_POKE:
wType = XTYP_POKE;
pMem = GLOBALLOCK(lo);
if (pMem == NULL) {
SETLASTERROR(psi->ci.pai, DMLERR_MEMORY_ERROR);
return;
}
wFmt = ((DDEPOKE FAR*)pMem)->cfFormat;
wStat = *(WORD FAR*)pMem;
hData = RecvPrep(psi->ci.pai, lo, HDATA_NOAPPFREE);
break;
case WM_DDE_ADVISE:
wType = XTYP_ADVSTART; /* set ST_ADVISE AFTER app oks advise loop */
pMem = GLOBALLOCK(lo);
if (pMem == NULL) {
SETLASTERROR(psi->ci.pai, DMLERR_MEMORY_ERROR);
return;
}
wFmt = ((DDEADVISE FAR*)pMem)->cfFormat;
wStat = *(WORD FAR*)pMem;
// If this is NACKed, we don't free it (sicko protocol!#$@) so we
// have to have this hang around till qreply gets it.
hMemFree = lo;
/*
* Check if we already are linked on this topic/item/format. If so,
* skip the callback.
*/
fQueueOnly = (BOOL)(DWORD)FindAdvList(psi->ci.pai->pServerAdvList, hwndServer,
psi->ci.aTopic, (ATOM)hi, wFmt);
break;
case WM_DDE_UNADVISE:
{
PADVLI padvli;
ATOM aItem;
if (padvli = FindAdvList(psi->ci.pai->pServerAdvList,
hwndServer, 0, hi, lo)) {
wFmt = padvli->wFmt;
aItem = padvli->aItem;
wType = XTYP_ADVSTOP;
MONLINK(psi->ci.pai, FALSE, 0,
(HSZ)psi->ci.aServerApp, (HSZ)psi->ci.aTopic,
(HSZ)aItem, wFmt, TRUE,
MAKEHCONV(hwndServer), psi->ci.hConvPartner);
if (!DeleteAdvList(psi->ci.pai->pServerAdvList,
hwndServer, 0, aItem, wFmt)) {
psi->ci.fs &= ~ST_ADVISE;
} else {
while (padvli = FindAdvList(psi->ci.pai->pServerAdvList,
hwndServer, 0, hi, lo)) {
/*
* simulate extra XTYP_ADVSTOP callbacks to server here
*/
MONLINK(psi->ci.pai, FALSE, 0,
(HSZ)psi->ci.aServerApp, (HSZ)psi->ci.aTopic,
(HSZ)padvli->aItem, padvli->wFmt, TRUE,
MAKEHCONV(hwndServer), psi->ci.hConvPartner);
MakeCallback(&psi->ci, MAKEHCONV(hwndServer),
(HSZ)psi->ci.aTopic,
(HSZ)padvli->aItem, padvli->wFmt,
XTYP_ADVSTOP, 0, 0, 0, msg, wStat,
NULL, // signals qreply to NOT ack
0, FALSE);
if (!DeleteAdvList(psi->ci.pai->pServerAdvList,
hwndServer, 0, padvli->aItem, padvli->wFmt)) {
psi->ci.fs &= ~ST_ADVISE;
}
}
}
MakeCallback(&psi->ci, MAKEHCONV(hwndServer), (HSZ)psi->ci.aTopic,
(HSZ)aItem, wFmt, XTYP_ADVSTOP, 0, 0,
(HSZ)hi, // item for ACK - see qreply
msg, wStat, (HWND)psi->ci.hConvPartner, 0, FALSE);
} else {
/* unexpected unadvise, NACK it. */
PostDdeMessage(&psi->ci, WM_DDE_ACK,
hwndServer, MAKELONG(0, hi), 0, 0);
return;
}
return;
}
case WM_DDE_ACK:
/*
* This is an ack in response to the FACKREQ bit being set.
* See if this refers to one of the advise loops.
*/
if ((pAdviseItem = FindAdvList(psi->ci.pai->pServerAdvList,
hwndServer, 0, hi, wFmt)) &&
(pAdviseItem->fsStatus & DDE_FACKREQ)) {
/*
* Update advise loop status - no longer waiting for an ack.
*/
pAdviseItem->fsStatus &= ~ADVST_WAITING;
if (pAdviseItem->fsStatus & ADVST_CHANGED) {
PostServerAdvise(hwndServer, psi, pAdviseItem, CADV_LATEACK);
}
}
if (hi)
GlobalDeleteAtom(hi); // message copy
// BUG: if a NACK is posted to us, WE need to free any data associated
// with it.
return;
}
MakeCallback(&psi->ci, MAKEHCONV(hwndServer), (HSZ)psi->ci.aTopic,
/* don't know the item on an execute */
wType == XTYP_EXECUTE ? 0L : MAKELONG(hi,0),
wFmt, wType, hData, dwData1, 0, msg, wStat, (HWND)psi->ci.hConvPartner,
hMemFree, fQueueOnly);
/*
* all freeing of atoms and hXXXX stuff is in QReply
*/
return;
}
VOID PostServerAdvise(
HWND hwnd,
PSERVERINFO psi,
PADVLI pali,
WORD cLoops)
{
HDDEDATA hData;
HANDLE hMem;
/*
* get the data from the server.
*/
hData = DoCallback(psi->ci.pai, MAKEHCONV(hwnd), (HSZ)psi->ci.aTopic,
(HSZ)pali->aItem, pali->wFmt, XTYP_ADVREQ, 0L,
(DWORD)cLoops, 0L);
if (!hData) {
return;
}
hData = DllEntry(&psi->ci, hData);
pali->fsStatus &= ~ADVST_CHANGED;
/*
* set Ack Request bit if advise loop calls for it.
*/
if (pali->fsStatus & DDE_FACKREQ) {
LPWORD lpFlags;
pali->fsStatus |= ADVST_WAITING;
lpFlags = (LPWORD)GLOBALPTR(HIWORD(hData));
if (lpFlags == NULL) {
SETLASTERROR(psi->ci.pai, DMLERR_MEMORY_ERROR);
return;
}
if (!(*lpFlags & DDE_FACKREQ)) {
if (LOWORD(hData) & HDATA_APPOWNED) {
// can't mess with it, must use a copy.
hMem = HIWORD(hData);
hData = CopyHDDEDATA(psi->ci.pai, hData);
lpFlags = (LPWORD)GLOBALLOCK(HIWORD(hData));
}
*lpFlags |= DDE_FACKREQ;
}
}
/*
* remove local data handle from local list
*/
FindPileItem(psi->ci.pai->pHDataPile, CmpHIWORD, (LPBYTE)&hData, FPI_DELETE);
/*
* post data to waiting client.
*/
IncHszCount(pali->aItem); // message copy
#ifdef DEBUG
cAtoms--; // Don't count this because its being shipped out.
#endif
if (!PostDdeMessage(&psi->ci, WM_DDE_DATA, hwnd,
MAKELONG(HIWORD(hData), pali->aItem), 0, 0)) {
FreeDataHandle(psi->ci.pai, hData, TRUE);
}
}
/***************************** Private Function ****************************\
* This routine handles callback replys.
* QReply is responsible for freeing any atoms or handles used
* with the message that generated the callback.
* It also must recover from dead partner windows.
*
* History:
* Created 9/12/89 Sanfords
\***************************************************************************/
void QReply(
PCBLI pcbi,
HDDEDATA hDataRet)
{
PSERVERINFO psi;
WORD fsStatus, msg;
WORD loOut, StatusRet, msgAssoc = 0;
HGLOBAL hGMemRet;
HGLOBAL hAssoc = 0;
SEMCHECKOUT();
// most notification callbacks require no work here.
if (((pcbi->wType & XCLASS_MASK) == XCLASS_NOTIFICATION) &&
(pcbi->wType != XTYP_ADVSTOP) &&
(pcbi->wType != XTYP_XACT_COMPLETE))
return;
StatusRet = LOWORD(hDataRet);
hGMemRet = HIWORD(hDataRet);
if (!IsWindow((HWND)pcbi->hConv)) {
if (pcbi->wType & XCLASS_DATA && hDataRet && hDataRet != CBR_BLOCK) {
FreeDataHandle(pcbi->pai, hDataRet, TRUE);
}
return;
}
psi = (PSERVERINFO)GetWindowLong((HWND)pcbi->hConv, GWL_PCI);
switch (pcbi->msg) {
case WM_DDE_REQUEST:
if (hGMemRet) {
hDataRet = DllEntry(&psi->ci, hDataRet);
loOut = HIWORD(hDataRet);
*(WORD FAR*)GLOBALLOCK(loOut) |=
((pcbi->fsStatus & DDE_FACKREQ) | DDE_FREQUESTED);
GlobalUnlock(loOut);
XmitPrep(hDataRet, psi->ci.pai);
msg = WM_DDE_DATA;
} else {
/*
* send a -ACK
*/
loOut = (StatusRet & (DDE_FBUSY | DDE_FAPPSTATUS));
msg = WM_DDE_ACK;
}
// reuse atom from request message
if (!PostDdeMessage(&psi->ci, msg, (HWND)pcbi->hConv,
MAKELONG(loOut, LOWORD(pcbi->hszItem)), 0, 0) && msg == WM_DDE_DATA)
FreeDataHandle(psi->ci.pai, hDataRet, TRUE);
break;
case WM_DDE_POKE:
if (StatusRet & DDE_FACK) {
FreeDataHandle(psi->ci.pai, pcbi->hData, TRUE);
} else {
// NACKS are properly freed by the 'poker'
FindPileItem(psi->ci.pai->pHDataPile, CmpHIWORD,
(LPBYTE)&pcbi->hData, FPI_DELETE);
hAssoc = hGMemRet;
msgAssoc = WM_DDE_POKE;
}
if (!PostDdeMessage(&psi->ci, WM_DDE_ACK, (HWND)pcbi->hConv,
MAKELONG(StatusRet & ~DDE_FACKRESERVED, LOWORD(pcbi->hszItem)),
msgAssoc, hAssoc)) {
if (!(StatusRet & DDE_FACK)) {
FreeDDEData(hGMemRet, pcbi->wFmt);
}
}
break;
case WM_DDE_EXECUTE:
/*
* LOWORD(hDataRet) is supposed to be the proper DDE_ constants to return.
* we just stick them in the given hData and return
* it as an ACK.
*/
PostDdeMessage(&psi->ci, WM_DDE_ACK, (HWND)pcbi->hConv,
MAKELONG(StatusRet & ~DDE_FACKRESERVED,HIWORD(pcbi->hData)),
0, 0);
break;
case WM_DDE_ADVISE:
/*
* hDataRet is fStartAdvise
*/
if ((BOOL)hDataRet) {
if (!AddAdvList(psi->ci.pai->pServerAdvList, (HWND)pcbi->hConv, psi->ci.aTopic,
(ATOM)pcbi->hszItem,
pcbi->fsStatus & (DDE_FDEFERUPD | DDE_FACKREQ),
pcbi->wFmt)) {
SETLASTERROR(psi->ci.pai, DMLERR_MEMORY_ERROR);
fsStatus = 0;
} else {
MONLINK(psi->ci.pai, TRUE, pcbi->fsStatus & DDE_FDEFERUPD,
(HSZ)psi->ci.aServerApp, (HSZ)psi->ci.aTopic,
pcbi->hszItem, pcbi->wFmt, TRUE,
pcbi->hConv, psi->ci.hConvPartner);
psi->ci.fs |= ST_ADVISE;
fsStatus = DDE_FACK;
}
GlobalUnlock(pcbi->hMemFree);
GLOBALFREE(pcbi->hMemFree); /* we free the hOptions on ACK */
} else {
fsStatus = 0;
hAssoc = hGMemRet;
msgAssoc = WM_DDE_ADVISE;
#ifdef DEBUG
if (pcbi->hMemFree) {
LogDdeObject(0xF000, pcbi->hMemFree);
}
#endif
}
goto AckBack;
break;
case WM_DDE_UNADVISE:
fsStatus = DDE_FACK;
if (pcbi->hwndPartner) { // set to null for simulated stops due to WILD stuff
// dwData2 == aItem to ack - this could have been wild.
PostDdeMessage(&psi->ci, WM_DDE_ACK, (HWND)pcbi->hConv,
MAKELONG(fsStatus, LOWORD(pcbi->dwData2)), 0, 0);
}
break;
case WM_DDE_DATA:
/*
* must be an advise data item for the CLIENT or maybe some requested
* data mistakenly sent here due to the client queue being flushed.
* hDataRet is fsStatus.
*/
/*
* Clean up the status incase the app is messed up.
*/
fsStatus = StatusRet & ~DDE_FACKRESERVED;
if (HIWORD(pcbi->hData) &&
(pcbi->fsStatus & DDE_FRELEASE) &&
(fsStatus & DDE_FACK || !(pcbi->fsStatus & DDE_FACKREQ)))
FreeDataHandle(psi->ci.pai, pcbi->hData, TRUE);
if (fsStatus & DDE_FBUSY)
fsStatus &= ~DDE_FACK;
if (HIWORD(pcbi->hData) && !(fsStatus & DDE_FACK)) {
msgAssoc = WM_DDE_DATA;
hAssoc = HIWORD(pcbi->hData);
}
/*
* send an ack back if requested.
*/
if (pcbi->fsStatus & DDE_FACKREQ) {
AckBack:
PostDdeMessage(&psi->ci, WM_DDE_ACK, (HWND)pcbi->hConv,
MAKELONG(fsStatus, LOWORD(pcbi->hszItem)),
msgAssoc, hAssoc);
} else {
if (LOWORD(pcbi->hszItem)) {
GlobalDeleteAtom(LOWORD(pcbi->hszItem)); // data message copy
}
}
break;
case 0:
switch (pcbi->wType) {
case XTYP_XACT_COMPLETE:
FreeHsz(LOWORD(pcbi->hszItem));
FreeDataHandle(psi->ci.pai, pcbi->hData, TRUE);
Deleteqi(((PCLIENTINFO)psi)->pQ, pcbi->dwData1);
}
}
}
/***************************** Private Function ****************************\
* This function assumes that a client transfer request has been completed -
* or should be completed by the time this is called.
*
* pci contains general client info
* pXad contains the transaction info
* pErr points to where to place the LastError code.
*
* Returns 0 on failure
* Returns TRUE or a Data Selector on success.
* On failure, the conversation is left in a XST_INCOMPLETE state.
* On success, the conversation is left in a XST_CONNECTED state.
*
* History:
* Created 9/1/89 Sanfords
\***************************************************************************/
long ClientXferRespond(
HWND hwndClient,
PXADATA pXad,
LPWORD pErr)
{
PCLIENTINFO pci;
if (pXad->state == XST_INCOMPLETE)
return(0);
pci = (PCLIENTINFO)GetWindowLong(hwndClient, GWL_PCI);
switch (pXad->pXferInfo->wType) {
case XTYP_REQUEST:
if (pXad->state != XST_DATARCVD) {
if (*pErr == DMLERR_NO_ERROR)
*pErr = DMLERR_DATAACKTIMEOUT;
goto failexit;
}
pXad->state = XST_CONNECTED;
return(pXad->pdata); /* this has the handle in low word */
break;
case XTYP_POKE:
if (pXad->state != XST_POKEACKRCVD) {
if (*pErr == DMLERR_NO_ERROR)
*pErr = DMLERR_POKEACKTIMEOUT;
goto failexit;
}
passexit:
pXad->state = XST_CONNECTED;
pXad->pdata = TRUE;
return(TRUE);
break;
case XTYP_EXECUTE:
if (pXad->state != XST_EXECACKRCVD) {
if (*pErr == DMLERR_NO_ERROR)
*pErr = DMLERR_EXECACKTIMEOUT;
goto failexit;
}
goto passexit;
case XTYP_ADVSTART:
case XTYP_ADVSTART | XTYPF_NODATA:
case XTYP_ADVSTART | XTYPF_ACKREQ:
case XTYP_ADVSTART | XTYPF_NODATA | XTYPF_ACKREQ:
if (pXad->state != XST_ADVACKRCVD) {
if (*pErr == DMLERR_NO_ERROR)
*pErr = DMLERR_ADVACKTIMEOUT;
goto failexit;
}
AssertF((UINT)(XTYPF_ACKREQ << 12) == DDE_FACKREQ &&
(UINT)(XTYPF_NODATA << 12) == DDE_FDEFERUPD,
"XTYPF_ constants are wrong");
if (!AddAdvList(pci->pClientAdvList, hwndClient, 0,
LOWORD(pXad->pXferInfo->hszItem),
(pXad->pXferInfo->wType & (XTYPF_ACKREQ | XTYPF_NODATA)) << 12,
pXad->pXferInfo->wFmt)) {
pXad->state = XST_INCOMPLETE;
SETLASTERROR(pci->ci.pai, DMLERR_MEMORY_ERROR);
return(FALSE);
} else {
pci->ci.fs |= ST_ADVISE;
MONLINK(pci->ci.pai, TRUE, pXad->pXferInfo->wType & XTYPF_NODATA,
(HSZ)pci->ci.aServerApp, (HSZ)pci->ci.aTopic,
pXad->pXferInfo->hszItem, pXad->pXferInfo->wFmt, FALSE,
pci->ci.hConvPartner, MAKEHCONV(hwndClient));
goto passexit;
}
break;
case XTYP_ADVSTOP:
if (pXad->state != XST_UNADVACKRCVD) {
if (*pErr == DMLERR_NO_ERROR)
*pErr = DMLERR_UNADVACKTIMEOUT;
goto failexit;
}
if (!DeleteAdvList(pci->pClientAdvList, 0, 0,
(ATOM)pXad->pXferInfo->hszItem, pXad->pXferInfo->wFmt))
pci->ci.fs &= ~ST_ADVISE;
MONLINK(pci->ci.pai, FALSE, pXad->pXferInfo->wType & XTYPF_NODATA,
(HSZ)pci->ci.aServerApp, (HSZ)pci->ci.aTopic,
pXad->pXferInfo->hszItem, pXad->pXferInfo->wFmt, FALSE,
pci->ci.hConvPartner, MAKEHCONV(hwndClient));
goto passexit;
}
failexit:
pXad->state = XST_INCOMPLETE;
return(0);
}