/****************************************************************** * WDML_HandlePokeReply * * */ static WDML_QUEUE_STATE WDML_HandlePokeReply(WDML_CONV* pConv, MSG* msg, WDML_XACT* pXAct, DWORD *ack) { UINT_PTR uiLo, uiHi; HSZ hsz; if (msg->message != WM_DDE_ACK && WIN_GetFullHandle((HWND)msg->wParam) != pConv->hwndServer) { return WDML_QS_PASS; } UnpackDDElParam(WM_DDE_ACK, msg->lParam, &uiLo, &uiHi); hsz = WDML_MakeHszFromAtom(pConv->instance, uiHi); if (DdeCmpStringHandles(hsz, pXAct->hszItem) != 0) { return WDML_QS_PASS; } FreeDDElParam(WM_DDE_ACK, msg->lParam); GlobalDeleteAtom(uiHi); if (ack) *ack = uiLo; pXAct->hMem = GlobalFree(pXAct->hMem); pXAct->hDdeData = (HDDEDATA)TRUE; return TRUE; }
/****************************************************************** * WDML_HandleIncomingData * * */ static WDML_QUEUE_STATE WDML_HandleIncomingData(WDML_CONV* pConv, MSG* msg, HDDEDATA* hdd) { UINT_PTR uiLo, uiHi; HDDEDATA hDdeDataIn, hDdeDataOut; WDML_LINK* pLink; WINE_DDEHEAD wdh; HSZ hsz; TRACE("WM_DDE_DATA message received in the Client Proc!\n"); /* wParam -- sending window handle */ /* lParam -- hDdeData & item HSZ */ UnpackDDElParam(WM_DDE_DATA, msg->lParam, &uiLo, &uiHi); hsz = WDML_MakeHszFromAtom(pConv->instance, uiHi); hDdeDataIn = WDML_Global2DataHandle(pConv, (HGLOBAL)uiLo, &wdh); /* billx: * For hot link, data should be passed to its callback with * XTYP_ADVDATA and callback should return the proper status. */ pLink = WDML_FindLink(pConv->instance, (HCONV)pConv, WDML_CLIENT_SIDE, hsz, uiLo != 0, wdh.cfFormat); if (!pLink) { WDML_DecHSZ(pConv->instance, hsz); DdeFreeDataHandle(hDdeDataIn); return WDML_QS_PASS; } if (hDdeDataIn != 0 && wdh.fAckReq) { WDML_PostAck(pConv, WDML_CLIENT_SIDE, 0, FALSE, TRUE, uiHi, msg->lParam, WM_DDE_DATA); if (msg->lParam) msg->lParam = 0; } else { GlobalDeleteAtom(uiHi); } hDdeDataOut = WDML_InvokeCallback(pConv->instance, XTYP_ADVDATA, pLink->uFmt, pLink->hConv, pConv->hszTopic, pLink->hszItem, hDdeDataIn, 0, 0); if (hDdeDataOut != (HDDEDATA)DDE_FACK || wdh.fRelease) { if (uiLo) GlobalFree((HANDLE)uiLo); } DdeFreeDataHandle(hDdeDataIn); WDML_DecHSZ(pConv->instance, hsz); if (msg->lParam) FreeDDElParam(WM_DDE_DATA, msg->lParam); return WDML_QS_HANDLED; }
/****************************************************************** * WDML_HandleRequestReply * * */ static WDML_QUEUE_STATE WDML_HandleRequestReply(WDML_CONV* pConv, MSG* msg, WDML_XACT* pXAct, DWORD *ack) { DDEACK ddeAck; WINE_DDEHEAD wdh; UINT_PTR uiLo, uiHi; HSZ hsz; if (WIN_GetFullHandle((HWND)msg->wParam) != pConv->hwndServer) return WDML_QS_PASS; switch (msg->message) { case WM_DDE_ACK: UnpackDDElParam(WM_DDE_ACK, msg->lParam, &uiLo, &uiHi); FreeDDElParam(WM_DDE_ACK, msg->lParam); GlobalDeleteAtom(uiHi); if (ack) *ack = uiLo; WDML_ExtractAck(uiLo, &ddeAck); pXAct->hDdeData = 0; if (ddeAck.fAck) ERR("Positive answer should appear in NACK for a request, assuming negative\n"); TRACE("Negative answer...\n"); break; case WM_DDE_DATA: UnpackDDElParam(WM_DDE_DATA, msg->lParam, &uiLo, &uiHi); TRACE("Got the result (%08lx)\n", uiLo); hsz = WDML_MakeHszFromAtom(pConv->instance, uiHi); if (DdeCmpStringHandles(hsz, pXAct->hszItem) != 0) return WDML_QS_PASS; pXAct->hDdeData = WDML_Global2DataHandle(pConv, (HGLOBAL)uiLo, &wdh); if (wdh.fRelease) { GlobalFree((HGLOBAL)uiLo); } if (wdh.fAckReq) { pConv->instance->lastError = DMLERR_MEMORY_ERROR; } else { GlobalDeleteAtom(uiHi); FreeDDElParam(WM_DDE_ACK, msg->lParam); } break; default: FreeDDElParam(msg->message, msg->lParam); return WDML_QS_PASS; } return WDML_QS_HANDLED; }
/****************************************************************** * WDML_ServerQueueUnadvise * * */ static WDML_XACT* WDML_ServerQueueUnadvise(WDML_CONV* pConv, LPARAM lParam) { UINT uiLo, uiHi; WDML_XACT* pXAct; UnpackDDElParam(WM_DDE_UNADVISE, lParam, &uiLo, &uiHi); pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_UNADVISE, uiLo, WDML_MakeHszFromAtom(pConv->instance, uiHi)); if (pXAct) pXAct->atom = uiHi; return pXAct; }
/****************************************************************** * WDML_ServerQueueRequest * * */ static WDML_XACT* WDML_ServerQueueRequest(WDML_CONV* pConv, LPARAM lParam) { UINT_PTR uiLo, uiHi; WDML_XACT* pXAct; UnpackDDElParam(WM_DDE_REQUEST, lParam, &uiLo, &uiHi); pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_REQUEST, uiLo, WDML_MakeHszFromAtom(pConv->instance, uiHi)); if (pXAct) pXAct->atom = uiHi; return pXAct; }
/****************************************************************** * WDML_HandleAdviseReply * * handles the reply to an advise request */ static WDML_QUEUE_STATE WDML_HandleAdviseReply(WDML_CONV* pConv, MSG* msg, WDML_XACT* pXAct, DWORD *ack) { DDEACK ddeAck; UINT_PTR uiLo, uiHi; HSZ hsz; if (msg->message != WM_DDE_ACK || WIN_GetFullHandle((HWND)msg->wParam) != pConv->hwndServer) { return WDML_QS_PASS; } UnpackDDElParam(WM_DDE_ACK, msg->lParam, &uiLo, &uiHi); hsz = WDML_MakeHszFromAtom(pConv->instance, uiHi); if (DdeCmpStringHandles(hsz, pXAct->hszItem) != 0) return WDML_QS_PASS; GlobalDeleteAtom(uiHi); FreeDDElParam(WM_DDE_ACK, msg->lParam); if (ack) *ack = uiLo; WDML_ExtractAck(uiLo, &ddeAck); if (ddeAck.fAck) { WDML_LINK* pLink; /* billx: first to see if the link is already created. */ pLink = WDML_FindLink(pConv->instance, (HCONV)pConv, WDML_CLIENT_SIDE, pXAct->hszItem, TRUE, pXAct->wFmt); if (pLink != NULL) { /* we found a link, and only need to modify it in case it changes */ pLink->transactionType = pXAct->wType; } else { WDML_AddLink(pConv->instance, (HCONV)pConv, WDML_CLIENT_SIDE, pXAct->wType, pXAct->hszItem, pXAct->wFmt); } pXAct->hDdeData = (HDDEDATA)1; } else { TRACE("Returning FALSE on XTYP_ADVSTART - fAck was FALSE\n"); GlobalFree(pXAct->hMem); pXAct->hDdeData = NULL; } return WDML_QS_HANDLED; }
/****************************************************************** * WDML_ServerQueuePoke * * */ static WDML_XACT* WDML_ServerQueuePoke(WDML_CONV* pConv, LPARAM lParam) { UINT uiLo, uiHi; WDML_XACT* pXAct; UnpackDDElParam(WM_DDE_POKE, lParam, &uiLo, &uiHi); pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_POKE, 0, WDML_MakeHszFromAtom(pConv->instance, uiHi)); if (pXAct) { pXAct->atom = uiHi; pXAct->hMem = (HGLOBAL)uiLo; } return pXAct; }
/****************************************************************** * WDML_ServerQueueAdvise * * */ static WDML_XACT* WDML_ServerQueueAdvise(WDML_CONV* pConv, LPARAM lParam) { UINT uiLo, uiHi; WDML_XACT* pXAct; /* XTYP_ADVSTART transaction: establish link and save link info to InstanceInfoTable */ if (!UnpackDDElParam(WM_DDE_ADVISE, lParam, &uiLo, &uiHi)) return NULL; pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_ADVISE, 0, WDML_MakeHszFromAtom(pConv->instance, uiHi)); if (pXAct) { pXAct->hMem = (HGLOBAL)uiLo; pXAct->atom = uiHi; } return pXAct; }
/****************************************************************** * WDML_HandleUnadviseReply * * */ static WDML_QUEUE_STATE WDML_HandleUnadviseReply(WDML_CONV* pConv, MSG* msg, WDML_XACT* pXAct, DWORD *ack) { DDEACK ddeAck; UINT_PTR uiLo, uiHi; HSZ hsz; if (msg->message != WM_DDE_ACK || WIN_GetFullHandle((HWND)msg->wParam) != pConv->hwndServer) { return WDML_QS_PASS; } UnpackDDElParam(WM_DDE_ACK, msg->lParam, &uiLo, &uiHi); hsz = WDML_MakeHszFromAtom(pConv->instance, uiHi); if (DdeCmpStringHandles(hsz, pXAct->hszItem) != 0) return WDML_QS_PASS; FreeDDElParam(WM_DDE_ACK, msg->lParam); GlobalDeleteAtom(uiHi); if (ack) *ack = uiLo; WDML_ExtractAck(uiLo, &ddeAck); TRACE("WM_DDE_ACK received while waiting for a timeout\n"); if (!ddeAck.fAck) { TRACE("Returning FALSE on XTYP_ADVSTOP - fAck was FALSE\n"); pXAct->hDdeData = NULL; } else { /* billx: remove the link */ WDML_RemoveLink(pConv->instance, (HCONV)pConv, WDML_CLIENT_SIDE, pXAct->hszItem, pXAct->wFmt); pXAct->hDdeData = (HDDEDATA)1; } return WDML_QS_HANDLED; }
/****************************************************************** * WDML_ServerNameProc * * */ static LRESULT CALLBACK WDML_ServerNameProc(HWND hwndServer, UINT iMsg, WPARAM wParam, LPARAM lParam) { HWND hwndClient; HSZ hszApp, hszTop; HDDEDATA hDdeData = 0; WDML_INSTANCE* pInstance; UINT uiLo, uiHi; switch (iMsg) { case WM_DDE_INITIATE: /* wParam -- sending window handle LOWORD(lParam) -- application atom HIWORD(lParam) -- topic atom */ TRACE("WM_DDE_INITIATE message received!\n"); hwndClient = (HWND)wParam; pInstance = WDML_GetInstanceFromWnd(hwndServer); TRACE("idInst=%ld, threadID=0x%lx\n", pInstance->instanceID, GetCurrentThreadId()); if (!pInstance) return 0; /* don't free DDEParams, since this is a broadcast */ UnpackDDElParam(WM_DDE_INITIATE, lParam, &uiLo, &uiHi); hszApp = WDML_MakeHszFromAtom(pInstance, uiLo); hszTop = WDML_MakeHszFromAtom(pInstance, uiHi); if (!(pInstance->CBFflags & CBF_FAIL_CONNECTIONS)) { BOOL self = FALSE; CONVCONTEXT cc; CONVCONTEXT* pcc = NULL; WDML_CONV* pConv; char buf[256]; if (GetWindowThreadProcessId(hwndClient, NULL) == GetWindowThreadProcessId(hwndServer, NULL) && WDML_GetInstanceFromWnd(hwndClient) == WDML_GetInstanceFromWnd(hwndServer)) { self = TRUE; } /* FIXME: so far, we don't grab distant convcontext, so only check if remote is * handled under DDEML, and if so build a default context */ if ((GetClassNameA(hwndClient, buf, sizeof(buf)) && strcmp(buf, WDML_szClientConvClassA) == 0) || (GetClassNameW(hwndClient, (LPWSTR)buf, sizeof(buf)/sizeof(WCHAR)) && lstrcmpW((LPWSTR)buf, WDML_szClientConvClassW) == 0)) { pcc = &cc; memset(pcc, 0, sizeof(*pcc)); pcc->cb = sizeof(*pcc); pcc->iCodePage = IsWindowUnicode(hwndClient) ? CP_WINUNICODE : CP_WINANSI; } if ((pInstance->CBFflags & CBF_FAIL_SELFCONNECTIONS) && self) { TRACE("Don't do self connection as requested\n"); } else if (hszApp && hszTop) { WDML_SERVER* pServer = (WDML_SERVER*)GetWindowLongA(hwndServer, GWL_WDML_SERVER); /* check filters for name service */ if (!pServer->filterOn || DdeCmpStringHandles(pServer->hszService, hszApp) == 0) { /* pass on to the callback */ hDdeData = WDML_InvokeCallback(pInstance, XTYP_CONNECT, 0, 0, hszTop, hszApp, 0, (DWORD)pcc, self); if ((UINT)hDdeData) { pConv = WDML_CreateServerConv(pInstance, hwndClient, hwndServer, hszApp, hszTop); if (pConv && pcc) pConv->wStatus |= ST_ISLOCAL; } } } else if (pInstance->servers) { /* pass on to the callback */ hDdeData = WDML_InvokeCallback(pInstance, XTYP_WILDCONNECT, 0, 0, hszTop, hszApp, 0, (DWORD)pcc, self); if (hDdeData == (HDDEDATA)CBR_BLOCK) { /* MS doc is not consistent here */ FIXME("CBR_BLOCK returned for WILDCONNECT\n"); } else if ((UINT)hDdeData != 0) { HSZPAIR* hszp; hszp = (HSZPAIR*)DdeAccessData(hDdeData, NULL); if (hszp) { int i; for (i = 0; hszp[i].hszSvc && hszp[i].hszTopic; i++) { pConv = WDML_CreateServerConv(pInstance, hwndClient, hwndServer, hszp[i].hszSvc, hszp[i].hszTopic); if (pConv && pcc) pConv->wStatus |= ST_ISLOCAL; } DdeUnaccessData(hDdeData); } if (!WDML_IsAppOwned(hDdeData)) DdeFreeDataHandle(hDdeData); } } } return 0; case WM_DDE_REQUEST: FIXME("WM_DDE_REQUEST message received!\n"); return 0; case WM_DDE_ADVISE: FIXME("WM_DDE_ADVISE message received!\n"); return 0; case WM_DDE_UNADVISE: FIXME("WM_DDE_UNADVISE message received!\n"); return 0; case WM_DDE_EXECUTE: FIXME("WM_DDE_EXECUTE message received!\n"); return 0; case WM_DDE_POKE: FIXME("WM_DDE_POKE message received!\n"); return 0; case WM_DDE_TERMINATE: FIXME("WM_DDE_TERMINATE message received!\n"); return 0; } return DefWindowProcA(hwndServer, iMsg, wParam, lParam); }
/****************************************************************** * 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; TRACE("%p %04x %08lx %08lx\n", hwnd, iMsg, wParam , lParam); 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); PostMessageW((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); SetWindowLongPtrW(hwnd, GWL_WDML_CONVERSATION, (ULONG_PTR)pConv); pConv->wStatus |= ST_CONNECTED; pConv->wConvst = XST_INIT1; /* check if server is handled by DDEML */ if ((GetClassNameA((HWND)wParam, buf, sizeof(buf)) && lstrcmpiA(buf, WDML_szServerConvClassA) == 0) || (GetClassNameW((HWND)wParam, (LPWSTR)buf, sizeof(buf)/sizeof(WCHAR)) && lstrcmpiW((LPWSTR)buf, WDML_szServerConvClassW) == 0)) { pConv->wStatus |= ST_ISLOCAL; } GlobalDeleteAtom(uiLo); GlobalDeleteAtom(uiHi); /* accept conversation */ return 1; } if (iMsg >= WM_DDE_FIRST && iMsg <= WM_DDE_LAST) { 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, NULL); } return 0; } return IsWindowUnicode(hwnd) ? DefWindowProcW(hwnd, iMsg, wParam, lParam) : DefWindowProcA(hwnd, iMsg, wParam, lParam); }