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