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