1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
6 * Copyright 1997 Alexandre Julliard
7 * Copyright 1997 Len White
8 * Copyright 1999 Keith Matthews
10 * Copyright 2001 Eric Pouech
21 #include "debugtools.h"
22 #include "dde/dde_private.h"
24 DEFAULT_DEBUG_CHANNEL(ddeml);
26 static LRESULT CALLBACK WDML_ClientProc(HWND, UINT, WPARAM, LPARAM); /* only for one client, not conv list */
27 static const char szClientClassA[] = "DdeClientAnsi";
29 /******************************************************************************
30 * DdeConnectList [USER32.@] Establishes conversation with DDE servers
33 * idInst [I] Instance identifier
34 * hszService [I] Handle to service name string
35 * hszTopic [I] Handle to topic name string
36 * hConvList [I] Handle to conversation list
37 * pCC [I] Pointer to structure with context data
40 * Success: Handle to new conversation list
43 HCONVLIST WINAPI DdeConnectList(DWORD idInst, HSZ hszService, HSZ hszTopic,
44 HCONVLIST hConvList, LPCONVCONTEXT pCC)
46 FIXME("(%ld,%d,%d,%d,%p): stub\n", idInst, hszService, hszTopic,
51 /*****************************************************************
52 * DdeQueryNextServer [USER32.@]
54 HCONV WINAPI DdeQueryNextServer(HCONVLIST hConvList, HCONV hConvPrev)
56 FIXME("(%d,%d): stub\n",hConvList,hConvPrev);
60 /******************************************************************************
61 * DdeDisconnectList [USER32.@] Destroys list and terminates conversations
67 BOOL WINAPI DdeDisconnectList(
68 HCONVLIST hConvList) /* [in] Handle to conversation list */
70 FIXME("(%d): stub\n", hConvList);
74 /*****************************************************************
75 * DdeConnect (USER32.@)
77 HCONV WINAPI DdeConnect(DWORD idInst, HSZ hszService, HSZ hszTopic,
84 WDML_INSTANCE* thisInstance;
87 TRACE("(0x%lx,%d,%d,%p)\n",idInst,hszService,hszTopic,pCC);
89 thisInstance = WDML_FindInstance(idInst);
95 /* make sure this conv is never created */
96 pConv = WDML_FindConv(thisInstance, WDML_CLIENT_SIDE, hszService, hszTopic);
99 ERR("This Conv already exists: (0x%lx)\n", (DWORD)pConv);
103 /* we need to establish a conversation with
104 server, so create a window for it */
106 wndclass.cbSize = sizeof(wndclass);
108 wndclass.lpfnWndProc = WDML_ClientProc;
109 wndclass.cbClsExtra = 0;
110 wndclass.cbWndExtra = 2 * sizeof(DWORD);
111 wndclass.hInstance = 0;
113 wndclass.hCursor = 0;
114 wndclass.hbrBackground = 0;
115 wndclass.lpszMenuName = NULL;
116 wndclass.lpszClassName = szClientClassA;
117 wndclass.hIconSm = 0;
119 RegisterClassExA(&wndclass);
121 hwndClient = CreateWindowA(szClientClassA, NULL, WS_POPUP, 0, 0, 0, 0, 0, 0, 0, 0);
123 SetWindowLongA(hwndClient, 0, (DWORD)thisInstance);
125 SendMessageA(HWND_BROADCAST, WM_DDE_INITIATE, (WPARAM)hwndClient,
126 PackDDElParam(WM_DDE_INITIATE, (UINT)hszService, (UINT)hszTopic));
128 if (UnpackDDElParam(WM_DDE_INITIATE, lParam, &uiLow, &uiHi))
129 FreeDDElParam(WM_DDE_INITIATE, lParam);
131 TRACE("WM_DDE_INITIATE was processed\n");
132 /* At this point, Client WM_DDE_ACK should have saved hwndServer
133 for this instance id and hwndClient if server responds.
134 So get HCONV and return it. And add it to conv list */
135 pConv = (WDML_CONV*)GetWindowLongA(hwndClient, 4);
136 if (pConv == NULL || pConv->hwndServer == 0)
138 ERR(".. but no Server window available\n");
141 /* finish init of pConv */
144 pConv->convContext = *pCC;
150 /*****************************************************************
151 * DdeDisconnect (USER32.@)
153 BOOL WINAPI DdeDisconnect(HCONV hConv)
155 WDML_CONV* pConv = NULL;
157 TRACE("(%ld)\n", (DWORD)hConv);
161 ERR("DdeDisconnect(): hConv = 0\n");
165 pConv = WDML_GetConv(hConv);
170 if (!PostMessageA(pConv->hwndServer, WM_DDE_TERMINATE,
171 (WPARAM)pConv->hwndClient, (LPARAM)hConv))
173 ERR("DdeDisconnect(): PostMessage returned 0\n");
180 /*****************************************************************
181 * DdeReconnect (DDEML.37)
182 * DdeReconnect (USER32.@)
184 HCONV WINAPI DdeReconnect(HCONV hConv)
186 FIXME("empty stub\n");
191 WDML_QS_ERROR, WDML_QS_HANDLED, WDML_QS_PASS
194 /******************************************************************
197 * Creates and queue an WM_DDE_ADVISE transaction
199 static WDML_XACT* WDML_QueueAdvise(WDML_CONV* pConv, UINT wType, UINT wFmt, HSZ hszItem)
201 DDEADVISE* pDdeAdvise;
204 TRACE("XTYP_ADVSTART (with%s data) transaction\n", (wType & XTYPF_NODATA) ? "out" : "");
206 pXAct = WDML_AllocTransaction(pConv->thisInstance, WM_DDE_ADVISE);
210 pXAct->u.advise.wType = wType & ~0x0F;
211 pXAct->u.advise.wFmt = wFmt;
212 pXAct->u.advise.hszItem = hszItem;
213 pXAct->u.advise.hDdeAdvise = GlobalAlloc(GHND | GMEM_DDESHARE, sizeof(DDEADVISE));
216 pDdeAdvise = (DDEADVISE*)GlobalLock(pXAct->u.advise.hDdeAdvise);
217 pDdeAdvise->fAckReq = (wType & XTYPF_ACKREQ) ? TRUE : FALSE;
218 pDdeAdvise->fDeferUpd = (wType & XTYPF_NODATA) ? TRUE : FALSE;
219 pDdeAdvise->cfFormat = wFmt;
220 GlobalUnlock(pXAct->u.advise.hDdeAdvise);
222 WDML_QueueTransaction(pConv, pXAct);
224 if (!PostMessageA(pConv->hwndServer, WM_DDE_ADVISE, (WPARAM)pConv->hwndClient,
225 PackDDElParam(WM_DDE_ADVISE, (UINT)pXAct->u.advise.hDdeAdvise, (UINT)hszItem)))
227 GlobalFree(pXAct->u.advise.hDdeAdvise);
228 WDML_UnQueueTransaction(pConv, pXAct);
229 WDML_FreeTransaction(pXAct);
236 /******************************************************************
237 * WDML_HandleAdviseReply
239 * handles the reply to an advise request
241 static WDML_QUEUE_STATE WDML_HandleAdviseReply(WDML_CONV* pConv, MSG* msg, WDML_XACT* pXAct)
247 if (msg->message != WM_DDE_ACK || msg->wParam != pConv->hwndServer)
252 UnpackDDElParam(WM_DDE_ACK, msg->lParam, &uiLo, &uiHi);
254 if (DdeCmpStringHandles(uiHi, pXAct->u.advise.hszItem) != 0)
257 GlobalDeleteAtom(uiHi);
260 ddeAck = *((DDEACK*)&wStatus);
266 /* billx: first to see if the link is already created. */
267 pLink = WDML_FindLink(pConv->thisInstance, (HCONV)pConv, WDML_CLIENT_SIDE,
268 pXAct->u.advise.hszItem, pXAct->u.advise.wFmt);
271 /* we found a link, and only need to modify it in case it changes */
272 pLink->transactionType = pXAct->u.advise.wType;
276 TRACE("Adding Link with hConv = 0x%lx\n", (DWORD)pConv);
277 WDML_AddLink(pConv->thisInstance, (HCONV)pConv, WDML_CLIENT_SIDE,
278 pXAct->u.advise.wType, pXAct->u.advise.hszItem,
279 pXAct->u.advise.wFmt);
284 TRACE("Returning TRUE on XTYP_ADVSTART - fAck was FALSE\n");
285 GlobalFree(pXAct->u.advise.hDdeAdvise);
287 pXAct->hDdeData = (HDDEDATA)1;
288 return WDML_QS_HANDLED;
291 /******************************************************************
294 * queues an unadvise transaction
296 static WDML_XACT* WDML_QueueUnadvise(WDML_CONV* pConv, UINT wFmt, HSZ hszItem)
300 TRACE("XTYP_ADVSTOP transaction\n");
302 pXAct = WDML_AllocTransaction(pConv->thisInstance, WM_DDE_UNADVISE);
306 pXAct->u.unadvise.wFmt = wFmt;
307 pXAct->u.unadvise.hszItem = hszItem;
309 WDML_QueueTransaction(pConv, pXAct);
311 /* end advise loop: post WM_DDE_UNADVISE to server to terminate link
312 on the specified item. */
314 if (!PostMessageA(pConv->hwndServer, WM_DDE_UNADVISE, (WPARAM)pConv->hwndClient,
315 PackDDElParam(WM_DDE_UNADVISE, wFmt, (UINT)hszItem)))
317 WDML_UnQueueTransaction(pConv, pXAct);
318 WDML_FreeTransaction(pXAct);
324 /******************************************************************
325 * WDML_HandleUnadviseReply
329 static WDML_QUEUE_STATE WDML_HandleUnadviseReply(WDML_CONV* pConv, MSG* msg, WDML_XACT* pXAct)
335 if (msg->message != WM_DDE_ACK || msg->wParam != pConv->hwndServer)
340 UnpackDDElParam(WM_DDE_ACK, msg->lParam, &uiLo, &uiHi);
342 if (DdeCmpStringHandles(uiHi, pXAct->u.unadvise.hszItem) != 0)
345 GlobalDeleteAtom(uiHi);
348 ddeAck = *((DDEACK*)&wStatus);
350 TRACE("WM_DDE_ACK received while waiting for a timeout\n");
354 TRACE("Returning TRUE on XTYP_ADVSTOP - fAck was FALSE\n");
358 /* billx: remove the link */
359 WDML_RemoveLink(pConv->thisInstance, (HCONV)pConv, WDML_CLIENT_SIDE,
360 pXAct->u.unadvise.hszItem, pXAct->u.unadvise.wFmt);
362 pXAct->hDdeData = (HDDEDATA)1;
363 return WDML_QS_HANDLED;
366 /******************************************************************
371 static WDML_XACT* WDML_QueueRequest(WDML_CONV* pConv, UINT wFmt, HSZ hszItem)
375 TRACE("XTYP_REQUEST transaction\n");
377 pXAct = WDML_AllocTransaction(pConv->thisInstance, WM_DDE_REQUEST);
381 pXAct->u.request.hszItem = hszItem;
383 WDML_QueueTransaction(pConv, pXAct);
385 /* end advise loop: post WM_DDE_UNADVISE to server to terminate link
386 * on the specified item.
389 if (!PostMessageA(pConv->hwndServer, WM_DDE_REQUEST, (WPARAM)pConv->hwndClient,
390 PackDDElParam(WM_DDE_REQUEST, wFmt, (UINT)hszItem)))
392 WDML_UnQueueTransaction(pConv, pXAct);
393 WDML_FreeTransaction(pXAct);
399 /******************************************************************
400 * WDML_HandleRequestReply
404 static WDML_QUEUE_STATE WDML_HandleRequestReply(WDML_CONV* pConv, MSG* msg, WDML_XACT* pXAct)
410 switch (msg->message)
413 if (msg->wParam != pConv->hwndServer)
415 UnpackDDElParam(WM_DDE_ACK, msg->lParam, &uiLo, &uiHi);
417 ddeAck = *((DDEACK*)&wStatus);
419 TRACE("Negative answer...\n");
421 /* FIXME: billx: we should return 0 and post a negatve WM_DDE_ACK. */
425 if (msg->wParam != pConv->hwndServer)
427 UnpackDDElParam(WM_DDE_DATA, msg->lParam, &uiLo, &uiHi);
428 TRACE("Got the result (%08lx)\n", (DWORD)uiLo);
429 if (DdeCmpStringHandles(uiHi, pXAct->u.request.hszItem) != 0)
431 /* FIXME: memory clean up ? */
432 pXAct->hDdeData = WDML_Global2DataHandle((HGLOBAL)uiLo);
439 return WDML_QS_HANDLED;
442 /******************************************************************
447 static WDML_XACT* WDML_QueueExecute(WDML_CONV* pConv, LPCVOID pData, DWORD cbData)
451 TRACE("XTYP_EXECUTE transaction\n");
453 pXAct = WDML_AllocTransaction(pConv->thisInstance, WM_DDE_EXECUTE);
457 if (cbData == (DWORD)-1)
459 HDDEDATA hDdeData = (HDDEDATA)pData;
462 pData = DdeAccessData(hDdeData, &dwSize);
465 pXAct->u.execute.hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, dwSize);
466 if (pXAct->u.execute.hMem)
470 pDst = GlobalLock(pXAct->u.execute.hMem);
473 memcpy(pDst, pData, dwSize);
474 GlobalUnlock(pXAct->u.execute.hMem);
478 GlobalFree(pXAct->u.execute.hMem);
479 pXAct->u.execute.hMem = 0;
482 DdeUnaccessData(hDdeData);
486 pXAct->u.execute.hMem = 0;
493 pXAct->u.execute.hMem = GlobalAlloc(GHND | GMEM_DDESHARE, cbData);
494 ptr = GlobalLock(pXAct->u.execute.hMem);
497 memcpy(ptr, pData, cbData);
498 GlobalUnlock(pXAct->u.execute.hMem);
502 WDML_QueueTransaction(pConv, pXAct);
504 if (!PostMessageA(pConv->hwndServer, WM_DDE_EXECUTE, (WPARAM)pConv->hwndClient,
505 pXAct->u.execute.hMem))
507 GlobalFree(pXAct->u.execute.hMem);
508 WDML_UnQueueTransaction(pConv, pXAct);
509 WDML_FreeTransaction(pXAct);
510 TRACE("Returning FALSE on XTYP_EXECUTE - PostMessage returned FALSE\n");
516 /******************************************************************
517 * WDML_HandleExecuteReply
521 static WDML_QUEUE_STATE WDML_HandleExecuteReply(WDML_CONV* pConv, MSG* msg, WDML_XACT* pXAct)
527 if (msg->message != WM_DDE_ACK || msg->wParam != pConv->hwndServer)
532 UnpackDDElParam(WM_DDE_ACK, msg->lParam, &uiLo, &uiHi);
533 FreeDDElParam(WM_DDE_ACK, msg->lParam);
535 if (uiHi != pXAct->u.execute.hMem)
541 ddeAck = *((DDEACK*)&wStatus);
544 GlobalFree(pXAct->u.execute.hMem);
546 pXAct->hDdeData = (HDDEDATA)1;
547 return WDML_QS_HANDLED;
550 /******************************************************************
555 static WDML_XACT* WDML_QueuePoke(WDML_CONV* pConv, LPCVOID pData, DWORD cbData,
556 UINT wFmt, HSZ hszItem)
560 TRACE("XTYP_POKE transaction\n");
562 pXAct = WDML_AllocTransaction(pConv->thisInstance, WM_DDE_POKE);
566 if (cbData == (DWORD)-1)
568 pXAct->u.poke.hMem = (HDDEDATA)pData;
574 pXAct->u.poke.hMem = GlobalAlloc(GHND | GMEM_DDESHARE, sizeof(DDEPOKE) + cbData);
575 ddePoke = GlobalLock(pXAct->u.poke.hMem);
578 memcpy(ddePoke->Value, pData, cbData);
579 ddePoke->fRelease = FALSE; /* FIXME: app owned ? */
580 ddePoke->cfFormat = wFmt;
581 GlobalUnlock(pXAct->u.poke.hMem);
585 pXAct->u.poke.hszItem = hszItem;
587 WDML_QueueTransaction(pConv, pXAct);
589 if (!PostMessageA(pConv->hwndServer, WM_DDE_POKE, (WPARAM)pConv->hwndClient,
590 PackDDElParam(WM_DDE_POKE, pXAct->u.execute.hMem, hszItem)))
592 GlobalFree(pXAct->u.execute.hMem);
593 WDML_UnQueueTransaction(pConv, pXAct);
594 WDML_FreeTransaction(pXAct);
595 TRACE("Returning FALSE on XTYP_POKE - PostMessage returned FALSE\n");
601 /******************************************************************
602 * WDML_HandlePokeReply
606 static WDML_QUEUE_STATE WDML_HandlePokeReply(WDML_CONV* pConv, MSG* msg, WDML_XACT* pXAct)
612 if (msg->message != WM_DDE_ACK && msg->wParam != pConv->hwndServer)
617 UnpackDDElParam(WM_DDE_ACK, msg->lParam, &uiLo, &uiHi);
618 if (uiHi != pXAct->u.poke.hszItem)
622 FreeDDElParam(WM_DDE_ACK, msg->lParam);
625 ddeAck = *((DDEACK*)&wStatus);
628 GlobalFree(pXAct->u.poke.hMem);
630 pXAct->hDdeData = (HDDEDATA)TRUE;
634 /******************************************************************
635 * WDML_HandleReplyData
639 static WDML_QUEUE_STATE WDML_HandleReplyData(WDML_CONV* pConv, MSG* msg, HDDEDATA* hdd)
642 HDDEDATA hDdeDataIn, hDdeDataOut;
645 TRACE("WM_DDE_DATA message received in the Client Proc!\n");
646 /* wParam -- sending window handle */
647 /* lParam -- hDdeData & item HSZ */
649 UnpackDDElParam(WM_DDE_DATA, msg->lParam, &uiLo, &uiHi);
651 hDdeDataIn = WDML_Global2DataHandle((HGLOBAL)uiLo);
654 * For hot link, data should be passed to its callback with
655 * XTYP_ADVDATA and callback should return the proper status.
658 for (pLink = pConv->thisInstance->links[WDML_CLIENT_SIDE]; pLink != NULL; pLink = pLink->next)
660 if (DdeCmpStringHandles((HSZ)uiHi, pLink->hszItem) == 0)
662 BOOL fRelease = FALSE;
663 BOOL fAckReq = FALSE;
666 /* item in the advise loop */
667 pConv = WDML_GetConv(pLink->hConv);
672 if ((pDdeData = GlobalLock(uiLo)) != NULL)
674 fRelease = pDdeData->fRelease;
675 fAckReq = pDdeData->fAckReq;
684 ddeAck.bAppReturnCode = 0;
686 ddeAck.fBusy = FALSE;
690 PostMessageA(pConv->hwndServer, WM_DDE_ACK, pConv->hwndClient,
691 ReuseDDElParam(msg->lParam, WM_DDE_DATA, WM_DDE_ACK,
692 *(WORD*)&ddeAck, (UINT)pLink->hszItem));
697 PostMessageA(pConv->hwndServer, WM_DDE_ACK, pConv->hwndClient,
698 PackDDElParam(WM_DDE_ACK, *(WORD*)&ddeAck, (UINT)pLink->hszItem));
703 if (pConv->thisInstance->callback != NULL /*&& thisInstance->processID == GetCurrentProcessId() */)
705 TRACE("Calling the callback, type = XTYP_ADVDATA, CB = 0x%lx, hConv = 0x%lx\n",
706 (DWORD)pConv->thisInstance->callback, (DWORD)pLink->hConv);
707 hDdeDataOut = (pConv->thisInstance->callback)(XTYP_ADVDATA,
714 if (hDdeDataOut == (HDDEDATA)DDE_FACK)
716 pLink->hDdeData = hDdeDataIn;
722 DdeFreeDataHandle(hDdeDataIn);
730 FreeDDElParam(WM_DDE_DATA, msg->lParam);
732 return WDML_QS_HANDLED;
735 /******************************************************************
736 * WDML_HandleReplyTerminate
740 static WDML_QUEUE_STATE WDML_HandleReplyTerminate(WDML_CONV* pConv, MSG* msg, HDDEDATA* hdd)
742 if ((LPARAM)pConv != msg->lParam)
745 /* billx: clean up the conv and associated links */
746 WDML_RemoveAllLinks(pConv->thisInstance, (HCONV)pConv, WDML_CLIENT_SIDE);
747 WDML_RemoveConv(pConv->thisInstance, WDML_CLIENT_SIDE, (HCONV)pConv);
748 DestroyWindow(msg->hwnd);
749 return WDML_QS_HANDLED;
752 /******************************************************************
755 * handles any incoming reply, and try to match to an already sent request
757 static WDML_QUEUE_STATE WDML_HandleReply(WDML_CONV* pConv, MSG* msg, HDDEDATA* hdd)
759 WDML_XACT* pXAct = pConv->transactions;
762 if (pConv->transactions)
764 /* first check message against a pending transaction, if any */
765 switch (pXAct->ddeMsg)
768 qs = WDML_HandleAdviseReply(pConv, msg, pXAct);
770 case WM_DDE_UNADVISE:
771 qs = WDML_HandleUnadviseReply(pConv, msg, pXAct);
774 qs = WDML_HandleExecuteReply(pConv, msg, pXAct);
777 qs = WDML_HandleRequestReply(pConv, msg, pXAct);
780 qs = WDML_HandlePokeReply(pConv, msg, pXAct);
792 /* now check the results */
798 case WDML_QS_HANDLED:
799 /* ok, we have resolved a pending transaction
800 * notify callback if asynchronous, and remove it in any case
802 WDML_UnQueueTransaction(pConv, pXAct);
803 if (pXAct->dwTimeout == TIMEOUT_ASYNC)
805 if (pConv->thisInstance->callback != NULL /*&& thisInstance->processID == GetCurrentProcessId() */)
807 TRACE("Calling the callback, type = XTYP_XACT_COMPLETE, CB = 0x%lx, hConv = 0x%lx\n",
808 (DWORD)pConv->thisInstance->callback, (DWORD)pConv);
809 (pConv->thisInstance->callback)(XTYP_XACT_COMPLETE, 0 /* FIXME */,
811 pConv->hszTopic, 0 /* FIXME */,
813 MAKELONG(0, pXAct->xActID),
820 *hdd = pXAct->hDdeData;
822 WDML_FreeTransaction(pXAct);
825 /* no pending transaction found, try a warm link or a termination request */
826 switch (msg->message)
829 qs = WDML_HandleReplyData(pConv, msg, hdd);
831 case WM_DDE_TERMINATE:
832 qs = WDML_HandleReplyTerminate(pConv, msg, hdd);
841 /******************************************************************
842 * WDML_SyncWaitTransactionReply
844 * waits until an answer for a sent request is received
845 * time out is also handled. only used for synchronous transactions
847 static HDDEDATA WDML_SyncWaitTransactionReply(HCONV hConv, DWORD dwTimeout, WDML_XACT* pXAct)
851 TRACE("Starting wait for a timeout of %ld ms\n", dwTimeout);
853 /* FIXME: time 32 bit wrap around */
854 dwTimeout += GetCurrentTime();
856 while ((dwTime = GetCurrentTime()) < dwTimeout)
858 /* we cannot hold the mutex all the time because when client and server run in a
859 * single process they need to share the access to the internal data
861 if (MsgWaitForMultipleObjects(0, NULL, FALSE,
862 dwTime - dwTimeout, QS_POSTMESSAGE) == WAIT_OBJECT_0 &&
863 WDML_WaitForMutex(handle_mutex))
870 pConv = WDML_GetConv(hConv);
873 /* conversation no longer available... return failure */
876 while (PeekMessageA(&msg, pConv->hwndClient, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE))
878 /* check that either pXAct has been processed or no more xActions are pending */
879 ret = (pConv->transactions == pXAct);
880 ret = WDML_HandleReply(pConv, &msg, &hdd) == WDML_QS_HANDLED &&
881 (pConv->transactions == NULL || ret);
884 WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE);
892 TRACE("Timeout !!\n");
893 if (WDML_WaitForMutex(handle_mutex))
898 pConv = WDML_GetConv(hConv);
903 switch (pConv->transactions->ddeMsg)
905 case WM_DDE_ADVISE: err = DMLERR_ADVACKTIMEOUT; break;
906 case WM_DDE_REQUEST: err = DMLERR_DATAACKTIMEOUT; break;
907 case WM_DDE_EXECUTE: err = DMLERR_EXECACKTIMEOUT; break;
908 case WM_DDE_POKE: err = DMLERR_POKEACKTIMEOUT; break;
909 case WM_DDE_UNADVISE: err = DMLERR_UNADVACKTIMEOUT; break;
910 default: err = DMLERR_INVALIDPARAMETER; break;
913 pConv->thisInstance->lastError = err;
914 WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE);
919 /*****************************************************************
920 * DdeClientTransaction (USER32.@)
922 HDDEDATA WINAPI DdeClientTransaction(LPBYTE pData, DWORD cbData, HCONV hConv, HSZ hszItem, UINT wFmt,
923 UINT wType, DWORD dwTimeout, LPDWORD pdwResult)
927 HDDEDATA hDdeData = 0;
929 TRACE("(0x%lx,%ld,0x%lx,0x%lx,%d,%d,%ld,0x%lx)\n",
930 (ULONG)pData,cbData,(DWORD)hConv,(DWORD)hszItem,wFmt,wType,
931 dwTimeout,(ULONG)pdwResult);
935 ERR("Invalid conversation handle\n");
939 if (!WDML_WaitForMutex(handle_mutex))
944 pConv = WDML_GetConv(hConv);
947 /* cannot set error... cannot get back to DDE instance */
954 if (hszItem != 0 || wFmt != 0)
956 pConv->thisInstance->lastError = DMLERR_INVALIDPARAMETER;
959 pXAct = WDML_QueueExecute(pConv, pData, cbData);
962 pXAct = WDML_QueuePoke(pConv, pData, cbData, wFmt, hszItem);
964 case XTYP_ADVSTART|XTYPF_NODATA:
965 case XTYP_ADVSTART|XTYPF_NODATA|XTYPF_ACKREQ:
967 case XTYP_ADVSTART|XTYPF_ACKREQ:
970 pConv->thisInstance->lastError = DMLERR_INVALIDPARAMETER;
973 pXAct = WDML_QueueAdvise(pConv, wType, wFmt, hszItem);
978 pConv->thisInstance->lastError = DMLERR_INVALIDPARAMETER;
981 pXAct = WDML_QueueUnadvise(pConv, wFmt, hszItem);
986 pConv->thisInstance->lastError = DMLERR_INVALIDPARAMETER;
989 pXAct = WDML_QueueRequest(pConv, wFmt, hszItem);
992 FIXME("Unknown transation\n");
993 /* unknown transaction type */
994 pConv->thisInstance->lastError = DMLERR_INVALIDPARAMETER;
998 pXAct->dwTimeout = dwTimeout;
999 /* FIXME: should set the app bits on *pdwResult */
1001 if (dwTimeout == TIMEOUT_ASYNC)
1005 *pdwResult = MAKELONG(0, pXAct->xActID);
1007 hDdeData = (HDDEDATA)1;
1010 WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE);
1012 if (dwTimeout != TIMEOUT_ASYNC)
1020 while (ReleaseMutex(handle_mutex))
1022 hDdeData = WDML_SyncWaitTransactionReply((HCONV)pConv, dwTimeout, pXAct);
1023 while (count-- != 0)
1024 WDML_WaitForMutex(handle_mutex);
1028 WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE);
1032 /******************************************************************
1035 * Window Proc created on client side for each conversation
1037 static LRESULT CALLBACK WDML_ClientProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
1041 if (iMsg == WM_DDE_ACK &&
1042 /* In response to WM_DDE_INITIATE, save server window */
1043 UnpackDDElParam(WM_DDE_ACK, lParam, &uiLow, &uiHi) &&
1044 (WDML_CONV*)GetWindowLongA(hwnd, 4) == NULL)
1046 WDML_INSTANCE* thisInstance = NULL;
1047 WDML_CONV* pConv = NULL;
1049 FreeDDElParam(WM_DDE_ACK, lParam);
1050 /* no converstation yet, add it */
1051 thisInstance = (WDML_INSTANCE*)GetWindowLongA(hwnd, 0);
1052 pConv = WDML_AddConv(thisInstance, WDML_CLIENT_SIDE, (HSZ)uiLow, (HSZ)uiHi,
1053 hwnd, (HWND)wParam);
1054 SetWindowLongA(hwnd, 4, (DWORD)pConv);
1055 /* FIXME: so far we only use the first window in the list... */
1059 if ((iMsg >= WM_DDE_FIRST && iMsg <= WM_DDE_LAST) && WDML_WaitForMutex(handle_mutex))
1061 WDML_CONV* pConv = (WDML_CONV*)GetWindowLongA(hwnd, 4);
1070 msg.wParam = wParam;
1071 msg.lParam = lParam;
1073 WDML_HandleReply(pConv, &msg, &hdd);
1076 WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE);
1080 return DefWindowProcA(hwnd, iMsg, wParam, lParam);
1084 /*****************************************************************
1085 * DdeAbandonTransaction (USER32.@)
1087 BOOL WINAPI DdeAbandonTransaction(DWORD idInst, HCONV hConv, DWORD idTransaction)
1089 FIXME("empty stub\n");
1094 /*****************************************************************
1095 * DdeImpersonateClient (USER32.@)
1097 BOOL WINAPI DdeImpersonateClient(HCONV hConv)
1102 if (!WDML_WaitForMutex(handle_mutex))
1106 pConv = WDML_GetConv(hConv);
1109 ret = ImpersonateDdeClientWindow(pConv->hwndClient, pConv->hwndServer);
1111 WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE);