Documentation fixes.
[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
13 #include <string.h>
14 #include "winbase.h"
15 #include "windef.h"
16 #include "wingdi.h"
17 #include "winuser.h"
18 #include "winerror.h"
19 #include "dde.h"
20 #include "ddeml.h"
21 #include "debugtools.h"
22 #include "dde/dde_private.h"
23
24 DEFAULT_DEBUG_CHANNEL(ddeml);
25
26 static const char szServerNameClassA[] = "DdeServerNameAnsi";
27 static const char szServerConvClassA[] = "DdeServerConvAnsi";
28
29 static LRESULT CALLBACK WDML_ServerNameProc(HWND, UINT, WPARAM, LPARAM);
30 static LRESULT CALLBACK WDML_ServerConvProc(HWND, UINT, WPARAM, LPARAM);
31
32 /******************************************************************************
33  * DdePostAdvise [USER32.@]  Send transaction to DDE callback function.
34  *
35  * RETURNS
36  *    Success: TRUE
37  *    Failure: FALSE
38  */
39 BOOL WINAPI DdePostAdvise(
40     DWORD idInst, /* [in] Instance identifier */
41     HSZ hszTopic, /* [in] Handle to topic name string */
42     HSZ hszItem)  /* [in] Handle to item name string */
43 {
44     WDML_INSTANCE*      thisInstance = NULL;
45     WDML_LINK*          pLink = NULL;
46     HDDEDATA            hDdeData = 0, hItemData = 0;
47     WDML_CONV*          pConv = NULL;
48     CHAR                pszTopic[MAX_BUFFER_LEN];
49     CHAR                pszItem[MAX_BUFFER_LEN];
50     
51     
52     TRACE("(%ld,%ld,%ld)\n",idInst,(DWORD)hszTopic,(DWORD)hszItem);
53     
54     if (idInst == 0)
55     {
56         return FALSE;
57     }
58     
59     thisInstance = WDML_FindInstance(idInst);
60     
61     if (thisInstance == NULL || thisInstance->links == NULL)
62     {
63         return FALSE;
64     }
65     
66     GlobalGetAtomNameA(hszTopic, (LPSTR)pszTopic, MAX_BUFFER_LEN);
67     GlobalGetAtomNameA(hszItem, (LPSTR)pszItem, MAX_BUFFER_LEN);
68     
69     for (pLink = thisInstance->links[WDML_SERVER_SIDE]; pLink != NULL; pLink = pLink->next)
70     {
71         if (DdeCmpStringHandles(hszItem, pLink->hszItem) == 0)
72         {
73             hDdeData = 0;
74             if (thisInstance->callback != NULL /* && thisInstance->Process_id == GetCurrentProcessId()*/)
75             {
76                 
77                 TRACE("Calling the callback, type=XTYP_ADVREQ, CB=0x%lx, hConv=0x%lx, Topic=%s, Item=%s\n",
78                       (DWORD)thisInstance->callback, (DWORD)pLink->hConv, pszTopic, pszItem);
79                 hDdeData = (thisInstance->callback)(XTYP_ADVREQ,
80                                                     pLink->uFmt,
81                                                     pLink->hConv,
82                                                     hszTopic,
83                                                     hszItem,
84                                                     0, 0, 0);
85                 TRACE("Callback was called\n");
86                 
87             }
88             
89             if (hDdeData)
90             {
91                 if (pLink->transactionType & XTYPF_NODATA)
92                 {
93                     TRACE("no data\n");
94                     hItemData = 0;
95                 }
96                 else
97                 {
98                     TRACE("with data\n");
99                     
100                     hItemData = WDML_DataHandle2Global(hDdeData, FALSE, FALSE, FALSE, FALSE);
101                 }
102                 
103                 pConv = WDML_GetConv(pLink->hConv);
104                 
105                 if (pConv == NULL ||
106                     !PostMessageA(pConv->hwndClient, WM_DDE_DATA, (WPARAM)pConv->hwndServer,
107                                   PackDDElParam(WM_DDE_DATA, (UINT)hItemData, (DWORD)hszItem)))
108                 {
109                     ERR("post message failed\n");
110                     DdeFreeDataHandle(hDdeData);
111                     return FALSE;
112                 }                   
113             }
114         }
115     }
116     
117     return TRUE;
118 }
119
120
121 /******************************************************************************
122  * DdeNameService [USER32.@]  {Un}registers service name of DDE server
123  *
124  * PARAMS
125  *    idInst [I] Instance identifier
126  *    hsz1   [I] Handle to service name string
127  *    hsz2   [I] Reserved
128  *    afCmd  [I] Service name flags
129  *
130  * RETURNS
131  *    Success: Non-zero
132  *    Failure: 0
133  */
134 HDDEDATA WINAPI DdeNameService(DWORD idInst, HSZ hsz1, HSZ hsz2, UINT afCmd)
135 {
136     WDML_SERVER*        pServer;
137     WDML_SERVER*        pServerTmp;
138     WDML_INSTANCE*      thisInstance;
139     HDDEDATA            hDdeData;
140     HSZ                 hsz2nd = 0;
141     HWND                hwndServer;
142     WNDCLASSEXA         wndclass;
143     
144     hDdeData = (HDDEDATA)NULL;
145     
146     TRACE("(%ld,%d,%d,%d): stub\n",idInst,hsz1,hsz2,afCmd);
147     
148     if (WDML_MaxInstanceID == 0)
149     {
150         /*  Nothing has been initialised - exit now ! 
151          *      needs something for DdeGetLastError */
152         return 0;
153     }
154     
155     if (!WDML_WaitForMutex(handle_mutex))
156     {
157         /* FIXME: setError DMLERR_SYS_ERROR; */
158         return 0;
159     }
160     
161     /*  First check instance
162      */
163     thisInstance = WDML_FindInstance(idInst);
164     if  (thisInstance == NULL)
165     {
166         TRACE("Instance not found as initialised\n");
167         WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE);
168         /*  Nothing has been initialised - exit now ! can return TRUE since effect is the same */
169         return FALSE;
170     }
171     
172     if (hsz2 != 0L)
173     {
174         /*      Illegal, reserved parameter
175          */
176         thisInstance->lastError = DMLERR_INVALIDPARAMETER;
177         WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE);
178         FIXME("Reserved parameter no-zero !!\n");
179         return FALSE;
180     }
181     if (hsz1 == 0L)
182     {
183         /*
184          *      General unregister situation
185          */
186         if (afCmd != DNS_UNREGISTER)
187         {
188             /*  don't know if we should check this but it makes sense
189              *  why supply REGISTER or filter flags if de-registering all
190              */
191             TRACE("General unregister unexpected flags\n");
192             thisInstance->lastError = DMLERR_DLL_USAGE;
193             WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE);
194             return FALSE;
195         }
196         /*      Loop to find all registered service and de-register them
197          */
198         if (thisInstance->servers == NULL)
199         {
200             /*  None to unregister !!  
201              */
202             TRACE("General de-register - nothing registered\n");
203             thisInstance->lastError = DMLERR_DLL_USAGE;
204             WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE);
205             return FALSE;
206         }
207         else
208         {
209             pServer = thisInstance->servers;
210             while (pServer != NULL)
211             {
212                 TRACE("general deregister - iteration\n");
213                 pServerTmp = pServer;
214                 pServer = pServer->next;
215                 WDML_ReleaseAtom(thisInstance, pServerTmp->hszService);
216                 /* finished - release heap space used as work store */
217                 HeapFree(GetProcessHeap(), 0, pServerTmp); 
218             }
219             thisInstance->servers = NULL;
220             TRACE("General de-register - finished\n");
221         }
222         WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE);
223         return (HDDEDATA)TRUE;
224     }
225     TRACE("Specific name action detected\n");
226     if (afCmd & DNS_REGISTER)
227     {
228         /* Register new service name
229          */
230         
231         pServer = WDML_FindServer(thisInstance, hsz1, 0);
232         if (pServer)
233             ERR("Trying to register already registered service!\n");
234         else
235         {
236             TRACE("Adding service name\n");
237             
238             WDML_ReserveAtom(thisInstance, hsz1);
239             
240             pServer = WDML_AddServer(thisInstance, hsz1, 0);
241             
242             WDML_BroadcastDDEWindows(WDML_szEventClass, WM_WDML_REGISTER, hsz1, hsz2nd);
243         }
244         
245         wndclass.cbSize        = sizeof(wndclass);
246         wndclass.style         = 0;
247         wndclass.lpfnWndProc   = WDML_ServerNameProc;
248         wndclass.cbClsExtra    = 0;
249         wndclass.cbWndExtra    = 2 * sizeof(DWORD);
250         wndclass.hInstance     = 0;
251         wndclass.hIcon         = 0;
252         wndclass.hCursor       = 0;
253         wndclass.hbrBackground = 0;
254         wndclass.lpszMenuName  = NULL;
255         wndclass.lpszClassName = szServerNameClassA;
256         wndclass.hIconSm       = 0;
257         
258         RegisterClassExA(&wndclass);
259         
260         hwndServer = CreateWindowA(szServerNameClassA, NULL,
261                                    WS_POPUP, 0, 0, 0, 0,
262                                    0, 0, 0, 0);
263         
264         SetWindowLongA(hwndServer, 0, (DWORD)thisInstance);
265         TRACE("Created nameServer=%04x for instance=%08lx\n", hwndServer, idInst);
266         
267         pServer->hwndServer = hwndServer;
268     }
269     if (afCmd & DNS_UNREGISTER)
270     {
271         TRACE("Broadcasting WM_DDE_TERMINATE message\n");
272         SendMessageA(HWND_BROADCAST, WM_DDE_TERMINATE, (WPARAM)NULL,
273                      PackDDElParam(WM_DDE_TERMINATE, (UINT)hsz1, (UINT)hsz2));
274         
275         WDML_RemoveServer(thisInstance, hsz1, hsz2);
276     }
277     if (afCmd & DNS_FILTERON)
278     {
279         /*      Set filter flags on to hold notifications of connection
280          *
281          *      test coded this way as this is the default setting
282          */
283         pServer = WDML_FindServer(thisInstance, hsz1, 0);
284         if (!pServer)
285         {
286             /*  trying to filter where no service names !!
287              */
288             thisInstance->lastError = DMLERR_DLL_USAGE;
289             WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE);
290             return FALSE;
291         } 
292         else 
293         {
294             pServer->filterOn = TRUE;
295         }
296     }
297     if (afCmd & DNS_FILTEROFF)
298     {
299         /*      Set filter flags on to hold notifications of connection
300          */
301         pServer = WDML_FindServer(thisInstance, hsz1, 0);
302         if (!pServer)
303         {
304             /*  trying to filter where no service names !!
305              */
306             thisInstance->lastError = DMLERR_DLL_USAGE;
307             WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE);
308             return FALSE;
309         }       
310         else 
311         {
312             pServer->filterOn = FALSE;
313         }
314     }
315     WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE);
316     return (HDDEDATA)TRUE;
317 }
318
319 /******************************************************************
320  *              WDML_CreateServerConv
321  *
322  *
323  */
324 static BOOL WDML_CreateServerConv(WDML_INSTANCE* thisInstance, HWND hwndClient, HWND hwndServerName,
325                                   HSZ hszApp, HSZ hszTopic)
326 {
327     WNDCLASSEXA wndclass;
328     HWND        hwndServerConv;
329     WDML_CONV*  pConv;
330     
331     wndclass.cbSize        = sizeof(wndclass);
332     wndclass.style         = 0;
333     wndclass.lpfnWndProc   = WDML_ServerConvProc;
334     wndclass.cbClsExtra    = 0;
335     wndclass.cbWndExtra    = 2 * sizeof(DWORD);
336     wndclass.hInstance     = 0;
337     wndclass.hIcon         = 0;
338     wndclass.hCursor       = 0;
339     wndclass.hbrBackground = 0;
340     wndclass.lpszMenuName  = NULL;
341     wndclass.lpszClassName = szServerConvClassA;
342     wndclass.hIconSm       = 0;
343     
344     RegisterClassExA(&wndclass);
345     
346     hwndServerConv = CreateWindowA(szServerConvClassA, 0,
347                                    WS_CHILD, 0, 0, 0, 0,
348                                    hwndServerName, 0, 0, 0);
349     TRACE("Created convServer=%04x (nameServer=%04x) for instance=%08lx\n", 
350           hwndServerConv, hwndServerName, thisInstance->instanceID);
351     
352     pConv = WDML_AddConv(thisInstance, WDML_SERVER_SIDE, hszApp, hszTopic, hwndClient, hwndServerConv);
353     
354     SetWindowLongA(hwndServerConv, 0, (DWORD)thisInstance);
355     SetWindowLongA(hwndServerConv, 4, (DWORD)pConv);
356     
357     /* this should be the only place using SendMessage for WM_DDE_ACK */
358     SendMessageA(hwndClient, WM_DDE_ACK, (WPARAM)hwndServerConv,
359                  PackDDElParam(WM_DDE_ACK, (UINT)hszApp, (UINT)hszTopic));
360
361 #if 0
362     if (thisInstance && thisInstance->callback != NULL /*&& thisInstance->Process_id == GetCurrentProcessId()*/)
363     {
364         /* confirm connection...
365          * FIXME: a better way would be to check for any incoming message if the conversation
366          * exists (and/or) has been confirmed...
367          * Anyway, always pretend we use a connection from a different instance...
368          */
369         (thisInstance->callback)(XTYP_CONNECT_CONFIRM, 0, (HCONV)pConv, hszApp, hszTopic, 0, 0, 0);
370     }
371 #endif
372
373     return TRUE;
374 }
375
376 /******************************************************************
377  *              WDML_ServerNameProc
378  *
379  *
380  */
381 static LRESULT CALLBACK WDML_ServerNameProc(HWND hwndServer, UINT iMsg, WPARAM wParam, LPARAM lParam)
382 {
383     HWND                hwndClient;
384     HSZ                 hszApp, hszTop;
385     HDDEDATA            hDdeData = 0;
386     WDML_INSTANCE*      thisInstance;
387     UINT                uiLow, uiHi;
388     
389     switch (iMsg)
390     {
391     case WM_DDE_INITIATE:
392         
393         /* wParam         -- sending window handle
394            LOWORD(lParam) -- application atom
395            HIWORD(lParam) -- topic atom */
396         
397         TRACE("WM_DDE_INITIATE message received in the Server Proc!\n");
398         hwndClient = (HWND)wParam;
399         
400         /* don't free DDEParams, since this is a broadcast */
401         UnpackDDElParam(WM_DDE_INITIATE, lParam, &uiLow, &uiHi);        
402         
403         hszApp = (HSZ)uiLow;
404         hszTop = (HSZ)uiHi;
405         
406         thisInstance = (WDML_INSTANCE*)GetWindowLongA(hwndServer, 0);
407         TRACE("idInst=%ld, ProcessID=0x%lx\n", thisInstance->instanceID, GetCurrentProcessId());
408         
409         if (hszApp && hszTop) 
410         {
411             /* pass on to the callback  */
412             if (thisInstance && thisInstance->callback != NULL /*&& thisInstance->Process_id == GetCurrentProcessId()*/)
413             {
414                 
415                 TRACE("calling the Callback, type = XTYP_CONNECT, CB=0x%lx\n",
416                       (DWORD)thisInstance->callback);
417                 hDdeData = (thisInstance->callback)(XTYP_CONNECT,
418                                                     0, 0,
419                                                     hszTop,
420                                                     hszApp,
421                                                     0, 0, 0);
422                 if ((UINT)hDdeData)
423                 {
424                     WDML_CreateServerConv(thisInstance, hwndClient, hwndServer, hszApp, hszTop);
425                 }
426             }
427         }
428         else
429         {
430             /* pass on to the callback  */
431             if (thisInstance && thisInstance->callback != NULL /*&& thisInstance->Process_id == GetCurrentProcessId()*/)
432             {
433                 TRACE("calling the Callback, type=XTYP_WILDCONNECT, CB=0x%lx\n",
434                       (DWORD)thisInstance->callback);
435                 hDdeData = (thisInstance->callback)(XTYP_WILDCONNECT,
436                                                     0, 0,
437                                                     hszTop,
438                                                     hszApp,
439                                                     0, 0, 0);
440                 if ((UINT)hDdeData)
441                 {
442                     HSZPAIR*    hszp;
443                     
444                     hszp = (HSZPAIR*)DdeAccessData(hDdeData, NULL);
445                     if (hszp)
446                     {
447                         int     i;
448                         for (i = 0; hszp[i].hszSvc && hszp[i].hszTopic; i++)
449                         {
450                             WDML_CreateServerConv(thisInstance, hwndClient, hwndServer, 
451                                                   hszp[i].hszSvc, hszp[i].hszTopic);
452                         }
453                         DdeUnaccessData(hDdeData);
454                     }
455                 }
456             }
457         }
458         
459         /*
460           billx: make a conv and add it to the server list - 
461           this can be delayed when link is created for the conv. NO NEED !!!
462         */
463         
464         return 0;
465         
466         
467     case WM_DDE_REQUEST:
468         FIXME("WM_DDE_REQUEST message received!\n");
469         return 0;
470     case WM_DDE_ADVISE:
471         FIXME("WM_DDE_ADVISE message received!\n");
472         return 0;
473     case WM_DDE_UNADVISE:
474         FIXME("WM_DDE_UNADVISE message received!\n");
475         return 0;
476     case WM_DDE_EXECUTE:
477         FIXME("WM_DDE_EXECUTE message received!\n");
478         return 0;
479     case WM_DDE_POKE:
480         FIXME("WM_DDE_POKE message received!\n");
481         return 0;
482     case WM_DDE_TERMINATE:
483         FIXME("WM_DDE_TERMINATE message received!\n");
484         return 0;
485
486     }
487     
488     return DefWindowProcA(hwndServer, iMsg, wParam, lParam);
489 }
490
491 /******************************************************************
492  *              WDML_ServerHandleRequest
493  *
494  *
495  */
496 static  LRESULT WDML_ServerHandleRequest(WDML_INSTANCE* thisInstance, WDML_CONV* pConv, 
497                                          HWND hwndServer, HWND hwndClient, LPARAM lParam)
498 {
499     UINT                uiLow, uiHi;
500     HSZ                 hszItem;
501     HDDEDATA            hDdeData;
502
503     TRACE("(%04x %04x %08lx)!\n", hwndServer, hwndClient, lParam);
504         
505     UnpackDDElParam(WM_DDE_REQUEST, lParam, &uiLow, &uiHi);
506
507     hszItem = (HSZ)uiHi;
508
509     hDdeData = 0;
510     if (thisInstance && thisInstance->callback != NULL /* && thisInstance->Process_id == GetCurrentProcessId() */)
511     {
512             
513         TRACE("calling the Callback, idInst=%ld, CB=0x%lx, uType=0x%x\n",
514               thisInstance->instanceID, (DWORD)thisInstance->callback, XTYP_REQUEST);
515         hDdeData = (thisInstance->callback)(XTYP_REQUEST, uiLow, (HCONV)pConv, 
516                                             pConv->hszTopic, hszItem, 0, 0, 0);
517     }
518         
519     if (hDdeData)
520     {
521         HGLOBAL hMem = WDML_DataHandle2Global(hDdeData, FALSE, FALSE, FALSE, FALSE);
522         if (!PostMessageA(hwndClient, WM_DDE_DATA, (WPARAM)hwndServer,
523                           ReuseDDElParam(lParam, WM_DDE_REQUEST, WM_DDE_DATA, (UINT)hMem, (UINT)hszItem)))
524         {
525             DdeFreeDataHandle(hDdeData);
526             GlobalFree(hMem);
527         }
528     }
529     else 
530     {
531         DDEACK  ddeAck;
532
533         ddeAck.bAppReturnCode = 0;
534         ddeAck.reserved       = 0;
535         ddeAck.fBusy          = FALSE;
536         ddeAck.fAck           = FALSE;
537         
538         TRACE("Posting a %s ack\n", ddeAck.fAck ? "positive" : "negative");
539         PostMessageA(hwndClient, WM_DDE_ACK, (WPARAM)hwndServer, 
540                      ReuseDDElParam(lParam, WM_DDE_REQUEST, WM_DDE_ACK, *((WORD*)&ddeAck), (UINT)hszItem));
541     }   
542
543     return 0;
544 }
545
546 /******************************************************************
547  *              WDML_ServerHandleAdvise
548  *
549  *
550  */
551 static  LRESULT WDML_ServerHandleAdvise(WDML_INSTANCE* thisInstance, WDML_CONV* pConv, 
552                                         HWND hwndServer, HWND hwndClient, LPARAM lParam)
553 {
554     UINT                uiLo, uiHi, uType;
555     HGLOBAL             hDdeAdvise;
556     HSZ                 hszItem;
557     WDML_LINK*          pLink;
558     DDEADVISE*          pDdeAdvise;
559     HDDEDATA            hDdeData;
560     DDEACK              ddeAck;
561
562     /* XTYP_ADVSTART transaction: 
563        establish link and save link info to InstanceInfoTable */
564         
565     TRACE("(%04x %04x %08lx)!\n", hwndServer, hwndClient, lParam);
566
567     UnpackDDElParam(WM_DDE_ADVISE, lParam, &uiLo, &uiHi);
568         
569     hDdeAdvise = (HGLOBAL)uiLo;
570     hszItem    = (HSZ)uiHi; /* FIXME: it should be a global atom */
571
572     if (!pConv) 
573     {
574         ERR("Got an advise on a not known conversation, dropping request\n");
575         FreeDDElParam(WM_DDE_ADVISE, lParam);
576         return 0;
577     }
578
579     pDdeAdvise = (DDEADVISE*)GlobalLock(hDdeAdvise);
580     uType = XTYP_ADVSTART | 
581             (pDdeAdvise->fDeferUpd ? XTYPF_NODATA : 0) |
582             (pDdeAdvise->fAckReq ? XTYPF_ACKREQ : 0);
583         
584     hDdeData = 0;
585     if (thisInstance && thisInstance->callback != NULL /* && thisInstance->Process_id == GetCurrentProcessId() */)
586     {
587         TRACE("calling the Callback, idInst=%ld, CB=0x%lx, uType=0x%x, uFmt=%x\n",
588               thisInstance->instanceID, (DWORD)thisInstance->callback, 
589               uType, pDdeAdvise->cfFormat);
590         hDdeData = (thisInstance->callback)(XTYP_ADVSTART, pDdeAdvise->cfFormat, (HCONV)pConv, 
591                                             pConv->hszTopic, hszItem, 0, 0, 0);
592     }
593     
594     ddeAck.bAppReturnCode = 0;
595     ddeAck.reserved       = 0;
596     ddeAck.fBusy          = FALSE;
597
598     if ((UINT)hDdeData || TRUE) /* FIXME (from Corel ?) some apps don't return this value */
599     {
600         ddeAck.fAck           = TRUE;
601         
602         /* billx: first to see if the link is already created. */
603         pLink = WDML_FindLink(thisInstance, (HCONV)pConv, WDML_SERVER_SIDE, 
604                               hszItem, pDdeAdvise->cfFormat);
605
606         if (pLink != NULL)
607         {
608             /* we found a link, and only need to modify it in case it changes */
609             pLink->transactionType = uType;
610         }
611         else
612         {
613             TRACE("Adding Link with hConv=0x%lx\n", (DWORD)pConv);
614             
615             WDML_AddLink(thisInstance, (HCONV)pConv, WDML_SERVER_SIDE, 
616                          uType, hszItem, pDdeAdvise->cfFormat);
617         }
618     }
619     else
620     {
621         TRACE("No data returned from the Callback\n");
622         
623         ddeAck.fAck           = FALSE;
624     }
625         
626     GlobalUnlock(hDdeAdvise);
627     if (ddeAck.fAck)
628         GlobalFree(hDdeAdvise);
629         
630     TRACE("Posting a %s ack\n", ddeAck.fAck ? "positive" : "negative");
631     PostMessageA(hwndClient, WM_DDE_ACK, (WPARAM)hwndServer, 
632                  ReuseDDElParam(lParam, WM_DDE_ADVISE, WM_DDE_ACK, *((WORD*)&ddeAck), (UINT)hszItem));
633
634     return 0L;
635 }
636
637 /******************************************************************
638  *              WDML_ServerHandleUnadvise
639  *
640  *
641  */
642 static  LRESULT WDML_ServerHandleUnadvise(WDML_INSTANCE* thisInstance, WDML_CONV* pConv, 
643                                           HWND hwndServer, HWND hwndClient, LPARAM lParam)
644 {
645     UINT                uiLo, uiHi;
646     HSZ                 hszItem;
647     WDML_LINK*          pLink;
648     DDEACK              ddeAck;
649
650     TRACE("(%04x %04x %08lx)!\n", hwndServer, hwndClient, lParam);
651         
652     /* billx: XTYP_ADVSTOP transaction */
653     UnpackDDElParam(WM_DDE_UNADVISE, lParam, &uiLo, &uiHi);
654         
655     /* uiLow: wFmt */
656     hszItem    = (HSZ)uiHi; /* FIXME: it should be a global atom */
657
658     if (hszItem == (HSZ)0 || uiLo == 0)
659     {
660         ERR("Unsupported yet options (null item or clipboard format\n");
661     }
662
663     pLink = WDML_FindLink(thisInstance, (HCONV)pConv, WDML_SERVER_SIDE, hszItem, uiLo);
664     if (pLink == NULL)
665     {
666         ERR("Couln'd find link for %08lx, dropping request\n", (DWORD)hszItem);
667         FreeDDElParam(WM_DDE_UNADVISE, lParam);
668         return 0;
669     }
670
671     /* callback shouldn't be invoked if CBF_FAIL_ADVISES is on. */
672     if (thisInstance && thisInstance->callback != NULL &&
673         !(thisInstance->CBFflags & CBF_SKIP_DISCONNECTS) /* && thisInstance->Process_id == GetCurrentProcessId() */)
674     {
675         TRACE("calling the Callback, idInst=%ld, CB=0x%lx, uType=0x%x\n",
676               thisInstance->instanceID, (DWORD)thisInstance->callback, XTYP_ADVSTOP);
677         (thisInstance->callback)(XTYP_ADVSTOP, uiLo, (HCONV)pConv, pConv->hszTopic, 
678                                  hszItem, 0, 0, 0);
679     }
680         
681     WDML_RemoveLink(thisInstance, (HCONV)pConv, WDML_SERVER_SIDE, hszItem, uiLo);
682         
683     /* send back ack */
684     ddeAck.bAppReturnCode = 0;
685     ddeAck.reserved       = 0;
686     ddeAck.fBusy          = FALSE;
687     ddeAck.fAck           = TRUE;
688     
689     PostMessageA(hwndClient, WM_DDE_ACK, (WPARAM)hwndServer,
690                  ReuseDDElParam(lParam, WM_DDE_UNADVISE, WM_DDE_ACK, *((WORD*)&ddeAck), (UINT)hszItem));
691         
692     return 0;
693 }
694
695 /******************************************************************
696  *              WDML_ServerHandleExecute
697  *
698  *
699  */
700 static  LRESULT WDML_ServerHandleExecute(WDML_INSTANCE* thisInstance, WDML_CONV* pConv, 
701                                          HWND hwndServer, HWND hwndClient, LPARAM lParam)
702 {
703     DDEACK              ddeAck;
704     HDDEDATA            hDdeData;
705
706     TRACE("(%04x %04x %08lx)!\n", hwndServer, hwndClient, lParam);
707         
708     if (hwndClient != pConv->hwndClient)
709         WARN("hmmm source window (%04x)\n", hwndClient);
710
711     hDdeData = 0;
712     if (thisInstance && thisInstance->callback != NULL /* && thisInstance->Process_id == GetCurrentProcessId() */)
713     {
714         LPVOID  ptr = GlobalLock((HGLOBAL)lParam);
715         
716         if (ptr)
717         {
718             hDdeData = DdeCreateDataHandle(0, ptr, GlobalSize((HGLOBAL)lParam),
719                                            0, 0, CF_TEXT, 0);
720             GlobalUnlock((HGLOBAL)lParam);
721         }  
722         TRACE("calling the Callback, idInst=%ld, CB=0x%lx, uType=0x%x\n",
723               thisInstance->instanceID, (DWORD)thisInstance->callback, XTYP_EXECUTE);
724         hDdeData = (thisInstance->callback)(XTYP_EXECUTE, 0, (HCONV)pConv, pConv->hszTopic, 0, 
725                                             hDdeData, 0L, 0L);
726     }
727         
728     ddeAck.bAppReturnCode = 0;
729     ddeAck.reserved       = 0;
730     ddeAck.fBusy          = FALSE;
731     ddeAck.fAck           = FALSE;
732     switch ((UINT)hDdeData)
733     {
734     case DDE_FACK:      
735         ddeAck.fAck = TRUE;     
736         break;
737     case DDE_FBUSY:     
738         ddeAck.fBusy = TRUE;    
739         break;
740     default:    
741         WARN("Bad result code\n");
742         /* fall thru */
743     case DDE_FNOTPROCESSED:                             
744         break;
745     }   
746     PostMessageA(pConv->hwndClient, WM_DDE_ACK, (WPARAM)hwndServer,
747                  PackDDElParam(WM_DDE_ACK, *((WORD*)&ddeAck), lParam));
748         
749     return 0;
750 }
751
752 /******************************************************************
753  *              WDML_ServerHandlePoke
754  *
755  *
756  */
757 static  LRESULT WDML_ServerHandlePoke(WDML_INSTANCE* thisInstance, WDML_CONV* pConv, 
758                                       HWND hwndServer, HWND hwndClient, LPARAM lParam)
759 {
760     UINT                uiLo, uiHi;
761     HSZ                 hszItem;
762     DDEACK              ddeAck;
763     DDEPOKE*            pDdePoke;
764     HDDEDATA            hDdeData;
765
766     TRACE("(%04x %04x %08lx)!\n", hwndServer, hwndClient, lParam);
767         
768     UnpackDDElParam(WM_DDE_UNADVISE, lParam, &uiLo, &uiHi);
769     hszItem = (HSZ)uiHi;
770
771     pDdePoke = (DDEPOKE*)GlobalLock((HGLOBAL)uiLo);
772     if (!pDdePoke)
773     {
774         return 0;
775     }
776
777     ddeAck.bAppReturnCode = 0;
778     ddeAck.reserved       = 0;
779     ddeAck.fBusy          = FALSE;
780     ddeAck.fAck           = FALSE;
781     if (thisInstance && thisInstance->callback != NULL)
782     {
783         hDdeData = DdeCreateDataHandle(thisInstance->instanceID, pDdePoke->Value, 
784                                        GlobalSize((HGLOBAL)uiLo) - sizeof(DDEPOKE) + 1, 
785                                        0, 0, pDdePoke->cfFormat, 0);
786         if (hDdeData) 
787         {
788             HDDEDATA    hDdeDataOut;
789             
790             TRACE("calling callback XTYP_POKE, idInst=%ld\n", 
791                   thisInstance->instanceID);
792             hDdeDataOut = (thisInstance->callback)(XTYP_POKE,
793                                                    pDdePoke->cfFormat, (HCONV)pConv,
794                                                    pConv->hszTopic, (HSZ)uiHi, 
795                                                    hDdeData, 0, 0);
796             switch ((UINT)hDdeDataOut) 
797             {
798             case DDE_FACK:
799                 ddeAck.fAck = TRUE;     
800                 break;
801             case DDE_FBUSY:
802                 ddeAck.fBusy = TRUE;
803                 break;
804             default:
805                 FIXME("Unsupported returned value %08lx\n", (DWORD)hDdeDataOut);
806                 /* fal thru */
807             case DDE_FNOTPROCESSED:                             
808                 break;
809             }
810             DdeFreeDataHandle(hDdeData);
811         }
812     }
813     GlobalUnlock((HGLOBAL)uiLo);
814     
815     if (!ddeAck.fAck)
816         GlobalFree((HGLOBAL)uiHi);
817     
818     PostMessageA(hwndClient, WM_DDE_ACK, (WPARAM)hwndServer,
819                  ReuseDDElParam(lParam, WM_DDE_POKE, WM_DDE_ACK, *((WORD*)&ddeAck), (UINT)hszItem));
820
821     return 0L;
822 }
823
824 /******************************************************************
825  *              WDML_ServerHandleTerminate
826  *
827  *
828  */
829 static  LRESULT WDML_ServerHandleTerminate(WDML_INSTANCE* thisInstance, WDML_CONV* pConv, 
830                                            HWND hwndServer, HWND hwndClient, LPARAM lParam)
831 {
832     UINT                uiLo, uiHi;
833     HSZ                 hszApp, hszTop;
834
835     TRACE("(%04x %04x %08lx)!\n", hwndServer, hwndClient, lParam);
836         
837     TRACE("WM_DDE_TERMINATE!\n");
838     /* XTYP_DISCONNECT transaction */
839     /* billx: two things to remove: the conv, and associated links.
840        callback shouldn't be called if CBF_SKIP_DISCONNECTS is on.
841        Respond with another WM_DDE_TERMINATE iMsg.*/
842     
843     /* don't free DDEParams, since this is a broadcast */
844     UnpackDDElParam(WM_DDE_TERMINATE, lParam, &uiLo, &uiHi);    
845         
846     hszApp = (HSZ)uiLo;
847     hszTop = (HSZ)uiHi;
848         
849     WDML_BroadcastDDEWindows(WDML_szEventClass, WM_WDML_UNREGISTER, hszApp, hszTop);
850     
851     /* PostMessageA(hwndClient, WM_DDE_TERMINATE, (WPARAM)hwndServer, (LPARAM)hConv); */
852     WDML_RemoveAllLinks(thisInstance, (HCONV)pConv, WDML_SERVER_SIDE);
853     WDML_RemoveConv(thisInstance, WDML_SERVER_SIDE, (HCONV)pConv);
854     /* DestroyWindow(hwnd); don't destroy it now, we may still need it. */
855         
856     return 0;
857 }
858
859 /******************************************************************
860  *              WDML_ServerConvProc
861  *
862  *
863  */
864 static LRESULT CALLBACK WDML_ServerConvProc(HWND hwndServer, UINT iMsg, WPARAM wParam, LPARAM lParam)
865 {
866     WDML_INSTANCE*      thisInstance;
867     WDML_CONV*          pConv;
868
869     if (iMsg < WM_DDE_FIRST || iMsg > WM_DDE_LAST)
870     {
871         return DefWindowProcA(hwndServer, iMsg, wParam, lParam);
872     }
873
874     TRACE("About to wait... \n");
875
876     if (!WDML_WaitForMutex(handle_mutex))
877     {
878         return 0;
879     }
880
881     thisInstance = (WDML_INSTANCE*)GetWindowLongA(hwndServer, 0);
882     pConv = (WDML_CONV*)GetWindowLongA(hwndServer, 4);
883     
884     switch (iMsg)
885     {
886     case WM_DDE_INITIATE:
887         FIXME("WM_DDE_INITIATE message received in the ServerConv Proc!\n");
888         break;
889         
890     case WM_DDE_REQUEST:
891         WDML_ServerHandleRequest(thisInstance, pConv, hwndServer, (HWND)wParam, lParam);
892         break;
893                 
894     case WM_DDE_ADVISE:
895         WDML_ServerHandleAdvise(thisInstance, pConv, hwndServer, (HWND)wParam, lParam);
896         break;
897         
898     case WM_DDE_UNADVISE:
899         WDML_ServerHandleUnadvise(thisInstance, pConv, hwndServer, (HWND)wParam, lParam);
900         break;
901         
902     case WM_DDE_EXECUTE:
903         WDML_ServerHandleExecute(thisInstance, pConv, hwndServer, (HWND)wParam, lParam);
904         break;
905         
906     case WM_DDE_POKE:
907         WDML_ServerHandlePoke(thisInstance, pConv, hwndServer, (HWND)wParam, lParam);
908         break;
909         
910     case WM_DDE_TERMINATE:
911         WDML_ServerHandleTerminate(thisInstance, pConv, hwndServer, (HWND)wParam, lParam);
912         break;
913
914     case WM_DDE_ACK:
915         WARN("Shouldn't receive a ACK message (never requests them). Ignoring it\n");
916         break;
917
918     default:
919         FIXME("Unsupported message %d\n", iMsg);
920     }
921
922     WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE);
923     
924     return 0;
925 }