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