Added parser template and made AVISplitter use it.
[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  *
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Lesser General Public
14  * License as published by the Free Software Foundation; either
15  * version 2.1 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public
23  * License along with this library; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25  */
26
27 #include <stdarg.h>
28 #include <string.h>
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "winuser.h"
33 #include "winerror.h"
34 #include "dde.h"
35 #include "ddeml.h"
36 #include "win.h"
37 #include "wine/debug.h"
38 #include "dde/dde_private.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(ddeml);
41
42 static const char  szServerNameClassA[] = "DdeServerNameAnsi";
43 const char  WDML_szServerConvClassA[] = "DdeServerConvAnsi";
44 const WCHAR WDML_szServerConvClassW[] = {'D','d','e','S','e','r','v','e','r','C','o','n','v','U','n','i','c','o','d','e',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 (!PostMessageA(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     WNDCLASSEXA         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(DWORD);
237         wndclass.hInstance     = 0;
238         wndclass.hIcon         = 0;
239         wndclass.hCursor       = 0;
240         wndclass.hbrBackground = 0;
241         wndclass.lpszMenuName  = NULL;
242         wndclass.lpszClassName = szServerNameClassA;
243         wndclass.hIconSm       = 0;
244
245         RegisterClassExA(&wndclass);
246
247         LeaveCriticalSection(&WDML_CritSect);
248         hwndServer = CreateWindowA(szServerNameClassA, NULL,
249                                    WS_POPUP, 0, 0, 0, 0,
250                                    0, 0, 0, 0);
251         EnterCriticalSection(&WDML_CritSect);
252
253         SetWindowLongA(hwndServer, GWL_WDML_INSTANCE, (DWORD)pInstance);
254         SetWindowLongA(hwndServer, GWL_WDML_SERVER, (DWORD)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
314     if (pInstance->unicode)
315     {
316         WNDCLASSEXW     wndclass;
317
318         wndclass.cbSize        = sizeof(wndclass);
319         wndclass.style         = 0;
320         wndclass.lpfnWndProc   = WDML_ServerConvProc;
321         wndclass.cbClsExtra    = 0;
322         wndclass.cbWndExtra    = 2 * sizeof(DWORD);
323         wndclass.hInstance     = 0;
324         wndclass.hIcon         = 0;
325         wndclass.hCursor       = 0;
326         wndclass.hbrBackground = 0;
327         wndclass.lpszMenuName  = NULL;
328         wndclass.lpszClassName = WDML_szServerConvClassW;
329         wndclass.hIconSm       = 0;
330
331         RegisterClassExW(&wndclass);
332
333         hwndServerConv = CreateWindowW(WDML_szServerConvClassW, 0,
334                                        WS_CHILD, 0, 0, 0, 0,
335                                        hwndServerName, 0, 0, 0);
336     }
337     else
338     {
339         WNDCLASSEXA     wndclass;
340
341         wndclass.cbSize        = sizeof(wndclass);
342         wndclass.style         = 0;
343         wndclass.lpfnWndProc   = WDML_ServerConvProc;
344         wndclass.cbClsExtra    = 0;
345         wndclass.cbWndExtra    = 2 * sizeof(DWORD);
346         wndclass.hInstance     = 0;
347         wndclass.hIcon         = 0;
348         wndclass.hCursor       = 0;
349         wndclass.hbrBackground = 0;
350         wndclass.lpszMenuName  = NULL;
351         wndclass.lpszClassName = WDML_szServerConvClassA;
352         wndclass.hIconSm       = 0;
353
354         RegisterClassExA(&wndclass);
355
356         hwndServerConv = CreateWindowA(WDML_szServerConvClassA, 0,
357                                        WS_CHILD, 0, 0, 0, 0,
358                                        hwndServerName, 0, 0, 0);
359     }
360
361     TRACE("Created convServer=%p (nameServer=%p) for instance=%08lx\n",
362           hwndServerConv, hwndServerName, pInstance->instanceID);
363
364     pConv = WDML_AddConv(pInstance, WDML_SERVER_SIDE, hszApp, hszTopic,
365                          hwndClient, hwndServerConv);
366     if (pConv)
367     {
368         SetWindowLongA(hwndServerConv, GWL_WDML_INSTANCE, (DWORD)pInstance);
369         SetWindowLongA(hwndServerConv, GWL_WDML_CONVERSATION, (DWORD)pConv);
370
371         /* this should be the only place using SendMessage for WM_DDE_ACK */
372         /* note: sent messages shall not use packing */
373         SendMessageA(hwndClient, WM_DDE_ACK, (WPARAM)hwndServerConv,
374                      MAKELPARAM(WDML_MakeAtomFromHsz(hszApp), WDML_MakeAtomFromHsz(hszTopic)));
375         /* we assume we're connected since we've sent an answer...
376          * I'm not sure what we can do... it doesn't look like the return value
377          * of SendMessage is used... sigh...
378          */
379         pConv->wStatus |= ST_CONNECTED;
380     }
381     else
382     {
383         DestroyWindow(hwndServerConv);
384     }
385     return pConv;
386 }
387
388 /******************************************************************
389  *              WDML_ServerNameProc
390  *
391  *
392  */
393 static LRESULT CALLBACK WDML_ServerNameProc(HWND hwndServer, UINT iMsg, WPARAM wParam, LPARAM lParam)
394 {
395     HWND                hwndClient;
396     HSZ                 hszApp, hszTop;
397     HDDEDATA            hDdeData = 0;
398     WDML_INSTANCE*      pInstance;
399     UINT_PTR            uiLo, uiHi;
400
401     switch (iMsg)
402     {
403     case WM_DDE_INITIATE:
404
405         /* wParam         -- sending window handle
406            LOWORD(lParam) -- application atom
407            HIWORD(lParam) -- topic atom */
408
409         TRACE("WM_DDE_INITIATE message received!\n");
410         hwndClient = (HWND)wParam;
411
412         pInstance = WDML_GetInstanceFromWnd(hwndServer);
413         TRACE("idInst=%ld, threadID=0x%lx\n", pInstance->instanceID, GetCurrentThreadId());
414         if (!pInstance) return 0;
415
416         /* don't free DDEParams, since this is a broadcast */
417         UnpackDDElParam(WM_DDE_INITIATE, lParam, &uiLo, &uiHi);
418
419         hszApp = WDML_MakeHszFromAtom(pInstance, uiLo);
420         hszTop = WDML_MakeHszFromAtom(pInstance, uiHi);
421
422         if (!(pInstance->CBFflags & CBF_FAIL_CONNECTIONS))
423         {
424             BOOL                self = FALSE;
425             CONVCONTEXT         cc;
426             CONVCONTEXT*        pcc = NULL;
427             WDML_CONV*          pConv;
428             char                buf[256];
429
430             if (GetWindowThreadProcessId(hwndClient, NULL) == GetWindowThreadProcessId(hwndServer, NULL) &&
431                 WDML_GetInstanceFromWnd(hwndClient) == WDML_GetInstanceFromWnd(hwndServer))
432             {
433                 self = TRUE;
434             }
435             /* FIXME: so far, we don't grab distant convcontext, so only check if remote is
436              * handled under DDEML, and if so build a default context
437              */
438             if ((GetClassNameA(hwndClient, buf, sizeof(buf)) &&
439                  strcmp(buf, WDML_szClientConvClassA) == 0) ||
440                 (GetClassNameW(hwndClient, (LPWSTR)buf, sizeof(buf)/sizeof(WCHAR)) &&
441                  lstrcmpW((LPWSTR)buf, WDML_szClientConvClassW) == 0))
442             {
443                 pcc = &cc;
444                 memset(pcc, 0, sizeof(*pcc));
445                 pcc->cb = sizeof(*pcc);
446                 pcc->iCodePage = IsWindowUnicode(hwndClient) ? CP_WINUNICODE : CP_WINANSI;
447             }
448             if ((pInstance->CBFflags & CBF_FAIL_SELFCONNECTIONS) && self)
449             {
450                 TRACE("Don't do self connection as requested\n");
451             }
452             else if (hszApp && hszTop)
453             {
454                 WDML_SERVER*    pServer = (WDML_SERVER*)GetWindowLongA(hwndServer, GWL_WDML_SERVER);
455
456                 /* check filters for name service */
457                 if (!pServer->filterOn || DdeCmpStringHandles(pServer->hszService, hszApp) == 0)
458                 {
459                     /* pass on to the callback  */
460                     hDdeData = WDML_InvokeCallback(pInstance, XTYP_CONNECT,
461                                                    0, 0, hszTop, hszApp, 0, (ULONG_PTR)pcc, self);
462                     if ((UINT)hDdeData)
463                     {
464                         pConv = WDML_CreateServerConv(pInstance, hwndClient, hwndServer,
465                                                       hszApp, hszTop);
466                         if (pConv)
467                         {
468                             if (pcc) pConv->wStatus |= ST_ISLOCAL;
469                             WDML_InvokeCallback(pInstance, XTYP_CONNECT_CONFIRM, 0, (HCONV)pConv,
470                                                 hszTop, hszApp, 0, (ULONG_PTR)pcc, self);
471                         }
472                     }
473                 }
474             }
475             else if (pInstance->servers)
476             {
477                 /* pass on to the callback  */
478                 hDdeData = WDML_InvokeCallback(pInstance, XTYP_WILDCONNECT,
479                                                0, 0, hszTop, hszApp, 0, (ULONG_PTR)pcc, self);
480
481                 if (hDdeData == (HDDEDATA)CBR_BLOCK)
482                 {
483                     /* MS doc is not consistent here */
484                     FIXME("CBR_BLOCK returned for WILDCONNECT\n");
485                 }
486                 else if ((UINT)hDdeData != 0)
487                 {
488                     HSZPAIR*    hszp;
489
490                     hszp = (HSZPAIR*)DdeAccessData(hDdeData, NULL);
491                     if (hszp)
492                     {
493                         int     i;
494                         for (i = 0; hszp[i].hszSvc && hszp[i].hszTopic; i++)
495                         {
496                             pConv = WDML_CreateServerConv(pInstance, hwndClient, hwndServer,
497                                                           hszp[i].hszSvc, hszp[i].hszTopic);
498                             if (pConv)
499                             {
500                                 if (pcc) pConv->wStatus |= ST_ISLOCAL;
501                                 WDML_InvokeCallback(pInstance, XTYP_CONNECT_CONFIRM, 0, (HCONV)pConv,
502                                                     hszp[i].hszTopic, hszp[i].hszSvc, 0, (ULONG_PTR)pcc, self);
503                             }
504                         }
505                         DdeUnaccessData(hDdeData);
506                     }
507                     if (!WDML_IsAppOwned(hDdeData)) DdeFreeDataHandle(hDdeData);
508                 }
509             }
510         }
511
512         return 0;
513
514
515     case WM_DDE_REQUEST:
516         FIXME("WM_DDE_REQUEST message received!\n");
517         return 0;
518     case WM_DDE_ADVISE:
519         FIXME("WM_DDE_ADVISE message received!\n");
520         return 0;
521     case WM_DDE_UNADVISE:
522         FIXME("WM_DDE_UNADVISE message received!\n");
523         return 0;
524     case WM_DDE_EXECUTE:
525         FIXME("WM_DDE_EXECUTE message received!\n");
526         return 0;
527     case WM_DDE_POKE:
528         FIXME("WM_DDE_POKE message received!\n");
529         return 0;
530     case WM_DDE_TERMINATE:
531         FIXME("WM_DDE_TERMINATE message received!\n");
532         return 0;
533
534     }
535
536     return DefWindowProcA(hwndServer, iMsg, wParam, lParam);
537 }
538
539 /******************************************************************
540  *              WDML_ServerQueueRequest
541  *
542  *
543  */
544 static  WDML_XACT*      WDML_ServerQueueRequest(WDML_CONV* pConv, LPARAM lParam)
545 {
546     UINT_PTR            uiLo, uiHi;
547     WDML_XACT*          pXAct;
548
549     UnpackDDElParam(WM_DDE_REQUEST, lParam, &uiLo, &uiHi);
550
551     pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_REQUEST,
552                                   uiLo, WDML_MakeHszFromAtom(pConv->instance, uiHi));
553     if (pXAct) pXAct->atom = uiHi;
554     return pXAct;
555 }
556
557 /******************************************************************
558  *              WDML_ServerHandleRequest
559  *
560  *
561  */
562 static  WDML_QUEUE_STATE WDML_ServerHandleRequest(WDML_CONV* pConv, WDML_XACT* pXAct)
563 {
564     HDDEDATA            hDdeData = 0;
565     BOOL                fAck = TRUE;
566
567     if (!(pConv->instance->CBFflags & CBF_FAIL_REQUESTS))
568     {
569
570         hDdeData = WDML_InvokeCallback(pConv->instance, XTYP_REQUEST, pXAct->wFmt, (HCONV)pConv,
571                                        pConv->hszTopic, pXAct->hszItem, 0, 0, 0);
572     }
573
574     switch ((ULONG_PTR)hDdeData)
575     {
576     case 0:
577         TRACE("No data returned from the Callback\n");
578         fAck = FALSE;
579         break;
580
581     case (ULONG_PTR)CBR_BLOCK:
582         return WDML_QS_BLOCK;
583
584     default:
585         {
586             HGLOBAL     hMem = WDML_DataHandle2Global(hDdeData, TRUE, FALSE, FALSE, FALSE);
587             if (!PostMessageA(pConv->hwndClient, WM_DDE_DATA, (WPARAM)pConv->hwndServer,
588                               ReuseDDElParam(pXAct->lParam, WM_DDE_REQUEST, WM_DDE_DATA,
589                                              (UINT_PTR)hMem, (UINT_PTR)pXAct->atom)))
590             {
591                 DdeFreeDataHandle(hDdeData);
592                 GlobalFree(hMem);
593                 fAck = FALSE;
594             }
595         }
596         break;
597     }
598
599     WDML_PostAck(pConv, WDML_SERVER_SIDE, 0, FALSE, fAck, pXAct->atom, pXAct->lParam, WM_DDE_REQUEST);
600
601     WDML_DecHSZ(pConv->instance, pXAct->hszItem);
602
603     return WDML_QS_HANDLED;
604 }
605
606 /******************************************************************
607  *              WDML_ServerQueueAdvise
608  *
609  *
610  */
611 static  WDML_XACT*      WDML_ServerQueueAdvise(WDML_CONV* pConv, LPARAM lParam)
612 {
613     UINT_PTR            uiLo, uiHi;
614     WDML_XACT*          pXAct;
615
616     /* XTYP_ADVSTART transaction:
617        establish link and save link info to InstanceInfoTable */
618
619     if (!UnpackDDElParam(WM_DDE_ADVISE, lParam, &uiLo, &uiHi))
620         return NULL;
621
622     pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_ADVISE,
623                                   0, WDML_MakeHszFromAtom(pConv->instance, uiHi));
624     if (pXAct)
625     {
626         pXAct->hMem = (HGLOBAL)uiLo;
627         pXAct->atom = uiHi;
628     }
629     return pXAct;
630 }
631
632 /******************************************************************
633  *              WDML_ServerHandleAdvise
634  *
635  *
636  */
637 static  WDML_QUEUE_STATE WDML_ServerHandleAdvise(WDML_CONV* pConv, WDML_XACT* pXAct)
638 {
639     UINT                uType;
640     WDML_LINK*          pLink;
641     DDEADVISE*          pDdeAdvise;
642     HDDEDATA            hDdeData = 0;
643     BOOL                fAck = TRUE;
644
645     pDdeAdvise = (DDEADVISE*)GlobalLock(pXAct->hMem);
646     uType = XTYP_ADVSTART |
647             (pDdeAdvise->fDeferUpd ? XTYPF_NODATA : 0) |
648             (pDdeAdvise->fAckReq ? XTYPF_ACKREQ : 0);
649
650     if (!(pConv->instance->CBFflags & CBF_FAIL_ADVISES))
651     {
652         hDdeData = WDML_InvokeCallback(pConv->instance, XTYP_ADVSTART, pDdeAdvise->cfFormat,
653                                        (HCONV)pConv, pConv->hszTopic, pXAct->hszItem, 0, 0, 0);
654     }
655
656     switch ((ULONG_PTR)hDdeData)
657     {
658     case 0:
659         TRACE("No data returned from the Callback\n");
660         fAck = FALSE;
661         break;
662
663     case (ULONG_PTR)CBR_BLOCK:
664         return WDML_QS_BLOCK;
665
666     default:
667         /* billx: first to see if the link is already created. */
668         pLink = WDML_FindLink(pConv->instance, (HCONV)pConv, WDML_SERVER_SIDE,
669                               pXAct->hszItem, TRUE, pDdeAdvise->cfFormat);
670
671         if (pLink != NULL)
672         {
673             /* we found a link, and only need to modify it in case it changes */
674             pLink->transactionType = uType;
675         }
676         else
677         {
678             TRACE("Adding Link with hConv %p\n", pConv);
679             WDML_AddLink(pConv->instance, (HCONV)pConv, WDML_SERVER_SIDE,
680                          uType, pXAct->hszItem, pDdeAdvise->cfFormat);
681         }
682         break;
683     }
684
685     GlobalUnlock(pXAct->hMem);
686     if (fAck)
687     {
688         GlobalFree(pXAct->hMem);
689     }
690     pXAct->hMem = 0;
691
692     WDML_PostAck(pConv, WDML_SERVER_SIDE, 0, FALSE, fAck, pXAct->atom, pXAct->lParam, WM_DDE_ADVISE);
693
694     WDML_DecHSZ(pConv->instance, pXAct->hszItem);
695
696     return WDML_QS_HANDLED;
697 }
698
699 /******************************************************************
700  *              WDML_ServerQueueUnadvise
701  *
702  *
703  */
704 static  WDML_XACT* WDML_ServerQueueUnadvise(WDML_CONV* pConv, LPARAM lParam)
705 {
706     UINT_PTR            uiLo, uiHi;
707     WDML_XACT*          pXAct;
708
709     UnpackDDElParam(WM_DDE_UNADVISE, lParam, &uiLo, &uiHi);
710
711     pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_UNADVISE,
712                                   uiLo, WDML_MakeHszFromAtom(pConv->instance, uiHi));
713     if (pXAct) pXAct->atom = uiHi;
714     return pXAct;
715 }
716
717 /******************************************************************
718  *              WDML_ServerHandleUnadvise
719  *
720  *
721  */
722 static  WDML_QUEUE_STATE WDML_ServerHandleUnadvise(WDML_CONV* pConv, WDML_XACT* pXAct)
723 {
724     WDML_LINK*  pLink;
725
726     if (pXAct->hszItem == NULL || pXAct->wFmt == 0)
727     {
728         ERR("Unsupported yet options (null item or clipboard format)\n");
729         return WDML_QS_ERROR;
730     }
731
732     pLink = WDML_FindLink(pConv->instance, (HCONV)pConv, WDML_SERVER_SIDE,
733                           pXAct->hszItem, TRUE, pXAct->wFmt);
734     if (pLink == NULL)
735     {
736         ERR("Couln'd find link for %p, dropping request\n", pXAct->hszItem);
737         FreeDDElParam(WM_DDE_UNADVISE, pXAct->lParam);
738         return WDML_QS_ERROR;
739     }
740
741     if (!(pConv->instance->CBFflags & CBF_FAIL_ADVISES))
742     {
743         WDML_InvokeCallback(pConv->instance, XTYP_ADVSTOP, pXAct->wFmt, (HCONV)pConv,
744                             pConv->hszTopic, pXAct->hszItem, 0, 0, 0);
745     }
746
747     WDML_RemoveLink(pConv->instance, (HCONV)pConv, WDML_SERVER_SIDE,
748                     pXAct->hszItem, pXAct->wFmt);
749
750     /* send back ack */
751     WDML_PostAck(pConv, WDML_SERVER_SIDE, 0, FALSE, TRUE, pXAct->atom,
752                  pXAct->lParam, WM_DDE_UNADVISE);
753
754     WDML_DecHSZ(pConv->instance, pXAct->hszItem);
755
756     return WDML_QS_HANDLED;
757 }
758
759 /******************************************************************
760  *              WDML_QueueExecute
761  *
762  *
763  */
764 static  WDML_XACT* WDML_ServerQueueExecute(WDML_CONV* pConv, LPARAM lParam)
765 {
766     WDML_XACT*  pXAct;
767
768     pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_EXECUTE, 0, 0);
769     if (pXAct)
770     {
771         pXAct->hMem    = (HGLOBAL)lParam;
772     }
773     return pXAct;
774 }
775
776  /******************************************************************
777  *              WDML_ServerHandleExecute
778  *
779  *
780  */
781 static  WDML_QUEUE_STATE WDML_ServerHandleExecute(WDML_CONV* pConv, WDML_XACT* pXAct)
782 {
783     HDDEDATA    hDdeData = DDE_FNOTPROCESSED;
784     BOOL        fAck = FALSE, fBusy = FALSE;
785
786     if (!(pConv->instance->CBFflags & CBF_FAIL_EXECUTES))
787     {
788         LPVOID  ptr = GlobalLock(pXAct->hMem);
789
790         if (ptr)
791         {
792             hDdeData = DdeCreateDataHandle(0, ptr, GlobalSize(pXAct->hMem),
793                                            0, 0, CF_TEXT, 0);
794             GlobalUnlock(pXAct->hMem);
795         }
796         hDdeData = WDML_InvokeCallback(pConv->instance, XTYP_EXECUTE, 0, (HCONV)pConv,
797                                        pConv->hszTopic, 0, hDdeData, 0L, 0L);
798     }
799
800     switch ((ULONG_PTR)hDdeData)
801     {
802     case (ULONG_PTR)CBR_BLOCK:
803         return WDML_QS_BLOCK;
804
805     case DDE_FACK:
806         fAck = TRUE;
807         break;
808     case DDE_FBUSY:
809         fBusy = TRUE;
810         break;
811     default:
812         FIXME("Unsupported returned value %p\n", hDdeData);
813         /* fall through */
814     case DDE_FNOTPROCESSED:
815         break;
816     }
817     WDML_PostAck(pConv, WDML_SERVER_SIDE, 0, fBusy, fAck, (UINT)pXAct->hMem, 0, 0);
818
819     return WDML_QS_HANDLED;
820 }
821
822 /******************************************************************
823  *              WDML_ServerQueuePoke
824  *
825  *
826  */
827 static  WDML_XACT* WDML_ServerQueuePoke(WDML_CONV* pConv, LPARAM lParam)
828 {
829     UINT_PTR            uiLo, uiHi;
830     WDML_XACT*          pXAct;
831
832     UnpackDDElParam(WM_DDE_POKE, lParam, &uiLo, &uiHi);
833
834     pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_POKE,
835                                   0, WDML_MakeHszFromAtom(pConv->instance, uiHi));
836     if (pXAct)
837     {
838         pXAct->atom = uiHi;
839         pXAct->hMem = (HGLOBAL)uiLo;
840     }
841     return pXAct;
842 }
843
844 /******************************************************************
845  *              WDML_ServerHandlePoke
846  *
847  *
848  */
849 static  WDML_QUEUE_STATE WDML_ServerHandlePoke(WDML_CONV* pConv, WDML_XACT* pXAct)
850 {
851     DDEPOKE*            pDdePoke;
852     HDDEDATA            hDdeData;
853     BOOL                fBusy = FALSE, fAck = FALSE;
854
855     pDdePoke = (DDEPOKE*)GlobalLock(pXAct->hMem);
856     if (!pDdePoke)
857     {
858         return WDML_QS_ERROR;
859     }
860
861     if (!(pConv->instance->CBFflags & CBF_FAIL_POKES))
862     {
863         hDdeData = DdeCreateDataHandle(pConv->instance->instanceID, pDdePoke->Value,
864                                        GlobalSize(pXAct->hMem) - sizeof(DDEPOKE) + 1,
865                                        0, 0, pDdePoke->cfFormat, 0);
866         if (hDdeData)
867         {
868             HDDEDATA    hDdeDataOut;
869
870             hDdeDataOut = WDML_InvokeCallback(pConv->instance, XTYP_POKE, pDdePoke->cfFormat,
871                                               (HCONV)pConv, pConv->hszTopic, pXAct->hszItem,
872                                               hDdeData, 0, 0);
873             switch ((ULONG_PTR)hDdeDataOut)
874             {
875             case DDE_FACK:
876                 fAck = TRUE;
877                 break;
878             case DDE_FBUSY:
879                 fBusy = TRUE;
880                 break;
881             default:
882                 FIXME("Unsupported returned value %p\n", hDdeDataOut);
883                 /* fal through */
884             case DDE_FNOTPROCESSED:
885                 break;
886             }
887             DdeFreeDataHandle(hDdeData);
888         }
889     }
890     GlobalUnlock(pXAct->hMem);
891
892     if (!fAck)
893     {
894         GlobalFree(pXAct->hMem);
895     }
896     WDML_PostAck(pConv, WDML_SERVER_SIDE, 0, fBusy, fAck, pXAct->atom, pXAct->lParam, WM_DDE_POKE);
897
898     WDML_DecHSZ(pConv->instance, pXAct->hszItem);
899
900     return WDML_QS_HANDLED;
901 }
902
903 /******************************************************************
904  *              WDML_ServerQueueTerminate
905  *
906  *
907  */
908 static  WDML_XACT*      WDML_ServerQueueTerminate(WDML_CONV* pConv, LPARAM lParam)
909 {
910     WDML_XACT*  pXAct;
911
912     pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_TERMINATE, 0, 0);
913     return pXAct;
914 }
915
916 /******************************************************************
917  *              WDML_ServerHandleTerminate
918  *
919  *
920  */
921 static  WDML_QUEUE_STATE WDML_ServerHandleTerminate(WDML_CONV* pConv, WDML_XACT* pXAct)
922 {
923     /* billx: two things to remove: the conv, and associated links.
924      * Respond with another WM_DDE_TERMINATE iMsg.
925      */
926     if (!(pConv->instance->CBFflags & CBF_SKIP_DISCONNECTS))
927     {
928         WDML_InvokeCallback(pConv->instance, XTYP_DISCONNECT, 0, (HCONV)pConv, 0, 0,
929                             0, 0, (pConv->wStatus & ST_ISSELF) ? 1 : 0);
930     }
931     PostMessageA(pConv->hwndClient, WM_DDE_TERMINATE, (WPARAM)pConv->hwndServer, 0);
932     WDML_RemoveConv(pConv, WDML_SERVER_SIDE);
933
934     return WDML_QS_HANDLED;
935 }
936
937 /******************************************************************
938  *              WDML_ServerHandle
939  *
940  *
941  */
942 WDML_QUEUE_STATE WDML_ServerHandle(WDML_CONV* pConv, WDML_XACT* pXAct)
943 {
944     WDML_QUEUE_STATE    qs = WDML_QS_ERROR;
945
946     switch (pXAct->ddeMsg)
947     {
948     case WM_DDE_INITIATE:
949         FIXME("WM_DDE_INITIATE shouldn't be there!\n");
950         break;
951     case WM_DDE_REQUEST:
952         qs = WDML_ServerHandleRequest(pConv, pXAct);
953         break;
954
955     case WM_DDE_ADVISE:
956         qs = WDML_ServerHandleAdvise(pConv, pXAct);
957         break;
958
959     case WM_DDE_UNADVISE:
960         qs = WDML_ServerHandleUnadvise(pConv, pXAct);
961         break;
962
963     case WM_DDE_EXECUTE:
964         qs = WDML_ServerHandleExecute(pConv, pXAct);
965         break;
966
967     case WM_DDE_POKE:
968         qs = WDML_ServerHandlePoke(pConv, pXAct);
969         break;
970
971     case WM_DDE_TERMINATE:
972         qs = WDML_ServerHandleTerminate(pConv, pXAct);
973         break;
974
975     case WM_DDE_ACK:
976         WARN("Shouldn't receive a ACK message (never requests them). Ignoring it\n");
977         break;
978
979     default:
980         FIXME("Unsupported message %d\n", pXAct->ddeMsg);
981     }
982     return qs;
983 }
984
985 /******************************************************************
986  *              WDML_ServerConvProc
987  *
988  *
989  */
990 static LRESULT CALLBACK WDML_ServerConvProc(HWND hwndServer, UINT iMsg, WPARAM wParam, LPARAM lParam)
991 {
992     WDML_INSTANCE*      pInstance;
993     WDML_CONV*          pConv;
994     WDML_XACT*          pXAct = NULL;
995
996     TRACE("%p %04x %08x %08lx\n", hwndServer, iMsg, wParam , lParam);
997
998     if (iMsg == WM_DESTROY)
999     {
1000         EnterCriticalSection(&WDML_CritSect);
1001         pConv = WDML_GetConvFromWnd(hwndServer);
1002         if (pConv && !(pConv->wStatus & ST_TERMINATED))
1003         {
1004             WDML_ServerHandleTerminate(pConv, NULL);
1005         }
1006         LeaveCriticalSection(&WDML_CritSect);
1007     }
1008     if (iMsg < WM_DDE_FIRST || iMsg > WM_DDE_LAST)
1009     {
1010         return IsWindowUnicode(hwndServer) ? DefWindowProcW(hwndServer, iMsg, wParam, lParam) :
1011                                              DefWindowProcA(hwndServer, iMsg, wParam, lParam);
1012     }
1013
1014     EnterCriticalSection(&WDML_CritSect);
1015
1016     pInstance = WDML_GetInstanceFromWnd(hwndServer);
1017     pConv = WDML_GetConvFromWnd(hwndServer);
1018
1019     if (!pConv)
1020     {
1021         ERR("Got a message (%x) on a not known conversation, dropping request\n", iMsg);
1022         goto theError;
1023     }
1024     if (pConv->hwndClient != WIN_GetFullHandle( (HWND)wParam ) || pConv->hwndServer != hwndServer)
1025     {
1026         ERR("mismatch between C/S windows and converstation\n");
1027         goto theError;
1028     }
1029     if (pConv->instance != pInstance || pConv->instance == NULL)
1030     {
1031         ERR("mismatch in instances\n");
1032         goto theError;
1033     }
1034
1035     switch (iMsg)
1036     {
1037     case WM_DDE_INITIATE:
1038         FIXME("WM_DDE_INITIATE message received!\n");
1039         break;
1040
1041     case WM_DDE_REQUEST:
1042         pXAct = WDML_ServerQueueRequest(pConv, lParam);
1043         break;
1044
1045     case WM_DDE_ADVISE:
1046         pXAct = WDML_ServerQueueAdvise(pConv, lParam);
1047         break;
1048
1049     case WM_DDE_UNADVISE:
1050         pXAct = WDML_ServerQueueUnadvise(pConv, lParam);
1051         break;
1052
1053     case WM_DDE_EXECUTE:
1054         pXAct = WDML_ServerQueueExecute(pConv, lParam);
1055         break;
1056
1057     case WM_DDE_POKE:
1058         pXAct = WDML_ServerQueuePoke(pConv, lParam);
1059         break;
1060
1061     case WM_DDE_TERMINATE:
1062         pXAct = WDML_ServerQueueTerminate(pConv, lParam);
1063         break;
1064
1065     case WM_DDE_ACK:
1066         WARN("Shouldn't receive a ACK message (never requests them). Ignoring it\n");
1067         break;
1068
1069     default:
1070         FIXME("Unsupported message %x\n", iMsg);
1071     }
1072
1073     if (pXAct)
1074     {
1075         pXAct->lParam = lParam;
1076         if (WDML_ServerHandle(pConv, pXAct) == WDML_QS_BLOCK)
1077         {
1078             WDML_QueueTransaction(pConv, pXAct);
1079         }
1080         else
1081         {
1082             WDML_FreeTransaction(pInstance, pXAct, TRUE);
1083         }
1084     }
1085  theError:
1086     LeaveCriticalSection(&WDML_CritSect);
1087     return 0;
1088 }