1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS kernel 4 * PURPOSE: Clipboard routines 5 * FILE: win32ss/user/ntuser/clipboard.c 6 * PROGRAMER: Filip Navara <xnavara@volny.cz> 7 * Pablo Borobia <pborobia@gmail.com> 8 * Rafal Harabien <rafalh@reactos.org> 9 */ 10 11 #include <win32k.h> 12 DBG_DEFAULT_CHANNEL(UserClipbrd); 13 14 #define DATA_DELAYED (HANDLE)0 15 #define DATA_SYNTH_USER (HANDLE)1 16 #define DATA_SYNTH_KRNL (HANDLE)2 17 #define IS_DATA_DELAYED(ce) ((ce)->hData == DATA_DELAYED) 18 #define IS_DATA_SYNTHESIZED(ce) ((ce)->hData == DATA_SYNTH_USER || (ce)->hData == DATA_SYNTH_KRNL) 19 20 static PWINSTATION_OBJECT FASTCALL 21 IntGetWinStaForCbAccess(VOID) 22 { 23 HWINSTA hWinSta; 24 PWINSTATION_OBJECT pWinStaObj; 25 NTSTATUS Status; 26 27 hWinSta = UserGetProcessWindowStation(); 28 Status = IntValidateWindowStationHandle(hWinSta, UserMode, WINSTA_ACCESSCLIPBOARD, &pWinStaObj, 0); 29 if (!NT_SUCCESS(Status)) 30 { 31 ERR("Cannot open winsta\n"); 32 SetLastNtError(Status); 33 return NULL; 34 } 35 36 return pWinStaObj; 37 } 38 39 /* If format exists, returns a non-null value (pointing to formated object) */ 40 static PCLIP FASTCALL 41 IntGetFormatElement(PWINSTATION_OBJECT pWinStaObj, UINT fmt) 42 { 43 DWORD i; 44 45 for (i = 0; i < pWinStaObj->cNumClipFormats; ++i) 46 { 47 if (pWinStaObj->pClipBase[i].fmt == fmt) 48 return &pWinStaObj->pClipBase[i]; 49 } 50 51 return NULL; 52 } 53 54 static BOOL FASTCALL 55 IntIsFormatAvailable(PWINSTATION_OBJECT pWinStaObj, UINT fmt) 56 { 57 return IntGetFormatElement(pWinStaObj, fmt) != NULL; 58 } 59 60 static VOID FASTCALL 61 IntFreeElementData(PCLIP pElement) 62 { 63 if (!IS_DATA_DELAYED(pElement) && 64 !IS_DATA_SYNTHESIZED(pElement)) 65 { 66 if (pElement->fGlobalHandle) 67 UserDeleteObject(pElement->hData, TYPE_CLIPDATA); 68 else if (pElement->fmt == CF_BITMAP || pElement->fmt == CF_PALETTE || 69 pElement->fmt == CF_DSPBITMAP) 70 { 71 GreSetObjectOwner(pElement->hData, GDI_OBJ_HMGR_POWNED); 72 GreDeleteObject(pElement->hData); 73 } 74 } 75 } 76 77 /* Adds a new format and data to the clipboard */ 78 static PCLIP NTAPI 79 IntAddFormatedData(PWINSTATION_OBJECT pWinStaObj, UINT fmt, HANDLE hData, BOOLEAN fGlobalHandle, BOOL bEnd) 80 { 81 PCLIP pElement = NULL; 82 83 /* Use existing entry with specified format */ 84 if (!bEnd) 85 pElement = IntGetFormatElement(pWinStaObj, fmt); 86 87 /* Put new entry at the end if nothing was found */ 88 if (!pElement) 89 { 90 /* Allocate bigger clipboard if needed. We could use lists but Windows uses array */ 91 if (pWinStaObj->cNumClipFormats % 4 == 0) 92 { 93 PCLIP pNewClip; 94 95 /* Allocate new clipboard */ 96 pNewClip = ExAllocatePoolWithTag(PagedPool, 97 (pWinStaObj->cNumClipFormats + 4) * sizeof(CLIP), 98 USERTAG_CLIPBOARD); 99 if (!pNewClip) 100 { 101 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 102 return NULL; 103 } 104 105 /* Copy data */ 106 memcpy(pNewClip, pWinStaObj->pClipBase, pWinStaObj->cNumClipFormats * sizeof(CLIP)); 107 108 /* Free old clipboard */ 109 if (pWinStaObj->pClipBase) 110 ExFreePoolWithTag(pWinStaObj->pClipBase, USERTAG_CLIPBOARD); 111 112 /* Update WinSta */ 113 pWinStaObj->pClipBase = pNewClip; 114 } 115 116 /* New element is at the end */ 117 pElement = &pWinStaObj->pClipBase[pWinStaObj->cNumClipFormats]; 118 pElement->fmt = fmt; 119 pWinStaObj->cNumClipFormats++; 120 } 121 else 122 IntFreeElementData(pElement); 123 124 pElement->hData = hData; 125 pElement->fGlobalHandle = fGlobalHandle; 126 127 return pElement; 128 } 129 130 static BOOL FASTCALL 131 IntIsClipboardOpenByMe(PWINSTATION_OBJECT pWinSta) 132 { 133 /* Check if the current thread has opened the clipboard */ 134 return (pWinSta->ptiClipLock && 135 pWinSta->ptiClipLock == PsGetCurrentThreadWin32Thread()); 136 } 137 138 static VOID NTAPI 139 IntSynthesizeDib( 140 PWINSTATION_OBJECT pWinStaObj, 141 HBITMAP hbm) 142 { 143 HDC hdc; 144 ULONG cjInfoSize, cjDataSize; 145 PCLIPBOARDDATA pClipboardData; 146 HANDLE hMem; 147 INT iResult; 148 struct 149 { 150 BITMAPINFOHEADER bmih; 151 RGBQUAD rgbColors[256]; 152 } bmiBuffer; 153 PBITMAPINFO pbmi = (PBITMAPINFO)&bmiBuffer; 154 155 /* Get the display DC */ 156 hdc = UserGetDCEx(NULL, NULL, DCX_USESTYLE); 157 if (!hdc) 158 { 159 return; 160 } 161 162 /* Get information about the bitmap format */ 163 pbmi->bmiHeader.biSize = sizeof(bmiBuffer.bmih); 164 iResult = GreGetDIBitsInternal(hdc, 165 hbm, 166 0, 167 0, 168 NULL, 169 pbmi, 170 DIB_RGB_COLORS, 171 0, 172 sizeof(bmiBuffer)); 173 if (iResult == 0) 174 { 175 goto cleanup; 176 } 177 178 /* Get the size for a full BITMAPINFO */ 179 cjInfoSize = DIB_BitmapInfoSize(pbmi, DIB_RGB_COLORS); 180 181 /* Calculate the size of the clipboard data, which is a packed DIB */ 182 cjDataSize = cjInfoSize + pbmi->bmiHeader.biSizeImage; 183 184 /* Create the clipboard data */ 185 pClipboardData = (PCLIPBOARDDATA)UserCreateObject(gHandleTable, 186 NULL, 187 NULL, 188 &hMem, 189 TYPE_CLIPDATA, 190 sizeof(CLIPBOARDDATA) + cjDataSize); 191 if (!pClipboardData) 192 { 193 goto cleanup; 194 } 195 196 /* Set the data size */ 197 pClipboardData->cbData = cjDataSize; 198 199 /* Copy the BITMAPINFOHEADER */ 200 memcpy(pClipboardData->Data, pbmi, sizeof(BITMAPINFOHEADER)); 201 202 /* Get the bitmap bits and the color table */ 203 iResult = GreGetDIBitsInternal(hdc, 204 hbm, 205 0, 206 abs(pbmi->bmiHeader.biHeight), 207 (LPBYTE)pClipboardData->Data + cjInfoSize, 208 (LPBITMAPINFO)pClipboardData->Data, 209 DIB_RGB_COLORS, 210 pbmi->bmiHeader.biSizeImage, 211 cjInfoSize); 212 213 /* Add the clipboard data */ 214 IntAddFormatedData(pWinStaObj, CF_DIB, hMem, TRUE, TRUE); 215 216 /* Release the extra reference (UserCreateObject added 2 references) */ 217 UserDereferenceObject(pClipboardData); 218 219 cleanup: 220 UserReleaseDC(NULL, hdc, FALSE); 221 } 222 223 static VOID WINAPI 224 IntSynthesizeBitmap(PWINSTATION_OBJECT pWinStaObj, PCLIP pBmEl) 225 { 226 HDC hdc = NULL; 227 PBITMAPINFO pBmi, pConvertedBmi = NULL; 228 HBITMAP hBm = NULL; 229 PCLIPBOARDDATA pMemObj; 230 PCLIP pDibEl; 231 ULONG Offset; 232 233 TRACE("IntSynthesizeBitmap(%p, %p)\n", pWinStaObj, pBmEl); 234 235 pDibEl = IntGetFormatElement(pWinStaObj, CF_DIB); 236 ASSERT(pDibEl && !IS_DATA_SYNTHESIZED(pDibEl)); 237 if (!pDibEl->fGlobalHandle) 238 return; 239 240 pMemObj = (PCLIPBOARDDATA)UserGetObject(gHandleTable, pDibEl->hData, TYPE_CLIPDATA); 241 if (!pMemObj) 242 return; 243 244 pBmi = (BITMAPINFO*)pMemObj->Data; 245 246 if (pMemObj->cbData < sizeof(DWORD) && pMemObj->cbData < pBmi->bmiHeader.biSize) 247 goto cleanup; 248 249 pConvertedBmi = DIB_ConvertBitmapInfo(pBmi, DIB_RGB_COLORS); 250 if (!pConvertedBmi) 251 goto cleanup; 252 253 Offset = DIB_BitmapInfoSize(pBmi, DIB_RGB_COLORS); 254 255 hdc = UserGetDCEx(NULL, NULL, DCX_USESTYLE); 256 if (!hdc) 257 goto cleanup; 258 259 hBm = GreCreateDIBitmapInternal(hdc, 260 pConvertedBmi->bmiHeader.biWidth, 261 pConvertedBmi->bmiHeader.biHeight, 262 CBM_INIT, 263 pMemObj->Data + Offset, 264 pConvertedBmi, 265 DIB_RGB_COLORS, 266 0, 267 pMemObj->cbData - Offset, 268 0); 269 270 if (hBm) 271 { 272 GreSetObjectOwner(hBm, GDI_OBJ_HMGR_PUBLIC); 273 pBmEl->hData = hBm; 274 } 275 276 cleanup: 277 if (hdc) 278 UserReleaseDC(NULL, hdc, FALSE); 279 280 if (pConvertedBmi) 281 DIB_FreeConvertedBitmapInfo(pConvertedBmi, pBmi, -1); 282 } 283 284 static VOID NTAPI 285 IntAddSynthesizedFormats(PWINSTATION_OBJECT pWinStaObj) 286 { 287 BOOL bHaveText, bHaveUniText, bHaveOemText, bHaveLocale, bHaveBm, bHaveDib; 288 289 bHaveText = IntIsFormatAvailable(pWinStaObj, CF_TEXT); 290 bHaveOemText = IntIsFormatAvailable(pWinStaObj, CF_OEMTEXT); 291 bHaveUniText = IntIsFormatAvailable(pWinStaObj, CF_UNICODETEXT); 292 bHaveLocale = IntIsFormatAvailable(pWinStaObj, CF_LOCALE); 293 bHaveBm = IntIsFormatAvailable(pWinStaObj, CF_BITMAP); 294 bHaveDib = IntIsFormatAvailable(pWinStaObj, CF_DIB); 295 296 /* Add CF_LOCALE format if we have CF_TEXT */ 297 if (!bHaveLocale && bHaveText) 298 { 299 PCLIPBOARDDATA pMemObj; 300 HANDLE hMem; 301 302 pMemObj = (PCLIPBOARDDATA)UserCreateObject(gHandleTable, NULL, NULL, &hMem, TYPE_CLIPDATA, 303 sizeof(CLIPBOARDDATA) + sizeof(LCID)); 304 if (pMemObj) 305 { 306 pMemObj->cbData = sizeof(LCID); 307 *((LCID*)pMemObj->Data) = NtCurrentTeb()->CurrentLocale; 308 IntAddFormatedData(pWinStaObj, CF_LOCALE, hMem, TRUE, TRUE); 309 310 /* Release the extra reference (UserCreateObject added 2 references) */ 311 UserDereferenceObject(pMemObj); 312 } 313 } 314 315 /* Add CF_TEXT. Note: it is synthesized in user32.dll */ 316 if (!bHaveText && (bHaveUniText || bHaveOemText)) 317 IntAddFormatedData(pWinStaObj, CF_TEXT, DATA_SYNTH_USER, FALSE, TRUE); 318 319 /* Add CF_OEMTEXT. Note: it is synthesized in user32.dll */ 320 if (!bHaveOemText && (bHaveUniText || bHaveText)) 321 IntAddFormatedData(pWinStaObj, CF_OEMTEXT, DATA_SYNTH_USER, FALSE, TRUE); 322 323 /* Add CF_UNICODETEXT. Note: it is synthesized in user32.dll */ 324 if (!bHaveUniText && (bHaveText || bHaveOemText)) 325 IntAddFormatedData(pWinStaObj, CF_UNICODETEXT, DATA_SYNTH_USER, FALSE, TRUE); 326 327 /* Add CF_BITMAP. Note: it is synthesized on demand */ 328 if (!bHaveBm && bHaveDib) 329 IntAddFormatedData(pWinStaObj, CF_BITMAP, DATA_SYNTH_KRNL, FALSE, TRUE); 330 331 /* Note: We need to render the DIB or DIBV5 format as soon as possible 332 because pallette information may change */ 333 if (!bHaveDib && bHaveBm) 334 IntSynthesizeDib(pWinStaObj, IntGetFormatElement(pWinStaObj, CF_BITMAP)->hData); 335 } 336 337 VOID NTAPI 338 UserEmptyClipboardData(PWINSTATION_OBJECT pWinSta) 339 { 340 DWORD i; 341 PCLIP pElement; 342 343 for (i = 0; i < pWinSta->cNumClipFormats; ++i) 344 { 345 pElement = &pWinSta->pClipBase[i]; 346 IntFreeElementData(pElement); 347 } 348 349 if (pWinSta->pClipBase) 350 ExFreePoolWithTag(pWinSta->pClipBase, USERTAG_CLIPBOARD); 351 352 pWinSta->pClipBase = NULL; 353 pWinSta->cNumClipFormats = 0; 354 } 355 356 /* UserClipboardRelease is called from IntSendDestroyMsg in window.c */ 357 VOID FASTCALL 358 UserClipboardRelease(PWND pWindow) 359 { 360 PWINSTATION_OBJECT pWinStaObj; 361 362 pWinStaObj = IntGetWinStaForCbAccess(); 363 if (!pWinStaObj) 364 return; 365 366 co_IntSendMessage(pWinStaObj->spwndClipOwner->head.h, WM_RENDERALLFORMATS, 0, 0); 367 368 /* If the window being destroyed is the current clipboard owner... */ 369 if (pWindow == pWinStaObj->spwndClipOwner) 370 { 371 /* ... make it release the clipboard */ 372 pWinStaObj->spwndClipOwner = NULL; 373 } 374 375 if (pWinStaObj->fClipboardChanged) 376 { 377 /* Add synthesized formats - they are rendered later */ 378 IntAddSynthesizedFormats(pWinStaObj); 379 380 /* Notify viewer windows in chain */ 381 pWinStaObj->fClipboardChanged = FALSE; 382 if (pWinStaObj->spwndClipViewer) 383 { 384 TRACE("Clipboard: sending WM_DRAWCLIPBOARD to %p\n", pWinStaObj->spwndClipViewer->head.h); 385 // For 32-bit applications this message is sent as a notification 386 co_IntSendMessageNoWait(pWinStaObj->spwndClipViewer->head.h, WM_DRAWCLIPBOARD, 0, 0); 387 } 388 } 389 390 ObDereferenceObject(pWinStaObj); 391 } 392 393 /* UserClipboardFreeWindow is called from co_UserFreeWindow in window.c */ 394 VOID FASTCALL 395 UserClipboardFreeWindow(PWND pWindow) 396 { 397 PWINSTATION_OBJECT pWinStaObj; 398 399 pWinStaObj = IntGetWinStaForCbAccess(); 400 if (!pWinStaObj) 401 return; 402 403 if (pWindow == pWinStaObj->spwndClipOwner) 404 { 405 /* The owner window was destroyed */ 406 pWinStaObj->spwndClipOwner = NULL; 407 } 408 409 /* Check if clipboard is not locked by this window, if yes, unlock it */ 410 if (pWindow == pWinStaObj->spwndClipOpen) 411 { 412 /* The window that opens the clipboard was destroyed */ 413 pWinStaObj->spwndClipOpen = NULL; 414 pWinStaObj->ptiClipLock = NULL; 415 } 416 /* Remove window from window chain */ 417 if (pWindow == pWinStaObj->spwndClipViewer) 418 pWinStaObj->spwndClipViewer = NULL; 419 420 ObDereferenceObject(pWinStaObj); 421 } 422 423 UINT APIENTRY 424 UserEnumClipboardFormats(UINT fmt) 425 { 426 UINT Ret = 0; 427 PCLIP pElement; 428 PWINSTATION_OBJECT pWinStaObj; 429 430 pWinStaObj = IntGetWinStaForCbAccess(); 431 if (!pWinStaObj) 432 goto cleanup; 433 434 /* Check if the clipboard has been opened */ 435 if (!IntIsClipboardOpenByMe(pWinStaObj)) 436 { 437 EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN); 438 goto cleanup; 439 } 440 441 if (fmt == 0) 442 { 443 /* Return first format */ 444 if (pWinStaObj->pClipBase) 445 Ret = pWinStaObj->pClipBase[0].fmt; 446 } 447 else 448 { 449 /* Return next format */ 450 pElement = IntGetFormatElement(pWinStaObj, fmt); 451 if (pElement != NULL) 452 { 453 ++pElement; 454 if (pElement < &pWinStaObj->pClipBase[pWinStaObj->cNumClipFormats]) 455 { 456 Ret = pElement->fmt; 457 } 458 } 459 } 460 461 cleanup: 462 if (pWinStaObj) 463 ObDereferenceObject(pWinStaObj); 464 465 return Ret; 466 } 467 468 BOOL NTAPI 469 UserOpenClipboard(HWND hWnd) 470 { 471 PWND pWindow = NULL; 472 BOOL bRet = FALSE; 473 PWINSTATION_OBJECT pWinStaObj = NULL; 474 475 if (hWnd) 476 { 477 pWindow = UserGetWindowObject(hWnd); 478 if (!pWindow) 479 goto cleanup; 480 } 481 482 pWinStaObj = IntGetWinStaForCbAccess(); 483 if (!pWinStaObj) 484 goto cleanup; 485 486 /* Check if we already opened the clipboard */ 487 if ((pWindow == pWinStaObj->spwndClipOpen) && IntIsClipboardOpenByMe(pWinStaObj)) 488 { 489 bRet = TRUE; 490 goto cleanup; 491 } 492 493 /* If the clipboard was already opened by somebody else, bail out */ 494 if ((pWindow != pWinStaObj->spwndClipOpen) && pWinStaObj->ptiClipLock) 495 { 496 ERR("Access denied!\n"); 497 EngSetLastError(ERROR_ACCESS_DENIED); 498 goto cleanup; 499 } 500 501 /* Open the clipboard */ 502 pWinStaObj->spwndClipOpen = pWindow; 503 pWinStaObj->ptiClipLock = PsGetCurrentThreadWin32Thread(); 504 bRet = TRUE; 505 506 cleanup: 507 if (pWinStaObj) 508 ObDereferenceObject(pWinStaObj); 509 510 return bRet; 511 } 512 513 BOOL APIENTRY 514 NtUserOpenClipboard(HWND hWnd, DWORD Unknown1) 515 { 516 BOOL bRet; 517 518 UserEnterExclusive(); 519 bRet = UserOpenClipboard(hWnd); 520 UserLeave(); 521 522 return bRet; 523 } 524 525 BOOL NTAPI 526 UserCloseClipboard(VOID) 527 { 528 BOOL bRet = FALSE; 529 PWINSTATION_OBJECT pWinStaObj; 530 531 pWinStaObj = IntGetWinStaForCbAccess(); 532 if (!pWinStaObj) 533 goto cleanup; 534 535 /* Check if the clipboard has been opened */ 536 if (!IntIsClipboardOpenByMe(pWinStaObj)) 537 { 538 EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN); 539 goto cleanup; 540 } 541 542 /* Clipboard is no longer open */ 543 pWinStaObj->spwndClipOpen = NULL; 544 pWinStaObj->ptiClipLock = NULL; 545 bRet = TRUE; 546 547 if (pWinStaObj->fClipboardChanged) 548 { 549 /* Add synthesized formats - they are rendered later */ 550 IntAddSynthesizedFormats(pWinStaObj); 551 552 /* Notify viewer windows in chain */ 553 pWinStaObj->fClipboardChanged = FALSE; 554 if (pWinStaObj->spwndClipViewer) 555 { 556 TRACE("Clipboard: sending WM_DRAWCLIPBOARD to %p\n", pWinStaObj->spwndClipViewer->head.h); 557 // For 32-bit applications this message is sent as a notification 558 co_IntSendMessageNoWait(pWinStaObj->spwndClipViewer->head.h, WM_DRAWCLIPBOARD, 0, 0); 559 } 560 } 561 562 cleanup: 563 if (pWinStaObj) 564 ObDereferenceObject(pWinStaObj); 565 566 return bRet; 567 } 568 569 BOOL APIENTRY 570 NtUserCloseClipboard(VOID) 571 { 572 BOOL bRet; 573 574 UserEnterExclusive(); 575 bRet = UserCloseClipboard(); 576 UserLeave(); 577 578 return bRet; 579 } 580 581 HWND APIENTRY 582 NtUserGetOpenClipboardWindow(VOID) 583 { 584 HWND hWnd = NULL; 585 PWINSTATION_OBJECT pWinStaObj; 586 587 UserEnterShared(); 588 589 pWinStaObj = IntGetWinStaForCbAccess(); 590 if (!pWinStaObj) 591 goto cleanup; 592 593 if (pWinStaObj->spwndClipOpen) 594 hWnd = pWinStaObj->spwndClipOpen->head.h; 595 596 ObDereferenceObject(pWinStaObj); 597 598 cleanup: 599 UserLeave(); 600 601 return hWnd; 602 } 603 604 BOOL APIENTRY 605 NtUserChangeClipboardChain(HWND hWndRemove, HWND hWndNewNext) 606 { 607 BOOL bRet = FALSE; 608 PWND pWindowRemove; 609 PWINSTATION_OBJECT pWinStaObj; 610 611 TRACE("NtUserChangeClipboardChain(%p, %p)\n", hWndRemove, hWndNewNext); 612 613 UserEnterExclusive(); 614 615 pWinStaObj = IntGetWinStaForCbAccess(); 616 if (!pWinStaObj) 617 goto cleanup; 618 619 pWindowRemove = UserGetWindowObject(hWndRemove); 620 621 if (pWindowRemove && pWinStaObj->spwndClipViewer) 622 { 623 if (pWindowRemove == pWinStaObj->spwndClipViewer) 624 pWinStaObj->spwndClipViewer = UserGetWindowObject(hWndNewNext); 625 626 if (pWinStaObj->spwndClipViewer) 627 bRet = (BOOL)co_IntSendMessage(pWinStaObj->spwndClipViewer->head.h, WM_CHANGECBCHAIN, (WPARAM)hWndRemove, (LPARAM)hWndNewNext); 628 } 629 630 ObDereferenceObject(pWinStaObj); 631 632 cleanup: 633 UserLeave(); 634 635 return bRet; 636 } 637 638 DWORD APIENTRY 639 NtUserCountClipboardFormats(VOID) 640 { 641 DWORD cFormats = 0; 642 PWINSTATION_OBJECT pWinStaObj; 643 644 UserEnterShared(); 645 646 pWinStaObj = IntGetWinStaForCbAccess(); 647 if (!pWinStaObj) 648 goto cleanup; 649 650 cFormats = pWinStaObj->cNumClipFormats; 651 652 ObDereferenceObject(pWinStaObj); 653 654 cleanup: 655 UserLeave(); 656 657 return cFormats; 658 } 659 660 BOOL NTAPI 661 UserEmptyClipboard(VOID) 662 { 663 BOOL bRet = FALSE; 664 PWINSTATION_OBJECT pWinStaObj; 665 666 pWinStaObj = IntGetWinStaForCbAccess(); 667 if (!pWinStaObj) 668 return FALSE; 669 670 /* Check if the clipboard has been opened */ 671 if (!IntIsClipboardOpenByMe(pWinStaObj)) 672 { 673 EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN); 674 goto cleanup; 675 } 676 677 UserEmptyClipboardData(pWinStaObj); 678 679 if (pWinStaObj->spwndClipOwner) 680 { 681 TRACE("Clipboard: WM_DESTROYCLIPBOARD to %p\n", pWinStaObj->spwndClipOwner->head.h); 682 // For 32-bit applications this message is sent as a notification 683 co_IntSendMessage(pWinStaObj->spwndClipOwner->head.h, WM_DESTROYCLIPBOARD, 0, 0); 684 } 685 686 pWinStaObj->spwndClipOwner = pWinStaObj->spwndClipOpen; 687 688 pWinStaObj->iClipSerialNumber++; 689 pWinStaObj->iClipSequenceNumber++; 690 pWinStaObj->fClipboardChanged = TRUE; 691 pWinStaObj->fInDelayedRendering = FALSE; 692 693 bRet = TRUE; 694 695 cleanup: 696 if (pWinStaObj) 697 ObDereferenceObject(pWinStaObj); 698 699 return bRet; 700 } 701 702 BOOL APIENTRY 703 NtUserEmptyClipboard(VOID) 704 { 705 BOOL bRet; 706 707 TRACE("NtUserEmptyClipboard()\n"); 708 709 UserEnterExclusive(); 710 bRet = UserEmptyClipboard(); 711 UserLeave(); 712 713 return bRet; 714 } 715 716 INT APIENTRY 717 NtUserGetClipboardFormatName(UINT fmt, LPWSTR lpszFormatName, INT cchMaxCount) 718 { 719 INT iRet = 0; 720 721 UserEnterShared(); 722 723 /* If the format is built-in we fail */ 724 if (fmt < 0xc000 || fmt > 0xffff) 725 { 726 /* Registetrated formats are >= 0xc000 */ 727 goto cleanup; 728 } 729 730 if (cchMaxCount < 1 || !lpszFormatName) 731 { 732 EngSetLastError(ERROR_INVALID_PARAMETER); 733 goto cleanup; 734 } 735 736 _SEH2_TRY 737 { 738 ProbeForWrite(lpszFormatName, cchMaxCount * sizeof(WCHAR), 1); 739 740 iRet = IntGetAtomName((RTL_ATOM)fmt, 741 lpszFormatName, 742 cchMaxCount * sizeof(WCHAR)); 743 iRet /= sizeof(WCHAR); 744 } 745 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 746 { 747 SetLastNtError(_SEH2_GetExceptionCode()); 748 } 749 _SEH2_END; 750 751 cleanup: 752 UserLeave(); 753 754 return iRet; 755 } 756 757 HWND APIENTRY 758 NtUserGetClipboardOwner(VOID) 759 { 760 HWND hWnd = NULL; 761 PWINSTATION_OBJECT pWinStaObj; 762 763 UserEnterShared(); 764 765 pWinStaObj = IntGetWinStaForCbAccess(); 766 if (!pWinStaObj) 767 goto cleanup; 768 769 if (pWinStaObj->spwndClipOwner) 770 hWnd = pWinStaObj->spwndClipOwner->head.h; 771 772 ObDereferenceObject(pWinStaObj); 773 774 cleanup: 775 UserLeave(); 776 777 return hWnd; 778 } 779 780 HWND APIENTRY 781 NtUserGetClipboardViewer(VOID) 782 { 783 HWND hWnd = NULL; 784 PWINSTATION_OBJECT pWinStaObj; 785 786 UserEnterShared(); 787 788 pWinStaObj = IntGetWinStaForCbAccess(); 789 if (!pWinStaObj) 790 goto cleanup; 791 792 if (pWinStaObj->spwndClipViewer) 793 hWnd = pWinStaObj->spwndClipViewer->head.h; 794 795 ObDereferenceObject(pWinStaObj); 796 797 cleanup: 798 UserLeave(); 799 800 return hWnd; 801 } 802 803 INT APIENTRY 804 NtUserGetPriorityClipboardFormat(UINT *paFormatPriorityList, INT cFormats) 805 { 806 INT i, iRet = 0; 807 PWINSTATION_OBJECT pWinStaObj; 808 809 UserEnterShared(); 810 811 pWinStaObj = IntGetWinStaForCbAccess(); 812 if (!pWinStaObj) 813 goto cleanup; 814 815 if (pWinStaObj->pClipBase == NULL) 816 { 817 iRet = 0; 818 } 819 else 820 { 821 _SEH2_TRY 822 { 823 ProbeForRead(paFormatPriorityList, cFormats * sizeof(UINT), sizeof(UINT)); 824 825 iRet = -1; 826 827 for (i = 0; i < cFormats; ++i) 828 { 829 if (IntIsFormatAvailable(pWinStaObj, paFormatPriorityList[i])) 830 { 831 iRet = paFormatPriorityList[i]; 832 break; 833 } 834 } 835 } 836 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 837 { 838 SetLastNtError(_SEH2_GetExceptionCode()); 839 } 840 _SEH2_END; 841 } 842 843 ObDereferenceObject(pWinStaObj); 844 845 cleanup: 846 UserLeave(); 847 848 return iRet; 849 850 } 851 852 BOOL APIENTRY 853 NtUserIsClipboardFormatAvailable(UINT fmt) 854 { 855 BOOL bRet = FALSE; 856 PWINSTATION_OBJECT pWinStaObj; 857 858 TRACE("NtUserIsClipboardFormatAvailable(%x)\n", fmt); 859 860 UserEnterShared(); 861 862 pWinStaObj = IntGetWinStaForCbAccess(); 863 if (!pWinStaObj) 864 goto cleanup; 865 866 if (IntIsFormatAvailable(pWinStaObj, fmt)) 867 bRet = TRUE; 868 869 ObDereferenceObject(pWinStaObj); 870 871 cleanup: 872 UserLeave(); 873 874 return bRet; 875 } 876 877 HANDLE APIENTRY 878 NtUserGetClipboardData(UINT fmt, PGETCLIPBDATA pgcd) 879 { 880 HANDLE hRet = NULL; 881 PCLIP pElement; 882 PWINSTATION_OBJECT pWinStaObj; 883 884 TRACE("NtUserGetClipboardData(%x, %p)\n", fmt, pgcd); 885 886 UserEnterShared(); 887 888 pWinStaObj = IntGetWinStaForCbAccess(); 889 if (!pWinStaObj) 890 goto cleanup; 891 892 /* Check if the clipboard has been opened */ 893 if (!IntIsClipboardOpenByMe(pWinStaObj)) 894 { 895 EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN); 896 goto cleanup; 897 } 898 899 pElement = IntGetFormatElement(pWinStaObj, fmt); 900 if (pElement && IS_DATA_DELAYED(pElement) && pWinStaObj->spwndClipOwner) 901 { 902 /* Send WM_RENDERFORMAT message */ 903 pWinStaObj->fInDelayedRendering = TRUE; 904 co_IntSendMessage(pWinStaObj->spwndClipOwner->head.h, WM_RENDERFORMAT, (WPARAM)fmt, 0); 905 pWinStaObj->fInDelayedRendering = FALSE; 906 907 /* Data should be in clipboard now */ 908 pElement = IntGetFormatElement(pWinStaObj, fmt); 909 } 910 911 if (!pElement || IS_DATA_DELAYED(pElement)) 912 goto cleanup; 913 914 if (IS_DATA_SYNTHESIZED(pElement)) 915 { 916 /* Note: Data is synthesized in usermode */ 917 /* TODO: Add more formats */ 918 switch (fmt) 919 { 920 case CF_UNICODETEXT: 921 case CF_TEXT: 922 case CF_OEMTEXT: 923 pElement = IntGetFormatElement(pWinStaObj, CF_UNICODETEXT); 924 if (IS_DATA_SYNTHESIZED(pElement)) 925 pElement = IntGetFormatElement(pWinStaObj, CF_TEXT); 926 if (IS_DATA_SYNTHESIZED(pElement)) 927 pElement = IntGetFormatElement(pWinStaObj, CF_OEMTEXT); 928 break; 929 case CF_BITMAP: 930 IntSynthesizeBitmap(pWinStaObj, pElement); 931 break; 932 default: 933 ASSERT(FALSE); 934 } 935 } 936 937 _SEH2_TRY 938 { 939 ProbeForWrite(pgcd, sizeof(*pgcd), 1); 940 pgcd->uFmtRet = pElement->fmt; 941 pgcd->fGlobalHandle = pElement->fGlobalHandle; 942 943 /* Text and bitmap needs more data */ 944 if (fmt == CF_TEXT) 945 { 946 PCLIP pLocaleEl; 947 948 pLocaleEl = IntGetFormatElement(pWinStaObj, CF_LOCALE); 949 if (pLocaleEl && !IS_DATA_DELAYED(pLocaleEl)) 950 pgcd->hLocale = pLocaleEl->hData; 951 } 952 else if (fmt == CF_BITMAP) 953 { 954 PCLIP pPaletteEl; 955 956 pPaletteEl = IntGetFormatElement(pWinStaObj, CF_PALETTE); 957 if (pPaletteEl && !IS_DATA_DELAYED(pPaletteEl)) 958 pgcd->hPalette = pPaletteEl->hData; 959 } 960 961 hRet = pElement->hData; 962 } 963 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 964 { 965 SetLastNtError(_SEH2_GetExceptionCode()); 966 } 967 _SEH2_END; 968 969 cleanup: 970 if (pWinStaObj) 971 ObDereferenceObject(pWinStaObj); 972 973 UserLeave(); 974 975 TRACE("NtUserGetClipboardData returns %p\n", hRet); 976 977 return hRet; 978 } 979 980 HANDLE NTAPI 981 UserSetClipboardData(UINT fmt, HANDLE hData, PSETCLIPBDATA scd) 982 { 983 HANDLE hRet = NULL; 984 PWINSTATION_OBJECT pWinStaObj; 985 986 pWinStaObj = IntGetWinStaForCbAccess(); 987 if (!pWinStaObj) 988 goto cleanup; 989 990 if (!fmt || !pWinStaObj->ptiClipLock) 991 { 992 ERR("Access denied!\n"); 993 EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN); 994 goto cleanup; 995 } 996 997 if (scd->fIncSerialNumber) 998 pWinStaObj->iClipSerialNumber++; 999 1000 /* Is it a delayed rendering? */ 1001 if (hData) 1002 { 1003 /* Is it a bitmap? */ 1004 if (fmt == CF_BITMAP) 1005 { 1006 /* Make bitmap public */ 1007 GreSetObjectOwner(hData, GDI_OBJ_HMGR_PUBLIC); 1008 } 1009 1010 /* Save data in the clipboard */ 1011 IntAddFormatedData(pWinStaObj, fmt, hData, scd->fGlobalHandle, FALSE); 1012 TRACE("hData stored\n"); 1013 1014 /* If the serial number was increased, increase also the sequence number */ 1015 if (scd->fIncSerialNumber) 1016 pWinStaObj->iClipSequenceNumber++; 1017 1018 pWinStaObj->fClipboardChanged = TRUE; 1019 1020 /* Note: Synthesized formats are added in NtUserCloseClipboard */ 1021 } 1022 else 1023 { 1024 /* This is a delayed rendering */ 1025 IntAddFormatedData(pWinStaObj, fmt, DATA_DELAYED, FALSE, FALSE); 1026 TRACE("SetClipboardData delayed format: %u\n", fmt); 1027 } 1028 1029 /* Return hData on success */ 1030 hRet = hData; 1031 1032 cleanup: 1033 TRACE("NtUserSetClipboardData returns: %p\n", hRet); 1034 1035 if (pWinStaObj) 1036 ObDereferenceObject(pWinStaObj); 1037 1038 return hRet; 1039 } 1040 1041 HANDLE APIENTRY 1042 NtUserSetClipboardData(UINT fmt, HANDLE hData, PSETCLIPBDATA pUnsafeScd) 1043 { 1044 SETCLIPBDATA scd; 1045 HANDLE hRet; 1046 1047 TRACE("NtUserSetClipboardData(%x %p %p)\n", fmt, hData, pUnsafeScd); 1048 1049 _SEH2_TRY 1050 { 1051 ProbeForRead(pUnsafeScd, sizeof(*pUnsafeScd), 1); 1052 RtlCopyMemory(&scd, pUnsafeScd, sizeof(scd)); 1053 } 1054 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1055 { 1056 SetLastNtError(_SEH2_GetExceptionCode()); 1057 _SEH2_YIELD(return NULL;) 1058 } 1059 _SEH2_END 1060 1061 UserEnterExclusive(); 1062 1063 /* Call internal function */ 1064 hRet = UserSetClipboardData(fmt, hData, &scd); 1065 1066 UserLeave(); 1067 1068 return hRet; 1069 } 1070 1071 HWND APIENTRY 1072 NtUserSetClipboardViewer(HWND hWndNewViewer) 1073 { 1074 HWND hWndNext = NULL; 1075 PWINSTATION_OBJECT pWinStaObj; 1076 PWND pWindow; 1077 1078 UserEnterExclusive(); 1079 1080 pWinStaObj = IntGetWinStaForCbAccess(); 1081 if (!pWinStaObj) 1082 goto cleanup; 1083 1084 pWindow = UserGetWindowObject(hWndNewViewer); 1085 if (!pWindow) 1086 { 1087 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE); 1088 goto cleanup; 1089 } 1090 1091 /* Return previous viewer. New viever window should 1092 send messages to rest of the chain */ 1093 if (pWinStaObj->spwndClipViewer) 1094 hWndNext = pWinStaObj->spwndClipViewer->head.h; 1095 1096 /* Set new viewer window */ 1097 pWinStaObj->spwndClipViewer = pWindow; 1098 1099 /* Notify viewer windows in chain */ 1100 pWinStaObj->fClipboardChanged = FALSE; 1101 if (pWinStaObj->spwndClipViewer) 1102 { 1103 TRACE("Clipboard: sending WM_DRAWCLIPBOARD to %p\n", pWinStaObj->spwndClipViewer->head.h); 1104 // For 32-bit applications this message is sent as a notification 1105 co_IntSendMessageNoWait(pWinStaObj->spwndClipViewer->head.h, WM_DRAWCLIPBOARD, 0, 0); 1106 } 1107 1108 cleanup: 1109 if (pWinStaObj) 1110 ObDereferenceObject(pWinStaObj); 1111 1112 UserLeave(); 1113 1114 return hWndNext; 1115 } 1116 1117 // Sequence number is incremented whenever the contents of the clipboard change 1118 // or the clipboard is emptied. If clipboard rendering is delayed, 1119 // the sequence number is not incremented until the changes are rendered. 1120 1121 DWORD APIENTRY 1122 NtUserGetClipboardSequenceNumber(VOID) 1123 { 1124 DWORD dwRet = 0; 1125 PWINSTATION_OBJECT pWinStaObj; 1126 1127 UserEnterShared(); 1128 1129 pWinStaObj = IntGetWinStaForCbAccess(); 1130 if (!pWinStaObj) 1131 goto cleanup; 1132 1133 /* Get windowstation sequence number */ 1134 dwRet = (DWORD)pWinStaObj->iClipSequenceNumber; 1135 1136 ObDereferenceObject(pWinStaObj); 1137 1138 cleanup: 1139 UserLeave(); 1140 1141 return dwRet; 1142 } 1143 1144 HANDLE APIENTRY 1145 NtUserConvertMemHandle( 1146 PVOID pData, 1147 DWORD cbData) 1148 { 1149 HANDLE hMem = NULL; 1150 PCLIPBOARDDATA pMemObj; 1151 1152 UserEnterExclusive(); 1153 1154 /* Create Clipboard data object */ 1155 pMemObj = UserCreateObject(gHandleTable, NULL, NULL, &hMem, TYPE_CLIPDATA, sizeof(CLIPBOARDDATA) + cbData); 1156 if (!pMemObj) 1157 goto cleanup; 1158 1159 pMemObj->cbData = cbData; 1160 1161 /* Copy data */ 1162 _SEH2_TRY 1163 { 1164 ProbeForRead(pData, cbData, 1); 1165 memcpy(pMemObj->Data, pData, cbData); 1166 } 1167 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1168 { 1169 pMemObj = NULL; 1170 } 1171 _SEH2_END; 1172 1173 /* Release the extra reference (UserCreateObject added 2 references) */ 1174 UserDereferenceObject(pMemObj); 1175 1176 /* If we failed to copy data, remove handle */ 1177 if (!pMemObj) 1178 { 1179 UserDeleteObject(hMem, TYPE_CLIPDATA); 1180 hMem = NULL; 1181 } 1182 1183 cleanup: 1184 UserLeave(); 1185 1186 return hMem; 1187 } 1188 1189 NTSTATUS APIENTRY 1190 NtUserCreateLocalMemHandle( 1191 HANDLE hMem, 1192 PVOID pData, 1193 DWORD cbData, 1194 DWORD *pcbData) 1195 { 1196 PCLIPBOARDDATA pMemObj; 1197 NTSTATUS Status = STATUS_SUCCESS; 1198 1199 UserEnterShared(); 1200 1201 /* Get Clipboard data object */ 1202 pMemObj = (PCLIPBOARDDATA)UserGetObject(gHandleTable, hMem, TYPE_CLIPDATA); 1203 if (!pMemObj) 1204 { 1205 Status = STATUS_INVALID_HANDLE; 1206 goto cleanup; 1207 } 1208 1209 /* Don't overrun */ 1210 if (cbData > pMemObj->cbData) 1211 cbData = pMemObj->cbData; 1212 1213 /* Copy data to usermode */ 1214 _SEH2_TRY 1215 { 1216 if (pcbData) 1217 { 1218 ProbeForWrite(pcbData, sizeof(*pcbData), 1); 1219 *pcbData = pMemObj->cbData; 1220 } 1221 1222 ProbeForWrite(pData, cbData, 1); 1223 memcpy(pData, pMemObj->Data, cbData); 1224 } 1225 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1226 { 1227 Status = _SEH2_GetExceptionCode(); 1228 } 1229 _SEH2_END; 1230 1231 cleanup: 1232 UserLeave(); 1233 1234 return Status; 1235 } 1236 1237 /* EOF */ 1238