|
|
/****************************** Module Header ******************************\
* Module Name: xact.c * * Copyright (c) 1985 - 1999, Microsoft Corporation * * DDE Manager transaction processing module * * Created: 11/3/91 Sanford Staab \***************************************************************************/
#include "precomp.h"
#pragma hdrstop
/***************************************************************************\
* DdeClientTransaction (DDEML API) * * Description: * Initiates all DDE transactions. * * History: * 11-1-91 sanfords Created. \***************************************************************************/
FUNCLOG8(LOG_GENERAL, HDDEDATA, DUMMYCALLINGTYPE, DdeClientTransaction, LPBYTE, pData, DWORD, cbData, HCONV, hConv, HSZ, hszItem, UINT, wFmt, UINT, wType, DWORD, ulTimeout, LPDWORD, pulResult) HDDEDATA DdeClientTransaction( LPBYTE pData, DWORD cbData, HCONV hConv, HSZ hszItem, UINT wFmt, UINT wType, DWORD ulTimeout, LPDWORD pulResult) { MSG msg; PCL_INSTANCE_INFO pcii = NULL; HDDEDATA hRet = 0; PCL_CONV_INFO pci; PDDEMLDATA pdd = NULL; PXACT_INFO pxi; BOOL fStarted; PDDE_DATA pdde;
EnterDDECrit;
pci = (PCL_CONV_INFO)ValidateCHandle((HANDLE)hConv, HTYPE_CLIENT_CONVERSATION, HINST_ANY); if (pci == NULL) { BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER); goto Exit; } pcii = pci->ci.pcii; if (ulTimeout != TIMEOUT_ASYNC && GetClientInfo()->CI_flags & CI_IN_SYNC_TRANSACTION) { SetLastDDEMLError(pcii, DMLERR_REENTRANCY); goto Exit; } if (!(pci->ci.state & ST_CONNECTED)) { SetLastDDEMLError(pcii, DMLERR_NO_CONV_ESTABLISHED); goto Exit; }
switch (wType) { case XTYP_POKE: case XTYP_ADVSTART: case XTYP_ADVSTART | XTYPF_NODATA: case XTYP_ADVSTART | XTYPF_ACKREQ: case XTYP_ADVSTART | XTYPF_NODATA | XTYPF_ACKREQ: case XTYP_REQUEST: case XTYP_ADVSTOP: if (hszItem == 0) { SetLastDDEMLError(pcii, DMLERR_INVALIDPARAMETER); goto Exit; } break;
case XTYP_EXECUTE: // just ignore wFmt & hszItem
break;
default: SetLastDDEMLError(pcii, DMLERR_INVALIDPARAMETER); goto Exit; }
pxi = DDEMLAlloc(sizeof(XACT_INFO)); if (pxi == NULL) { SetLastDDEMLError(pcii, DMLERR_MEMORY_ERROR); goto Exit; }
switch (wType) { case XTYP_EXECUTE: case XTYP_POKE: if ((LONG)cbData == -1L) {
// We are accepting an existing data handle for export to another
// app.
pdd = (PDDEMLDATA)ValidateCHandle((HANDLE)pData, HTYPE_DATA_HANDLE, HINST_ANY); if (pdd == NULL) { InvParam: SetLastDDEMLError(pcii, DMLERR_INVALIDPARAMETER); DDEMLFree(pxi); goto Exit; }
// make sure data handle holds apropriate data for this transaction
if ((pdd->flags & HDATA_EXECUTE && wType != XTYP_EXECUTE) || (!(pdd->flags & HDATA_EXECUTE) && wType == XTYP_EXECUTE)) { goto InvParam; }
// To simplify life, use a copy if this handle is potentially
// a relay or APPOWNED handle.
if (pdd->flags & (HDATA_APPOWNED | HDATA_NOAPPFREE)) { pxi->hDDESent = CopyDDEData(pdd->hDDE, wType == XTYP_EXECUTE); if (!pxi->hDDESent) { MemErr: DDEMLFree(pxi); SetLastDDEMLError(pcii, DMLERR_MEMORY_ERROR); goto Exit; } USERGLOBALLOCK(pxi->hDDESent, pdde); if (pdde == NULL) { FreeDDEData(pxi->hDDESent, TRUE, TRUE); goto MemErr; } pdde->wStatus = DDE_FRELEASE; USERGLOBALUNLOCK(pxi->hDDESent); } else { pxi->hDDESent = pdd->hDDE; }
// make sure handle has proper format
if (wType == XTYP_POKE) { USERGLOBALLOCK(pxi->hDDESent, pdde); if (pdde == NULL) { goto InvParam; } pdde->wFmt = (WORD)wFmt; USERGLOBALUNLOCK(pxi->hDDESent); }
} else { // Convert data in buffer into an apropriate hDDE
if (wType == XTYP_POKE) { pxi->hDDESent = AllocAndSetDDEData(pData, cbData, DDE_FRELEASE, (WORD)wFmt); } else { pxi->hDDESent = AllocAndSetDDEData(pData, cbData, 0, 0); } if (!pxi->hDDESent) { goto MemErr; } } }
// FINALLY - start the transaction
pxi->pcoi = (PCONV_INFO)pci; pxi->gaItem = LocalToGlobalAtom(LATOM_FROM_HSZ(hszItem)); // pxi copy
pxi->wFmt = (WORD)wFmt; pxi->wType = (WORD)wType;
switch (wType) { case XTYP_ADVSTART: case XTYP_ADVSTART | XTYPF_NODATA: case XTYP_ADVSTART | XTYPF_ACKREQ: case XTYP_ADVSTART | XTYPF_NODATA | XTYPF_ACKREQ: fStarted = ClStartAdvise(pxi); break;
case XTYP_ADVSTOP: fStarted = ClStartUnadvise(pxi); break;
case XTYP_EXECUTE: fStarted = ClStartExecute(pxi); break;
case XTYP_POKE: fStarted = ClStartPoke(pxi); break;
case XTYP_REQUEST: fStarted = ClStartRequest(pxi); }
if (!fStarted) { // if we copied or allocated data - free it.
if (pxi->hDDESent && (pdd == NULL || pxi->hDDESent != pdd->hDDE)) { FreeDDEData(pxi->hDDESent, FALSE, TRUE); // free data copy
} GlobalDeleteAtom(pxi->gaItem); // pxi copy
DDEMLFree(pxi); goto Exit; }
if (pdd != NULL && !(pdd->flags & (HDATA_NOAPPFREE | HDATA_APPOWNED))) {
// invalidate given handle on success - unless we copied it because
// the app will either be return ing it from a callback or potentially
// using it again.
DDEMLFree(pdd); DestroyHandle((HANDLE)pData); }
if (ulTimeout == TIMEOUT_ASYNC) {
// asynchronous transaction
if (pulResult != NULL) { pxi->hXact = CreateHandle((ULONG_PTR)pxi, HTYPE_TRANSACTION, InstFromHandle(pcii->hInstClient)); *pulResult = HandleToUlong(pxi->hXact); } hRet = (HDDEDATA)TRUE;
} else {
// synchronous transaction
GetClientInfo()->CI_flags |= CI_IN_SYNC_TRANSACTION; pcii->flags |= IIF_IN_SYNC_XACT;
pxi->flags |= XIF_SYNCHRONOUS; NtUserSetTimer(pci->ci.hwndConv, TID_TIMEOUT, ulTimeout, NULL);
LeaveDDECrit; CheckDDECritOut;
GetMessage(&msg, (HWND)NULL, 0, 0);
/*
* stay in modal loop until a timeout happens. */ while (msg.hwnd != pci->ci.hwndConv || msg.message != WM_TIMER || (msg.wParam != TID_TIMEOUT)) {
if (!CallMsgFilter(&msg, MSGF_DDEMGR)) DispatchMessage(&msg);
GetMessage(&msg, (HWND)NULL, 0, 0); }
EnterDDECrit;
NtUserKillTimer(pci->ci.hwndConv, TID_TIMEOUT); GetClientInfo()->CI_flags &= ~CI_IN_SYNC_TRANSACTION; pcii->flags &= ~IIF_IN_SYNC_XACT;
if (pxi->flags & XIF_COMPLETE) { if (pulResult != NULL) { *pulResult = pxi->wStatus; // NACK status bits
} switch (wType) { case XTYP_ADVSTART: case XTYP_ADVSTART | XTYPF_NODATA: case XTYP_ADVSTART | XTYPF_ACKREQ: case XTYP_ADVSTART | XTYPF_NODATA | XTYPF_ACKREQ: case XTYP_ADVSTOP: case XTYP_EXECUTE: case XTYP_POKE: hRet = (HDDEDATA)((ULONG_PTR)((pxi->wStatus & DDE_FACK) ? TRUE : FALSE)); if (!hRet) { if (pxi->wStatus & DDE_FBUSY) { SetLastDDEMLError(pcii, DMLERR_BUSY); } else { SetLastDDEMLError(pcii, DMLERR_NOTPROCESSED); } } break;
case XTYP_REQUEST: if (pxi->hDDEResult == 0) { hRet = (HDDEDATA)((ULONG_PTR)((pxi->wStatus & DDE_FACK) ? TRUE : FALSE)); if (!hRet) { if (pxi->wStatus & DDE_FBUSY) { SetLastDDEMLError(pcii, DMLERR_BUSY); } else { SetLastDDEMLError(pcii, DMLERR_NOTPROCESSED); } } break; } // Note that if the incoming data didn't have the DDE_FRELEASE
// bit set, the transaction code would have made a copy so
// the app is free to keep is as long as he likes.
hRet = InternalCreateDataHandle(pcii, (LPBYTE)pxi->hDDEResult, (DWORD)-1, 0, HDATA_READONLY, 0, 0); pxi->hDDEResult = 0; // so cleanup doesn't free it.
}
(pxi->pfnResponse)((struct tagXACT_INFO *)pxi, 0, 0); // cleanup transaction
} else { // Timed out
// abandon the transaction and make it asyncronous so it will
// clean itself up when the response finally comes in.
pxi->flags &= ~XIF_SYNCHRONOUS; pxi->flags |= XIF_ABANDONED;
switch (wType) { case XTYP_ADVSTART: case XTYP_ADVSTART | XTYPF_NODATA: case XTYP_ADVSTART | XTYPF_ACKREQ: case XTYP_ADVSTART | XTYPF_NODATA | XTYPF_ACKREQ: SetLastDDEMLError(pcii, DMLERR_ADVACKTIMEOUT); break; case XTYP_ADVSTOP: SetLastDDEMLError(pcii, DMLERR_UNADVACKTIMEOUT); break; case XTYP_EXECUTE: SetLastDDEMLError(pcii, DMLERR_EXECACKTIMEOUT); break; case XTYP_POKE: SetLastDDEMLError(pcii, DMLERR_POKEACKTIMEOUT); break; case XTYP_REQUEST: SetLastDDEMLError(pcii, DMLERR_DATAACKTIMEOUT); break; } // cleanup of pxi happens when transaction actually completes.
} } if (pci->ci.state & ST_FREE_CONV_RES_NOW) { /*
* The conversation was terminated during the synchronous transaction * so we need to clean up now that we are out of the loop. */ FreeConversationResources((PCONV_INFO)pci); }
Exit: /*
* Because this API is capable of blocking DdeUninitialize(), we check * before exit to see if it needs to be called. */ if (pcii != NULL && (pcii->afCmd & APPCMD_UNINIT_ASAP) && // !(pcii->flags & IIF_IN_SYNC_XACT) &&
!pcii->cInDDEMLCallback) { DdeUninitialize(HandleToUlong(pcii->hInstClient)); hRet = 0; } LeaveDDECrit; return (hRet); }
/***************************************************************************\
* GetConvContext * * Description: * Retrieves conversation context information from the DDEML client window * given. pl points to a CONVCONTEXT structure. * * History: * 11-12-91 sanfords Created. \***************************************************************************/ VOID GetConvContext( HWND hwnd, LONG *pl) { int i;
for (i = 0; i < sizeof(CONVCONTEXT); i += 4) { *pl++ = GetWindowLong(hwnd, GWL_CONVCONTEXT + i); } }
/***************************************************************************\
* SetConvContext * * Description: * * History: * 11-19-92 sanfords Created. \***************************************************************************/ VOID SetConvContext( HWND hwnd, LONG *pl) { int i;
for (i = 0; i < sizeof(CONVCONTEXT); i += 4) { SetWindowLong(hwnd, GWL_CONVCONTEXT + i, *pl++); } }
/***************************************************************************\
* DdeQueryConvInfo (DDEML API) * * Description: * Retrieves detailed conversation information on a per conversation/ * transaction basis. * * History: * 11-12-91 sanfords Created. \***************************************************************************/
FUNCLOG3(LOG_GENERAL, UINT, DUMMYCALLINGTYPE, DdeQueryConvInfo, HCONV, hConv, DWORD, idTransaction, PCONVINFO, pConvInfo) UINT DdeQueryConvInfo( HCONV hConv, DWORD idTransaction, PCONVINFO pConvInfo) { PCONV_INFO pcoi; PXACT_INFO pxi; CONVINFO ci; UINT uiRet = 0;
EnterDDECrit;
if (!ValidateTransaction(hConv, (HANDLE)LongToHandle( idTransaction ), &pcoi, &pxi)) { goto Exit; }
try { if (pConvInfo->cb > sizeof(CONVINFO)) { SetLastDDEMLError(pcoi->pcii, DMLERR_INVALIDPARAMETER); goto Exit; } ci.cb = pConvInfo->cb; ci.hConvPartner = 0; // no longer supported.
ci.hszSvcPartner = NORMAL_HSZ_FROM_LATOM(pcoi->laService); ci.hszServiceReq = NORMAL_HSZ_FROM_LATOM(pcoi->laServiceRequested); ci.hszTopic = NORMAL_HSZ_FROM_LATOM(pcoi->laTopic); ci.wStatus = pcoi->state; ci.wLastError = (WORD)pcoi->pcii->LastError; if (pcoi->state & ST_CLIENT) { ci.hConvList = ((PCL_CONV_INFO)pcoi)->hConvList; GetConvContext(pcoi->hwndConv, (LONG *)&ci.ConvCtxt); } else { ci.hConvList = 0; if (pcoi->state & ST_ISLOCAL) { GetConvContext(pcoi->hwndPartner, (LONG *)&ci.ConvCtxt); } else { ci.ConvCtxt = DefConvContext; } } if (pxi == NULL) { ci.hUser = pcoi->hUser; ci.hszItem = 0; ci.wFmt = 0; ci.wType = 0; ci.wConvst = XST_CONNECTED; } else { ci.hUser = pxi->hUser; // BUG - not fixable - This will result in extra local atoms
// since we can never know when he is done with them.
ci.hszItem = NORMAL_HSZ_FROM_LATOM(GlobalToLocalAtom(pxi->gaItem)); ci.wFmt = pxi->wFmt; ci.wType = pxi->wType; ci.wConvst = pxi->state; } ci.hwnd = pcoi->hwndConv; ci.hwndPartner = pcoi->hwndPartner; RtlCopyMemory((LPSTR)pConvInfo, (LPSTR)&ci, pConvInfo->cb); } except(W32ExceptionHandler(FALSE, RIP_WARNING)) { SetLastDDEMLError(pcoi->pcii, DMLERR_INVALIDPARAMETER); goto Exit; } uiRet = TRUE;
Exit: LeaveDDECrit; return (uiRet); }
/***************************************************************************\
* DdeSetUserHandle (DDEML API) * * Description: * Sets a user DWORD on a per conversation/transaction basis. * * History: * 11-12-91 sanfords Created. \***************************************************************************/
FUNCLOG3(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, DdeSetUserHandle, HCONV, hConv, DWORD, id, DWORD_PTR, hUser) BOOL DdeSetUserHandle( HCONV hConv, DWORD id, DWORD_PTR hUser) { PCONV_INFO pcoi; PXACT_INFO pxi; BOOL fRet = FALSE;
EnterDDECrit;
if (!ValidateTransaction(hConv, (HANDLE)LongToHandle( id ), &pcoi, &pxi)) { goto Exit; } if (pxi == NULL) { pcoi->hUser = hUser; } else { pxi->hUser = hUser; } fRet = TRUE;
Exit: LeaveDDECrit; return (fRet); }
VOID AbandonTransaction( PCONV_INFO pcoi, PXACT_INFO pxi) { if (pxi != NULL) { pxi->flags |= XIF_ABANDONED; } else { for (pxi = pcoi->pxiIn; pxi != NULL; pxi = pxi->next) { pxi->flags |= XIF_ABANDONED; } } }
BOOL AbandonEnumerateProc( HWND hwnd, LPARAM idTransaction) { PCONV_INFO pcoi;
pcoi = (PCONV_INFO)GetWindowLongPtr(hwnd, GWLP_PCI); if (!pcoi || !(pcoi->state & ST_CLIENT)) { return(TRUE); } while (pcoi) { AbandonTransaction(pcoi, (PXACT_INFO)idTransaction); pcoi = pcoi->next; } return(TRUE); }
/***************************************************************************\
* DdeAbandonTransaction (DDEML API) * * Description: * Cancels application interest in completing an asynchronous transaction. * * History: * 11-12-91 sanfords Created. \***************************************************************************/
FUNCLOG3(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, DdeAbandonTransaction, DWORD, idInst, HCONV, hConv, DWORD, idTransaction) BOOL DdeAbandonTransaction( DWORD idInst, HCONV hConv, DWORD idTransaction) { PCONV_INFO pcoi; PXACT_INFO pxi; PCL_INSTANCE_INFO pcii; BOOL fRet = FALSE;
EnterDDECrit;
pcii = ValidateInstance((HANDLE)LongToHandle( idInst ));
if (hConv == 0 && idTransaction == 0) { EnumChildWindows(pcii->hwndMother, AbandonEnumerateProc, 0); goto Exit; } if (idTransaction == 0) { idTransaction = QID_SYNC; } if (!ValidateTransaction(hConv, (HANDLE)LongToHandle( idTransaction ), &pcoi, &pxi)) { goto Exit; } if (pcii == NULL || pcoi->pcii != pcii) { SetLastDDEMLError(pcoi->pcii, DMLERR_INVALIDPARAMETER); goto Exit; } AbandonTransaction(pcoi, pxi); fRet = TRUE;
Exit: LeaveDDECrit; return (fRet); }
/***************************************************************************\
* UpdateLinkIfChanged * * Description: * Helper function for updating a link * * Returns: TRUE if pxi was used - ie fMustReallocPxi * * History: * 3-11-92 sanfords Created. * 8-24-92 sanfords added cLinksToGo \***************************************************************************/ BOOL UpdateLinkIfChanged( PADVISE_LINK paLink, PXACT_INFO pxi, PCONV_INFO pcoi, PADVISE_LINK paLinkLast, PBOOL pfSwapped, DWORD cLinksToGo) { ADVISE_LINK aLinkT;
CheckDDECritIn;
*pfSwapped = FALSE; if (paLink->state & ADVST_CHANGED && !(paLink->state & ADVST_WAITING)) { pxi->pfnResponse = SvRespAdviseDataAck; pxi->pcoi = pcoi; pxi->gaItem = LocalToGlobalAtom(paLink->laItem); // pxi copy
pxi->wFmt = paLink->wFmt; pxi->wType = paLink->wType; paLink->state &= ~ADVST_CHANGED; if (SvStartAdviseUpdate(pxi, cLinksToGo)) { if (pxi->wType & DDE_FACKREQ) { paLink->state |= ADVST_WAITING; /*
* swap paLink with the last non-moved link to make ack search find * oldest updated format. */ if (paLink != paLinkLast) { aLinkT = *paLink; RtlMoveMemory(paLink, paLink + 1, (PBYTE)paLinkLast - (PBYTE)paLink); *paLinkLast = aLinkT; *pfSwapped = TRUE; } } return(TRUE); } else { GlobalDeleteAtom(pxi->gaItem); // pxi copy
return(FALSE); } } return(FALSE); }
/***************************************************************************\
* DdePostAdvise (DDEML API) * * Description: * Updates outstanding server advise links as needed. * * History: * 11-12-91 sanfords Created. \***************************************************************************/
FUNCLOG3(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, DdePostAdvise, DWORD, idInst, HSZ, hszTopic, HSZ, hszItem) BOOL DdePostAdvise( DWORD idInst, HSZ hszTopic, HSZ hszItem) { PCL_INSTANCE_INFO pcii; PSVR_CONV_INFO psi; PXACT_INFO pxi; PADVISE_LINK paLink; BOOL fRet = FALSE, fSwapped, fFound; int iServer, iLink; PLINK_COUNT pLinkCount; #if DBG
int cLinks; #endif
EnterDDECrit;
pcii = ValidateInstance((HANDLE)LongToHandle( idInst )); if (pcii == NULL) { BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER); goto Exit; } if ((ValidateHSZ(hszTopic) == HSZT_INVALID) || (ValidateHSZ(hszItem) == HSZT_INVALID)) { SetLastDDEMLError(pcii, DMLERR_INVALIDPARAMETER); goto Exit; }
/*
* Initialize all link counters and check if any links qualify */ fFound = FALSE; for (pLinkCount = pcii->pLinkCount; pLinkCount; pLinkCount = pLinkCount->next) { pLinkCount->Count = pLinkCount->Total; fFound |= pLinkCount->laTopic == LATOM_FROM_HSZ(hszTopic) && pLinkCount->laItem == LATOM_FROM_HSZ(hszItem); } if (!fFound && hszTopic && hszItem) { fRet = TRUE; goto Exit; }
/*
* preallocate incase we are low on memory. */ pxi = DDEMLAlloc(sizeof(XACT_INFO)); if (pxi == NULL) { SetLastDDEMLError(pcii, DMLERR_MEMORY_ERROR); fRet = FALSE; goto Exit; }
/*
* For each server window on the specified topic */ for (iServer = 0; iServer < pcii->cServerLookupAlloc; iServer++) { if (hszTopic == 0 || pcii->aServerLookup[iServer].laTopic == LATOM_FROM_HSZ(hszTopic)) {
/*
* For each conversation within that window */ psi = (PSVR_CONV_INFO)GetWindowLongPtr( pcii->aServerLookup[iServer].hwndServer, GWLP_PSI); UserAssert(psi != NULL && psi->ci.pcii == pcii); // sanity check
while (psi != NULL) {
/*
* UpdateLinkIfChanged might leave the critical section so lock this conversation */ psi->ci.cLocks++;
#if DBG
/*
* Rememeber the number of links so we can assert if they change during the loop below */ cLinks = psi->ci.cLinks; #endif
/*
* For each active link on the given item... */ for (paLink = psi->ci.aLinks, iLink = 0; iLink < psi->ci.cLinks; paLink++, iLink++) { if (hszItem == 0 || paLink->laItem == LATOM_FROM_HSZ(hszItem)) {
// Bit of a hack here. For FACKREQ links, we don't want the server to
// outrun the client so we set the ADVST_WAITING bit till the ack is
// received. When the ack comes in, the protocol code has to search
// the aLinks array again to locate the apropriate link state flags and
// clear the ADVST_WAITING flag. At that time, if the ADVST_CHANGED flag
// is set, it is cleared and another SvStartAdviseUpdate transaction
// is started to get the link up to date. To complicate matters,
// the ACK contains no format information. Thus we need to move
// the Link info to the end of the list so that the right format
// is updated when the ack comes in.
paLink->state |= ADVST_CHANGED; if (UpdateLinkIfChanged(paLink, pxi, &psi->ci, &psi->ci.aLinks[psi->ci.cLinks - 1], &fSwapped, --paLink->pLinkCount->Count)) { if (fSwapped) { paLink--; } /*
* preallocate for next advise */ pxi = DDEMLAlloc(sizeof(XACT_INFO)); if (pxi == NULL) { SetLastDDEMLError(pcii, DMLERR_MEMORY_ERROR); /*
* Unlock the conversation */ psi->ci.cLocks--; if ((psi->ci.cLocks == 0) && (psi->ci.state & ST_FREE_CONV_RES_NOW)) { RIPMSG1(RIP_ERROR, "DdePostAdvise: Conversation terminated. psi:%#p", psi); FreeConversationResources((PCONV_INFO)psi); } goto Exit; } } /*
* We might have left the crit sect... */ UserAssert(pcii == ValidateInstance((HANDLE)LongToHandle( idInst ))); } } #if DBG
if (cLinks != psi->ci.cLinks) { RIPMSG1(RIP_ERROR, "DdePostAdvise: cLinks changed. psi:%#p", psi); } #endif
/*
* If the converstaion got nuked, stop working on this conversation chain. */ psi->ci.cLocks--; if ((psi->ci.cLocks == 0) && (psi->ci.state & ST_FREE_CONV_RES_NOW)) { RIPMSG1(RIP_ERROR, "DdePostAdvise: Conversation terminated. psi:%#p", psi); FreeConversationResources((PCONV_INFO)psi); break; }
psi = (PSVR_CONV_INFO)psi->ci.next; // next conversation
} } } DDEMLFree(pxi); fRet = TRUE;
Exit: /*
* Because callbacks are capable of blocking DdeUninitialize(), we check * before exit to see if it needs to be called. */ UserAssert(pcii == ValidateInstance((HANDLE)LongToHandle( idInst ))); if (pcii != NULL && pcii->afCmd & APPCMD_UNINIT_ASAP && !(pcii->flags & IIF_IN_SYNC_XACT) && !pcii->cInDDEMLCallback) { DdeUninitialize(HandleToUlong(pcii->hInstClient)); fRet = TRUE; } LeaveDDECrit; return (fRet); }
/***************************************************************************\
* LinkTransaction * * Description: * Adds a transaction structure to the associated conversation's transaction * queue. * * History: * 11-12-91 sanfords Created. \***************************************************************************/ VOID LinkTransaction( PXACT_INFO pxi) { CheckDDECritIn;
pxi->next = NULL; if (pxi->pcoi->pxiOut == NULL) { pxi->pcoi->pxiIn = pxi->pcoi->pxiOut = pxi; } else { pxi->pcoi->pxiIn->next = pxi; pxi->pcoi->pxiIn = pxi; } #if DBG
/*
* Temporary check to find stress bug - make sure pxi list is not * looped on itself. If it is, this loop will never exit and things * will get investigated. (sanfords) */ { PXACT_INFO pxiT;
for (pxiT = pxi->pcoi->pxiOut; pxiT != NULL; pxiT = pxiT->next) { ; } } #endif // DBG
}
/***************************************************************************\
* UnlinkTransaction * * Description: * Removes a transaction structure from the associated conversation's transaction * queue. * * History: * 11-12-91 sanfords Created. \***************************************************************************/ VOID UnlinkTransaction( PXACT_INFO pxi) { CheckDDECritIn; if (pxi == pxi->pcoi->pxiOut) { pxi->pcoi->pxiOut = pxi->next; if (pxi->next == NULL) { pxi->pcoi->pxiIn = NULL; } } }
/***************************************************************************\
* ValidateTransaction * * Description: * Common validation code for DDEML APIs that take a conversation handle * and a transaction ID. *ppxi may be null on return if hXact was 0. * Returns fSuccess. * * History: * 11-12-91 sanfords Created. \***************************************************************************/ BOOL ValidateTransaction( HCONV hConv, HANDLE hXact, PCONV_INFO *ppcoi, PXACT_INFO *ppxi) { PCL_INSTANCE_INFO pcii;
*ppcoi = (PCONV_INFO)ValidateCHandle((HANDLE)hConv, HTYPE_CLIENT_CONVERSATION, HINST_ANY); if (*ppcoi == NULL) { *ppcoi = (PCONV_INFO)ValidateCHandle((HANDLE)hConv, HTYPE_SERVER_CONVERSATION, HINST_ANY); } if (*ppcoi == NULL) { BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER); return (FALSE); } pcii = ValidateInstance((*ppcoi)->pcii->hInstClient); if (pcii != (*ppcoi)->pcii) { BestSetLastDDEMLError(DMLERR_INVALIDPARAMETER); return (FALSE); }
if (hXact == (HANDLE)IntToPtr( QID_SYNC )) { *ppxi = NULL; } else { *ppxi = (PXACT_INFO)ValidateCHandle(hXact, HTYPE_TRANSACTION, InstFromHandle((*ppcoi)->pcii->hInstClient)); if (*ppxi == NULL) { SetLastDDEMLError((*ppcoi)->pcii, DMLERR_INVALIDPARAMETER); return (FALSE); } } return (TRUE); }
|