/***************************************************************** * DdeAbandonTransaction (USER32.@) */ BOOL WINAPI DdeAbandonTransaction(DWORD idInst, HCONV hConv, DWORD idTransaction) { WDML_INSTANCE* pInstance; WDML_CONV* pConv; WDML_XACT* pXAct; if ((pInstance = WDML_GetInstance(idInst))) { if (hConv) { if ((pConv = WDML_GetConv(hConv, TRUE)) && pConv->instance == pInstance) { pXAct = pConv->transactions; while (pXAct) { WDML_XACT *nextXAct = pXAct->next; if (pXAct->dwTimeout == TIMEOUT_ASYNC && (idTransaction == 0 || pXAct->xActID == idTransaction)) { WDML_UnQueueTransaction(pConv, pXAct); WDML_FreeTransaction(pInstance, pXAct, TRUE); } pXAct = nextXAct; } } } else { for (pConv = pInstance->convs[WDML_CLIENT_SIDE]; pConv; pConv = pConv->next) { if (!(pConv->wStatus & ST_CONNECTED)) continue; pXAct = pConv->transactions; while (pXAct) { WDML_XACT *nextXAct = pXAct->next; if (pXAct->dwTimeout == TIMEOUT_ASYNC) { WDML_UnQueueTransaction(pConv, pXAct); WDML_FreeTransaction(pInstance, pXAct, TRUE); } pXAct = nextXAct; } } } } return TRUE; }
/***************************************************************** * DdeAbandonTransaction (USER32.@) */ BOOL WINAPI DdeAbandonTransaction(DWORD idInst, HCONV hConv, DWORD idTransaction) { WDML_INSTANCE* pInstance; WDML_CONV* pConv; WDML_XACT* pXAct; TRACE("(%08lx,%p,%08lx);\n", idInst, hConv, idTransaction); EnterCriticalSection(&WDML_CritSect); if ((pInstance = WDML_GetInstance(idInst))) { if (hConv) { if ((pConv = WDML_GetConv(hConv, TRUE)) && pConv->instance == pInstance) { for (pXAct = pConv->transactions; pXAct; pXAct = pXAct->next) { if (pXAct->dwTimeout == TIMEOUT_ASYNC && (idTransaction == 0 || pXAct->xActID == idTransaction)) { WDML_UnQueueTransaction(pConv, pXAct); WDML_FreeTransaction(pInstance, pXAct, TRUE); } } } } else { for (pConv = pInstance->convs[WDML_CLIENT_SIDE]; pConv; pConv = pConv->next) { if (!(pConv->wStatus & ST_CONNECTED)) continue; for (pXAct = pConv->transactions; pXAct; pXAct = pXAct->next) { if (pXAct->dwTimeout == TIMEOUT_ASYNC) { WDML_UnQueueTransaction(pConv, pXAct); WDML_FreeTransaction(pInstance, pXAct, TRUE); } } } } } LeaveCriticalSection(&WDML_CritSect); return TRUE; }
/***************************************************************** * DdeClientTransaction (USER32.@) */ HDDEDATA WINAPI DdeClientTransaction(LPBYTE pData, DWORD cbData, HCONV hConv, HSZ hszItem, UINT wFmt, UINT wType, DWORD dwTimeout, LPDWORD pdwResult) { WDML_CONV* pConv; WDML_XACT* pXAct; HDDEDATA hDdeData; TRACE("(%p,%d,%p,%p,%x,%x,%d,%p)\n", pData, cbData, hConv, hszItem, wFmt, wType, dwTimeout, pdwResult); if (hConv == 0) { WARN("Invalid conversation handle NULL\n"); return 0; } pConv = WDML_GetConv(hConv, TRUE); if (pConv == NULL) { /* cannot set error... cannot get back to DDE instance */ return 0; } switch (wType) { case XTYP_EXECUTE: /* Windows simply ignores hszItem and wFmt in this case */ pXAct = WDML_ClientQueueExecute(pConv, pData, cbData); if (pXAct == NULL) return 0; break; case XTYP_POKE: if (!hszItem) { pConv->instance->lastError = DMLERR_INVALIDPARAMETER; return 0; } pXAct = WDML_ClientQueuePoke(pConv, pData, cbData, wFmt, hszItem); break; case XTYP_ADVSTART|XTYPF_NODATA: case XTYP_ADVSTART|XTYPF_NODATA|XTYPF_ACKREQ: case XTYP_ADVSTART: case XTYP_ADVSTART|XTYPF_ACKREQ: if (pData) { pConv->instance->lastError = DMLERR_INVALIDPARAMETER; return 0; } pXAct = WDML_ClientQueueAdvise(pConv, wType, wFmt, hszItem); break; case XTYP_ADVSTOP: if (pData) { pConv->instance->lastError = DMLERR_INVALIDPARAMETER; return 0; } pXAct = WDML_ClientQueueUnadvise(pConv, wFmt, hszItem); break; case XTYP_REQUEST: if (pData || !hszItem) { pConv->instance->lastError = DMLERR_INVALIDPARAMETER; return 0; } pXAct = WDML_ClientQueueRequest(pConv, wFmt, hszItem); break; default: FIXME("Unknown transaction type %04x\n", wType); /* unknown transaction type */ pConv->instance->lastError = DMLERR_INVALIDPARAMETER; return 0; } if (pXAct == NULL) { pConv->instance->lastError = DMLERR_MEMORY_ERROR; return 0; } WDML_QueueTransaction(pConv, pXAct); TRACE("pConv->wStatus %04x\n", pConv->wStatus); if (pConv->wStatus & ST_BLOCKED) { TRACE("Transactions are blocked, add to the queue and exit\n"); return (HDDEDATA)1; } hDdeData = WDML_ClientHandle(pConv, pXAct, dwTimeout, pdwResult); if (dwTimeout != TIMEOUT_ASYNC) { WDML_UnQueueTransaction(pConv, pXAct); WDML_FreeTransaction(pConv->instance, pXAct, TRUE); } return hDdeData; }
/****************************************************************** * WDML_HandleReply * * handles any incoming reply, and try to match to an already sent request */ static WDML_QUEUE_STATE WDML_HandleReply(WDML_CONV* pConv, MSG* msg, HDDEDATA* hdd, DWORD *ack) { WDML_XACT* pXAct = pConv->transactions; WDML_QUEUE_STATE qs; if (pConv->transactions) { /* first check message against a pending transaction, if any */ switch (pXAct->ddeMsg) { case WM_DDE_ADVISE: qs = WDML_HandleAdviseReply(pConv, msg, pXAct, ack); break; case WM_DDE_UNADVISE: qs = WDML_HandleUnadviseReply(pConv, msg, pXAct, ack); break; case WM_DDE_EXECUTE: qs = WDML_HandleExecuteReply(pConv, msg, pXAct, ack); break; case WM_DDE_REQUEST: qs = WDML_HandleRequestReply(pConv, msg, pXAct, ack); break; case WM_DDE_POKE: qs = WDML_HandlePokeReply(pConv, msg, pXAct, ack); break; case WM_DDE_TERMINATE: qs = WDML_HandleTerminateReply(pConv, msg, pXAct); break; default: qs = WDML_QS_ERROR; FIXME("oooch\n"); } } else { qs = WDML_QS_PASS; } /* now check the results */ switch (qs) { case WDML_QS_ERROR: case WDML_QS_SWALLOWED: *hdd = 0; break; case WDML_QS_HANDLED: /* ok, we have resolved a pending transaction * notify callback if asynchronous, and remove it in any case */ WDML_UnQueueTransaction(pConv, pXAct); if (pXAct->dwTimeout == TIMEOUT_ASYNC && pXAct->ddeMsg != WM_DDE_TERMINATE) { WDML_InvokeCallback(pConv->instance, XTYP_XACT_COMPLETE, pXAct->wFmt, (HCONV)pConv, pConv->hszTopic, pXAct->hszItem, pXAct->hDdeData, MAKELONG(0, pXAct->xActID), 0 /* FIXME */); qs = WDML_QS_PASS; } else { *hdd = pXAct->hDdeData; } WDML_FreeTransaction(pConv->instance, pXAct, TRUE); break; case WDML_QS_PASS: /* no pending transaction found, try a warm/hot link or a termination request */ switch (msg->message) { case WM_DDE_DATA: qs = WDML_HandleIncomingData(pConv, msg, hdd); break; case WM_DDE_TERMINATE: qs = WDML_HandleIncomingTerminate(pConv, msg, hdd); break; } break; case WDML_QS_BLOCK: FIXME("shouldn't be used on client side\n"); break; } return qs; }
/***************************************************************** * DdeClientTransaction (USER32.@) */ HDDEDATA WINAPI DdeClientTransaction(LPBYTE pData, DWORD cbData, HCONV hConv, HSZ hszItem, UINT wFmt, UINT wType, DWORD dwTimeout, LPDWORD pdwResult) { WDML_CONV* pConv; WDML_XACT* pXAct; HDDEDATA hDdeData = 0; TRACE("(%p,%ld,%p,%p,%x,%x,%ld,%p)\n", pData, cbData, hConv, hszItem, wFmt, wType, dwTimeout, pdwResult); if (hConv == 0) { WARN("Invalid conversation handle NULL\n"); return 0; } EnterCriticalSection(&WDML_CritSect); pConv = WDML_GetConv(hConv, TRUE); if (pConv == NULL) { /* cannot set error... cannot get back to DDE instance */ goto theError; } switch (wType) { case XTYP_EXECUTE: /* Windows simply ignores hszItem and wFmt in this case */ pXAct = WDML_ClientQueueExecute(pConv, pData, cbData); break; case XTYP_POKE: pXAct = WDML_ClientQueuePoke(pConv, pData, cbData, wFmt, hszItem); break; case XTYP_ADVSTART|XTYPF_NODATA: case XTYP_ADVSTART|XTYPF_NODATA|XTYPF_ACKREQ: case XTYP_ADVSTART: case XTYP_ADVSTART|XTYPF_ACKREQ: if (pData) { pConv->instance->lastError = DMLERR_INVALIDPARAMETER; goto theError; } pXAct = WDML_ClientQueueAdvise(pConv, wType, wFmt, hszItem); break; case XTYP_ADVSTOP: if (pData) { pConv->instance->lastError = DMLERR_INVALIDPARAMETER; goto theError; } pXAct = WDML_ClientQueueUnadvise(pConv, wFmt, hszItem); break; case XTYP_REQUEST: if (pData) { pConv->instance->lastError = DMLERR_INVALIDPARAMETER; goto theError; } pXAct = WDML_ClientQueueRequest(pConv, wFmt, hszItem); break; default: FIXME("Unknown transation\n"); /* unknown transaction type */ pConv->instance->lastError = DMLERR_INVALIDPARAMETER; goto theError; } if (pXAct == NULL) { pConv->instance->lastError = DMLERR_MEMORY_ERROR; goto theError; } WDML_QueueTransaction(pConv, pXAct); if (!PostMessageW(pConv->hwndServer, pXAct->ddeMsg, (WPARAM)pConv->hwndClient, pXAct->lParam)) { WARN("Failed posting message %x to %p (error=0x%lx)\n", pXAct->ddeMsg, pConv->hwndServer, GetLastError()); pConv->wStatus &= ~ST_CONNECTED; WDML_UnQueueTransaction(pConv, pXAct); WDML_FreeTransaction(pConv->instance, pXAct, TRUE); goto theError; } pXAct->dwTimeout = dwTimeout; /* FIXME: should set the app bits on *pdwResult */ if (dwTimeout == TIMEOUT_ASYNC) { if (pdwResult) { *pdwResult = MAKELONG(0, pXAct->xActID); } hDdeData = (HDDEDATA)1; } else { DWORD count, i; count = WDML_CritSect.RecursionCount; for (i = 0; i < count; i++) LeaveCriticalSection(&WDML_CritSect); hDdeData = WDML_SyncWaitTransactionReply((HCONV)pConv, dwTimeout, pXAct, pdwResult); for (i = 0; i < count; i++) EnterCriticalSection(&WDML_CritSect); } LeaveCriticalSection(&WDML_CritSect); return hDdeData; theError: LeaveCriticalSection(&WDML_CritSect); return 0; }