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