📄 client.c
字号:
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;}/****************************************************************** * WDML_SyncWaitTransactionReply * * waits until an answer for a sent request is received * time out is also handled. only used for synchronous transactions */static HDDEDATA WDML_SyncWaitTransactionReply(HCONV hConv, DWORD dwTimeout, WDML_XACT* pXAct){ DWORD dwTime; DWORD err; WDML_CONV* pConv; TRACE("Starting wait for a timeout of %ld ms\n", dwTimeout); /* FIXME: time 32 bit wrap around */ dwTimeout += GetCurrentTime(); while ((dwTime = GetCurrentTime()) < dwTimeout) { /* we cannot be in the crit sect all the time because when client and server run in a * single process they need to share the access to the internal data */ if (MsgWaitForMultipleObjects(0, NULL, FALSE, dwTimeout - dwTime, QS_POSTMESSAGE) == WAIT_OBJECT_0) { BOOL ret = FALSE; MSG msg; WDML_CONV* pConv; HDDEDATA hdd; EnterCriticalSection(&WDML_CritSect); pConv = WDML_GetConv(hConv, FALSE); if (pConv == NULL) { LeaveCriticalSection(&WDML_CritSect); /* conversation no longer available... return failure */ break; } while (PeekMessageA(&msg, pConv->hwndClient, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE)) { /* check that either pXAct has been processed or no more xActions are pending */ ret = (pConv->transactions == pXAct); ret = WDML_HandleReply(pConv, &msg, &hdd) == WDML_QS_HANDLED && (pConv->transactions == NULL || ret); if (ret) break; } LeaveCriticalSection(&WDML_CritSect); if (ret) { return hdd; } } } TRACE("Timeout !!\n"); EnterCriticalSection(&WDML_CritSect); pConv = WDML_GetConv(hConv, FALSE); if (pConv != NULL) { if (pConv->transactions) { switch (pConv->transactions->ddeMsg) { case WM_DDE_ADVISE: err = DMLERR_ADVACKTIMEOUT; break; case WM_DDE_REQUEST: err = DMLERR_DATAACKTIMEOUT; break; case WM_DDE_EXECUTE: err = DMLERR_EXECACKTIMEOUT; break; case WM_DDE_POKE: err = DMLERR_POKEACKTIMEOUT; break; case WM_DDE_UNADVISE: err = DMLERR_UNADVACKTIMEOUT; break; default: err = DMLERR_INVALIDPARAMETER; break; } pConv->instance->lastError = err; } } LeaveCriticalSection(&WDML_CritSect); 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 = 0; TRACE("(%p,%ld,%p,%p,%x,%x,%ld,%p)\n", pData, cbData, hConv, hszItem, wFmt, wType, dwTimeout, pdwResult); if (hConv == 0) { ERR("Invalid conversation handle\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: if (hszItem != 0 || wFmt != 0) { pConv->instance->lastError = DMLERR_INVALIDPARAMETER; goto theError; } 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 (!PostMessageA(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; if (pdwResult) { *pdwResult = 0L; } count = WDML_CritSect.RecursionCount; for (i = 0; i < count; i++) LeaveCriticalSection(&WDML_CritSect); hDdeData = WDML_SyncWaitTransactionReply((HCONV)pConv, dwTimeout, pXAct); for (i = 0; i < count; i++) EnterCriticalSection(&WDML_CritSect); } LeaveCriticalSection(&WDML_CritSect); return hDdeData; theError: LeaveCriticalSection(&WDML_CritSect); return 0;}/***************************************************************** * DdeAbandonTransaction (USER32.@) */BOOL WINAPI DdeAbandonTransaction(DWORD idInst, HCONV hConv, DWORD idTransaction){ WDML_INSTANCE* pInstance; WDML_CONV* pConv; WDML_XACT* pXAct; TRACE("(%08lx,%p,%08ld);\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;}/****************************************************************** * WDML_ClientProc * * Window Proc created on client side for each conversation */static LRESULT CALLBACK WDML_ClientProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam){ UINT uiLo, uiHi; WDML_CONV* pConv = NULL; HSZ hszSrv, hszTpc; if (iMsg == WM_DDE_ACK && /* in the initial WM_INITIATE sendmessage */ ((pConv = WDML_GetConvFromWnd(hwnd)) == NULL || pConv->wStatus == XST_INIT1)) { /* In response to WM_DDE_INITIATE, save server window */ char buf[256]; WDML_INSTANCE* pInstance; /* note: sent messages do not need packing */ uiLo = LOWORD(lParam); uiHi = HIWORD(lParam); /* FIXME: convlist should be handled here */ if (pConv) { /* we already have started the conv with a server, drop other replies */ GlobalDeleteAtom(uiLo); GlobalDeleteAtom(uiHi); PostMessageA((HWND)wParam, WM_DDE_TERMINATE, (WPARAM)hwnd, 0); return 0; } pInstance = WDML_GetInstanceFromWnd(hwnd); hszSrv = WDML_MakeHszFromAtom(pInstance, uiLo); hszTpc = WDML_MakeHszFromAtom(pInstance, uiHi); pConv = WDML_AddConv(pInstance, WDML_CLIENT_SIDE, hszSrv, hszTpc, hwnd, (HWND)wParam); SetWindowLongA(hwnd, GWL_WDML_CONVERSATION, (DWORD)pConv); pConv->wStatus |= ST_CONNECTED; pConv->wConvst = XST_INIT1; /* check if server is handled by DDEML */ if ((GetClassNameA((HWND)wParam, buf, sizeof(buf)) && strcmp(buf, WDML_szServerConvClassA) == 0) || (GetClassNameW((HWND)wParam, (LPWSTR)buf, sizeof(buf)/sizeof(WCHAR)) && lstrcmpW((LPWSTR)buf, WDML_szServerConvClassW) == 0)) { pConv->wStatus |= ST_ISLOCAL; } WDML_BroadcastDDEWindows(WDML_szEventClass, WM_WDML_CONNECT_CONFIRM, (WPARAM)hwnd, wParam); GlobalDeleteAtom(uiLo); GlobalDeleteAtom(uiHi); /* accept conversation */ return 1; } if (iMsg >= WM_DDE_FIRST && iMsg <= WM_DDE_LAST) { EnterCriticalSection(&WDML_CritSect); pConv = WDML_GetConvFromWnd(hwnd); if (pConv) { MSG msg; HDDEDATA hdd; msg.hwnd = hwnd; msg.message = iMsg; msg.wParam = wParam; msg.lParam = lParam; WDML_HandleReply(pConv, &msg, &hdd); } LeaveCriticalSection(&WDML_CritSect); return 0; } return (IsWindowUnicode(hwnd)) ? DefWindowProcA(hwnd, iMsg, wParam, lParam) : DefWindowProcW(hwnd, iMsg, wParam, lParam);}/***************************************************************** * 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) { ERR("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 (PostMessageA(pConv->hwndServer, pXAct->ddeMsg, (WPARAM)pConv->hwndClient, pXAct->lParam)) WDML_SyncWaitTransactionReply(hConv, 10000, pXAct); 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;}/***************************************************************** * DdeImpersonateClient (USER32.@) */BOOL WINAPI DdeImpersonateClient(HCONV hConv){ WDML_CONV* pConv; BOOL ret = FALSE; TRACE("(%p)\n", hConv); EnterCriticalSection(&WDML_CritSect); pConv = WDML_GetConv(hConv, TRUE); if (pConv) { ret = ImpersonateDdeClientWindow(pConv->hwndClient, pConv->hwndServer); } LeaveCriticalSection(&WDML_CritSect); return ret;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -