Handle wParam in WM_PAINT properly: if non-null, it is the hdc we are
[wine] / dlls / user / dde / server.c
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2
3 /*
4  * DDEML library
5  *
6  * Copyright 1997 Alexandre Julliard
7  * Copyright 1997 Len White
8  * Copyright 1999 Keith Matthews
9  * Copyright 2000 Corel
10  * Copyright 2001 Eric Pouech
11  * Copyright 2003, 2004, 2005 Dmitry Timoshkov
12  *
13  * This library is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU Lesser General Public
15  * License as published by the Free Software Foundation; either
16  * version 2.1 of the License, or (at your option) any later version.
17  *
18  * This library is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21  * Lesser General Public License for more details.
22  *
23  * You should have received a copy of the GNU Lesser General Public
24  * License along with this library; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26  */
27
28 #include <stdarg.h>
29 #include <string.h>
30 #include "windef.h"
31 #include "winbase.h"
32 #include "wingdi.h"
33 #include "winuser.h"
34 #include "winerror.h"
35 #include "dde.h"
36 #include "ddeml.h"
37 #include "win.h"
38 #include "wine/debug.h"
39 #include "dde/dde_private.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(ddeml);
42
43 static const WCHAR szServerNameClass[] = {'W','i','n','e','D','d','e','S','e','r','v','e','r','N','a','m','e',0};
44 const WCHAR WDML_szServerConvClass[] = {'W','i','n','e','D','d','e','S','e','r','v','e','r','C','o','n','v',0};
45
46 static LRESULT CALLBACK WDML_ServerNameProc(HWND, UINT, WPARAM, LPARAM);
47 static LRESULT CALLBACK WDML_ServerConvProc(HWND, UINT, WPARAM, LPARAM);
48
49 /******************************************************************************
50  * DdePostAdvise [USER32.@]  Send transaction to DDE callback function.
51  *
52  * PARAMS
53  *      idInst    [I] Instance identifier
54  *      hszTopic  [I] Handle to topic name string
55  *      hszItem   [I] Handle to item name string
56  *
57  * RETURNS
58  *    Success: TRUE
59  *    Failure: FALSE
60  */
61 BOOL WINAPI DdePostAdvise(DWORD idInst, HSZ hszTopic, HSZ hszItem)
62 {
63     WDML_INSTANCE*      pInstance = NULL;
64     WDML_LINK*          pLink = NULL;
65     HDDEDATA            hDdeData = 0;
66     HGLOBAL             hItemData = 0;
67     WDML_CONV*          pConv = NULL;
68     ATOM                atom = 0;
69     UINT                count;
70
71     TRACE("(%ld,%p,%p)\n", idInst, hszTopic, hszItem);
72
73     EnterCriticalSection(&WDML_CritSect);
74
75     pInstance = WDML_GetInstance(idInst);
76
77     if (pInstance == NULL || pInstance->links == NULL)
78     {
79         goto theError;
80     }
81
82     atom = WDML_MakeAtomFromHsz(hszItem);
83     if (!atom) goto theError;
84
85     /* first compute the number of links which will trigger a message */
86     count = 0;
87     for (pLink = pInstance->links[WDML_SERVER_SIDE]; pLink != NULL; pLink = pLink->next)
88     {
89         if (DdeCmpStringHandles(hszItem, pLink->hszItem) == 0)
90         {
91             count++;
92         }
93     }
94     if (count >= CADV_LATEACK)
95     {
96         FIXME("too high value for count\n");
97         count &= 0xFFFF;
98     }
99
100     for (pLink = pInstance->links[WDML_SERVER_SIDE]; pLink != NULL; pLink = pLink->next)
101     {
102         if (DdeCmpStringHandles(hszItem, pLink->hszItem) == 0)
103         {
104             hDdeData = WDML_InvokeCallback(pInstance, XTYP_ADVREQ, pLink->uFmt, pLink->hConv,
105                                            hszTopic, hszItem, 0, --count, 0);
106
107             if (hDdeData == (HDDEDATA)CBR_BLOCK)
108             {
109                 /* MS doc is not consistent here */
110                 FIXME("CBR_BLOCK returned for ADVREQ\n");
111                 continue;
112             }
113             if (hDdeData)
114             {
115                 if (pLink->transactionType & XTYPF_NODATA)
116                 {
117                     TRACE("no data\n");
118                     hItemData = 0;
119                 }
120                 else
121                 {
122                     TRACE("with data\n");
123
124                     hItemData = WDML_DataHandle2Global(hDdeData, FALSE, FALSE, FALSE, FALSE);
125                 }
126
127                 pConv = WDML_GetConv(pLink->hConv, TRUE);
128
129                 if (pConv == NULL)
130                 {
131                     if (!WDML_IsAppOwned(hDdeData))  DdeFreeDataHandle(hDdeData);
132                     goto theError;
133                 }
134
135                 if (!PostMessageW(pConv->hwndClient, WM_DDE_DATA, (WPARAM)pConv->hwndServer,
136                                   PackDDElParam(WM_DDE_DATA, (UINT_PTR)hItemData, atom)))
137                 {
138                     ERR("post message failed\n");
139                     pConv->wStatus &= ~ST_CONNECTED;
140                     if (!WDML_IsAppOwned(hDdeData))  DdeFreeDataHandle(hDdeData);
141                     GlobalFree(hItemData);
142                     goto theError;
143                 }
144                 if (!WDML_IsAppOwned(hDdeData))  DdeFreeDataHandle(hDdeData);
145             }
146         }
147     }
148     LeaveCriticalSection(&WDML_CritSect);
149     return TRUE;
150  theError:
151     LeaveCriticalSection(&WDML_CritSect);
152     if (atom) GlobalDeleteAtom(atom);
153     return FALSE;
154 }
155
156
157 /******************************************************************************
158  * DdeNameService [USER32.@]  {Un}registers service name of DDE server
159  *
160  * PARAMS
161  *    idInst [I] Instance identifier
162  *    hsz1   [I] Handle to service name string
163  *    hsz2   [I] Reserved
164  *    afCmd  [I] Service name flags
165  *
166  * RETURNS
167  *    Success: Non-zero
168  *    Failure: 0
169  */
170 HDDEDATA WINAPI DdeNameService(DWORD idInst, HSZ hsz1, HSZ hsz2, UINT afCmd)
171 {
172     WDML_SERVER*        pServer;
173     WDML_INSTANCE*      pInstance;
174     HDDEDATA            hDdeData;
175     HWND                hwndServer;
176     WNDCLASSEXW         wndclass;
177
178     hDdeData = NULL;
179
180     TRACE("(%ld,%p,%p,%x)\n", idInst, hsz1, hsz2, afCmd);
181
182     EnterCriticalSection(&WDML_CritSect);
183
184     /*  First check instance
185      */
186     pInstance = WDML_GetInstance(idInst);
187     if  (pInstance == NULL)
188     {
189         TRACE("Instance not found as initialised\n");
190         /*  Nothing has been initialised - exit now ! can return TRUE since effect is the same */
191         goto theError;
192     }
193
194     if (hsz2 != 0L)
195     {
196         /*      Illegal, reserved parameter
197          */
198         pInstance->lastError = DMLERR_INVALIDPARAMETER;
199         WARN("Reserved parameter no-zero !!\n");
200         goto theError;
201     }
202     if (hsz1 == 0 && !(afCmd & DNS_UNREGISTER))
203     {
204         /*      don't know if we should check this but it makes sense
205          *      why supply REGISTER or filter flags if de-registering all
206          */
207         TRACE("General unregister unexpected flags\n");
208         pInstance->lastError = DMLERR_INVALIDPARAMETER;
209         goto theError;
210     }
211
212     switch (afCmd & (DNS_REGISTER | DNS_UNREGISTER))
213     {
214     case DNS_REGISTER:
215         pServer = WDML_FindServer(pInstance, hsz1, 0);
216         if (pServer)
217         {
218             ERR("Trying to register already registered service!\n");
219             pInstance->lastError = DMLERR_DLL_USAGE;
220             goto theError;
221         }
222
223         TRACE("Adding service name\n");
224
225         WDML_IncHSZ(pInstance, hsz1);
226
227         pServer = WDML_AddServer(pInstance, hsz1, 0);
228
229         WDML_BroadcastDDEWindows(WDML_szEventClass, WM_WDML_REGISTER,
230                                  pServer->atomService, pServer->atomServiceSpec);
231
232         wndclass.cbSize        = sizeof(wndclass);
233         wndclass.style         = 0;
234         wndclass.lpfnWndProc   = WDML_ServerNameProc;
235         wndclass.cbClsExtra    = 0;
236         wndclass.cbWndExtra    = 2 * sizeof(ULONG_PTR);
237         wndclass.hInstance     = 0;
238         wndclass.hIcon         = 0;
239         wndclass.hCursor       = 0;
240         wndclass.hbrBackground = 0;
241         wndclass.lpszMenuName  = NULL;
242         wndclass.lpszClassName = szServerNameClass;
243         wndclass.hIconSm       = 0;
244
245         RegisterClassExW(&wndclass);
246
247         LeaveCriticalSection(&WDML_CritSect);
248         hwndServer = CreateWindowW(szServerNameClass, NULL,
249                                    WS_POPUP, 0, 0, 0, 0,
250                                    0, 0, 0, 0);
251         EnterCriticalSection(&WDML_CritSect);
252
253         SetWindowLongPtrW(hwndServer, GWL_WDML_INSTANCE, (ULONG_PTR)pInstance);
254         SetWindowLongPtrW(hwndServer, GWL_WDML_SERVER, (ULONG_PTR)pServer);
255         TRACE("Created nameServer=%p for instance=%08lx\n", hwndServer, idInst);
256
257         pServer->hwndServer = hwndServer;
258         break;
259
260     case DNS_UNREGISTER:
261         if (hsz1 == 0L)
262         {
263             /* General unregister situation
264              * terminate all server side pending conversations
265              */
266             while (pInstance->servers)
267                 WDML_RemoveServer(pInstance, pInstance->servers->hszService, 0);
268             pInstance->servers = NULL;
269             TRACE("General de-register - finished\n");
270         }
271         else
272         {
273             WDML_RemoveServer(pInstance, hsz1, 0L);
274         }
275         break;
276     }
277
278     if (afCmd & (DNS_FILTERON | DNS_FILTEROFF))
279     {
280         /*      Set filter flags on to hold notifications of connection
281          */
282         pServer = WDML_FindServer(pInstance, hsz1, 0);
283         if (!pServer)
284         {
285             /*  trying to filter where no service names !!
286              */
287             pInstance->lastError = DMLERR_DLL_USAGE;
288             goto theError;
289         }
290         else
291         {
292             pServer->filterOn = (afCmd & DNS_FILTERON) != 0;
293         }
294     }
295     LeaveCriticalSection(&WDML_CritSect);
296     return (HDDEDATA)TRUE;
297
298  theError:
299     LeaveCriticalSection(&WDML_CritSect);
300     return FALSE;
301 }
302
303 /******************************************************************
304  *              WDML_CreateServerConv
305  *
306  *
307  */
308 static WDML_CONV* WDML_CreateServerConv(WDML_INSTANCE* pInstance, HWND hwndClient,
309                                         HWND hwndServerName, HSZ hszApp, HSZ hszTopic)
310 {
311     HWND        hwndServerConv;
312     WDML_CONV*  pConv;
313     WNDCLASSEXW wndclass;
314
315     wndclass.cbSize        = sizeof(wndclass);
316     wndclass.style         = 0;
317     wndclass.lpfnWndProc   = WDML_ServerConvProc;
318     wndclass.cbClsExtra    = 0;
319     wndclass.cbWndExtra    = 2 * sizeof(ULONG_PTR);
320     wndclass.hInstance     = 0;
321     wndclass.hIcon         = 0;
322     wndclass.hCursor       = 0;
323     wndclass.hbrBackground = 0;
324     wndclass.lpszMenuName  = NULL;
325     wndclass.lpszClassName = WDML_szServerConvClass;
326     wndclass.hIconSm       = 0;
327
328     RegisterClassExW(&wndclass);
329
330     hwndServerConv = CreateWindowW(WDML_szServerConvClass, 0,
331                                        WS_CHILD, 0, 0, 0, 0,
332                                        hwndServerName, 0, 0, 0);
333
334     TRACE("Created convServer=%p (nameServer=%p) for instance=%08lx\n",
335           hwndServerConv, hwndServerName, pInstance->instanceID);
336
337     pConv = WDML_AddConv(pInstance, WDML_SERVER_SIDE, hszApp, hszTopic,
338                          hwndClient, hwndServerConv);
339     if (pConv)
340     {
341         SetWindowLongPtrW(hwndServerConv, GWL_WDML_INSTANCE, (ULONG_PTR)pInstance);
342         SetWindowLongPtrW(hwndServerConv, GWL_WDML_CONVERSATION, (ULONG_PTR)pConv);
343
344         /* this should be the only place using SendMessage for WM_DDE_ACK */
345         /* note: sent messages shall not use packing */
346         SendMessageW(hwndClient, WM_DDE_ACK, (WPARAM)hwndServerConv,
347                      MAKELPARAM(WDML_MakeAtomFromHsz(hszApp), WDML_MakeAtomFromHsz(hszTopic)));
348         /* we assume we're connected since we've sent an answer...
349          * I'm not sure what we can do... it doesn't look like the return value
350          * of SendMessage is used... sigh...
351          */
352         pConv->wStatus |= ST_CONNECTED;
353     }
354     else
355     {
356         DestroyWindow(hwndServerConv);
357     }
358     return pConv;
359 }
360
361 /******************************************************************
362  *              WDML_ServerNameProc
363  *
364  *
365  */
366 static LRESULT CALLBACK WDML_ServerNameProc(HWND hwndServer, UINT iMsg, WPARAM wParam, LPARAM lParam)
367 {
368     HWND                hwndClient;
369     HSZ                 hszApp, hszTop;
370     HDDEDATA            hDdeData = 0;
371     WDML_INSTANCE*      pInstance;
372     UINT_PTR            uiLo, uiHi;
373
374     switch (iMsg)
375     {
376     case WM_DDE_INITIATE:
377
378         /* wParam         -- sending window handle
379            LOWORD(lParam) -- application atom
380            HIWORD(lParam) -- topic atom */
381
382         TRACE("WM_DDE_INITIATE message received!\n");
383         hwndClient = (HWND)wParam;
384
385         pInstance = WDML_GetInstanceFromWnd(hwndServer);
386         TRACE("idInst=%ld, threadID=0x%lx\n", pInstance->instanceID, GetCurrentThreadId());
387         if (!pInstance) return 0;
388
389         /* don't free DDEParams, since this is a broadcast */
390         UnpackDDElParam(WM_DDE_INITIATE, lParam, &uiLo, &uiHi);
391
392         hszApp = WDML_MakeHszFromAtom(pInstance, uiLo);
393         hszTop = WDML_MakeHszFromAtom(pInstance, uiHi);
394
395         if (!(pInstance->CBFflags & CBF_FAIL_CONNECTIONS))
396         {
397             BOOL                self = FALSE;
398             CONVCONTEXT         cc;
399             CONVCONTEXT*        pcc = NULL;
400             WDML_CONV*          pConv;
401             WCHAR               buf[256];
402
403             if (GetWindowThreadProcessId(hwndClient, NULL) == GetWindowThreadProcessId(hwndServer, NULL) &&
404                 WDML_GetInstanceFromWnd(hwndClient) == WDML_GetInstanceFromWnd(hwndServer))
405             {
406                 self = TRUE;
407             }
408             /* FIXME: so far, we don't grab distant convcontext, so only check if remote is
409              * handled under DDEML, and if so build a default context
410              */
411             if (GetClassNameW(hwndClient, buf, sizeof(buf)/sizeof(WCHAR)) &&
412                  lstrcmpiW(buf, WDML_szClientConvClass) == 0)
413             {
414                 pcc = &cc;
415                 memset(pcc, 0, sizeof(*pcc));
416                 pcc->cb = sizeof(*pcc);
417                 pcc->iCodePage = CP_WINUNICODE;
418             }
419             if ((pInstance->CBFflags & CBF_FAIL_SELFCONNECTIONS) && self)
420             {
421                 TRACE("Don't do self connection as requested\n");
422             }
423             else if (hszApp && hszTop)
424             {
425                 WDML_SERVER*    pServer = (WDML_SERVER*)GetWindowLongPtrW(hwndServer, GWL_WDML_SERVER);
426
427                 /* check filters for name service */
428                 if (!pServer->filterOn || DdeCmpStringHandles(pServer->hszService, hszApp) == 0)
429                 {
430                     /* pass on to the callback  */
431                     hDdeData = WDML_InvokeCallback(pInstance, XTYP_CONNECT,
432                                                    0, 0, hszTop, hszApp, 0, (ULONG_PTR)pcc, self);
433                     if ((ULONG_PTR)hDdeData)
434                     {
435                         pConv = WDML_CreateServerConv(pInstance, hwndClient, hwndServer,
436                                                       hszApp, hszTop);
437                         if (pConv)
438                         {
439                             if (pcc) pConv->wStatus |= ST_ISLOCAL;
440                             WDML_InvokeCallback(pInstance, XTYP_CONNECT_CONFIRM, 0, (HCONV)pConv,
441                                                 hszTop, hszApp, 0, (ULONG_PTR)pcc, self);
442                         }
443                     }
444                 }
445             }
446             else if (pInstance->servers)
447             {
448                 /* pass on to the callback  */
449                 hDdeData = WDML_InvokeCallback(pInstance, XTYP_WILDCONNECT,
450                                                0, 0, hszTop, hszApp, 0, (ULONG_PTR)pcc, self);
451
452                 if (hDdeData == (HDDEDATA)CBR_BLOCK)
453                 {
454                     /* MS doc is not consistent here */
455                     FIXME("CBR_BLOCK returned for WILDCONNECT\n");
456                 }
457                 else if ((ULONG_PTR)hDdeData != 0)
458                 {
459                     HSZPAIR*    hszp;
460
461                     hszp = (HSZPAIR*)DdeAccessData(hDdeData, NULL);
462                     if (hszp)
463                     {
464                         int     i;
465                         for (i = 0; hszp[i].hszSvc && hszp[i].hszTopic; i++)
466                         {
467                             pConv = WDML_CreateServerConv(pInstance, hwndClient, hwndServer,
468                                                           hszp[i].hszSvc, hszp[i].hszTopic);
469                             if (pConv)
470                             {
471                                 if (pcc) pConv->wStatus |= ST_ISLOCAL;
472                                 WDML_InvokeCallback(pInstance, XTYP_CONNECT_CONFIRM, 0, (HCONV)pConv,
473                                                     hszp[i].hszTopic, hszp[i].hszSvc, 0, (ULONG_PTR)pcc, self);
474                             }
475                         }
476                         DdeUnaccessData(hDdeData);
477                     }
478                     if (!WDML_IsAppOwned(hDdeData)) DdeFreeDataHandle(hDdeData);
479                 }
480             }
481         }
482
483         return 0;
484
485     case WM_DDE_REQUEST:
486         FIXME("WM_DDE_REQUEST message received!\n");
487         return 0;
488     case WM_DDE_ADVISE:
489         FIXME("WM_DDE_ADVISE message received!\n");
490         return 0;
491     case WM_DDE_UNADVISE:
492         FIXME("WM_DDE_UNADVISE message received!\n");
493         return 0;
494     case WM_DDE_EXECUTE:
495         FIXME("WM_DDE_EXECUTE message received!\n");
496         return 0;
497     case WM_DDE_POKE:
498         FIXME("WM_DDE_POKE message received!\n");
499         return 0;
500     case WM_DDE_TERMINATE:
501         FIXME("WM_DDE_TERMINATE message received!\n");
502         return 0;
503     default:
504         break;
505     }
506
507     return DefWindowProcW(hwndServer, iMsg, wParam, lParam);
508 }
509
510 /******************************************************************
511  *              WDML_ServerQueueRequest
512  *
513  *
514  */
515 static  WDML_XACT*      WDML_ServerQueueRequest(WDML_CONV* pConv, LPARAM lParam)
516 {
517     UINT_PTR            uiLo, uiHi;
518     WDML_XACT*          pXAct;
519
520     UnpackDDElParam(WM_DDE_REQUEST, lParam, &uiLo, &uiHi);
521
522     pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_REQUEST,
523                                   uiLo, WDML_MakeHszFromAtom(pConv->instance, uiHi));
524     if (pXAct) pXAct->atom = uiHi;
525     return pXAct;
526 }
527
528 /******************************************************************
529  *              WDML_ServerHandleRequest
530  *
531  *
532  */
533 static  WDML_QUEUE_STATE WDML_ServerHandleRequest(WDML_CONV* pConv, WDML_XACT* pXAct)
534 {
535     HDDEDATA            hDdeData = 0;
536     BOOL                fAck = TRUE;
537
538     if (!(pConv->instance->CBFflags & CBF_FAIL_REQUESTS))
539     {
540
541         hDdeData = WDML_InvokeCallback(pConv->instance, XTYP_REQUEST, pXAct->wFmt, (HCONV)pConv,
542                                        pConv->hszTopic, pXAct->hszItem, 0, 0, 0);
543     }
544
545     switch ((ULONG_PTR)hDdeData)
546     {
547     case 0:
548         TRACE("No data returned from the Callback\n");
549         fAck = FALSE;
550         break;
551
552     case (ULONG_PTR)CBR_BLOCK:
553         return WDML_QS_BLOCK;
554
555     default:
556         {
557             HGLOBAL     hMem = WDML_DataHandle2Global(hDdeData, TRUE, FALSE, FALSE, FALSE);
558             if (!PostMessageW(pConv->hwndClient, WM_DDE_DATA, (WPARAM)pConv->hwndServer,
559                               ReuseDDElParam(pXAct->lParam, WM_DDE_REQUEST, WM_DDE_DATA,
560                                              (UINT_PTR)hMem, (UINT_PTR)pXAct->atom)))
561             {
562                 DdeFreeDataHandle(hDdeData);
563                 GlobalFree(hMem);
564                 fAck = FALSE;
565             }
566         }
567         break;
568     }
569
570     WDML_PostAck(pConv, WDML_SERVER_SIDE, 0, FALSE, fAck, pXAct->atom, pXAct->lParam, WM_DDE_REQUEST);
571
572     WDML_DecHSZ(pConv->instance, pXAct->hszItem);
573
574     return WDML_QS_HANDLED;
575 }
576
577 /******************************************************************
578  *              WDML_ServerQueueAdvise
579  *
580  *
581  */
582 static  WDML_XACT*      WDML_ServerQueueAdvise(WDML_CONV* pConv, LPARAM lParam)
583 {
584     UINT_PTR            uiLo, uiHi;
585     WDML_XACT*          pXAct;
586
587     /* XTYP_ADVSTART transaction:
588        establish link and save link info to InstanceInfoTable */
589
590     if (!UnpackDDElParam(WM_DDE_ADVISE, lParam, &uiLo, &uiHi))
591         return NULL;
592
593     pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_ADVISE,
594                                   0, WDML_MakeHszFromAtom(pConv->instance, uiHi));
595     if (pXAct)
596     {
597         pXAct->hMem = (HGLOBAL)uiLo;
598         pXAct->atom = uiHi;
599     }
600     return pXAct;
601 }
602
603 /******************************************************************
604  *              WDML_ServerHandleAdvise
605  *
606  *
607  */
608 static  WDML_QUEUE_STATE WDML_ServerHandleAdvise(WDML_CONV* pConv, WDML_XACT* pXAct)
609 {
610     UINT                uType;
611     WDML_LINK*          pLink;
612     DDEADVISE*          pDdeAdvise;
613     HDDEDATA            hDdeData = 0;
614     BOOL                fAck = TRUE;
615
616     pDdeAdvise = (DDEADVISE*)GlobalLock(pXAct->hMem);
617     uType = XTYP_ADVSTART |
618             (pDdeAdvise->fDeferUpd ? XTYPF_NODATA : 0) |
619             (pDdeAdvise->fAckReq ? XTYPF_ACKREQ : 0);
620
621     if (!(pConv->instance->CBFflags & CBF_FAIL_ADVISES))
622     {
623         hDdeData = WDML_InvokeCallback(pConv->instance, XTYP_ADVSTART, pDdeAdvise->cfFormat,
624                                        (HCONV)pConv, pConv->hszTopic, pXAct->hszItem, 0, 0, 0);
625     }
626
627     switch ((ULONG_PTR)hDdeData)
628     {
629     case 0:
630         TRACE("No data returned from the Callback\n");
631         fAck = FALSE;
632         break;
633
634     case (ULONG_PTR)CBR_BLOCK:
635         return WDML_QS_BLOCK;
636
637     default:
638         /* billx: first to see if the link is already created. */
639         pLink = WDML_FindLink(pConv->instance, (HCONV)pConv, WDML_SERVER_SIDE,
640                               pXAct->hszItem, TRUE, pDdeAdvise->cfFormat);
641
642         if (pLink != NULL)
643         {
644             /* we found a link, and only need to modify it in case it changes */
645             pLink->transactionType = uType;
646         }
647         else
648         {
649             TRACE("Adding Link with hConv %p\n", pConv);
650             WDML_AddLink(pConv->instance, (HCONV)pConv, WDML_SERVER_SIDE,
651                          uType, pXAct->hszItem, pDdeAdvise->cfFormat);
652         }
653         break;
654     }
655
656     GlobalUnlock(pXAct->hMem);
657     if (fAck)
658     {
659         GlobalFree(pXAct->hMem);
660     }
661     pXAct->hMem = 0;
662
663     WDML_PostAck(pConv, WDML_SERVER_SIDE, 0, FALSE, fAck, pXAct->atom, pXAct->lParam, WM_DDE_ADVISE);
664
665     WDML_DecHSZ(pConv->instance, pXAct->hszItem);
666
667     return WDML_QS_HANDLED;
668 }
669
670 /******************************************************************
671  *              WDML_ServerQueueUnadvise
672  *
673  *
674  */
675 static  WDML_XACT* WDML_ServerQueueUnadvise(WDML_CONV* pConv, LPARAM lParam)
676 {
677     UINT_PTR            uiLo, uiHi;
678     WDML_XACT*          pXAct;
679
680     UnpackDDElParam(WM_DDE_UNADVISE, lParam, &uiLo, &uiHi);
681
682     pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_UNADVISE,
683                                   uiLo, WDML_MakeHszFromAtom(pConv->instance, uiHi));
684     if (pXAct) pXAct->atom = uiHi;
685     return pXAct;
686 }
687
688 /******************************************************************
689  *              WDML_ServerHandleUnadvise
690  *
691  *
692  */
693 static  WDML_QUEUE_STATE WDML_ServerHandleUnadvise(WDML_CONV* pConv, WDML_XACT* pXAct)
694 {
695     WDML_LINK*  pLink;
696
697     if (pXAct->hszItem == NULL || pXAct->wFmt == 0)
698     {
699         ERR("Unsupported yet options (null item or clipboard format)\n");
700         return WDML_QS_ERROR;
701     }
702
703     pLink = WDML_FindLink(pConv->instance, (HCONV)pConv, WDML_SERVER_SIDE,
704                           pXAct->hszItem, TRUE, pXAct->wFmt);
705     if (pLink == NULL)
706     {
707         ERR("Couln'd find link for %p, dropping request\n", pXAct->hszItem);
708         FreeDDElParam(WM_DDE_UNADVISE, pXAct->lParam);
709         return WDML_QS_ERROR;
710     }
711
712     if (!(pConv->instance->CBFflags & CBF_FAIL_ADVISES))
713     {
714         WDML_InvokeCallback(pConv->instance, XTYP_ADVSTOP, pXAct->wFmt, (HCONV)pConv,
715                             pConv->hszTopic, pXAct->hszItem, 0, 0, 0);
716     }
717
718     WDML_RemoveLink(pConv->instance, (HCONV)pConv, WDML_SERVER_SIDE,
719                     pXAct->hszItem, pXAct->wFmt);
720
721     /* send back ack */
722     WDML_PostAck(pConv, WDML_SERVER_SIDE, 0, FALSE, TRUE, pXAct->atom,
723                  pXAct->lParam, WM_DDE_UNADVISE);
724
725     WDML_DecHSZ(pConv->instance, pXAct->hszItem);
726
727     return WDML_QS_HANDLED;
728 }
729
730 /******************************************************************
731  *              WDML_QueueExecute
732  *
733  *
734  */
735 static  WDML_XACT* WDML_ServerQueueExecute(WDML_CONV* pConv, LPARAM lParam)
736 {
737     WDML_XACT*  pXAct;
738
739     pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_EXECUTE, 0, 0);
740     if (pXAct)
741     {
742         pXAct->hMem    = (HGLOBAL)lParam;
743     }
744     return pXAct;
745 }
746
747  /******************************************************************
748  *              WDML_ServerHandleExecute
749  *
750  *
751  */
752 static  WDML_QUEUE_STATE WDML_ServerHandleExecute(WDML_CONV* pConv, WDML_XACT* pXAct)
753 {
754     HDDEDATA    hDdeData = DDE_FNOTPROCESSED;
755     BOOL        fAck = FALSE, fBusy = FALSE;
756
757     if (!(pConv->instance->CBFflags & CBF_FAIL_EXECUTES))
758     {
759         LPVOID  ptr = GlobalLock(pXAct->hMem);
760
761         if (ptr)
762         {
763             hDdeData = DdeCreateDataHandle(0, ptr, GlobalSize(pXAct->hMem),
764                                            0, 0, CF_TEXT, 0);
765             GlobalUnlock(pXAct->hMem);
766         }
767         hDdeData = WDML_InvokeCallback(pConv->instance, XTYP_EXECUTE, 0, (HCONV)pConv,
768                                        pConv->hszTopic, 0, hDdeData, 0L, 0L);
769     }
770
771     switch ((ULONG_PTR)hDdeData)
772     {
773     case (ULONG_PTR)CBR_BLOCK:
774         return WDML_QS_BLOCK;
775
776     case DDE_FACK:
777         fAck = TRUE;
778         break;
779     case DDE_FBUSY:
780         fBusy = TRUE;
781         break;
782     default:
783         FIXME("Unsupported returned value %p\n", hDdeData);
784         /* fall through */
785     case DDE_FNOTPROCESSED:
786         break;
787     }
788     WDML_PostAck(pConv, WDML_SERVER_SIDE, 0, fBusy, fAck, (UINT)pXAct->hMem, 0, 0);
789
790     return WDML_QS_HANDLED;
791 }
792
793 /******************************************************************
794  *              WDML_ServerQueuePoke
795  *
796  *
797  */
798 static  WDML_XACT* WDML_ServerQueuePoke(WDML_CONV* pConv, LPARAM lParam)
799 {
800     UINT_PTR            uiLo, uiHi;
801     WDML_XACT*          pXAct;
802
803     UnpackDDElParam(WM_DDE_POKE, lParam, &uiLo, &uiHi);
804
805     pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_POKE,
806                                   0, WDML_MakeHszFromAtom(pConv->instance, uiHi));
807     if (pXAct)
808     {
809         pXAct->atom = uiHi;
810         pXAct->hMem = (HGLOBAL)uiLo;
811     }
812     return pXAct;
813 }
814
815 /******************************************************************
816  *              WDML_ServerHandlePoke
817  *
818  *
819  */
820 static  WDML_QUEUE_STATE WDML_ServerHandlePoke(WDML_CONV* pConv, WDML_XACT* pXAct)
821 {
822     DDEPOKE*            pDdePoke;
823     HDDEDATA            hDdeData;
824     BOOL                fBusy = FALSE, fAck = FALSE;
825
826     pDdePoke = (DDEPOKE*)GlobalLock(pXAct->hMem);
827     if (!pDdePoke)
828     {
829         return WDML_QS_ERROR;
830     }
831
832     if (!(pConv->instance->CBFflags & CBF_FAIL_POKES))
833     {
834         hDdeData = DdeCreateDataHandle(pConv->instance->instanceID, pDdePoke->Value,
835                                        GlobalSize(pXAct->hMem) - sizeof(DDEPOKE) + 1,
836                                        0, 0, pDdePoke->cfFormat, 0);
837         if (hDdeData)
838         {
839             HDDEDATA    hDdeDataOut;
840
841             hDdeDataOut = WDML_InvokeCallback(pConv->instance, XTYP_POKE, pDdePoke->cfFormat,
842                                               (HCONV)pConv, pConv->hszTopic, pXAct->hszItem,
843                                               hDdeData, 0, 0);
844             switch ((ULONG_PTR)hDdeDataOut)
845             {
846             case DDE_FACK:
847                 fAck = TRUE;
848                 break;
849             case DDE_FBUSY:
850                 fBusy = TRUE;
851                 break;
852             default:
853                 FIXME("Unsupported returned value %p\n", hDdeDataOut);
854                 /* fal through */
855             case DDE_FNOTPROCESSED:
856                 break;
857             }
858             DdeFreeDataHandle(hDdeData);
859         }
860     }
861     GlobalUnlock(pXAct->hMem);
862
863     if (!fAck)
864     {
865         GlobalFree(pXAct->hMem);
866     }
867     WDML_PostAck(pConv, WDML_SERVER_SIDE, 0, fBusy, fAck, pXAct->atom, pXAct->lParam, WM_DDE_POKE);
868
869     WDML_DecHSZ(pConv->instance, pXAct->hszItem);
870
871     return WDML_QS_HANDLED;
872 }
873
874 /******************************************************************
875  *              WDML_ServerQueueTerminate
876  *
877  *
878  */
879 static  WDML_XACT*      WDML_ServerQueueTerminate(WDML_CONV* pConv, LPARAM lParam)
880 {
881     WDML_XACT*  pXAct;
882
883     pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_TERMINATE, 0, 0);
884     return pXAct;
885 }
886
887 /******************************************************************
888  *              WDML_ServerHandleTerminate
889  *
890  *
891  */
892 static  WDML_QUEUE_STATE WDML_ServerHandleTerminate(WDML_CONV* pConv, WDML_XACT* pXAct)
893 {
894     /* billx: two things to remove: the conv, and associated links.
895      * Respond with another WM_DDE_TERMINATE iMsg.
896      */
897     if (!(pConv->instance->CBFflags & CBF_SKIP_DISCONNECTS))
898     {
899         WDML_InvokeCallback(pConv->instance, XTYP_DISCONNECT, 0, (HCONV)pConv, 0, 0,
900                             0, 0, (pConv->wStatus & ST_ISSELF) ? 1 : 0);
901     }
902     PostMessageW(pConv->hwndClient, WM_DDE_TERMINATE, (WPARAM)pConv->hwndServer, 0);
903     WDML_RemoveConv(pConv, WDML_SERVER_SIDE);
904
905     return WDML_QS_HANDLED;
906 }
907
908 /******************************************************************
909  *              WDML_ServerHandle
910  *
911  *
912  */
913 WDML_QUEUE_STATE WDML_ServerHandle(WDML_CONV* pConv, WDML_XACT* pXAct)
914 {
915     WDML_QUEUE_STATE    qs = WDML_QS_ERROR;
916
917     switch (pXAct->ddeMsg)
918     {
919     case WM_DDE_INITIATE:
920         FIXME("WM_DDE_INITIATE shouldn't be there!\n");
921         break;
922     case WM_DDE_REQUEST:
923         qs = WDML_ServerHandleRequest(pConv, pXAct);
924         break;
925
926     case WM_DDE_ADVISE:
927         qs = WDML_ServerHandleAdvise(pConv, pXAct);
928         break;
929
930     case WM_DDE_UNADVISE:
931         qs = WDML_ServerHandleUnadvise(pConv, pXAct);
932         break;
933
934     case WM_DDE_EXECUTE:
935         qs = WDML_ServerHandleExecute(pConv, pXAct);
936         break;
937
938     case WM_DDE_POKE:
939         qs = WDML_ServerHandlePoke(pConv, pXAct);
940         break;
941
942     case WM_DDE_TERMINATE:
943         qs = WDML_ServerHandleTerminate(pConv, pXAct);
944         break;
945
946     case WM_DDE_ACK:
947         WARN("Shouldn't receive a ACK message (never requests them). Ignoring it\n");
948         break;
949
950     default:
951         FIXME("Unsupported message %d\n", pXAct->ddeMsg);
952     }
953     return qs;
954 }
955
956 /******************************************************************
957  *              WDML_ServerConvProc
958  *
959  *
960  */
961 static LRESULT CALLBACK WDML_ServerConvProc(HWND hwndServer, UINT iMsg, WPARAM wParam, LPARAM lParam)
962 {
963     WDML_INSTANCE*      pInstance;
964     WDML_CONV*          pConv;
965     WDML_XACT*          pXAct = NULL;
966
967     TRACE("%p %04x %08x %08lx\n", hwndServer, iMsg, wParam , lParam);
968
969     if (iMsg == WM_DESTROY)
970     {
971         EnterCriticalSection(&WDML_CritSect);
972         pConv = WDML_GetConvFromWnd(hwndServer);
973         if (pConv && !(pConv->wStatus & ST_TERMINATED))
974         {
975             WDML_ServerHandleTerminate(pConv, NULL);
976         }
977         LeaveCriticalSection(&WDML_CritSect);
978     }
979     if (iMsg < WM_DDE_FIRST || iMsg > WM_DDE_LAST)
980     {
981         return DefWindowProcW(hwndServer, iMsg, wParam, lParam);
982     }
983
984     EnterCriticalSection(&WDML_CritSect);
985
986     pInstance = WDML_GetInstanceFromWnd(hwndServer);
987     pConv = WDML_GetConvFromWnd(hwndServer);
988
989     if (!pConv)
990     {
991         ERR("Got a message (%x) on a not known conversation, dropping request\n", iMsg);
992         goto theError;
993     }
994     if (pConv->hwndClient != WIN_GetFullHandle( (HWND)wParam ) || pConv->hwndServer != hwndServer)
995     {
996         ERR("mismatch between C/S windows and converstation\n");
997         goto theError;
998     }
999     if (pConv->instance != pInstance || pConv->instance == NULL)
1000     {
1001         ERR("mismatch in instances\n");
1002         goto theError;
1003     }
1004
1005     switch (iMsg)
1006     {
1007     case WM_DDE_INITIATE:
1008         FIXME("WM_DDE_INITIATE message received!\n");
1009         break;
1010
1011     case WM_DDE_REQUEST:
1012         pXAct = WDML_ServerQueueRequest(pConv, lParam);
1013         break;
1014
1015     case WM_DDE_ADVISE:
1016         pXAct = WDML_ServerQueueAdvise(pConv, lParam);
1017         break;
1018
1019     case WM_DDE_UNADVISE:
1020         pXAct = WDML_ServerQueueUnadvise(pConv, lParam);
1021         break;
1022
1023     case WM_DDE_EXECUTE:
1024         pXAct = WDML_ServerQueueExecute(pConv, lParam);
1025         break;
1026
1027     case WM_DDE_POKE:
1028         pXAct = WDML_ServerQueuePoke(pConv, lParam);
1029         break;
1030
1031     case WM_DDE_TERMINATE:
1032         pXAct = WDML_ServerQueueTerminate(pConv, lParam);
1033         break;
1034
1035     case WM_DDE_ACK:
1036         WARN("Shouldn't receive a ACK message (never requests them). Ignoring it\n");
1037         break;
1038
1039     default:
1040         FIXME("Unsupported message %x\n", iMsg);
1041     }
1042
1043     if (pXAct)
1044     {
1045         pXAct->lParam = lParam;
1046         if (WDML_ServerHandle(pConv, pXAct) == WDML_QS_BLOCK)
1047         {
1048             WDML_QueueTransaction(pConv, pXAct);
1049         }
1050         else
1051         {
1052             WDML_FreeTransaction(pInstance, pXAct, TRUE);
1053         }
1054     }
1055  theError:
1056     LeaveCriticalSection(&WDML_CritSect);
1057     return 0;
1058 }