xref: /reactos/win32ss/user/user32/misc/ddeclient.c (revision c2c66aff)
1*c2c66affSColin Finck /*
2*c2c66affSColin Finck  * DDEML library
3*c2c66affSColin Finck  *
4*c2c66affSColin Finck  * Copyright 1997 Alexandre Julliard
5*c2c66affSColin Finck  * Copyright 1997 Len White
6*c2c66affSColin Finck  * Copyright 1999 Keith Matthews
7*c2c66affSColin Finck  * Copyright 2000 Corel
8*c2c66affSColin Finck  * Copyright 2001 Eric Pouech
9*c2c66affSColin Finck  * Copyright 2004, 2005 Dmitry Timoshkov
10*c2c66affSColin Finck  *
11*c2c66affSColin Finck  * This library is free software; you can redistribute it and/or
12*c2c66affSColin Finck  * modify it under the terms of the GNU Lesser General Public
13*c2c66affSColin Finck  * License as published by the Free Software Foundation; either
14*c2c66affSColin Finck  * version 2.1 of the License, or (at your option) any later version.
15*c2c66affSColin Finck  *
16*c2c66affSColin Finck  * This library is distributed in the hope that it will be useful,
17*c2c66affSColin Finck  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18*c2c66affSColin Finck  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19*c2c66affSColin Finck  * Lesser General Public License for more details.
20*c2c66affSColin Finck  *
21*c2c66affSColin Finck  * You should have received a copy of the GNU Lesser General Public
22*c2c66affSColin Finck  * License along with this library; if not, write to the Free Software
23*c2c66affSColin Finck  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24*c2c66affSColin Finck  */
25*c2c66affSColin Finck 
26*c2c66affSColin Finck #include <user32.h>
27*c2c66affSColin Finck 
28*c2c66affSColin Finck #include <wine/debug.h>
29*c2c66affSColin Finck 
30*c2c66affSColin Finck WINE_DEFAULT_DEBUG_CHANNEL(ddeml);
31*c2c66affSColin Finck 
32*c2c66affSColin Finck static LRESULT CALLBACK WDML_ClientProc(HWND, UINT, WPARAM, LPARAM);	/* only for one client, not conv list */
33*c2c66affSColin Finck const char WDML_szClientConvClassA[] = "DDEMLAnsiClient";
34*c2c66affSColin Finck const WCHAR WDML_szClientConvClassW[] = L"DDEMLUnicodeClient";
35*c2c66affSColin Finck 
36*c2c66affSColin Finck /******************************************************************************
37*c2c66affSColin Finck  * DdeConnectList [USER32.@]  Establishes conversation with DDE servers
38*c2c66affSColin Finck  *
39*c2c66affSColin Finck  * PARAMS
40*c2c66affSColin Finck  *    idInst     [I] Instance identifier
41*c2c66affSColin Finck  *    hszService [I] Handle to service name string
42*c2c66affSColin Finck  *    hszTopic   [I] Handle to topic name string
43*c2c66affSColin Finck  *    hConvList  [I] Handle to conversation list
44*c2c66affSColin Finck  *    pCC        [I] Pointer to structure with context data
45*c2c66affSColin Finck  *
46*c2c66affSColin Finck  * RETURNS
47*c2c66affSColin Finck  *    Success: Handle to new conversation list
48*c2c66affSColin Finck  *    Failure: 0
49*c2c66affSColin Finck  */
50*c2c66affSColin Finck HCONVLIST WINAPI DdeConnectList(DWORD idInst, HSZ hszService, HSZ hszTopic,
51*c2c66affSColin Finck 				HCONVLIST hConvList, PCONVCONTEXT pCC)
52*c2c66affSColin Finck {
53*c2c66affSColin Finck     FIXME("(%d,%p,%p,%p,%p): stub\n", idInst, hszService, hszTopic, hConvList, pCC);
54*c2c66affSColin Finck     return (HCONVLIST)1;
55*c2c66affSColin Finck }
56*c2c66affSColin Finck 
57*c2c66affSColin Finck /*****************************************************************
58*c2c66affSColin Finck  * DdeQueryNextServer [USER32.@]
59*c2c66affSColin Finck  */
60*c2c66affSColin Finck HCONV WINAPI DdeQueryNextServer(HCONVLIST hConvList, HCONV hConvPrev)
61*c2c66affSColin Finck {
62*c2c66affSColin Finck     FIXME("(%p,%p): stub\n", hConvList, hConvPrev);
63*c2c66affSColin Finck     return 0;
64*c2c66affSColin Finck }
65*c2c66affSColin Finck 
66*c2c66affSColin Finck /******************************************************************************
67*c2c66affSColin Finck  * DdeDisconnectList [USER32.@]  Destroys list and terminates conversations
68*c2c66affSColin Finck  *
69*c2c66affSColin Finck  *
70*c2c66affSColin Finck  * PARAMS
71*c2c66affSColin Finck  *    hConvList  [I] Handle to conversation list
72*c2c66affSColin Finck  *
73*c2c66affSColin Finck  * RETURNS
74*c2c66affSColin Finck  *    Success: TRUE
75*c2c66affSColin Finck  *    Failure: FALSE
76*c2c66affSColin Finck  */
77*c2c66affSColin Finck BOOL WINAPI DdeDisconnectList(HCONVLIST hConvList)
78*c2c66affSColin Finck {
79*c2c66affSColin Finck     FIXME("(%p): stub\n", hConvList);
80*c2c66affSColin Finck     return TRUE;
81*c2c66affSColin Finck }
82*c2c66affSColin Finck 
83*c2c66affSColin Finck /*****************************************************************
84*c2c66affSColin Finck  *            DdeConnect   (USER32.@)
85*c2c66affSColin Finck  */
86*c2c66affSColin Finck HCONV WINAPI DdeConnect(DWORD idInst, HSZ hszService, HSZ hszTopic,
87*c2c66affSColin Finck 			PCONVCONTEXT pCC)
88*c2c66affSColin Finck {
89*c2c66affSColin Finck     HWND		hwndClient;
90*c2c66affSColin Finck     WDML_INSTANCE*	pInstance;
91*c2c66affSColin Finck     WDML_CONV*		pConv;
92*c2c66affSColin Finck     ATOM		aSrv = 0, aTpc = 0;
93*c2c66affSColin Finck 
94*c2c66affSColin Finck     TRACE("(0x%x,%p,%p,%p)\n", idInst, hszService, hszTopic, pCC);
95*c2c66affSColin Finck 
96*c2c66affSColin Finck     pInstance = WDML_GetInstance(idInst);
97*c2c66affSColin Finck     if (!pInstance)
98*c2c66affSColin Finck         return NULL;
99*c2c66affSColin Finck 
100*c2c66affSColin Finck     /* make sure this conv is never created */
101*c2c66affSColin Finck     pConv = WDML_FindConv(pInstance, WDML_CLIENT_SIDE, hszService, hszTopic);
102*c2c66affSColin Finck     if (pConv != NULL)
103*c2c66affSColin Finck     {
104*c2c66affSColin Finck 	ERR("This Conv already exists: (%p)\n", pConv);
105*c2c66affSColin Finck 	return NULL;
106*c2c66affSColin Finck     }
107*c2c66affSColin Finck 
108*c2c66affSColin Finck     /* we need to establish a conversation with
109*c2c66affSColin Finck        server, so create a window for it       */
110*c2c66affSColin Finck 
111*c2c66affSColin Finck     if (pInstance->unicode)
112*c2c66affSColin Finck     {
113*c2c66affSColin Finck         WNDCLASSEXW wndclass;
114*c2c66affSColin Finck 
115*c2c66affSColin Finck         wndclass.cbSize        = sizeof(wndclass);
116*c2c66affSColin Finck         wndclass.style         = 0;
117*c2c66affSColin Finck         wndclass.lpfnWndProc   = WDML_ClientProc;
118*c2c66affSColin Finck         wndclass.cbClsExtra    = 0;
119*c2c66affSColin Finck         wndclass.cbWndExtra    = 2 * sizeof(ULONG_PTR);
120*c2c66affSColin Finck         wndclass.hInstance     = 0;
121*c2c66affSColin Finck         wndclass.hIcon         = 0;
122*c2c66affSColin Finck         wndclass.hCursor       = 0;
123*c2c66affSColin Finck         wndclass.hbrBackground = 0;
124*c2c66affSColin Finck         wndclass.lpszMenuName  = NULL;
125*c2c66affSColin Finck         wndclass.lpszClassName = WDML_szClientConvClassW;
126*c2c66affSColin Finck         wndclass.hIconSm       = 0;
127*c2c66affSColin Finck 
128*c2c66affSColin Finck         RegisterClassExW(&wndclass);
129*c2c66affSColin Finck 
130*c2c66affSColin Finck         hwndClient = CreateWindowW(WDML_szClientConvClassW, NULL, WS_POPUP, 0, 0, 0, 0, 0, 0, 0, 0);
131*c2c66affSColin Finck     }
132*c2c66affSColin Finck     else
133*c2c66affSColin Finck     {
134*c2c66affSColin Finck         WNDCLASSEXA wndclass;
135*c2c66affSColin Finck 
136*c2c66affSColin Finck         wndclass.cbSize        = sizeof(wndclass);
137*c2c66affSColin Finck         wndclass.style         = 0;
138*c2c66affSColin Finck         wndclass.lpfnWndProc   = WDML_ClientProc;
139*c2c66affSColin Finck         wndclass.cbClsExtra    = 0;
140*c2c66affSColin Finck         wndclass.cbWndExtra    = 2 * sizeof(ULONG_PTR);
141*c2c66affSColin Finck         wndclass.hInstance     = 0;
142*c2c66affSColin Finck         wndclass.hIcon         = 0;
143*c2c66affSColin Finck         wndclass.hCursor       = 0;
144*c2c66affSColin Finck         wndclass.hbrBackground = 0;
145*c2c66affSColin Finck         wndclass.lpszMenuName  = NULL;
146*c2c66affSColin Finck         wndclass.lpszClassName = WDML_szClientConvClassA;
147*c2c66affSColin Finck         wndclass.hIconSm       = 0;
148*c2c66affSColin Finck 
149*c2c66affSColin Finck         RegisterClassExA(&wndclass);
150*c2c66affSColin Finck 
151*c2c66affSColin Finck         hwndClient = CreateWindowA(WDML_szClientConvClassA, NULL, WS_POPUP, 0, 0, 0, 0, 0, 0, 0, 0);
152*c2c66affSColin Finck     }
153*c2c66affSColin Finck 
154*c2c66affSColin Finck     SetWindowLongPtrW(hwndClient, GWL_WDML_INSTANCE, (ULONG_PTR)pInstance);
155*c2c66affSColin Finck 
156*c2c66affSColin Finck     if (hszService)
157*c2c66affSColin Finck     {
158*c2c66affSColin Finck 	aSrv = WDML_MakeAtomFromHsz(hszService);
159*c2c66affSColin Finck 	if (!aSrv) goto theEnd;
160*c2c66affSColin Finck     }
161*c2c66affSColin Finck     if (hszTopic)
162*c2c66affSColin Finck     {
163*c2c66affSColin Finck 	aTpc = WDML_MakeAtomFromHsz(hszTopic);
164*c2c66affSColin Finck 	if (!aTpc) goto theEnd;
165*c2c66affSColin Finck     }
166*c2c66affSColin Finck 
167*c2c66affSColin Finck     /* note: sent messages shall not use packing */
168*c2c66affSColin Finck     SendMessageTimeoutW( HWND_BROADCAST, WM_DDE_INITIATE, (WPARAM)hwndClient, MAKELPARAM(aSrv, aTpc),
169*c2c66affSColin Finck                          SMTO_ABORTIFHUNG, 0, NULL );
170*c2c66affSColin Finck 
171*c2c66affSColin Finck     pInstance = WDML_GetInstance(idInst);
172*c2c66affSColin Finck     if (!pInstance)
173*c2c66affSColin Finck     {
174*c2c66affSColin Finck 	goto theEnd;
175*c2c66affSColin Finck     }
176*c2c66affSColin Finck 
177*c2c66affSColin Finck     /* At this point, Client WM_DDE_ACK should have saved hwndServer
178*c2c66affSColin Finck        for this instance id and hwndClient if server responds.
179*c2c66affSColin Finck        So get HCONV and return it. And add it to conv list */
180*c2c66affSColin Finck     pConv = WDML_GetConvFromWnd(hwndClient);
181*c2c66affSColin Finck     if (pConv == NULL || pConv->hwndServer == 0)
182*c2c66affSColin Finck     {
183*c2c66affSColin Finck 	WARN("Done with INITIATE, but no Server window available\n");
184*c2c66affSColin Finck 	pConv = NULL;
185*c2c66affSColin Finck 	pInstance->lastError = DMLERR_NO_CONV_ESTABLISHED;
186*c2c66affSColin Finck 	goto theEnd;
187*c2c66affSColin Finck     }
188*c2c66affSColin Finck     TRACE("Connected to Server window (%p)\n", pConv->hwndServer);
189*c2c66affSColin Finck     pConv->wConvst = XST_CONNECTED;
190*c2c66affSColin Finck 
191*c2c66affSColin Finck     /* finish init of pConv */
192*c2c66affSColin Finck     if (pCC != NULL)
193*c2c66affSColin Finck     {
194*c2c66affSColin Finck 	pConv->convContext = *pCC;
195*c2c66affSColin Finck     }
196*c2c66affSColin Finck     else
197*c2c66affSColin Finck     {
198*c2c66affSColin Finck 	memset(&pConv->convContext, 0, sizeof(pConv->convContext));
199*c2c66affSColin Finck 	pConv->convContext.cb = sizeof(pConv->convContext);
200*c2c66affSColin Finck 	pConv->convContext.iCodePage = (pInstance->unicode) ? CP_WINUNICODE : CP_WINANSI;
201*c2c66affSColin Finck     }
202*c2c66affSColin Finck 
203*c2c66affSColin Finck  theEnd:
204*c2c66affSColin Finck 
205*c2c66affSColin Finck     if (aSrv) GlobalDeleteAtom(aSrv);
206*c2c66affSColin Finck     if (aTpc) GlobalDeleteAtom(aTpc);
207*c2c66affSColin Finck     return (HCONV)pConv;
208*c2c66affSColin Finck }
209*c2c66affSColin Finck 
210*c2c66affSColin Finck /*****************************************************************
211*c2c66affSColin Finck  *            DdeReconnect   (DDEML.37)
212*c2c66affSColin Finck  *            DdeReconnect   (USER32.@)
213*c2c66affSColin Finck  */
214*c2c66affSColin Finck HCONV WINAPI DdeReconnect(HCONV hConv)
215*c2c66affSColin Finck {
216*c2c66affSColin Finck     WDML_CONV*	pConv;
217*c2c66affSColin Finck     WDML_CONV*	pNewConv = NULL;
218*c2c66affSColin Finck     ATOM	aSrv = 0, aTpc = 0;
219*c2c66affSColin Finck 
220*c2c66affSColin Finck     TRACE("(%p)\n", hConv);
221*c2c66affSColin Finck 
222*c2c66affSColin Finck     pConv = WDML_GetConv(hConv, FALSE);
223*c2c66affSColin Finck     if (pConv != NULL && (pConv->wStatus & ST_CLIENT))
224*c2c66affSColin Finck     {
225*c2c66affSColin Finck 	BOOL	ret;
226*c2c66affSColin Finck 
227*c2c66affSColin Finck 	/* to reestablish a connection, we have to make sure that:
228*c2c66affSColin Finck 	 * 1/ pConv is the conversation attached to the client window (it wouldn't be
229*c2c66affSColin Finck 	 *    if a call to DdeReconnect would have already been done...)
230*c2c66affSColin Finck 	 *    FIXME: is this really an error ???
231*c2c66affSColin Finck 	 * 2/ the pConv conversation had really been deconnected
232*c2c66affSColin Finck 	 */
233*c2c66affSColin Finck 	if (pConv == WDML_GetConvFromWnd(pConv->hwndClient) &&
234*c2c66affSColin Finck 	    (pConv->wStatus & ST_TERMINATED) && !(pConv->wStatus & ST_CONNECTED))
235*c2c66affSColin Finck 	{
236*c2c66affSColin Finck 	    HWND	hwndClient = pConv->hwndClient;
237*c2c66affSColin Finck 	    HWND	hwndServer = pConv->hwndServer;
238*c2c66affSColin Finck 
239*c2c66affSColin Finck 	    SetWindowLongPtrW(pConv->hwndClient, GWL_WDML_CONVERSATION, 0);
240*c2c66affSColin Finck 
241*c2c66affSColin Finck 	    aSrv = WDML_MakeAtomFromHsz(pConv->hszService);
242*c2c66affSColin Finck 	    aTpc = WDML_MakeAtomFromHsz(pConv->hszTopic);
243*c2c66affSColin Finck 	    if (!aSrv || !aTpc)	goto theEnd;
244*c2c66affSColin Finck 
245*c2c66affSColin Finck             /* note: sent messages shall not use packing */
246*c2c66affSColin Finck 	    ret = SendMessageW(hwndServer, WM_DDE_INITIATE, (WPARAM)hwndClient,
247*c2c66affSColin Finck                                MAKELPARAM(aSrv, aTpc));
248*c2c66affSColin Finck 
249*c2c66affSColin Finck 	    pConv = WDML_GetConv(hConv, FALSE);
250*c2c66affSColin Finck 	    if (pConv == NULL)
251*c2c66affSColin Finck 	    {
252*c2c66affSColin Finck 		FIXME("Should fail reconnection\n");
253*c2c66affSColin Finck 		goto theEnd;
254*c2c66affSColin Finck 	    }
255*c2c66affSColin Finck 
256*c2c66affSColin Finck 	    if (ret && (pNewConv = WDML_GetConvFromWnd(pConv->hwndClient)) != NULL)
257*c2c66affSColin Finck 	    {
258*c2c66affSColin Finck 		/* re-establish all links... */
259*c2c66affSColin Finck 		WDML_LINK* pLink;
260*c2c66affSColin Finck 
261*c2c66affSColin Finck 		for (pLink = pConv->instance->links[WDML_CLIENT_SIDE]; pLink; pLink = pLink->next)
262*c2c66affSColin Finck 		{
263*c2c66affSColin Finck 		    if (pLink->hConv == hConv)
264*c2c66affSColin Finck 		    {
265*c2c66affSColin Finck 			/* try to reestablish the links... */
266*c2c66affSColin Finck 			DdeClientTransaction(NULL, 0, (HCONV)pNewConv, pLink->hszItem, pLink->uFmt,
267*c2c66affSColin Finck 					     pLink->transactionType, 1000, NULL);
268*c2c66affSColin Finck 		    }
269*c2c66affSColin Finck 		}
270*c2c66affSColin Finck 	    }
271*c2c66affSColin Finck 	    else
272*c2c66affSColin Finck 	    {
273*c2c66affSColin Finck 		/* reset the conversation as it was */
274*c2c66affSColin Finck 		SetWindowLongPtrW(pConv->hwndClient, GWL_WDML_CONVERSATION, (ULONG_PTR)pConv);
275*c2c66affSColin Finck 	    }
276*c2c66affSColin Finck 	}
277*c2c66affSColin Finck     }
278*c2c66affSColin Finck 
279*c2c66affSColin Finck  theEnd:
280*c2c66affSColin Finck 
281*c2c66affSColin Finck     if (aSrv) GlobalDeleteAtom(aSrv);
282*c2c66affSColin Finck     if (aTpc) GlobalDeleteAtom(aTpc);
283*c2c66affSColin Finck     return (HCONV)pNewConv;
284*c2c66affSColin Finck }
285*c2c66affSColin Finck 
286*c2c66affSColin Finck /******************************************************************
287*c2c66affSColin Finck  *		WDML_ClientQueueAdvise
288*c2c66affSColin Finck  *
289*c2c66affSColin Finck  * Creates and queue an WM_DDE_ADVISE transaction
290*c2c66affSColin Finck  */
291*c2c66affSColin Finck static WDML_XACT*	WDML_ClientQueueAdvise(WDML_CONV* pConv, UINT wType, UINT wFmt, HSZ hszItem)
292*c2c66affSColin Finck {
293*c2c66affSColin Finck     DDEADVISE*		pDdeAdvise;
294*c2c66affSColin Finck     WDML_XACT*		pXAct;
295*c2c66affSColin Finck     ATOM		atom;
296*c2c66affSColin Finck 
297*c2c66affSColin Finck     TRACE("XTYP_ADVSTART (with%s data) transaction\n", (wType & XTYPF_NODATA) ? "out" : "");
298*c2c66affSColin Finck 
299*c2c66affSColin Finck     atom = WDML_MakeAtomFromHsz(hszItem);
300*c2c66affSColin Finck     if (!atom) return NULL;
301*c2c66affSColin Finck 
302*c2c66affSColin Finck     pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_ADVISE, wFmt, hszItem);
303*c2c66affSColin Finck     if (!pXAct)
304*c2c66affSColin Finck     {
305*c2c66affSColin Finck 	GlobalDeleteAtom(atom);
306*c2c66affSColin Finck 	return NULL;
307*c2c66affSColin Finck     }
308*c2c66affSColin Finck 
309*c2c66affSColin Finck     pXAct->wType = wType & ~0x0F;
310*c2c66affSColin Finck     pXAct->hMem = GlobalAlloc(GHND | GMEM_DDESHARE, sizeof(DDEADVISE));
311*c2c66affSColin Finck     /* FIXME: hMem is unfreed for now... should be deleted in server */
312*c2c66affSColin Finck 
313*c2c66affSColin Finck     /* pack DdeAdvise	*/
314*c2c66affSColin Finck     pDdeAdvise = GlobalLock(pXAct->hMem);
315*c2c66affSColin Finck     pDdeAdvise->fAckReq   = (wType & XTYPF_ACKREQ) != 0;
316*c2c66affSColin Finck     pDdeAdvise->fDeferUpd = (wType & XTYPF_NODATA) != 0;
317*c2c66affSColin Finck     pDdeAdvise->cfFormat  = wFmt;
318*c2c66affSColin Finck     GlobalUnlock(pXAct->hMem);
319*c2c66affSColin Finck 
320*c2c66affSColin Finck     pXAct->lParam = PackDDElParam(WM_DDE_ADVISE, (UINT_PTR)pXAct->hMem, atom);
321*c2c66affSColin Finck 
322*c2c66affSColin Finck     return pXAct;
323*c2c66affSColin Finck }
324*c2c66affSColin Finck 
325*c2c66affSColin Finck /******************************************************************
326*c2c66affSColin Finck  *		WDML_HandleAdviseReply
327*c2c66affSColin Finck  *
328*c2c66affSColin Finck  * handles the reply to an advise request
329*c2c66affSColin Finck  */
330*c2c66affSColin Finck static WDML_QUEUE_STATE WDML_HandleAdviseReply(WDML_CONV* pConv, MSG* msg, WDML_XACT* pXAct, DWORD *ack)
331*c2c66affSColin Finck {
332*c2c66affSColin Finck     DDEACK		ddeAck;
333*c2c66affSColin Finck     UINT_PTR		uiLo, uiHi;
334*c2c66affSColin Finck     HSZ			hsz;
335*c2c66affSColin Finck 
336*c2c66affSColin Finck     if (msg->message != WM_DDE_ACK || WIN_GetFullHandle((HWND)msg->wParam) != pConv->hwndServer)
337*c2c66affSColin Finck     {
338*c2c66affSColin Finck 	return WDML_QS_PASS;
339*c2c66affSColin Finck     }
340*c2c66affSColin Finck 
341*c2c66affSColin Finck     UnpackDDElParam(WM_DDE_ACK, msg->lParam, &uiLo, &uiHi);
342*c2c66affSColin Finck     hsz = WDML_MakeHszFromAtom(pConv->instance, uiHi);
343*c2c66affSColin Finck 
344*c2c66affSColin Finck     if (DdeCmpStringHandles(hsz, pXAct->hszItem) != 0)
345*c2c66affSColin Finck 	return WDML_QS_PASS;
346*c2c66affSColin Finck 
347*c2c66affSColin Finck     GlobalDeleteAtom(uiHi);
348*c2c66affSColin Finck     FreeDDElParam(WM_DDE_ACK, msg->lParam);
349*c2c66affSColin Finck 
350*c2c66affSColin Finck     if (ack) *ack = uiLo;
351*c2c66affSColin Finck     WDML_ExtractAck(uiLo, &ddeAck);
352*c2c66affSColin Finck 
353*c2c66affSColin Finck     if (ddeAck.fAck)
354*c2c66affSColin Finck     {
355*c2c66affSColin Finck 	WDML_LINK*	pLink;
356*c2c66affSColin Finck 
357*c2c66affSColin Finck 	/* billx: first to see if the link is already created. */
358*c2c66affSColin Finck 	pLink = WDML_FindLink(pConv->instance, (HCONV)pConv, WDML_CLIENT_SIDE,
359*c2c66affSColin Finck 			      pXAct->hszItem, TRUE, pXAct->wFmt);
360*c2c66affSColin Finck 	if (pLink != NULL)
361*c2c66affSColin Finck 	{
362*c2c66affSColin Finck 	    /* we found a link, and only need to modify it in case it changes */
363*c2c66affSColin Finck 	    pLink->transactionType = pXAct->wType;
364*c2c66affSColin Finck 	}
365*c2c66affSColin Finck 	else
366*c2c66affSColin Finck 	{
367*c2c66affSColin Finck 	    WDML_AddLink(pConv->instance, (HCONV)pConv, WDML_CLIENT_SIDE,
368*c2c66affSColin Finck 			 pXAct->wType, pXAct->hszItem, pXAct->wFmt);
369*c2c66affSColin Finck 	}
370*c2c66affSColin Finck         pXAct->hDdeData = (HDDEDATA)1;
371*c2c66affSColin Finck     }
372*c2c66affSColin Finck     else
373*c2c66affSColin Finck     {
374*c2c66affSColin Finck 	TRACE("Returning FALSE on XTYP_ADVSTART - fAck was FALSE\n");
375*c2c66affSColin Finck 	GlobalFree(pXAct->hMem);
376*c2c66affSColin Finck         pXAct->hDdeData = NULL;
377*c2c66affSColin Finck     }
378*c2c66affSColin Finck 
379*c2c66affSColin Finck     return WDML_QS_HANDLED;
380*c2c66affSColin Finck }
381*c2c66affSColin Finck 
382*c2c66affSColin Finck /******************************************************************
383*c2c66affSColin Finck  *		WDML_ClientQueueUnadvise
384*c2c66affSColin Finck  *
385*c2c66affSColin Finck  * queues an unadvise transaction
386*c2c66affSColin Finck  */
387*c2c66affSColin Finck static WDML_XACT*	WDML_ClientQueueUnadvise(WDML_CONV* pConv, UINT wFmt, HSZ hszItem)
388*c2c66affSColin Finck {
389*c2c66affSColin Finck     WDML_XACT*	pXAct;
390*c2c66affSColin Finck     ATOM	atom;
391*c2c66affSColin Finck 
392*c2c66affSColin Finck     TRACE("XTYP_ADVSTOP transaction\n");
393*c2c66affSColin Finck 
394*c2c66affSColin Finck     atom = WDML_MakeAtomFromHsz(hszItem);
395*c2c66affSColin Finck     if (!atom) return NULL;
396*c2c66affSColin Finck 
397*c2c66affSColin Finck     pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_UNADVISE, wFmt, hszItem);
398*c2c66affSColin Finck     if (!pXAct)
399*c2c66affSColin Finck     {
400*c2c66affSColin Finck 	GlobalDeleteAtom(atom);
401*c2c66affSColin Finck 	return NULL;
402*c2c66affSColin Finck     }
403*c2c66affSColin Finck 
404*c2c66affSColin Finck     /* end advise loop: post WM_DDE_UNADVISE to server to terminate link
405*c2c66affSColin Finck      * on the specified item.
406*c2c66affSColin Finck      */
407*c2c66affSColin Finck     pXAct->lParam = PackDDElParam(WM_DDE_UNADVISE, wFmt, atom);
408*c2c66affSColin Finck     return pXAct;
409*c2c66affSColin Finck }
410*c2c66affSColin Finck 
411*c2c66affSColin Finck /******************************************************************
412*c2c66affSColin Finck  *		WDML_HandleUnadviseReply
413*c2c66affSColin Finck  *
414*c2c66affSColin Finck  *
415*c2c66affSColin Finck  */
416*c2c66affSColin Finck static WDML_QUEUE_STATE WDML_HandleUnadviseReply(WDML_CONV* pConv, MSG* msg, WDML_XACT* pXAct, DWORD *ack)
417*c2c66affSColin Finck {
418*c2c66affSColin Finck     DDEACK	ddeAck;
419*c2c66affSColin Finck     UINT_PTR	uiLo, uiHi;
420*c2c66affSColin Finck     HSZ		hsz;
421*c2c66affSColin Finck 
422*c2c66affSColin Finck     if (msg->message != WM_DDE_ACK || WIN_GetFullHandle((HWND)msg->wParam) != pConv->hwndServer)
423*c2c66affSColin Finck     {
424*c2c66affSColin Finck 	return WDML_QS_PASS;
425*c2c66affSColin Finck     }
426*c2c66affSColin Finck 
427*c2c66affSColin Finck     UnpackDDElParam(WM_DDE_ACK, msg->lParam, &uiLo, &uiHi);
428*c2c66affSColin Finck     hsz = WDML_MakeHszFromAtom(pConv->instance, uiHi);
429*c2c66affSColin Finck 
430*c2c66affSColin Finck     if (DdeCmpStringHandles(hsz, pXAct->hszItem) != 0)
431*c2c66affSColin Finck 	return WDML_QS_PASS;
432*c2c66affSColin Finck 
433*c2c66affSColin Finck     FreeDDElParam(WM_DDE_ACK, msg->lParam);
434*c2c66affSColin Finck     GlobalDeleteAtom(uiHi);
435*c2c66affSColin Finck 
436*c2c66affSColin Finck     if (ack) *ack = uiLo;
437*c2c66affSColin Finck     WDML_ExtractAck(uiLo, &ddeAck);
438*c2c66affSColin Finck 
439*c2c66affSColin Finck     TRACE("WM_DDE_ACK received while waiting for a timeout\n");
440*c2c66affSColin Finck 
441*c2c66affSColin Finck     if (!ddeAck.fAck)
442*c2c66affSColin Finck     {
443*c2c66affSColin Finck 	TRACE("Returning FALSE on XTYP_ADVSTOP - fAck was FALSE\n");
444*c2c66affSColin Finck         pXAct->hDdeData = NULL;
445*c2c66affSColin Finck     }
446*c2c66affSColin Finck     else
447*c2c66affSColin Finck     {
448*c2c66affSColin Finck 	/* billx: remove the link */
449*c2c66affSColin Finck 	WDML_RemoveLink(pConv->instance, (HCONV)pConv, WDML_CLIENT_SIDE,
450*c2c66affSColin Finck 			pXAct->hszItem, pXAct->wFmt);
451*c2c66affSColin Finck         pXAct->hDdeData = (HDDEDATA)1;
452*c2c66affSColin Finck     }
453*c2c66affSColin Finck     return WDML_QS_HANDLED;
454*c2c66affSColin Finck }
455*c2c66affSColin Finck 
456*c2c66affSColin Finck /******************************************************************
457*c2c66affSColin Finck  *		WDML_ClientQueueRequest
458*c2c66affSColin Finck  *
459*c2c66affSColin Finck  *
460*c2c66affSColin Finck  */
461*c2c66affSColin Finck static WDML_XACT*	WDML_ClientQueueRequest(WDML_CONV* pConv, UINT wFmt, HSZ hszItem)
462*c2c66affSColin Finck {
463*c2c66affSColin Finck     WDML_XACT*	pXAct;
464*c2c66affSColin Finck     ATOM	atom;
465*c2c66affSColin Finck 
466*c2c66affSColin Finck     TRACE("XTYP_REQUEST transaction\n");
467*c2c66affSColin Finck 
468*c2c66affSColin Finck     atom = WDML_MakeAtomFromHsz(hszItem);
469*c2c66affSColin Finck     if (!atom) return NULL;
470*c2c66affSColin Finck 
471*c2c66affSColin Finck     pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_REQUEST, wFmt, hszItem);
472*c2c66affSColin Finck     if (!pXAct)
473*c2c66affSColin Finck     {
474*c2c66affSColin Finck 	GlobalDeleteAtom(atom);
475*c2c66affSColin Finck 	return NULL;
476*c2c66affSColin Finck     }
477*c2c66affSColin Finck 
478*c2c66affSColin Finck     pXAct->lParam = PackDDElParam(WM_DDE_REQUEST, wFmt, atom);
479*c2c66affSColin Finck 
480*c2c66affSColin Finck     return pXAct;
481*c2c66affSColin Finck }
482*c2c66affSColin Finck 
483*c2c66affSColin Finck /******************************************************************
484*c2c66affSColin Finck  *		WDML_HandleRequestReply
485*c2c66affSColin Finck  *
486*c2c66affSColin Finck  *
487*c2c66affSColin Finck  */
488*c2c66affSColin Finck static WDML_QUEUE_STATE WDML_HandleRequestReply(WDML_CONV* pConv, MSG* msg, WDML_XACT* pXAct, DWORD *ack)
489*c2c66affSColin Finck {
490*c2c66affSColin Finck     DDEACK		ddeAck;
491*c2c66affSColin Finck     WINE_DDEHEAD	wdh;
492*c2c66affSColin Finck     UINT_PTR		uiLo, uiHi;
493*c2c66affSColin Finck     HSZ			hsz;
494*c2c66affSColin Finck 
495*c2c66affSColin Finck     if (WIN_GetFullHandle((HWND)msg->wParam) != pConv->hwndServer)
496*c2c66affSColin Finck 	return WDML_QS_PASS;
497*c2c66affSColin Finck 
498*c2c66affSColin Finck     switch (msg->message)
499*c2c66affSColin Finck     {
500*c2c66affSColin Finck     case WM_DDE_ACK:
501*c2c66affSColin Finck         UnpackDDElParam(WM_DDE_ACK, msg->lParam, &uiLo, &uiHi);
502*c2c66affSColin Finck         FreeDDElParam(WM_DDE_ACK, msg->lParam);
503*c2c66affSColin Finck 	GlobalDeleteAtom(uiHi);
504*c2c66affSColin Finck        if (ack) *ack = uiLo;
505*c2c66affSColin Finck 	WDML_ExtractAck(uiLo, &ddeAck);
506*c2c66affSColin Finck 	pXAct->hDdeData = 0;
507*c2c66affSColin Finck 	if (ddeAck.fAck)
508*c2c66affSColin Finck 	    ERR("Positive answer should appear in NACK for a request, assuming negative\n");
509*c2c66affSColin Finck 	TRACE("Negative answer...\n");
510*c2c66affSColin Finck 	break;
511*c2c66affSColin Finck 
512*c2c66affSColin Finck     case WM_DDE_DATA:
513*c2c66affSColin Finck         UnpackDDElParam(WM_DDE_DATA, msg->lParam, &uiLo, &uiHi);
514*c2c66affSColin Finck 	TRACE("Got the result (%08lx)\n", uiLo);
515*c2c66affSColin Finck 
516*c2c66affSColin Finck 	hsz = WDML_MakeHszFromAtom(pConv->instance, uiHi);
517*c2c66affSColin Finck 
518*c2c66affSColin Finck 	if (DdeCmpStringHandles(hsz, pXAct->hszItem) != 0)
519*c2c66affSColin Finck 	    return WDML_QS_PASS;
520*c2c66affSColin Finck 
521*c2c66affSColin Finck 	pXAct->hDdeData = WDML_Global2DataHandle(pConv, (HGLOBAL)uiLo, &wdh);
522*c2c66affSColin Finck 	if (wdh.fRelease)
523*c2c66affSColin Finck 	{
524*c2c66affSColin Finck 	    GlobalFree((HGLOBAL)uiLo);
525*c2c66affSColin Finck 	}
526*c2c66affSColin Finck 	if (wdh.fAckReq)
527*c2c66affSColin Finck 	{
528*c2c66affSColin Finck 	    pConv->instance->lastError = DMLERR_MEMORY_ERROR;
529*c2c66affSColin Finck 	}
530*c2c66affSColin Finck 	else
531*c2c66affSColin Finck 	{
532*c2c66affSColin Finck 	    GlobalDeleteAtom(uiHi);
533*c2c66affSColin Finck             FreeDDElParam(WM_DDE_ACK, msg->lParam);
534*c2c66affSColin Finck 	}
535*c2c66affSColin Finck 	break;
536*c2c66affSColin Finck 
537*c2c66affSColin Finck     default:
538*c2c66affSColin Finck         FreeDDElParam(msg->message, msg->lParam);
539*c2c66affSColin Finck 	return WDML_QS_PASS;
540*c2c66affSColin Finck     }
541*c2c66affSColin Finck 
542*c2c66affSColin Finck     return WDML_QS_HANDLED;
543*c2c66affSColin Finck }
544*c2c66affSColin Finck 
545*c2c66affSColin Finck /******************************************************************
546*c2c66affSColin Finck  *		WDML_BuildExecuteCommand
547*c2c66affSColin Finck  *
548*c2c66affSColin Finck  * Creates a DDE block suitable for sending in WM_DDE_COMMAND
549*c2c66affSColin Finck  * It also takes care of string conversion between the two window procedures
550*c2c66affSColin Finck  */
551*c2c66affSColin Finck static	HGLOBAL	WDML_BuildExecuteCommand(WDML_CONV* pConv, LPCVOID pData, DWORD cbData)
552*c2c66affSColin Finck {
553*c2c66affSColin Finck     HGLOBAL	hMem;
554*c2c66affSColin Finck     BOOL	clientUnicode, serverUnicode;
555*c2c66affSColin Finck     DWORD	memSize;
556*c2c66affSColin Finck 
557*c2c66affSColin Finck     clientUnicode = pConv->instance->unicode;
558*c2c66affSColin Finck     TRACE("client %p uses unicode = %d\n", pConv->hwndClient, clientUnicode);
559*c2c66affSColin Finck     /* FIXME: how exactly Windows determines what to use for the server side? */
560*c2c66affSColin Finck     serverUnicode = IsWindowUnicode(pConv->hwndServer) && IsWindowUnicode(pConv->hwndClient);
561*c2c66affSColin Finck     TRACE("server %p uses unicode = %d\n", pConv->hwndServer, serverUnicode);
562*c2c66affSColin Finck 
563*c2c66affSColin Finck     if (clientUnicode == serverUnicode)
564*c2c66affSColin Finck     {
565*c2c66affSColin Finck 	memSize = cbData;
566*c2c66affSColin Finck     }
567*c2c66affSColin Finck     else
568*c2c66affSColin Finck     {
569*c2c66affSColin Finck 	if (clientUnicode)
570*c2c66affSColin Finck 	{
571*c2c66affSColin Finck 	    memSize = WideCharToMultiByte( CP_ACP, 0, pData, cbData / sizeof(WCHAR), NULL, 0, NULL, NULL);
572*c2c66affSColin Finck 	}
573*c2c66affSColin Finck 	else
574*c2c66affSColin Finck 	{
575*c2c66affSColin Finck 	    memSize = MultiByteToWideChar( CP_ACP, 0, pData, cbData, NULL, 0) * sizeof(WCHAR);
576*c2c66affSColin Finck 	}
577*c2c66affSColin Finck     }
578*c2c66affSColin Finck 
579*c2c66affSColin Finck     hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, memSize);
580*c2c66affSColin Finck 
581*c2c66affSColin Finck     if (hMem)
582*c2c66affSColin Finck     {
583*c2c66affSColin Finck 	LPSTR	pDst;
584*c2c66affSColin Finck 
585*c2c66affSColin Finck 	pDst = GlobalLock(hMem);
586*c2c66affSColin Finck 	if (pDst)
587*c2c66affSColin Finck 	{
588*c2c66affSColin Finck 	    if (clientUnicode == serverUnicode)
589*c2c66affSColin Finck 	    {
590*c2c66affSColin Finck 		memcpy(pDst, pData, cbData);
591*c2c66affSColin Finck 	    }
592*c2c66affSColin Finck 	    else
593*c2c66affSColin Finck 	    {
594*c2c66affSColin Finck 		if (clientUnicode)
595*c2c66affSColin Finck 		{
596*c2c66affSColin Finck 		    WideCharToMultiByte( CP_ACP, 0, pData, cbData / sizeof(WCHAR), pDst, memSize, NULL, NULL);
597*c2c66affSColin Finck 		}
598*c2c66affSColin Finck 		else
599*c2c66affSColin Finck 		{
600*c2c66affSColin Finck 		    MultiByteToWideChar( CP_ACP, 0, pData, cbData, (LPWSTR)pDst, memSize/sizeof(WCHAR));
601*c2c66affSColin Finck 		}
602*c2c66affSColin Finck 	    }
603*c2c66affSColin Finck 
604*c2c66affSColin Finck 	    GlobalUnlock(hMem);
605*c2c66affSColin Finck 	}
606*c2c66affSColin Finck 	else
607*c2c66affSColin Finck 	{
608*c2c66affSColin Finck 	    GlobalFree(hMem);
609*c2c66affSColin Finck 	    hMem = 0;
610*c2c66affSColin Finck 	}
611*c2c66affSColin Finck     }
612*c2c66affSColin Finck     return hMem;
613*c2c66affSColin Finck }
614*c2c66affSColin Finck 
615*c2c66affSColin Finck /******************************************************************
616*c2c66affSColin Finck  *		WDML_ClientQueueExecute
617*c2c66affSColin Finck  *
618*c2c66affSColin Finck  *
619*c2c66affSColin Finck  */
620*c2c66affSColin Finck static WDML_XACT*	WDML_ClientQueueExecute(WDML_CONV* pConv, LPVOID pData, DWORD cbData)
621*c2c66affSColin Finck {
622*c2c66affSColin Finck     WDML_XACT*	pXAct;
623*c2c66affSColin Finck 
624*c2c66affSColin Finck     TRACE("XTYP_EXECUTE transaction\n");
625*c2c66affSColin Finck 
626*c2c66affSColin Finck     if (pData == NULL)
627*c2c66affSColin Finck     {
628*c2c66affSColin Finck         if (cbData == (DWORD)-1)
629*c2c66affSColin Finck             pConv->instance->lastError = DMLERR_INVALIDPARAMETER;
630*c2c66affSColin Finck         else
631*c2c66affSColin Finck             pConv->instance->lastError = DMLERR_MEMORY_ERROR;
632*c2c66affSColin Finck         return NULL;
633*c2c66affSColin Finck     }
634*c2c66affSColin Finck 
635*c2c66affSColin Finck     pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_EXECUTE, 0, 0);
636*c2c66affSColin Finck     if (!pXAct)
637*c2c66affSColin Finck 	return NULL;
638*c2c66affSColin Finck 
639*c2c66affSColin Finck     if (cbData == (DWORD)-1)
640*c2c66affSColin Finck     {
641*c2c66affSColin Finck 	HDDEDATA	hDdeData = pData;
642*c2c66affSColin Finck 
643*c2c66affSColin Finck 	pData = DdeAccessData(hDdeData, &cbData);
644*c2c66affSColin Finck 	if (pData)
645*c2c66affSColin Finck 	{
646*c2c66affSColin Finck 	    pXAct->hMem = WDML_BuildExecuteCommand(pConv, pData, cbData);
647*c2c66affSColin Finck 	    DdeUnaccessData(hDdeData);
648*c2c66affSColin Finck 	}
649*c2c66affSColin Finck     }
650*c2c66affSColin Finck     else
651*c2c66affSColin Finck     {
652*c2c66affSColin Finck 	pXAct->hMem = WDML_BuildExecuteCommand(pConv, pData, cbData);
653*c2c66affSColin Finck     }
654*c2c66affSColin Finck 
655*c2c66affSColin Finck     pXAct->lParam = (LPARAM)pXAct->hMem;
656*c2c66affSColin Finck 
657*c2c66affSColin Finck     return pXAct;
658*c2c66affSColin Finck }
659*c2c66affSColin Finck 
660*c2c66affSColin Finck /******************************************************************
661*c2c66affSColin Finck  *		WDML_HandleExecuteReply
662*c2c66affSColin Finck  *
663*c2c66affSColin Finck  *
664*c2c66affSColin Finck  */
665*c2c66affSColin Finck static WDML_QUEUE_STATE WDML_HandleExecuteReply(WDML_CONV* pConv, MSG* msg, WDML_XACT* pXAct, DWORD *ack)
666*c2c66affSColin Finck {
667*c2c66affSColin Finck     DDEACK	ddeAck;
668*c2c66affSColin Finck     UINT_PTR	uiLo, uiHi;
669*c2c66affSColin Finck 
670*c2c66affSColin Finck     if (msg->message != WM_DDE_ACK || WIN_GetFullHandle((HWND)msg->wParam) != pConv->hwndServer)
671*c2c66affSColin Finck     {
672*c2c66affSColin Finck 	return WDML_QS_PASS;
673*c2c66affSColin Finck     }
674*c2c66affSColin Finck 
675*c2c66affSColin Finck     UnpackDDElParam(WM_DDE_ACK, msg->lParam, &uiLo, &uiHi);
676*c2c66affSColin Finck     FreeDDElParam(WM_DDE_ACK, msg->lParam);
677*c2c66affSColin Finck 
678*c2c66affSColin Finck     if ((HANDLE)uiHi != pXAct->hMem)
679*c2c66affSColin Finck     {
680*c2c66affSColin Finck         return WDML_QS_PASS;
681*c2c66affSColin Finck     }
682*c2c66affSColin Finck 
683*c2c66affSColin Finck     if (ack) *ack = uiLo;
684*c2c66affSColin Finck     WDML_ExtractAck(uiLo, &ddeAck);
685*c2c66affSColin Finck     pXAct->hDdeData = (HDDEDATA)(UINT_PTR)ddeAck.fAck;
686*c2c66affSColin Finck 
687*c2c66affSColin Finck     TRACE("hDdeData = %p\n", pXAct->hDdeData);
688*c2c66affSColin Finck     pConv->instance->lastError = (pXAct->hDdeData != 0) ? DMLERR_NO_ERROR : DMLERR_NOTPROCESSED;
689*c2c66affSColin Finck 
690*c2c66affSColin Finck     return WDML_QS_HANDLED;
691*c2c66affSColin Finck }
692*c2c66affSColin Finck 
693*c2c66affSColin Finck /******************************************************************
694*c2c66affSColin Finck  *		WDML_ClientQueuePoke
695*c2c66affSColin Finck  *
696*c2c66affSColin Finck  *
697*c2c66affSColin Finck  */
698*c2c66affSColin Finck static WDML_XACT*	WDML_ClientQueuePoke(WDML_CONV* pConv, LPVOID pData, DWORD cbData,
699*c2c66affSColin Finck 					     UINT wFmt, HSZ hszItem)
700*c2c66affSColin Finck {
701*c2c66affSColin Finck     DDE_DATAHANDLE_HEAD *dh;
702*c2c66affSColin Finck     WDML_XACT *pXAct;
703*c2c66affSColin Finck     DDEPOKE *ddePoke;
704*c2c66affSColin Finck     HGLOBAL hglobal;
705*c2c66affSColin Finck     ATOM atom;
706*c2c66affSColin Finck 
707*c2c66affSColin Finck     TRACE("XTYP_POKE transaction\n");
708*c2c66affSColin Finck 
709*c2c66affSColin Finck     atom = WDML_MakeAtomFromHsz(hszItem);
710*c2c66affSColin Finck     if (!atom) return NULL;
711*c2c66affSColin Finck 
712*c2c66affSColin Finck     pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_POKE, wFmt, hszItem);
713*c2c66affSColin Finck     if (!pXAct)
714*c2c66affSColin Finck     {
715*c2c66affSColin Finck         GlobalDeleteAtom(atom);
716*c2c66affSColin Finck         return NULL;
717*c2c66affSColin Finck     }
718*c2c66affSColin Finck 
719*c2c66affSColin Finck     if (cbData == (DWORD)-1)
720*c2c66affSColin Finck     {
721*c2c66affSColin Finck         hglobal = pData;
722*c2c66affSColin Finck         dh = GlobalLock(hglobal);
723*c2c66affSColin Finck         cbData = GlobalSize(hglobal) - sizeof(DDE_DATAHANDLE_HEAD);
724*c2c66affSColin Finck         pData = dh + 1;
725*c2c66affSColin Finck         GlobalUnlock(hglobal);
726*c2c66affSColin Finck     }
727*c2c66affSColin Finck 
728*c2c66affSColin Finck     pXAct->hMem = GlobalAlloc(GHND | GMEM_DDESHARE, FIELD_OFFSET(DDEPOKE, Value[cbData]));
729*c2c66affSColin Finck     ddePoke = GlobalLock(pXAct->hMem);
730*c2c66affSColin Finck     if (!ddePoke)
731*c2c66affSColin Finck     {
732*c2c66affSColin Finck         pConv->instance->lastError = DMLERR_MEMORY_ERROR;
733*c2c66affSColin Finck         return NULL;
734*c2c66affSColin Finck     }
735*c2c66affSColin Finck 
736*c2c66affSColin Finck     ddePoke->unused = 0;
737*c2c66affSColin Finck     ddePoke->fRelease = TRUE;
738*c2c66affSColin Finck     ddePoke->cfFormat = wFmt;
739*c2c66affSColin Finck     memcpy(ddePoke->Value, pData, cbData);
740*c2c66affSColin Finck     GlobalUnlock(pXAct->hMem);
741*c2c66affSColin Finck 
742*c2c66affSColin Finck     pXAct->lParam = PackDDElParam(WM_DDE_POKE, (UINT_PTR)pXAct->hMem, atom);
743*c2c66affSColin Finck 
744*c2c66affSColin Finck     return pXAct;
745*c2c66affSColin Finck }
746*c2c66affSColin Finck 
747*c2c66affSColin Finck /******************************************************************
748*c2c66affSColin Finck  *		WDML_HandlePokeReply
749*c2c66affSColin Finck  *
750*c2c66affSColin Finck  *
751*c2c66affSColin Finck  */
752*c2c66affSColin Finck static WDML_QUEUE_STATE WDML_HandlePokeReply(WDML_CONV* pConv, MSG* msg, WDML_XACT* pXAct, DWORD *ack)
753*c2c66affSColin Finck {
754*c2c66affSColin Finck     UINT_PTR	uiLo, uiHi;
755*c2c66affSColin Finck     HSZ		hsz;
756*c2c66affSColin Finck 
757*c2c66affSColin Finck     if (msg->message != WM_DDE_ACK && WIN_GetFullHandle((HWND)msg->wParam) != pConv->hwndServer)
758*c2c66affSColin Finck     {
759*c2c66affSColin Finck 	return WDML_QS_PASS;
760*c2c66affSColin Finck     }
761*c2c66affSColin Finck 
762*c2c66affSColin Finck     UnpackDDElParam(WM_DDE_ACK, msg->lParam, &uiLo, &uiHi);
763*c2c66affSColin Finck     hsz = WDML_MakeHszFromAtom(pConv->instance, uiHi);
764*c2c66affSColin Finck     if (DdeCmpStringHandles(hsz, pXAct->hszItem) != 0)
765*c2c66affSColin Finck     {
766*c2c66affSColin Finck 	return WDML_QS_PASS;
767*c2c66affSColin Finck     }
768*c2c66affSColin Finck     FreeDDElParam(WM_DDE_ACK, msg->lParam);
769*c2c66affSColin Finck     GlobalDeleteAtom(uiHi);
770*c2c66affSColin Finck 
771*c2c66affSColin Finck     if (ack) *ack = uiLo;
772*c2c66affSColin Finck     pXAct->hMem = GlobalFree(pXAct->hMem);
773*c2c66affSColin Finck 
774*c2c66affSColin Finck     pXAct->hDdeData = (HDDEDATA)TRUE;
775*c2c66affSColin Finck     return TRUE;
776*c2c66affSColin Finck }
777*c2c66affSColin Finck 
778*c2c66affSColin Finck /******************************************************************
779*c2c66affSColin Finck  *		WDML_ClientQueueTerminate
780*c2c66affSColin Finck  *
781*c2c66affSColin Finck  * Creates and queue an WM_DDE_TERMINATE transaction
782*c2c66affSColin Finck  */
783*c2c66affSColin Finck static WDML_XACT*	WDML_ClientQueueTerminate(WDML_CONV* pConv)
784*c2c66affSColin Finck {
785*c2c66affSColin Finck     WDML_XACT*		pXAct;
786*c2c66affSColin Finck 
787*c2c66affSColin Finck     pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_TERMINATE, 0, 0);
788*c2c66affSColin Finck     if (!pXAct)
789*c2c66affSColin Finck 	return NULL;
790*c2c66affSColin Finck 
791*c2c66affSColin Finck     pXAct->lParam = 0;
792*c2c66affSColin Finck     pConv->wStatus &= ~ST_CONNECTED;
793*c2c66affSColin Finck 
794*c2c66affSColin Finck     return pXAct;
795*c2c66affSColin Finck }
796*c2c66affSColin Finck 
797*c2c66affSColin Finck /******************************************************************
798*c2c66affSColin Finck  *		WDML_HandleTerminateReply
799*c2c66affSColin Finck  *
800*c2c66affSColin Finck  * handles the reply to a terminate request
801*c2c66affSColin Finck  */
802*c2c66affSColin Finck static WDML_QUEUE_STATE WDML_HandleTerminateReply(WDML_CONV* pConv, MSG* msg)
803*c2c66affSColin Finck {
804*c2c66affSColin Finck     if (msg->message != WM_DDE_TERMINATE)
805*c2c66affSColin Finck     {
806*c2c66affSColin Finck 	/* FIXME: should delete data passed here */
807*c2c66affSColin Finck 	return WDML_QS_SWALLOWED;
808*c2c66affSColin Finck     }
809*c2c66affSColin Finck 
810*c2c66affSColin Finck     if (WIN_GetFullHandle((HWND)msg->wParam) != pConv->hwndServer)
811*c2c66affSColin Finck     {
812*c2c66affSColin Finck 	FIXME("hmmm shouldn't happen\n");
813*c2c66affSColin Finck 	return WDML_QS_PASS;
814*c2c66affSColin Finck     }
815*c2c66affSColin Finck     if (!(pConv->instance->CBFflags & CBF_SKIP_DISCONNECTS))
816*c2c66affSColin Finck     {
817*c2c66affSColin Finck 	WDML_InvokeCallback(pConv->instance, XTYP_DISCONNECT, 0, (HCONV)pConv,
818*c2c66affSColin Finck 			    0, 0, 0, 0, (pConv->wStatus & ST_ISSELF) ? 1 : 0);
819*c2c66affSColin Finck     }
820*c2c66affSColin Finck     WDML_RemoveConv(pConv, WDML_CLIENT_SIDE);
821*c2c66affSColin Finck     return WDML_QS_HANDLED;
822*c2c66affSColin Finck }
823*c2c66affSColin Finck 
824*c2c66affSColin Finck /******************************************************************
825*c2c66affSColin Finck  *		WDML_HandleIncomingData
826*c2c66affSColin Finck  *
827*c2c66affSColin Finck  *
828*c2c66affSColin Finck  */
829*c2c66affSColin Finck static WDML_QUEUE_STATE WDML_HandleIncomingData(WDML_CONV* pConv, MSG* msg, HDDEDATA* hdd)
830*c2c66affSColin Finck {
831*c2c66affSColin Finck     UINT_PTR		uiLo, uiHi;
832*c2c66affSColin Finck     HDDEDATA		hDdeDataIn, hDdeDataOut;
833*c2c66affSColin Finck     WDML_LINK*		pLink;
834*c2c66affSColin Finck     WINE_DDEHEAD	wdh;
835*c2c66affSColin Finck     HSZ			hsz;
836*c2c66affSColin Finck 
837*c2c66affSColin Finck     TRACE("WM_DDE_DATA message received in the Client Proc!\n");
838*c2c66affSColin Finck     /* wParam -- sending window handle	*/
839*c2c66affSColin Finck     /* lParam -- hDdeData & item HSZ	*/
840*c2c66affSColin Finck 
841*c2c66affSColin Finck     UnpackDDElParam(WM_DDE_DATA, msg->lParam, &uiLo, &uiHi);
842*c2c66affSColin Finck     hsz = WDML_MakeHszFromAtom(pConv->instance, uiHi);
843*c2c66affSColin Finck 
844*c2c66affSColin Finck     hDdeDataIn = WDML_Global2DataHandle(pConv, (HGLOBAL)uiLo, &wdh);
845*c2c66affSColin Finck 
846*c2c66affSColin Finck     /* billx:
847*c2c66affSColin Finck      *  For hot link, data should be passed to its callback with
848*c2c66affSColin Finck      * XTYP_ADVDATA and callback should return the proper status.
849*c2c66affSColin Finck      */
850*c2c66affSColin Finck     pLink = WDML_FindLink(pConv->instance, (HCONV)pConv, WDML_CLIENT_SIDE, hsz,
851*c2c66affSColin Finck                           uiLo != 0, wdh.cfFormat);
852*c2c66affSColin Finck     if (!pLink)
853*c2c66affSColin Finck     {
854*c2c66affSColin Finck 	WDML_DecHSZ(pConv->instance, hsz);
855*c2c66affSColin Finck         DdeFreeDataHandle(hDdeDataIn);
856*c2c66affSColin Finck 	return WDML_QS_PASS;
857*c2c66affSColin Finck     }
858*c2c66affSColin Finck 
859*c2c66affSColin Finck     if (hDdeDataIn != 0 && wdh.fAckReq)
860*c2c66affSColin Finck     {
861*c2c66affSColin Finck 	WDML_PostAck(pConv, WDML_CLIENT_SIDE, 0, FALSE, TRUE, uiHi, msg->lParam, WM_DDE_DATA);
862*c2c66affSColin Finck 	if (msg->lParam)
863*c2c66affSColin Finck 	    msg->lParam = 0;
864*c2c66affSColin Finck     }
865*c2c66affSColin Finck     else
866*c2c66affSColin Finck     {
867*c2c66affSColin Finck 	GlobalDeleteAtom(uiHi);
868*c2c66affSColin Finck     }
869*c2c66affSColin Finck 
870*c2c66affSColin Finck     hDdeDataOut = WDML_InvokeCallback(pConv->instance, XTYP_ADVDATA, pLink->uFmt, pLink->hConv,
871*c2c66affSColin Finck 				      pConv->hszTopic, pLink->hszItem, hDdeDataIn, 0, 0);
872*c2c66affSColin Finck 
873*c2c66affSColin Finck     if (hDdeDataOut != (HDDEDATA)DDE_FACK || wdh.fRelease)
874*c2c66affSColin Finck     {
875*c2c66affSColin Finck         if (uiLo) GlobalFree((HANDLE)uiLo);
876*c2c66affSColin Finck     }
877*c2c66affSColin Finck 
878*c2c66affSColin Finck     DdeFreeDataHandle(hDdeDataIn);
879*c2c66affSColin Finck 
880*c2c66affSColin Finck     WDML_DecHSZ(pConv->instance, hsz);
881*c2c66affSColin Finck     if (msg->lParam)
882*c2c66affSColin Finck 	FreeDDElParam(WM_DDE_DATA, msg->lParam);
883*c2c66affSColin Finck 
884*c2c66affSColin Finck     return WDML_QS_HANDLED;
885*c2c66affSColin Finck }
886*c2c66affSColin Finck 
887*c2c66affSColin Finck /******************************************************************
888*c2c66affSColin Finck  *		WDML_HandleIncomingTerminate
889*c2c66affSColin Finck  *
890*c2c66affSColin Finck  *
891*c2c66affSColin Finck  */
892*c2c66affSColin Finck static WDML_QUEUE_STATE WDML_HandleIncomingTerminate(WDML_CONV* pConv, MSG* msg, HDDEDATA* hdd)
893*c2c66affSColin Finck {
894*c2c66affSColin Finck     if (pConv->hwndServer != WIN_GetFullHandle((HWND)msg->wParam))
895*c2c66affSColin Finck 	return WDML_QS_PASS;
896*c2c66affSColin Finck 
897*c2c66affSColin Finck     pConv->wStatus |= ST_TERMINATED;
898*c2c66affSColin Finck     if (pConv->wStatus & ST_CONNECTED)
899*c2c66affSColin Finck     {
900*c2c66affSColin Finck 	/* don't care about result code (if server exists or not) */
901*c2c66affSColin Finck 	PostMessageW(pConv->hwndServer, WM_DDE_TERMINATE, (WPARAM)pConv->hwndClient, 0L);
902*c2c66affSColin Finck 	pConv->wStatus &= ~ST_CONNECTED;
903*c2c66affSColin Finck     }
904*c2c66affSColin Finck     /* have to keep connection around to allow reconnection */
905*c2c66affSColin Finck     return WDML_QS_HANDLED;
906*c2c66affSColin Finck }
907*c2c66affSColin Finck 
908*c2c66affSColin Finck /******************************************************************
909*c2c66affSColin Finck  *		WDML_HandleReply
910*c2c66affSColin Finck  *
911*c2c66affSColin Finck  * handles any incoming reply, and try to match to an already sent request
912*c2c66affSColin Finck  */
913*c2c66affSColin Finck static WDML_QUEUE_STATE WDML_HandleReply(WDML_CONV* pConv, MSG* msg, HDDEDATA* hdd, DWORD *ack)
914*c2c66affSColin Finck {
915*c2c66affSColin Finck     WDML_XACT*		pXAct = pConv->transactions;
916*c2c66affSColin Finck     WDML_QUEUE_STATE	qs;
917*c2c66affSColin Finck 
918*c2c66affSColin Finck     if (pConv->transactions)
919*c2c66affSColin Finck     {
920*c2c66affSColin Finck 	if (ack) *ack = DDE_FNOTPROCESSED;
921*c2c66affSColin Finck 	/* first check message against a pending transaction, if any */
922*c2c66affSColin Finck 	switch (pXAct->ddeMsg)
923*c2c66affSColin Finck 	{
924*c2c66affSColin Finck 	case WM_DDE_ADVISE:
925*c2c66affSColin Finck 	    qs = WDML_HandleAdviseReply(pConv, msg, pXAct, ack);
926*c2c66affSColin Finck 	    break;
927*c2c66affSColin Finck 	case WM_DDE_UNADVISE:
928*c2c66affSColin Finck 	    qs = WDML_HandleUnadviseReply(pConv, msg, pXAct, ack);
929*c2c66affSColin Finck 	    break;
930*c2c66affSColin Finck 	case WM_DDE_EXECUTE:
931*c2c66affSColin Finck 	    qs = WDML_HandleExecuteReply(pConv, msg, pXAct, ack);
932*c2c66affSColin Finck 	    break;
933*c2c66affSColin Finck 	case WM_DDE_REQUEST:
934*c2c66affSColin Finck 	    qs = WDML_HandleRequestReply(pConv, msg, pXAct, ack);
935*c2c66affSColin Finck 	    break;
936*c2c66affSColin Finck 	case WM_DDE_POKE:
937*c2c66affSColin Finck 	    qs = WDML_HandlePokeReply(pConv, msg, pXAct, ack);
938*c2c66affSColin Finck 	    break;
939*c2c66affSColin Finck 	case WM_DDE_TERMINATE:
940*c2c66affSColin Finck 	    qs = WDML_HandleTerminateReply(pConv, msg);
941*c2c66affSColin Finck 	    break;
942*c2c66affSColin Finck 	default:
943*c2c66affSColin Finck 	    qs = WDML_QS_ERROR;
944*c2c66affSColin Finck 	    FIXME("oooch\n");
945*c2c66affSColin Finck 	}
946*c2c66affSColin Finck     }
947*c2c66affSColin Finck     else
948*c2c66affSColin Finck     {
949*c2c66affSColin Finck 	qs = WDML_QS_PASS;
950*c2c66affSColin Finck     }
951*c2c66affSColin Finck 
952*c2c66affSColin Finck     /* now check the results */
953*c2c66affSColin Finck     switch (qs)
954*c2c66affSColin Finck     {
955*c2c66affSColin Finck     case WDML_QS_ERROR:
956*c2c66affSColin Finck     case WDML_QS_SWALLOWED:
957*c2c66affSColin Finck 	*hdd = 0;
958*c2c66affSColin Finck 	break;
959*c2c66affSColin Finck     case WDML_QS_HANDLED:
960*c2c66affSColin Finck 	/* ok, we have resolved a pending transaction
961*c2c66affSColin Finck 	 * notify callback if asynchronous.
962*c2c66affSColin Finck 	 */
963*c2c66affSColin Finck 	if (pXAct->dwTimeout == TIMEOUT_ASYNC && pXAct->ddeMsg != WM_DDE_TERMINATE)
964*c2c66affSColin Finck 	{
965*c2c66affSColin Finck 	    WDML_InvokeCallback(pConv->instance, XTYP_XACT_COMPLETE, pXAct->wFmt,
966*c2c66affSColin Finck 				(HCONV)pConv, pConv->hszTopic, pXAct->hszItem,
967*c2c66affSColin Finck 				pXAct->hDdeData, MAKELONG(0, pXAct->xActID), 0 /* FIXME */);
968*c2c66affSColin Finck 	    qs = WDML_QS_PASS;
969*c2c66affSColin Finck 	}
970*c2c66affSColin Finck 	else
971*c2c66affSColin Finck 	{
972*c2c66affSColin Finck 	    *hdd = pXAct->hDdeData;
973*c2c66affSColin Finck 	}
974*c2c66affSColin Finck 	break;
975*c2c66affSColin Finck     case WDML_QS_PASS:
976*c2c66affSColin Finck 	/* no pending transaction found, try a warm/hot link or a termination request */
977*c2c66affSColin Finck 	switch (msg->message)
978*c2c66affSColin Finck 	{
979*c2c66affSColin Finck 	case WM_DDE_DATA:
980*c2c66affSColin Finck 	    qs = WDML_HandleIncomingData(pConv, msg, hdd);
981*c2c66affSColin Finck 	    break;
982*c2c66affSColin Finck 	case WM_DDE_TERMINATE:
983*c2c66affSColin Finck 	    qs = WDML_HandleIncomingTerminate(pConv, msg, hdd);
984*c2c66affSColin Finck 	    break;
985*c2c66affSColin Finck         case WM_DDE_ACK:
986*c2c66affSColin Finck             /* This happens at end of DdeClientTransaction XTYP_EXECUTE
987*c2c66affSColin Finck              * Without this assignment, DdeClientTransaction's return value is undefined
988*c2c66affSColin Finck              */
989*c2c66affSColin Finck             *hdd = (HDDEDATA)TRUE;
990*c2c66affSColin Finck             if (ack)
991*c2c66affSColin Finck                 *ack = DDE_FACK;
992*c2c66affSColin Finck 	    break;
993*c2c66affSColin Finck 	}
994*c2c66affSColin Finck 	break;
995*c2c66affSColin Finck     case WDML_QS_BLOCK:
996*c2c66affSColin Finck 	FIXME("shouldn't be used on client side\n");
997*c2c66affSColin Finck 	break;
998*c2c66affSColin Finck     }
999*c2c66affSColin Finck 
1000*c2c66affSColin Finck     return qs;
1001*c2c66affSColin Finck }
1002*c2c66affSColin Finck 
1003*c2c66affSColin Finck /******************************************************************
1004*c2c66affSColin Finck  *		WDML_SyncWaitTransactionReply
1005*c2c66affSColin Finck  *
1006*c2c66affSColin Finck  * waits until an answer for a sent request is received
1007*c2c66affSColin Finck  * time out is also handled. only used for synchronous transactions
1008*c2c66affSColin Finck  */
1009*c2c66affSColin Finck static HDDEDATA WDML_SyncWaitTransactionReply(HCONV hConv, DWORD dwTimeout, const WDML_XACT* pXAct, DWORD *ack)
1010*c2c66affSColin Finck {
1011*c2c66affSColin Finck     DWORD	start, elapsed;
1012*c2c66affSColin Finck     DWORD	err;
1013*c2c66affSColin Finck     WDML_CONV*	pConv;
1014*c2c66affSColin Finck 
1015*c2c66affSColin Finck     TRACE("Starting wait for a timeout of %d ms\n", dwTimeout);
1016*c2c66affSColin Finck 
1017*c2c66affSColin Finck     start = GetTickCount();
1018*c2c66affSColin Finck     while ((elapsed = GetTickCount() - start) < dwTimeout)
1019*c2c66affSColin Finck     {
1020*c2c66affSColin Finck 	/* we cannot be in the crit sect all the time because when client and server run in a
1021*c2c66affSColin Finck 	 * single process they need to share the access to the internal data
1022*c2c66affSColin Finck 	 */
1023*c2c66affSColin Finck 	if (MsgWaitForMultipleObjects(0, NULL, FALSE,
1024*c2c66affSColin Finck 				      dwTimeout - elapsed, QS_POSTMESSAGE) == WAIT_OBJECT_0)
1025*c2c66affSColin Finck 	{
1026*c2c66affSColin Finck 	    MSG		msg;
1027*c2c66affSColin Finck 
1028*c2c66affSColin Finck 	    while (PeekMessageW(&msg, 0, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE))
1029*c2c66affSColin Finck 	    {
1030*c2c66affSColin Finck                 HDDEDATA hdd = NULL;
1031*c2c66affSColin Finck 
1032*c2c66affSColin Finck                 pConv = WDML_GetConv(hConv, FALSE);
1033*c2c66affSColin Finck                 if (pConv == NULL)
1034*c2c66affSColin Finck                 {
1035*c2c66affSColin Finck                     /* conversation no longer available... return failure */
1036*c2c66affSColin Finck                     return 0;
1037*c2c66affSColin Finck                 }
1038*c2c66affSColin Finck                 if (msg.hwnd == pConv->hwndClient)
1039*c2c66affSColin Finck                 {
1040*c2c66affSColin Finck                     /* check that either pXAct has been processed or no more xActions are pending */
1041*c2c66affSColin Finck                     BOOL ret = (pConv->transactions == pXAct);
1042*c2c66affSColin Finck                     if (WDML_HandleReply(pConv, &msg, &hdd, ack) == WDML_QS_HANDLED)
1043*c2c66affSColin Finck                     {
1044*c2c66affSColin Finck                         TRACE("WDML_HandleReply returned WDML_QS_HANDLED\n");
1045*c2c66affSColin Finck                         ret = TRUE;
1046*c2c66affSColin Finck                     }
1047*c2c66affSColin Finck                     else
1048*c2c66affSColin Finck                         ret = (pConv->transactions == NULL || ret);
1049*c2c66affSColin Finck 
1050*c2c66affSColin Finck                     if (ret)
1051*c2c66affSColin Finck                     {
1052*c2c66affSColin Finck                         pConv->instance->lastError = hdd ? DMLERR_NO_ERROR : DMLERR_NOTPROCESSED;
1053*c2c66affSColin Finck                         return hdd;
1054*c2c66affSColin Finck                     }
1055*c2c66affSColin Finck                 }
1056*c2c66affSColin Finck                 else
1057*c2c66affSColin Finck                 {
1058*c2c66affSColin Finck                     DispatchMessageW(&msg);
1059*c2c66affSColin Finck                 }
1060*c2c66affSColin Finck             }
1061*c2c66affSColin Finck 	}
1062*c2c66affSColin Finck     }
1063*c2c66affSColin Finck 
1064*c2c66affSColin Finck     TRACE("Timeout !!\n");
1065*c2c66affSColin Finck 
1066*c2c66affSColin Finck     pConv = WDML_GetConv(hConv, FALSE);
1067*c2c66affSColin Finck     if (pConv != NULL)
1068*c2c66affSColin Finck     {
1069*c2c66affSColin Finck 	if (pConv->transactions)
1070*c2c66affSColin Finck 	{
1071*c2c66affSColin Finck 	    switch (pConv->transactions->ddeMsg)
1072*c2c66affSColin Finck 	    {
1073*c2c66affSColin Finck 	    case WM_DDE_ADVISE:		err = DMLERR_ADVACKTIMEOUT;	break;
1074*c2c66affSColin Finck 	    case WM_DDE_REQUEST:	err = DMLERR_DATAACKTIMEOUT; 	break;
1075*c2c66affSColin Finck 	    case WM_DDE_EXECUTE:	err = DMLERR_EXECACKTIMEOUT;	break;
1076*c2c66affSColin Finck 	    case WM_DDE_POKE:		err = DMLERR_POKEACKTIMEOUT;	break;
1077*c2c66affSColin Finck 	    case WM_DDE_UNADVISE:	err = DMLERR_UNADVACKTIMEOUT;	break;
1078*c2c66affSColin Finck 	    default:			err = DMLERR_INVALIDPARAMETER;	break;
1079*c2c66affSColin Finck 	    }
1080*c2c66affSColin Finck 
1081*c2c66affSColin Finck 	    pConv->instance->lastError = err;
1082*c2c66affSColin Finck 	}
1083*c2c66affSColin Finck     }
1084*c2c66affSColin Finck 
1085*c2c66affSColin Finck     return 0;
1086*c2c66affSColin Finck }
1087*c2c66affSColin Finck 
1088*c2c66affSColin Finck 
1089*c2c66affSColin Finck /*****************************************************************
1090*c2c66affSColin Finck  *            WDML_ClientHandle
1091*c2c66affSColin Finck  */
1092*c2c66affSColin Finck HDDEDATA WDML_ClientHandle(WDML_CONV *pConv, WDML_XACT *pXAct, DWORD dwTimeout, LPDWORD pdwResult)
1093*c2c66affSColin Finck {
1094*c2c66affSColin Finck     HDDEDATA hDdeData;
1095*c2c66affSColin Finck 
1096*c2c66affSColin Finck     if (!PostMessageW(pConv->hwndServer, pXAct->ddeMsg, (WPARAM)pConv->hwndClient, pXAct->lParam))
1097*c2c66affSColin Finck     {
1098*c2c66affSColin Finck         WARN("Failed posting message %x to %p (error=0x%x)\n",
1099*c2c66affSColin Finck               pXAct->ddeMsg, pConv->hwndServer, GetLastError());
1100*c2c66affSColin Finck         pConv->wStatus &= ~ST_CONNECTED;
1101*c2c66affSColin Finck         pConv->instance->lastError = DMLERR_POSTMSG_FAILED;
1102*c2c66affSColin Finck         return 0;
1103*c2c66affSColin Finck     }
1104*c2c66affSColin Finck     pXAct->dwTimeout = dwTimeout;
1105*c2c66affSColin Finck     /* FIXME: should set the app bits on *pdwResult */
1106*c2c66affSColin Finck 
1107*c2c66affSColin Finck     if (dwTimeout == TIMEOUT_ASYNC)
1108*c2c66affSColin Finck     {
1109*c2c66affSColin Finck         if (pdwResult)
1110*c2c66affSColin Finck             *pdwResult = MAKELONG(0, pXAct->xActID);
1111*c2c66affSColin Finck 
1112*c2c66affSColin Finck         hDdeData = (HDDEDATA)1;
1113*c2c66affSColin Finck     }
1114*c2c66affSColin Finck     else
1115*c2c66affSColin Finck         hDdeData = WDML_SyncWaitTransactionReply((HCONV)pConv, dwTimeout, pXAct, pdwResult);
1116*c2c66affSColin Finck 
1117*c2c66affSColin Finck     return hDdeData;
1118*c2c66affSColin Finck }
1119*c2c66affSColin Finck 
1120*c2c66affSColin Finck 
1121*c2c66affSColin Finck /*****************************************************************
1122*c2c66affSColin Finck  *            DdeClientTransaction  (USER32.@)
1123*c2c66affSColin Finck  */
1124*c2c66affSColin Finck HDDEDATA WINAPI DdeClientTransaction(LPBYTE pData, DWORD cbData, HCONV hConv, HSZ hszItem, UINT wFmt,
1125*c2c66affSColin Finck 				     UINT wType, DWORD dwTimeout, LPDWORD pdwResult)
1126*c2c66affSColin Finck {
1127*c2c66affSColin Finck     WDML_CONV*		pConv;
1128*c2c66affSColin Finck     WDML_XACT*		pXAct;
1129*c2c66affSColin Finck     HDDEDATA		hDdeData;
1130*c2c66affSColin Finck 
1131*c2c66affSColin Finck     TRACE("(%p,%d,%p,%p,%x,%x,%d,%p)\n",
1132*c2c66affSColin Finck 	  pData, cbData, hConv, hszItem, wFmt, wType, dwTimeout, pdwResult);
1133*c2c66affSColin Finck 
1134*c2c66affSColin Finck     if (hConv == 0)
1135*c2c66affSColin Finck     {
1136*c2c66affSColin Finck 	WARN("Invalid conversation handle NULL\n");
1137*c2c66affSColin Finck 	return 0;
1138*c2c66affSColin Finck     }
1139*c2c66affSColin Finck 
1140*c2c66affSColin Finck     pConv = WDML_GetConv(hConv, TRUE);
1141*c2c66affSColin Finck     if (pConv == NULL)
1142*c2c66affSColin Finck     {
1143*c2c66affSColin Finck 	/* cannot set error... cannot get back to DDE instance */
1144*c2c66affSColin Finck         return 0;
1145*c2c66affSColin Finck     }
1146*c2c66affSColin Finck 
1147*c2c66affSColin Finck     switch (wType)
1148*c2c66affSColin Finck     {
1149*c2c66affSColin Finck     case XTYP_EXECUTE:
1150*c2c66affSColin Finck     /* Windows simply ignores hszItem and wFmt in this case */
1151*c2c66affSColin Finck 	pXAct = WDML_ClientQueueExecute(pConv, pData, cbData);
1152*c2c66affSColin Finck 	if (pXAct == NULL)
1153*c2c66affSColin Finck 	    return 0;
1154*c2c66affSColin Finck 	break;
1155*c2c66affSColin Finck     case XTYP_POKE:
1156*c2c66affSColin Finck         if (!hszItem)
1157*c2c66affSColin Finck         {
1158*c2c66affSColin Finck             pConv->instance->lastError = DMLERR_INVALIDPARAMETER;
1159*c2c66affSColin Finck             return 0;
1160*c2c66affSColin Finck         }
1161*c2c66affSColin Finck         pXAct = WDML_ClientQueuePoke(pConv, pData, cbData, wFmt, hszItem);
1162*c2c66affSColin Finck         break;
1163*c2c66affSColin Finck     case XTYP_ADVSTART|XTYPF_NODATA:
1164*c2c66affSColin Finck     case XTYP_ADVSTART|XTYPF_NODATA|XTYPF_ACKREQ:
1165*c2c66affSColin Finck     case XTYP_ADVSTART:
1166*c2c66affSColin Finck     case XTYP_ADVSTART|XTYPF_ACKREQ:
1167*c2c66affSColin Finck 	if (pData)
1168*c2c66affSColin Finck 	{
1169*c2c66affSColin Finck 	    pConv->instance->lastError = DMLERR_INVALIDPARAMETER;
1170*c2c66affSColin Finck             return 0;
1171*c2c66affSColin Finck 	}
1172*c2c66affSColin Finck 	pXAct = WDML_ClientQueueAdvise(pConv, wType, wFmt, hszItem);
1173*c2c66affSColin Finck 	break;
1174*c2c66affSColin Finck     case XTYP_ADVSTOP:
1175*c2c66affSColin Finck 	if (pData)
1176*c2c66affSColin Finck 	{
1177*c2c66affSColin Finck 	    pConv->instance->lastError = DMLERR_INVALIDPARAMETER;
1178*c2c66affSColin Finck             return 0;
1179*c2c66affSColin Finck 	}
1180*c2c66affSColin Finck 	pXAct = WDML_ClientQueueUnadvise(pConv, wFmt, hszItem);
1181*c2c66affSColin Finck 	break;
1182*c2c66affSColin Finck     case XTYP_REQUEST:
1183*c2c66affSColin Finck 	if (pData || !hszItem)
1184*c2c66affSColin Finck 	{
1185*c2c66affSColin Finck 	    pConv->instance->lastError = DMLERR_INVALIDPARAMETER;
1186*c2c66affSColin Finck             return 0;
1187*c2c66affSColin Finck 	}
1188*c2c66affSColin Finck 	pXAct = WDML_ClientQueueRequest(pConv, wFmt, hszItem);
1189*c2c66affSColin Finck 	break;
1190*c2c66affSColin Finck     default:
1191*c2c66affSColin Finck         FIXME("Unknown transaction type %04x\n", wType);
1192*c2c66affSColin Finck 	/* unknown transaction type */
1193*c2c66affSColin Finck 	pConv->instance->lastError = DMLERR_INVALIDPARAMETER;
1194*c2c66affSColin Finck         return 0;
1195*c2c66affSColin Finck     }
1196*c2c66affSColin Finck 
1197*c2c66affSColin Finck     if (pXAct == NULL)
1198*c2c66affSColin Finck     {
1199*c2c66affSColin Finck 	pConv->instance->lastError = DMLERR_MEMORY_ERROR;
1200*c2c66affSColin Finck         return 0;
1201*c2c66affSColin Finck     }
1202*c2c66affSColin Finck 
1203*c2c66affSColin Finck     WDML_QueueTransaction(pConv, pXAct);
1204*c2c66affSColin Finck 
1205*c2c66affSColin Finck     TRACE("pConv->wStatus %04x\n", pConv->wStatus);
1206*c2c66affSColin Finck 
1207*c2c66affSColin Finck     if (pConv->wStatus & ST_BLOCKED)
1208*c2c66affSColin Finck     {
1209*c2c66affSColin Finck         TRACE("Transactions are blocked, add to the queue and exit\n");
1210*c2c66affSColin Finck         return (HDDEDATA)1;
1211*c2c66affSColin Finck     }
1212*c2c66affSColin Finck 
1213*c2c66affSColin Finck     hDdeData = WDML_ClientHandle(pConv, pXAct, dwTimeout, pdwResult);
1214*c2c66affSColin Finck     if (dwTimeout != TIMEOUT_ASYNC)
1215*c2c66affSColin Finck     {
1216*c2c66affSColin Finck         WDML_UnQueueTransaction(pConv, pXAct);
1217*c2c66affSColin Finck         WDML_FreeTransaction(pConv->instance, pXAct, TRUE);
1218*c2c66affSColin Finck     }
1219*c2c66affSColin Finck 
1220*c2c66affSColin Finck     return hDdeData;
1221*c2c66affSColin Finck }
1222*c2c66affSColin Finck 
1223*c2c66affSColin Finck /*****************************************************************
1224*c2c66affSColin Finck  *            DdeAbandonTransaction (USER32.@)
1225*c2c66affSColin Finck  */
1226*c2c66affSColin Finck BOOL WINAPI DdeAbandonTransaction(DWORD idInst, HCONV hConv, DWORD idTransaction)
1227*c2c66affSColin Finck {
1228*c2c66affSColin Finck     WDML_INSTANCE*	pInstance;
1229*c2c66affSColin Finck     WDML_CONV*		pConv;
1230*c2c66affSColin Finck     WDML_XACT*          pXAct;
1231*c2c66affSColin Finck 
1232*c2c66affSColin Finck     if ((pInstance = WDML_GetInstance(idInst)))
1233*c2c66affSColin Finck     {
1234*c2c66affSColin Finck         if (hConv)
1235*c2c66affSColin Finck         {
1236*c2c66affSColin Finck             if ((pConv = WDML_GetConv(hConv, TRUE)) && pConv->instance == pInstance)
1237*c2c66affSColin Finck             {
1238*c2c66affSColin Finck 
1239*c2c66affSColin Finck                 pXAct = pConv->transactions;
1240*c2c66affSColin Finck                 while (pXAct) {
1241*c2c66affSColin Finck                     WDML_XACT *nextXAct = pXAct->next;
1242*c2c66affSColin Finck 
1243*c2c66affSColin Finck                     if (pXAct->dwTimeout == TIMEOUT_ASYNC &&
1244*c2c66affSColin Finck                         (idTransaction == 0 || pXAct->xActID == idTransaction))
1245*c2c66affSColin Finck                     {
1246*c2c66affSColin Finck                         WDML_UnQueueTransaction(pConv, pXAct);
1247*c2c66affSColin Finck                         WDML_FreeTransaction(pInstance, pXAct, TRUE);
1248*c2c66affSColin Finck                     }
1249*c2c66affSColin Finck                     pXAct = nextXAct;
1250*c2c66affSColin Finck                 }
1251*c2c66affSColin Finck             }
1252*c2c66affSColin Finck         }
1253*c2c66affSColin Finck         else
1254*c2c66affSColin Finck         {
1255*c2c66affSColin Finck             for (pConv = pInstance->convs[WDML_CLIENT_SIDE]; pConv; pConv = pConv->next)
1256*c2c66affSColin Finck             {
1257*c2c66affSColin Finck                 if (!(pConv->wStatus & ST_CONNECTED)) continue;
1258*c2c66affSColin Finck                 pXAct = pConv->transactions;
1259*c2c66affSColin Finck                 while (pXAct) {
1260*c2c66affSColin Finck                     WDML_XACT *nextXAct = pXAct->next;
1261*c2c66affSColin Finck 
1262*c2c66affSColin Finck                     if (pXAct->dwTimeout == TIMEOUT_ASYNC)
1263*c2c66affSColin Finck                     {
1264*c2c66affSColin Finck                         WDML_UnQueueTransaction(pConv, pXAct);
1265*c2c66affSColin Finck                         WDML_FreeTransaction(pInstance, pXAct, TRUE);
1266*c2c66affSColin Finck                     }
1267*c2c66affSColin Finck                     pXAct = nextXAct;
1268*c2c66affSColin Finck                 }
1269*c2c66affSColin Finck             }
1270*c2c66affSColin Finck         }
1271*c2c66affSColin Finck     }
1272*c2c66affSColin Finck 
1273*c2c66affSColin Finck     return TRUE;
1274*c2c66affSColin Finck }
1275*c2c66affSColin Finck 
1276*c2c66affSColin Finck /******************************************************************
1277*c2c66affSColin Finck  *		WDML_ClientProc
1278*c2c66affSColin Finck  *
1279*c2c66affSColin Finck  * Window Proc created on client side for each conversation
1280*c2c66affSColin Finck  */
1281*c2c66affSColin Finck static LRESULT CALLBACK WDML_ClientProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
1282*c2c66affSColin Finck {
1283*c2c66affSColin Finck     UINT	uiLo, uiHi;
1284*c2c66affSColin Finck     WDML_CONV*	pConv = NULL;
1285*c2c66affSColin Finck     HSZ		hszSrv, hszTpc;
1286*c2c66affSColin Finck 
1287*c2c66affSColin Finck     TRACE("%p %04x %08lx %08lx\n", hwnd, iMsg, wParam , lParam);
1288*c2c66affSColin Finck 
1289*c2c66affSColin Finck     if (iMsg == WM_DDE_ACK &&
1290*c2c66affSColin Finck 	/* in the initial WM_INITIATE sendmessage */
1291*c2c66affSColin Finck 	((pConv = WDML_GetConvFromWnd(hwnd)) == NULL || pConv->wStatus == XST_INIT1))
1292*c2c66affSColin Finck     {
1293*c2c66affSColin Finck 	/* In response to WM_DDE_INITIATE, save server window  */
1294*c2c66affSColin Finck 	char		buf[256];
1295*c2c66affSColin Finck 	WDML_INSTANCE*	pInstance;
1296*c2c66affSColin Finck 
1297*c2c66affSColin Finck         /* note: sent messages do not need packing */
1298*c2c66affSColin Finck 	uiLo = LOWORD(lParam);
1299*c2c66affSColin Finck         uiHi = HIWORD(lParam);
1300*c2c66affSColin Finck 
1301*c2c66affSColin Finck 	/* FIXME: convlist should be handled here */
1302*c2c66affSColin Finck 	if (pConv)
1303*c2c66affSColin Finck 	{
1304*c2c66affSColin Finck 	    /* we already have started the conv with a server, drop other replies */
1305*c2c66affSColin Finck 	    GlobalDeleteAtom(uiLo);
1306*c2c66affSColin Finck 	    GlobalDeleteAtom(uiHi);
1307*c2c66affSColin Finck             PostMessageW((HWND)wParam, WM_DDE_TERMINATE, (WPARAM)hwnd, 0);
1308*c2c66affSColin Finck 	    return 0;
1309*c2c66affSColin Finck 	}
1310*c2c66affSColin Finck 
1311*c2c66affSColin Finck 	pInstance = WDML_GetInstanceFromWnd(hwnd);
1312*c2c66affSColin Finck 
1313*c2c66affSColin Finck 	hszSrv = WDML_MakeHszFromAtom(pInstance, uiLo);
1314*c2c66affSColin Finck 	hszTpc = WDML_MakeHszFromAtom(pInstance, uiHi);
1315*c2c66affSColin Finck 
1316*c2c66affSColin Finck 	pConv = WDML_AddConv(pInstance, WDML_CLIENT_SIDE, hszSrv, hszTpc, hwnd, (HWND)wParam);
1317*c2c66affSColin Finck 
1318*c2c66affSColin Finck 	SetWindowLongPtrW(hwnd, GWL_WDML_CONVERSATION, (ULONG_PTR)pConv);
1319*c2c66affSColin Finck 	pConv->wStatus |= ST_CONNECTED;
1320*c2c66affSColin Finck 	pConv->wConvst = XST_INIT1;
1321*c2c66affSColin Finck 
1322*c2c66affSColin Finck 	/* check if server is handled by DDEML */
1323*c2c66affSColin Finck 	if ((GetClassNameA((HWND)wParam, buf, sizeof(buf)) &&
1324*c2c66affSColin Finck 	     lstrcmpiA(buf, WDML_szServerConvClassA) == 0) ||
1325*c2c66affSColin Finck 	    (GetClassNameW((HWND)wParam, (LPWSTR)buf, sizeof(buf)/sizeof(WCHAR)) &&
1326*c2c66affSColin Finck 	     lstrcmpiW((LPWSTR)buf, WDML_szServerConvClassW) == 0))
1327*c2c66affSColin Finck 	{
1328*c2c66affSColin Finck 	    pConv->wStatus |= ST_ISLOCAL;
1329*c2c66affSColin Finck 	}
1330*c2c66affSColin Finck 
1331*c2c66affSColin Finck 	GlobalDeleteAtom(uiLo);
1332*c2c66affSColin Finck 	GlobalDeleteAtom(uiHi);
1333*c2c66affSColin Finck 
1334*c2c66affSColin Finck 	/* accept conversation */
1335*c2c66affSColin Finck 	return 1;
1336*c2c66affSColin Finck     }
1337*c2c66affSColin Finck 
1338*c2c66affSColin Finck     if (iMsg >= WM_DDE_FIRST && iMsg <= WM_DDE_LAST)
1339*c2c66affSColin Finck     {
1340*c2c66affSColin Finck 	pConv = WDML_GetConvFromWnd(hwnd);
1341*c2c66affSColin Finck 
1342*c2c66affSColin Finck 	if (pConv)
1343*c2c66affSColin Finck 	{
1344*c2c66affSColin Finck 	    MSG		msg;
1345*c2c66affSColin Finck 	    HDDEDATA	hdd;
1346*c2c66affSColin Finck 
1347*c2c66affSColin Finck 	    msg.hwnd = hwnd;
1348*c2c66affSColin Finck 	    msg.message = iMsg;
1349*c2c66affSColin Finck 	    msg.wParam = wParam;
1350*c2c66affSColin Finck 	    msg.lParam = lParam;
1351*c2c66affSColin Finck 
1352*c2c66affSColin Finck 	    WDML_HandleReply(pConv, &msg, &hdd, NULL);
1353*c2c66affSColin Finck 	}
1354*c2c66affSColin Finck 
1355*c2c66affSColin Finck 	return 0;
1356*c2c66affSColin Finck     }
1357*c2c66affSColin Finck 
1358*c2c66affSColin Finck     return IsWindowUnicode(hwnd) ? DefWindowProcW(hwnd, iMsg, wParam, lParam) :
1359*c2c66affSColin Finck                                    DefWindowProcA(hwnd, iMsg, wParam, lParam);
1360*c2c66affSColin Finck }
1361*c2c66affSColin Finck 
1362*c2c66affSColin Finck /*****************************************************************
1363*c2c66affSColin Finck  *            DdeDisconnect   (USER32.@)
1364*c2c66affSColin Finck  */
1365*c2c66affSColin Finck BOOL WINAPI DdeDisconnect(HCONV hConv)
1366*c2c66affSColin Finck {
1367*c2c66affSColin Finck     WDML_CONV*	pConv;
1368*c2c66affSColin Finck     WDML_XACT*	pXAct;
1369*c2c66affSColin Finck     BOOL	ret = FALSE;
1370*c2c66affSColin Finck 
1371*c2c66affSColin Finck     TRACE("(%p)\n", hConv);
1372*c2c66affSColin Finck 
1373*c2c66affSColin Finck     if (hConv == 0)
1374*c2c66affSColin Finck     {
1375*c2c66affSColin Finck 	WARN("DdeDisconnect(): hConv = 0\n");
1376*c2c66affSColin Finck 	return FALSE;
1377*c2c66affSColin Finck     }
1378*c2c66affSColin Finck 
1379*c2c66affSColin Finck     pConv = WDML_GetConv(hConv, TRUE);
1380*c2c66affSColin Finck     if (pConv != NULL)
1381*c2c66affSColin Finck     {
1382*c2c66affSColin Finck         if (pConv->wStatus & ST_CLIENT)
1383*c2c66affSColin Finck         {
1384*c2c66affSColin Finck             /* FIXME: should abandon all pending transactions */
1385*c2c66affSColin Finck             pXAct = WDML_ClientQueueTerminate(pConv);
1386*c2c66affSColin Finck             if (pXAct != NULL)
1387*c2c66affSColin Finck             {
1388*c2c66affSColin Finck                 if (PostMessageW(pConv->hwndServer, pXAct->ddeMsg,
1389*c2c66affSColin Finck                                  (WPARAM)pConv->hwndClient, pXAct->lParam))
1390*c2c66affSColin Finck                 {
1391*c2c66affSColin Finck                     WDML_SyncWaitTransactionReply(hConv, 10000, pXAct, NULL);
1392*c2c66affSColin Finck                     ret = TRUE;
1393*c2c66affSColin Finck                 }
1394*c2c66affSColin Finck                 else
1395*c2c66affSColin Finck                     pConv->instance->lastError = DMLERR_POSTMSG_FAILED;
1396*c2c66affSColin Finck 
1397*c2c66affSColin Finck                 WDML_FreeTransaction(pConv->instance, pXAct, TRUE);
1398*c2c66affSColin Finck                 /* still have to destroy data associated with conversation */
1399*c2c66affSColin Finck                 WDML_RemoveConv(pConv, WDML_CLIENT_SIDE);
1400*c2c66affSColin Finck             }
1401*c2c66affSColin Finck             else
1402*c2c66affSColin Finck             {
1403*c2c66affSColin Finck                 FIXME("Not implemented yet for a server side conversation\n");
1404*c2c66affSColin Finck             }
1405*c2c66affSColin Finck         }
1406*c2c66affSColin Finck     }
1407*c2c66affSColin Finck 
1408*c2c66affSColin Finck     return ret;
1409*c2c66affSColin Finck }
1410*c2c66affSColin Finck 
1411*c2c66affSColin Finck /*****************************************************************
1412*c2c66affSColin Finck  *            DdeImpersonateClient (USER32.@)
1413*c2c66affSColin Finck  */
1414*c2c66affSColin Finck BOOL WINAPI DdeImpersonateClient(HCONV hConv)
1415*c2c66affSColin Finck {
1416*c2c66affSColin Finck     WDML_CONV*	pConv;
1417*c2c66affSColin Finck     BOOL	ret = FALSE;
1418*c2c66affSColin Finck 
1419*c2c66affSColin Finck     TRACE("(%p)\n", hConv);
1420*c2c66affSColin Finck 
1421*c2c66affSColin Finck     pConv = WDML_GetConv(hConv, TRUE);
1422*c2c66affSColin Finck     if (pConv)
1423*c2c66affSColin Finck     {
1424*c2c66affSColin Finck 	ret = ImpersonateDdeClientWindow(pConv->hwndClient, pConv->hwndServer);
1425*c2c66affSColin Finck     }
1426*c2c66affSColin Finck     return ret;
1427*c2c66affSColin Finck }
1428