/***************************************************************** * 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; }
/***************************************************************** * DdeDisconnect (USER32.@) */ BOOL WINAPI DdeDisconnect(HCONV hConv) { WDML_CONV* pConv = NULL; WDML_XACT* pXAct; DWORD count, i; BOOL ret = FALSE; TRACE("(%p)\n", hConv); if (hConv == 0) { WARN("DdeDisconnect(): hConv = 0\n"); return FALSE; } EnterCriticalSection(&WDML_CritSect); pConv = WDML_GetConv(hConv, TRUE); if (pConv != NULL) { if (pConv->wStatus & ST_CLIENT) { /* FIXME: should abandon all pending transactions */ pXAct = WDML_ClientQueueTerminate(pConv); if (pXAct != NULL) { count = WDML_CritSect.RecursionCount; for (i = 0; i < count; i++) LeaveCriticalSection(&WDML_CritSect); if (PostMessageW(pConv->hwndServer, pXAct->ddeMsg, (WPARAM)pConv->hwndClient, pXAct->lParam)) WDML_SyncWaitTransactionReply(hConv, 10000, pXAct, NULL); for (i = 0; i < count; i++) EnterCriticalSection(&WDML_CritSect); ret = TRUE; WDML_FreeTransaction(pConv->instance, pXAct, TRUE); /* still have to destroy data assosiated with conversation */ WDML_RemoveConv(pConv, WDML_CLIENT_SIDE); } else { FIXME("Not implemented yet for a server side conversation\n"); } } } LeaveCriticalSection(&WDML_CritSect); return ret; }
/***************************************************************** * DdeDisconnect (USER32.@) */ BOOL WINAPI DdeDisconnect(HCONV hConv) { WDML_CONV* pConv; WDML_XACT* pXAct; BOOL ret = FALSE; TRACE("(%p)\n", hConv); if (hConv == 0) { WARN("DdeDisconnect(): hConv = 0\n"); return FALSE; } pConv = WDML_GetConv(hConv, TRUE); if (pConv != NULL) { if (pConv->wStatus & ST_CLIENT) { /* FIXME: should abandon all pending transactions */ pXAct = WDML_ClientQueueTerminate(pConv); if (pXAct != NULL) { if (PostMessageW(pConv->hwndServer, pXAct->ddeMsg, (WPARAM)pConv->hwndClient, pXAct->lParam)) { WDML_SyncWaitTransactionReply(hConv, 10000, pXAct, NULL); ret = TRUE; } else pConv->instance->lastError = DMLERR_POSTMSG_FAILED; WDML_FreeTransaction(pConv->instance, pXAct, TRUE); /* still have to destroy data associated with conversation */ WDML_RemoveConv(pConv, WDML_CLIENT_SIDE); } else { FIXME("Not implemented yet for a server side conversation\n"); } } } return ret; }
/****************************************************************** * WDML_ServerConvProc * * */ static LRESULT CALLBACK WDML_ServerConvProc(HWND hwndServer, UINT iMsg, WPARAM wParam, LPARAM lParam) { WDML_INSTANCE* pInstance; WDML_CONV* pConv; WDML_XACT* pXAct = NULL; if (iMsg == WM_DESTROY) { EnterCriticalSection(&WDML_CritSect); pConv = WDML_GetConvFromWnd(hwndServer); if (pConv && !(pConv->wStatus & ST_TERMINATED)) { WDML_ServerHandleTerminate(pConv, NULL); } LeaveCriticalSection(&WDML_CritSect); } if (iMsg < WM_DDE_FIRST || iMsg > WM_DDE_LAST) { return DefWindowProcA(hwndServer, iMsg, wParam, lParam); } EnterCriticalSection(&WDML_CritSect); pInstance = WDML_GetInstanceFromWnd(hwndServer); pConv = WDML_GetConvFromWnd(hwndServer); if (!pConv) { ERR("Got a message (%u) on a not known conversation, dropping request\n", iMsg); goto theError; } if (pConv->hwndClient != WIN_GetFullHandle( (HWND)wParam ) || pConv->hwndServer != hwndServer) { ERR("mismatch between C/S windows and converstation\n"); goto theError; } if (pConv->instance != pInstance || pConv->instance == NULL) { ERR("mismatch in instances\n"); goto theError; } switch (iMsg) { case WM_DDE_INITIATE: FIXME("WM_DDE_INITIATE message received!\n"); break; case WM_DDE_REQUEST: pXAct = WDML_ServerQueueRequest(pConv, lParam); break; case WM_DDE_ADVISE: pXAct = WDML_ServerQueueAdvise(pConv, lParam); break; case WM_DDE_UNADVISE: pXAct = WDML_ServerQueueUnadvise(pConv, lParam); break; case WM_DDE_EXECUTE: pXAct = WDML_ServerQueueExecute(pConv, lParam); break; case WM_DDE_POKE: pXAct = WDML_ServerQueuePoke(pConv, lParam); break; case WM_DDE_TERMINATE: pXAct = WDML_ServerQueueTerminate(pConv, lParam); break; case WM_DDE_ACK: WARN("Shouldn't receive a ACK message (never requests them). Ignoring it\n"); break; default: FIXME("Unsupported message %d\n", iMsg); } if (pXAct) { pXAct->lParam = lParam; if (WDML_ServerHandle(pConv, pXAct) == WDML_QS_BLOCK) { WDML_QueueTransaction(pConv, pXAct); } else { WDML_FreeTransaction(pInstance, pXAct, TRUE); } } theError: LeaveCriticalSection(&WDML_CritSect); return 0; }
/****************************************************************** * WDML_ServerConvProc * * */ static LRESULT CALLBACK WDML_ServerConvProc(HWND hwndServer, UINT iMsg, WPARAM wParam, LPARAM lParam) { WDML_INSTANCE* pInstance; WDML_CONV* pConv; WDML_XACT* pXAct = NULL; TRACE("%p %04x %08lx %08lx\n", hwndServer, iMsg, wParam, lParam); if (iMsg == WM_DESTROY) { pConv = WDML_GetConvFromWnd(hwndServer); if (pConv && !(pConv->wStatus & ST_TERMINATED)) { WDML_ServerHandleTerminate(pConv, NULL); } } if (iMsg < WM_DDE_FIRST || iMsg > WM_DDE_LAST) { return IsWindowUnicode(hwndServer) ? DefWindowProcW(hwndServer, iMsg, wParam, lParam) : DefWindowProcA(hwndServer, iMsg, wParam, lParam); } pInstance = WDML_GetInstanceFromWnd(hwndServer); pConv = WDML_GetConvFromWnd(hwndServer); if (!pConv) { ERR("Got a message (%x) on a not known conversation, dropping request\n", iMsg); return 0; } if (pConv->hwndClient != WIN_GetFullHandle( (HWND)wParam ) || pConv->hwndServer != hwndServer) { ERR("mismatch between C/S windows and conversation\n"); return 0; } if (pConv->instance != pInstance || pConv->instance == NULL) { ERR("mismatch in instances\n"); return 0; } switch (iMsg) { case WM_DDE_INITIATE: FIXME("WM_DDE_INITIATE message received!\n"); break; case WM_DDE_REQUEST: pXAct = WDML_ServerQueueRequest(pConv, lParam); break; case WM_DDE_ADVISE: pXAct = WDML_ServerQueueAdvise(pConv, lParam); break; case WM_DDE_UNADVISE: pXAct = WDML_ServerQueueUnadvise(pConv, lParam); break; case WM_DDE_EXECUTE: pXAct = WDML_ServerQueueExecute(pConv, lParam); break; case WM_DDE_POKE: pXAct = WDML_ServerQueuePoke(pConv, lParam); break; case WM_DDE_TERMINATE: pXAct = WDML_ServerQueueTerminate(pConv, lParam); break; case WM_DDE_ACK: WARN("Shouldn't receive a ACK message (never requests them). Ignoring it\n"); break; default: FIXME("Unsupported message %x\n", iMsg); break; } if (pXAct) { pXAct->lParam = lParam; if ((pConv->wStatus & ST_BLOCKED) || WDML_ServerHandle(pConv, pXAct) == WDML_QS_BLOCK) { TRACE("Transactions are blocked, add to the queue and exit\n"); WDML_QueueTransaction(pConv, pXAct); } else { WDML_FreeTransaction(pInstance, pXAct, TRUE); } } else pConv->instance->lastError = DMLERR_MEMORY_ERROR; return 0; }
/***************************************************************** * 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; }