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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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