1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Win32k subsystem 4 * PURPOSE: Dynamic Data Exchange 5 * FILE: win32ss/user/ntuser/dde.c 6 * PROGRAMER: 7 */ 8 9 #include <win32k.h> 10 11 #include <dde.h> 12 13 DBG_DEFAULT_CHANNEL(UserMisc); 14 15 // 16 // Default information used to support client impersonation. 17 // 18 SECURITY_QUALITY_OF_SERVICE gqosDefault = {sizeof(SECURITY_QUALITY_OF_SERVICE),SecurityImpersonation,SECURITY_STATIC_TRACKING,TRUE}; 19 20 typedef struct _DDEIMP 21 { 22 SECURITY_QUALITY_OF_SERVICE qos; 23 SECURITY_CLIENT_CONTEXT ClientContext; 24 WORD cRefInit; 25 WORD cRefConv; 26 } DDEIMP, *PDDEIMP; 27 28 typedef struct _DDE_DATA 29 { 30 LPARAM lParam; 31 int cbSize; 32 PVOID pvBuffer; 33 } DDE_DATA, *PDDE_DATA; 34 35 typedef struct _DDE_PROP 36 { 37 PWND spwnd; 38 PWND spwndPartner; 39 PDDEIMP pddei; 40 } DDE_PROP, *PDDE_PROP; 41 42 43 // 44 // DDE Posting message callback to user side. 45 // 46 int 47 APIENTRY 48 IntDDEPostCallback( 49 IN PWND pWnd, 50 IN UINT Msg, 51 IN WPARAM wParam, 52 IN OUT LPARAM *lParam, 53 IN OUT PVOID *Buffer) 54 { 55 NTSTATUS Status; 56 ULONG ArgumentLength, ResultLength; 57 PVOID Argument, ResultPointer; 58 PDDEPOSTGET_CALLBACK_ARGUMENTS Common; 59 int size = 0; 60 ResultPointer = NULL; 61 ResultLength = ArgumentLength = sizeof(DDEPOSTGET_CALLBACK_ARGUMENTS); 62 63 Argument = IntCbAllocateMemory(ArgumentLength); 64 if (NULL == Argument) 65 { 66 return FALSE; 67 } 68 69 Common = (PDDEPOSTGET_CALLBACK_ARGUMENTS) Argument; 70 71 Common->pvData = 0; 72 Common->size = 0; 73 Common->hwnd = UserHMGetHandle(pWnd); 74 Common->message = Msg; 75 Common->wParam = wParam; 76 Common->lParam = *lParam; 77 78 UserLeaveCo(); 79 80 Status = KeUserModeCallback(USER32_CALLBACK_DDEPOST, 81 Argument, 82 ArgumentLength, 83 &ResultPointer, 84 &ResultLength); 85 86 UserEnterCo(); 87 88 if (!NT_SUCCESS(Status) || ResultPointer == NULL ) 89 { 90 ERR("DDE Post callback failed!\n"); 91 IntCbFreeMemory(Argument); 92 return 0; 93 } 94 95 RtlCopyMemory(Common, ResultPointer, ArgumentLength); 96 97 size = Common->size; 98 *lParam = Common->lParam; 99 *Buffer = Common->pvData; 100 101 IntCbFreeMemory(Argument); 102 103 return size ? size : -1; 104 } 105 106 // 107 // DDE Get/Peek message callback to user side. 108 // 109 BOOL 110 APIENTRY 111 IntDDEGetCallback( 112 IN PWND pWnd, 113 IN OUT PMSG pMsg, 114 IN PVOID Buffer, 115 IN int size) 116 { 117 NTSTATUS Status; 118 ULONG ArgumentLength, ResultLength; 119 PVOID Argument, ResultPointer; 120 PDDEPOSTGET_CALLBACK_ARGUMENTS Common; 121 122 ResultPointer = NULL; 123 ResultLength = ArgumentLength = sizeof(DDEPOSTGET_CALLBACK_ARGUMENTS)+size; 124 125 Argument = IntCbAllocateMemory(ArgumentLength); 126 if (NULL == Argument) 127 { 128 return FALSE; 129 } 130 131 Common = (PDDEPOSTGET_CALLBACK_ARGUMENTS) Argument; 132 133 Common->size = size; 134 Common->hwnd = pMsg->hwnd; 135 Common->message = pMsg->message; 136 Common->wParam = pMsg->wParam; 137 Common->lParam = pMsg->lParam; 138 139 if (size && Buffer) RtlCopyMemory(&Common->buffer, Buffer, size); 140 141 UserLeaveCo(); 142 143 Status = KeUserModeCallback(USER32_CALLBACK_DDEGET, 144 Argument, 145 ArgumentLength, 146 &ResultPointer, 147 &ResultLength); 148 149 UserEnterCo(); 150 151 if (!NT_SUCCESS(Status) || ResultPointer == NULL ) 152 { 153 ERR("DDE Get callback failed!\n"); 154 IntCbFreeMemory(Argument); 155 return FALSE; 156 } 157 158 RtlMoveMemory(Common, ResultPointer, ArgumentLength); 159 160 pMsg->lParam = Common->lParam; 161 162 IntCbFreeMemory(Argument); 163 164 return TRUE; 165 } 166 167 // 168 // DDE Post message hook, intercept DDE messages before going on to the target Processes Thread queue. 169 // 170 BOOL 171 APIENTRY 172 IntDdePostMessageHook( 173 IN PWND pWnd, 174 IN UINT Msg, 175 IN WPARAM wParam, 176 IN OUT LPARAM *lParam, 177 IN OUT LONG_PTR *ExtraInfo) 178 { 179 PWND pWndClient; 180 PDDE_DATA pddeData; 181 int size; 182 HGDIOBJ Object = NULL; 183 PVOID userBuf = NULL; 184 PVOID Buffer = NULL; 185 LPARAM lp = *lParam; 186 187 if (pWnd->head.pti->ppi != gptiCurrent->ppi) 188 { 189 TRACE("Posting long DDE 0x%x\n",Msg); 190 // Initiate is sent only across borders. 191 if (Msg == WM_DDE_INITIATE) 192 { 193 return FALSE; 194 } 195 196 pWndClient = UserGetWindowObject((HWND)wParam); 197 if (pWndClient == NULL) 198 { 199 // This is terminating so post it. 200 if ( Msg == WM_DDE_TERMINATE) 201 { 202 TRACE("DDE Posted WM_DDE_TERMINATE\n"); 203 return TRUE; 204 } 205 TRACE("Invalid DDE Client Window handle\n"); 206 return FALSE; 207 } 208 209 if ( Msg == WM_DDE_REQUEST || Msg == WM_DDE_UNADVISE ) 210 { 211 // Do not bother to callback after validation. 212 return TRUE; 213 } 214 215 if ( Msg == WM_DDE_TERMINATE ) 216 { 217 //// FIXME Remove Stuff if any... 218 219 // Do not bother to callback. 220 return TRUE; 221 } 222 223 if ( Msg == WM_DDE_EXECUTE && *lParam == 0) 224 { 225 // Do not bother to do a callback. 226 TRACE("DDE Post EXECUTE lParam 0\n"); 227 return FALSE; 228 } 229 230 // Callback. 231 if ((size = IntDDEPostCallback(pWnd, Msg, wParam, &lp, &userBuf)) == 0) 232 { 233 ERR("DDE Post Callback return 0 0x%x\n", Msg); 234 return FALSE; 235 } 236 237 // No error HACK. 238 if (size == -1) 239 { 240 size = 0; 241 } 242 else 243 { 244 // Set buffer with users data size. 245 Buffer = ExAllocatePoolWithTag(PagedPool, size, USERTAG_DDE); 246 if (Buffer == NULL) 247 { 248 ERR("Failed to allocate %i bytes.\n", size); 249 return FALSE; 250 } 251 // No SEH? Yes, the user memory is freed after the Acknowledgment or at Termination. 252 RtlCopyMemory(Buffer, userBuf, size); 253 } 254 255 TRACE("DDE Post size %d 0x%x\n",size, Msg); 256 257 switch(Msg) 258 { 259 case WM_DDE_POKE: 260 { 261 DDEPOKE *pddePoke = Buffer; 262 NT_ASSERT(pddePoke != NULL); 263 switch(pddePoke->cfFormat) 264 { 265 case CF_BITMAP: 266 case CF_DIB: 267 case CF_PALETTE: 268 RtlCopyMemory(&Object, pddePoke->Value, sizeof(HGDIOBJ)); 269 break; 270 default: 271 break; 272 } 273 break; 274 } 275 case WM_DDE_DATA: 276 { 277 DDEDATA *pddeData2 = Buffer; 278 NT_ASSERT(pddeData2 != NULL); 279 switch(pddeData2->cfFormat) 280 { 281 case CF_BITMAP: 282 case CF_DIB: 283 case CF_PALETTE: 284 RtlCopyMemory(&Object, pddeData2->Value, sizeof(HGDIOBJ)); 285 break; 286 default: 287 break; 288 } 289 break; 290 } 291 default: 292 break; 293 } 294 295 if (Object) 296 { 297 // Give gdi object to the other process. 298 GreSetObjectOwner(Object, pWnd->head.pti->ppi->W32Pid); 299 } 300 301 pddeData = ExAllocatePoolWithTag(PagedPool, sizeof(DDE_DATA), USERTAG_DDE5); 302 if (pddeData == NULL) 303 { 304 ERR("Failed to allocate DDE_DATA\n"); 305 ExFreePoolWithTag(Buffer, USERTAG_DDE); 306 return FALSE; 307 } 308 309 pddeData->cbSize = size; 310 pddeData->pvBuffer = Buffer; 311 pddeData->lParam = lp; 312 313 TRACE("DDE Post lParam c=%08lx\n",lp); 314 *lParam = lp; 315 316 // Attach this data packet to the user message. 317 *ExtraInfo = (LONG_PTR)pddeData; 318 } 319 return TRUE; 320 } 321 322 // 323 // DDE Get/Peek message hook, take preprocessed information and recombined it for the current Process Thread. 324 // 325 BOOL APIENTRY 326 IntDdeGetMessageHook(PMSG pMsg, LONG_PTR ExtraInfo) 327 { 328 PWND pWnd, pWndClient; 329 PDDE_DATA pddeData; 330 PDDE_PROP pddeProp; 331 BOOL Ret; 332 333 pWnd = UserGetWindowObject(pMsg->hwnd); 334 if (pWnd == NULL) 335 { 336 ERR("DDE Get Window is dead. %p\n", pMsg->hwnd); 337 return TRUE; 338 } 339 340 if (pMsg->message == WM_DDE_TERMINATE) 341 { 342 pddeProp = (PDDE_PROP)UserGetProp(pWnd, AtomDDETrack, TRUE); 343 if (pddeProp) 344 { 345 pWndClient = UserGetWindowObject((HWND)pMsg->wParam); 346 if (pWndClient == NULL) 347 { 348 ERR("DDE Get Client WM_DDE_TERMINATE\n"); 349 } 350 351 UserRemoveProp(pWnd, AtomDDETrack, TRUE); 352 ExFreePoolWithTag(pddeProp, USERTAG_DDE1); 353 } 354 return TRUE; 355 } 356 357 TRACE("DDE Get Msg 0x%x\n",pMsg->message); 358 359 pddeData = (PDDE_DATA)ExtraInfo; 360 361 if ( pddeData ) 362 { 363 TRACE("DDE Get size %d lParam c=%08lx lp c=%08lx\n",pddeData->cbSize, pMsg->lParam, pddeData->lParam); 364 365 // Callback. 366 Ret = IntDDEGetCallback( pWnd, pMsg, pddeData->pvBuffer, pddeData->cbSize); 367 if (!Ret) 368 { 369 ERR("DDE Get CB failed\n"); 370 } 371 372 if (pddeData->pvBuffer) ExFreePoolWithTag(pddeData->pvBuffer, USERTAG_DDE); 373 374 ExFreePoolWithTag(pddeData, USERTAG_DDE5); 375 376 return Ret; 377 } 378 TRACE("DDE Get No DDE Data found!\n"); 379 return TRUE; 380 } 381 382 // 383 // DDE Send message hook, intercept DDE messages and associate them in a partnership with property. 384 // 385 BOOL FASTCALL 386 IntDdeSendMessageHook(PWND pWnd, UINT Msg, WPARAM wParam, LPARAM lParam) 387 { 388 PWND pWndServer; 389 PDDE_PROP pddeProp; 390 391 if (pWnd->head.pti->ppi != gptiCurrent->ppi) 392 { 393 TRACE("Sending long DDE 0x%x\n",Msg); 394 395 // Allow only Acknowledge and Initiate to be sent across borders. 396 if (Msg != WM_DDE_ACK ) 397 { 398 if (Msg == WM_DDE_INITIATE) return TRUE; 399 return FALSE; 400 } 401 402 TRACE("Sending long WM_DDE_ACK\n"); 403 404 pWndServer = UserGetWindowObject((HWND)wParam); 405 if (pWndServer == NULL) 406 { 407 ERR("Invalid DDE Server Window handle\n"); 408 return FALSE; 409 } 410 411 // Setup property so this conversation can be tracked. 412 pddeProp = ExAllocatePoolWithTag(PagedPool, sizeof(DDE_PROP), USERTAG_DDE1); 413 if (pddeProp == NULL) 414 { 415 ERR("failed to allocate DDE_PROP\n"); 416 return FALSE; 417 } 418 419 pddeProp->spwnd = pWndServer; 420 pddeProp->spwndPartner = pWnd; 421 422 UserSetProp(pWndServer, AtomDDETrack, (HANDLE)pddeProp, TRUE); 423 } 424 return TRUE; 425 } 426 427 428 BOOL 429 APIENTRY 430 NtUserDdeGetQualityOfService( 431 IN HWND hwndClient, 432 IN HWND hWndServer, 433 OUT PSECURITY_QUALITY_OF_SERVICE pqosPrev) 434 { 435 STUB 436 437 return 0; 438 } 439 440 BOOL 441 APIENTRY 442 NtUserDdeSetQualityOfService( 443 IN HWND hwndClient, 444 IN PSECURITY_QUALITY_OF_SERVICE pqosNew, 445 OUT PSECURITY_QUALITY_OF_SERVICE pqosPrev) 446 { 447 STUB 448 449 return 0; 450 } 451 452 BOOL 453 APIENTRY 454 NtUserImpersonateDdeClientWindow( 455 HWND hWndClient, 456 HWND hWndServer) 457 { 458 STUB 459 460 return 0; 461 } 462 463 DWORD 464 APIENTRY 465 NtUserDdeInitialize( 466 DWORD Unknown0, 467 DWORD Unknown1, 468 DWORD Unknown2, 469 DWORD Unknown3, 470 DWORD Unknown4) 471 { 472 STUB 473 474 return 0; 475 } 476 477