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