/****************************************************************** * 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; }
/***************************************************************** * DdeReconnect (DDEML.37) * DdeReconnect (USER32.@) */ HCONV WINAPI DdeReconnect(HCONV hConv) { WDML_CONV* pConv; WDML_CONV* pNewConv = NULL; ATOM aSrv = 0, aTpc = 0; TRACE("(%p)\n", hConv); pConv = WDML_GetConv(hConv, FALSE); if (pConv != NULL && (pConv->wStatus & ST_CLIENT)) { BOOL ret; /* to reestablish a connection, we have to make sure that: * 1/ pConv is the conversation attached to the client window (it wouldn't be * if a call to DdeReconnect would have already been done...) * FIXME: is this really an error ??? * 2/ the pConv conversation had really been deconnected */ if (pConv == WDML_GetConvFromWnd(pConv->hwndClient) && (pConv->wStatus & ST_TERMINATED) && !(pConv->wStatus & ST_CONNECTED)) { HWND hwndClient = pConv->hwndClient; HWND hwndServer = pConv->hwndServer; SetWindowLongPtrW(pConv->hwndClient, GWL_WDML_CONVERSATION, 0); aSrv = WDML_MakeAtomFromHsz(pConv->hszService); aTpc = WDML_MakeAtomFromHsz(pConv->hszTopic); if (!aSrv || !aTpc) goto theEnd; /* note: sent messages shall not use packing */ ret = SendMessageW(hwndServer, WM_DDE_INITIATE, (WPARAM)hwndClient, MAKELPARAM(aSrv, aTpc)); pConv = WDML_GetConv(hConv, FALSE); if (pConv == NULL) { FIXME("Should fail reconnection\n"); goto theEnd; } if (ret && (pNewConv = WDML_GetConvFromWnd(pConv->hwndClient)) != NULL) { /* re-establish all links... */ WDML_LINK* pLink; for (pLink = pConv->instance->links[WDML_CLIENT_SIDE]; pLink; pLink = pLink->next) { if (pLink->hConv == hConv) { /* try to reestablish the links... */ DdeClientTransaction(NULL, 0, (HCONV)pNewConv, pLink->hszItem, pLink->uFmt, pLink->transactionType, 1000, NULL); } } } else { /* reset the conversation as it was */ SetWindowLongPtrW(pConv->hwndClient, GWL_WDML_CONVERSATION, (ULONG_PTR)pConv); } } } theEnd: if (aSrv) GlobalDeleteAtom(aSrv); if (aTpc) GlobalDeleteAtom(aTpc); return (HCONV)pNewConv; }
/***************************************************************** * DdeConnect (USER32.@) */ HCONV WINAPI DdeConnect(DWORD idInst, HSZ hszService, HSZ hszTopic, PCONVCONTEXT pCC) { HWND hwndClient; WDML_INSTANCE* pInstance; WDML_CONV* pConv; ATOM aSrv = 0, aTpc = 0; TRACE("(0x%x,%p,%p,%p)\n", idInst, hszService, hszTopic, pCC); pInstance = WDML_GetInstance(idInst); if (!pInstance) return NULL; /* make sure this conv is never created */ pConv = WDML_FindConv(pInstance, WDML_CLIENT_SIDE, hszService, hszTopic); if (pConv != NULL) { ERR("This Conv already exists: (%p)\n", pConv); return NULL; } /* we need to establish a conversation with server, so create a window for it */ if (pInstance->unicode) { WNDCLASSEXW wndclass; wndclass.cbSize = sizeof(wndclass); wndclass.style = 0; wndclass.lpfnWndProc = WDML_ClientProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 2 * sizeof(ULONG_PTR); wndclass.hInstance = 0; wndclass.hIcon = 0; wndclass.hCursor = 0; wndclass.hbrBackground = 0; wndclass.lpszMenuName = NULL; wndclass.lpszClassName = WDML_szClientConvClassW; wndclass.hIconSm = 0; RegisterClassExW(&wndclass); hwndClient = CreateWindowW(WDML_szClientConvClassW, NULL, WS_POPUP, 0, 0, 0, 0, 0, 0, 0, 0); } else { WNDCLASSEXA wndclass; wndclass.cbSize = sizeof(wndclass); wndclass.style = 0; wndclass.lpfnWndProc = WDML_ClientProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 2 * sizeof(ULONG_PTR); wndclass.hInstance = 0; wndclass.hIcon = 0; wndclass.hCursor = 0; wndclass.hbrBackground = 0; wndclass.lpszMenuName = NULL; wndclass.lpszClassName = WDML_szClientConvClassA; wndclass.hIconSm = 0; RegisterClassExA(&wndclass); hwndClient = CreateWindowA(WDML_szClientConvClassA, NULL, WS_POPUP, 0, 0, 0, 0, 0, 0, 0, 0); } SetWindowLongPtrW(hwndClient, GWL_WDML_INSTANCE, (ULONG_PTR)pInstance); if (hszService) { aSrv = WDML_MakeAtomFromHsz(hszService); if (!aSrv) goto theEnd; } if (hszTopic) { aTpc = WDML_MakeAtomFromHsz(hszTopic); if (!aTpc) goto theEnd; } /* note: sent messages shall not use packing */ SendMessageTimeoutW( HWND_BROADCAST, WM_DDE_INITIATE, (WPARAM)hwndClient, MAKELPARAM(aSrv, aTpc), SMTO_ABORTIFHUNG, 0, NULL ); pInstance = WDML_GetInstance(idInst); if (!pInstance) { goto theEnd; } /* At this point, Client WM_DDE_ACK should have saved hwndServer for this instance id and hwndClient if server responds. So get HCONV and return it. And add it to conv list */ pConv = WDML_GetConvFromWnd(hwndClient); if (pConv == NULL || pConv->hwndServer == 0) { WARN("Done with INITIATE, but no Server window available\n"); pConv = NULL; pInstance->lastError = DMLERR_NO_CONV_ESTABLISHED; goto theEnd; } TRACE("Connected to Server window (%p)\n", pConv->hwndServer); pConv->wConvst = XST_CONNECTED; /* finish init of pConv */ if (pCC != NULL) { pConv->convContext = *pCC; } else { memset(&pConv->convContext, 0, sizeof(pConv->convContext)); pConv->convContext.cb = sizeof(pConv->convContext); pConv->convContext.iCodePage = (pInstance->unicode) ? CP_WINUNICODE : CP_WINANSI; } theEnd: if (aSrv) GlobalDeleteAtom(aSrv); if (aTpc) GlobalDeleteAtom(aTpc); return (HCONV)pConv; }
/****************************************************************** * 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); }