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