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