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