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 if (!pWindow) 379 return; 380 381 pWinStaObj = IntGetWinStaForCbAccess(); 382 if (!pWinStaObj) 383 return; 384 385 co_IntSendMessage(UserHMGetHandle(pWinStaObj->spwndClipOwner), WM_RENDERALLFORMATS, 0, 0); 386 387 /* If the window being destroyed is the current clipboard owner... */ 388 if (pWindow == pWinStaObj->spwndClipOwner) 389 { 390 /* ... make it release the clipboard */ 391 pWinStaObj->spwndClipOwner = NULL; 392 } 393 394 if (pWinStaObj->fClipboardChanged) 395 { 396 /* Add synthesized formats - they are rendered later */ 397 IntAddSynthesizedFormats(pWinStaObj); 398 399 /* Notify viewer windows in chain */ 400 pWinStaObj->fClipboardChanged = FALSE; 401 if (pWinStaObj->spwndClipViewer) 402 { 403 TRACE("Clipboard: sending WM_DRAWCLIPBOARD to %p\n", UserHMGetHandle(pWinStaObj->spwndClipViewer)); 404 // For 32-bit applications this message is sent as a notification 405 co_IntSendMessageNoWait(UserHMGetHandle(pWinStaObj->spwndClipViewer), WM_DRAWCLIPBOARD, 0, 0); 406 } 407 } 408 409 ObDereferenceObject(pWinStaObj); 410 } 411 412 /* UserClipboardFreeWindow is called from co_UserFreeWindow in window.c */ 413 VOID FASTCALL 414 UserClipboardFreeWindow(PWND pWindow) 415 { 416 PWINSTATION_OBJECT pWinStaObj; 417 418 pWinStaObj = IntGetWinStaForCbAccess(); 419 if (!pWinStaObj) 420 return; 421 422 if (pWindow == pWinStaObj->spwndClipOwner) 423 { 424 /* The owner window was destroyed */ 425 pWinStaObj->spwndClipOwner = NULL; 426 } 427 428 /* Check if clipboard is not locked by this window, if yes, unlock it */ 429 if (pWindow == pWinStaObj->spwndClipOpen) 430 { 431 /* The window that opens the clipboard was destroyed */ 432 pWinStaObj->spwndClipOpen = NULL; 433 pWinStaObj->ptiClipLock = NULL; 434 } 435 /* Remove window from window chain */ 436 if (pWindow == pWinStaObj->spwndClipViewer) 437 pWinStaObj->spwndClipViewer = NULL; 438 439 ObDereferenceObject(pWinStaObj); 440 } 441 442 UINT APIENTRY 443 UserEnumClipboardFormats(UINT fmt) 444 { 445 UINT Ret = 0; 446 PCLIP pElement; 447 PWINSTATION_OBJECT pWinStaObj; 448 449 pWinStaObj = IntGetWinStaForCbAccess(); 450 if (!pWinStaObj) 451 goto cleanup; 452 453 /* Check if the clipboard has been opened */ 454 if (!IntIsClipboardOpenByMe(pWinStaObj)) 455 { 456 EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN); 457 goto cleanup; 458 } 459 460 if (fmt == 0) 461 { 462 /* Return first format */ 463 if (pWinStaObj->pClipBase) 464 Ret = pWinStaObj->pClipBase[0].fmt; 465 } 466 else 467 { 468 /* Return next format */ 469 pElement = IntGetFormatElement(pWinStaObj, fmt); 470 if (pElement != NULL) 471 { 472 ++pElement; 473 if (pElement < &pWinStaObj->pClipBase[pWinStaObj->cNumClipFormats]) 474 { 475 Ret = pElement->fmt; 476 } 477 } 478 } 479 480 cleanup: 481 if (pWinStaObj) 482 ObDereferenceObject(pWinStaObj); 483 484 return Ret; 485 } 486 487 BOOL NTAPI 488 UserOpenClipboard(HWND hWnd) 489 { 490 PWND pWindow = NULL; 491 BOOL bRet = FALSE; 492 PWINSTATION_OBJECT pWinStaObj = NULL; 493 494 if (hWnd) 495 { 496 pWindow = UserGetWindowObject(hWnd); 497 if (!pWindow) 498 goto cleanup; 499 } 500 501 pWinStaObj = IntGetWinStaForCbAccess(); 502 if (!pWinStaObj) 503 goto cleanup; 504 505 /* Check if we already opened the clipboard */ 506 if ((pWindow == pWinStaObj->spwndClipOpen) && IntIsClipboardOpenByMe(pWinStaObj)) 507 { 508 bRet = TRUE; 509 goto cleanup; 510 } 511 512 /* If the clipboard was already opened by somebody else, bail out */ 513 if ((pWindow != pWinStaObj->spwndClipOpen) && pWinStaObj->ptiClipLock) 514 { 515 ERR("Access denied!\n"); 516 EngSetLastError(ERROR_ACCESS_DENIED); 517 goto cleanup; 518 } 519 520 /* Open the clipboard */ 521 pWinStaObj->spwndClipOpen = pWindow; 522 pWinStaObj->ptiClipLock = PsGetCurrentThreadWin32Thread(); 523 bRet = TRUE; 524 525 cleanup: 526 if (pWinStaObj) 527 ObDereferenceObject(pWinStaObj); 528 529 return bRet; 530 } 531 532 BOOL APIENTRY 533 NtUserOpenClipboard(HWND hWnd, DWORD Unknown1) 534 { 535 BOOL bRet; 536 537 UserEnterExclusive(); 538 bRet = UserOpenClipboard(hWnd); 539 UserLeave(); 540 541 return bRet; 542 } 543 544 BOOL NTAPI 545 UserCloseClipboard(VOID) 546 { 547 BOOL bRet = FALSE; 548 PWINSTATION_OBJECT pWinStaObj; 549 550 pWinStaObj = IntGetWinStaForCbAccess(); 551 if (!pWinStaObj) 552 goto cleanup; 553 554 /* Check if the clipboard has been opened */ 555 if (!IntIsClipboardOpenByMe(pWinStaObj)) 556 { 557 EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN); 558 goto cleanup; 559 } 560 561 /* Clipboard is no longer open */ 562 pWinStaObj->spwndClipOpen = NULL; 563 pWinStaObj->ptiClipLock = NULL; 564 bRet = TRUE; 565 566 if (pWinStaObj->fClipboardChanged) 567 { 568 /* Add synthesized formats - they are rendered later */ 569 IntAddSynthesizedFormats(pWinStaObj); 570 571 /* Notify viewer windows in chain */ 572 pWinStaObj->fClipboardChanged = FALSE; 573 if (pWinStaObj->spwndClipViewer) 574 { 575 TRACE("Clipboard: sending WM_DRAWCLIPBOARD to %p\n", UserHMGetHandle(pWinStaObj->spwndClipViewer)); 576 // For 32-bit applications this message is sent as a notification 577 co_IntSendMessageNoWait(UserHMGetHandle(pWinStaObj->spwndClipViewer), WM_DRAWCLIPBOARD, 0, 0); 578 } 579 } 580 581 cleanup: 582 if (pWinStaObj) 583 ObDereferenceObject(pWinStaObj); 584 585 return bRet; 586 } 587 588 BOOL APIENTRY 589 NtUserCloseClipboard(VOID) 590 { 591 BOOL bRet; 592 593 UserEnterExclusive(); 594 bRet = UserCloseClipboard(); 595 UserLeave(); 596 597 return bRet; 598 } 599 600 HWND APIENTRY 601 NtUserGetOpenClipboardWindow(VOID) 602 { 603 HWND hWnd = NULL; 604 PWINSTATION_OBJECT pWinStaObj; 605 606 UserEnterShared(); 607 608 pWinStaObj = IntGetWinStaForCbAccess(); 609 if (!pWinStaObj) 610 goto cleanup; 611 612 if (pWinStaObj->spwndClipOpen) 613 hWnd = UserHMGetHandle(pWinStaObj->spwndClipOpen); 614 615 ObDereferenceObject(pWinStaObj); 616 617 cleanup: 618 UserLeave(); 619 620 return hWnd; 621 } 622 623 BOOL APIENTRY 624 NtUserChangeClipboardChain(HWND hWndRemove, HWND hWndNewNext) 625 { 626 BOOL bRet = FALSE; 627 PWND pWindowRemove; 628 PWINSTATION_OBJECT pWinStaObj; 629 630 TRACE("NtUserChangeClipboardChain(%p, %p)\n", hWndRemove, hWndNewNext); 631 632 UserEnterExclusive(); 633 634 pWinStaObj = IntGetWinStaForCbAccess(); 635 if (!pWinStaObj) 636 goto cleanup; 637 638 pWindowRemove = UserGetWindowObject(hWndRemove); 639 640 if (pWindowRemove && pWinStaObj->spwndClipViewer) 641 { 642 if (pWindowRemove == pWinStaObj->spwndClipViewer) 643 pWinStaObj->spwndClipViewer = UserGetWindowObject(hWndNewNext); 644 645 if (pWinStaObj->spwndClipViewer) 646 bRet = (BOOL)co_IntSendMessage(UserHMGetHandle(pWinStaObj->spwndClipViewer), WM_CHANGECBCHAIN, (WPARAM)hWndRemove, (LPARAM)hWndNewNext); 647 } 648 649 ObDereferenceObject(pWinStaObj); 650 651 cleanup: 652 UserLeave(); 653 654 return bRet; 655 } 656 657 DWORD APIENTRY 658 NtUserCountClipboardFormats(VOID) 659 { 660 DWORD cFormats = 0; 661 PWINSTATION_OBJECT pWinStaObj; 662 663 UserEnterShared(); 664 665 pWinStaObj = IntGetWinStaForCbAccess(); 666 if (!pWinStaObj) 667 goto cleanup; 668 669 cFormats = pWinStaObj->cNumClipFormats; 670 671 ObDereferenceObject(pWinStaObj); 672 673 cleanup: 674 UserLeave(); 675 676 return cFormats; 677 } 678 679 BOOL NTAPI 680 UserEmptyClipboard(VOID) 681 { 682 BOOL bRet = FALSE; 683 PWINSTATION_OBJECT pWinStaObj; 684 685 pWinStaObj = IntGetWinStaForCbAccess(); 686 if (!pWinStaObj) 687 return FALSE; 688 689 /* Check if the clipboard has been opened */ 690 if (!IntIsClipboardOpenByMe(pWinStaObj)) 691 { 692 EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN); 693 goto cleanup; 694 } 695 696 UserEmptyClipboardData(pWinStaObj); 697 698 if (pWinStaObj->spwndClipOwner) 699 { 700 TRACE("Clipboard: WM_DESTROYCLIPBOARD to %p\n", UserHMGetHandle(pWinStaObj->spwndClipOwner)); 701 // For 32-bit applications this message is sent as a notification 702 co_IntSendMessage(UserHMGetHandle(pWinStaObj->spwndClipOwner), WM_DESTROYCLIPBOARD, 0, 0); 703 } 704 705 pWinStaObj->spwndClipOwner = pWinStaObj->spwndClipOpen; 706 707 pWinStaObj->iClipSerialNumber++; 708 pWinStaObj->iClipSequenceNumber++; 709 pWinStaObj->fClipboardChanged = TRUE; 710 pWinStaObj->fInDelayedRendering = FALSE; 711 712 bRet = TRUE; 713 714 cleanup: 715 if (pWinStaObj) 716 ObDereferenceObject(pWinStaObj); 717 718 return bRet; 719 } 720 721 BOOL APIENTRY 722 NtUserEmptyClipboard(VOID) 723 { 724 BOOL bRet; 725 726 TRACE("NtUserEmptyClipboard()\n"); 727 728 UserEnterExclusive(); 729 bRet = UserEmptyClipboard(); 730 UserLeave(); 731 732 return bRet; 733 } 734 735 INT APIENTRY 736 NtUserGetClipboardFormatName(UINT fmt, LPWSTR lpszFormatName, INT cchMaxCount) 737 { 738 INT iRet = 0; 739 740 UserEnterShared(); 741 742 /* If the format is built-in we fail */ 743 if (fmt < 0xc000 || fmt > 0xffff) 744 { 745 /* Registetrated formats are >= 0xc000 */ 746 goto cleanup; 747 } 748 749 if (cchMaxCount < 1 || !lpszFormatName) 750 { 751 EngSetLastError(ERROR_INVALID_PARAMETER); 752 goto cleanup; 753 } 754 755 _SEH2_TRY 756 { 757 ProbeForWrite(lpszFormatName, cchMaxCount * sizeof(WCHAR), 1); 758 759 iRet = IntGetAtomName((RTL_ATOM)fmt, 760 lpszFormatName, 761 cchMaxCount * sizeof(WCHAR)); 762 iRet /= sizeof(WCHAR); 763 } 764 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 765 { 766 SetLastNtError(_SEH2_GetExceptionCode()); 767 } 768 _SEH2_END; 769 770 cleanup: 771 UserLeave(); 772 773 return iRet; 774 } 775 776 HWND APIENTRY 777 NtUserGetClipboardOwner(VOID) 778 { 779 HWND hWnd = NULL; 780 PWINSTATION_OBJECT pWinStaObj; 781 782 UserEnterShared(); 783 784 pWinStaObj = IntGetWinStaForCbAccess(); 785 if (!pWinStaObj) 786 goto cleanup; 787 788 if (pWinStaObj->spwndClipOwner) 789 hWnd = UserHMGetHandle(pWinStaObj->spwndClipOwner); 790 791 ObDereferenceObject(pWinStaObj); 792 793 cleanup: 794 UserLeave(); 795 796 return hWnd; 797 } 798 799 HWND APIENTRY 800 NtUserGetClipboardViewer(VOID) 801 { 802 HWND hWnd = NULL; 803 PWINSTATION_OBJECT pWinStaObj; 804 805 UserEnterShared(); 806 807 pWinStaObj = IntGetWinStaForCbAccess(); 808 if (!pWinStaObj) 809 goto cleanup; 810 811 if (pWinStaObj->spwndClipViewer) 812 hWnd = UserHMGetHandle(pWinStaObj->spwndClipViewer); 813 814 ObDereferenceObject(pWinStaObj); 815 816 cleanup: 817 UserLeave(); 818 819 return hWnd; 820 } 821 822 INT APIENTRY 823 NtUserGetPriorityClipboardFormat(UINT *paFormatPriorityList, INT cFormats) 824 { 825 INT i, iRet = 0; 826 PWINSTATION_OBJECT pWinStaObj; 827 828 UserEnterShared(); 829 830 pWinStaObj = IntGetWinStaForCbAccess(); 831 if (!pWinStaObj) 832 goto cleanup; 833 834 if (pWinStaObj->pClipBase == NULL) 835 { 836 iRet = 0; 837 } 838 else 839 { 840 _SEH2_TRY 841 { 842 ProbeForRead(paFormatPriorityList, cFormats * sizeof(UINT), sizeof(UINT)); 843 844 iRet = -1; 845 846 for (i = 0; i < cFormats; ++i) 847 { 848 if (IntIsFormatAvailable(pWinStaObj, paFormatPriorityList[i])) 849 { 850 iRet = paFormatPriorityList[i]; 851 break; 852 } 853 } 854 } 855 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 856 { 857 SetLastNtError(_SEH2_GetExceptionCode()); 858 } 859 _SEH2_END; 860 } 861 862 ObDereferenceObject(pWinStaObj); 863 864 cleanup: 865 UserLeave(); 866 867 return iRet; 868 869 } 870 871 BOOL APIENTRY 872 NtUserIsClipboardFormatAvailable(UINT fmt) 873 { 874 BOOL bRet = FALSE; 875 PWINSTATION_OBJECT pWinStaObj; 876 877 TRACE("NtUserIsClipboardFormatAvailable(%x)\n", fmt); 878 879 UserEnterShared(); 880 881 pWinStaObj = IntGetWinStaForCbAccess(); 882 if (!pWinStaObj) 883 goto cleanup; 884 885 if (IntIsFormatAvailable(pWinStaObj, fmt)) 886 bRet = TRUE; 887 888 ObDereferenceObject(pWinStaObj); 889 890 cleanup: 891 UserLeave(); 892 893 return bRet; 894 } 895 896 HANDLE APIENTRY 897 NtUserGetClipboardData(UINT fmt, PGETCLIPBDATA pgcd) 898 { 899 HANDLE hRet = NULL; 900 PCLIP pElement; 901 PWINSTATION_OBJECT pWinStaObj; 902 UINT uSourceFmt = fmt; 903 904 TRACE("NtUserGetClipboardData(%x, %p)\n", fmt, pgcd); 905 906 UserEnterShared(); 907 908 pWinStaObj = IntGetWinStaForCbAccess(); 909 if (!pWinStaObj) 910 goto cleanup; 911 912 /* Check if the clipboard has been opened */ 913 if (!IntIsClipboardOpenByMe(pWinStaObj)) 914 { 915 EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN); 916 goto cleanup; 917 } 918 919 pElement = IntGetFormatElement(pWinStaObj, fmt); 920 if (!pElement) 921 goto cleanup; 922 923 if (IS_DATA_SYNTHESIZED(pElement)) 924 { 925 /* Note: Data is synthesized in usermode */ 926 /* TODO: Add more formats */ 927 switch (fmt) 928 { 929 case CF_UNICODETEXT: 930 case CF_TEXT: 931 case CF_OEMTEXT: 932 uSourceFmt = CF_UNICODETEXT; 933 pElement = IntGetFormatElement(pWinStaObj, uSourceFmt); 934 if (IS_DATA_SYNTHESIZED(pElement)) 935 { 936 uSourceFmt = CF_TEXT; 937 pElement = IntGetFormatElement(pWinStaObj, uSourceFmt); 938 } 939 if (IS_DATA_SYNTHESIZED(pElement)) 940 { 941 uSourceFmt = CF_OEMTEXT; 942 pElement = IntGetFormatElement(pWinStaObj, uSourceFmt); 943 } 944 break; 945 946 case CF_BITMAP: 947 IntSynthesizeBitmap(pWinStaObj, pElement); 948 break; 949 950 case CF_METAFILEPICT: 951 uSourceFmt = CF_ENHMETAFILE; 952 pElement = IntGetFormatElement(pWinStaObj, uSourceFmt); 953 break; 954 955 case CF_ENHMETAFILE: 956 uSourceFmt = CF_METAFILEPICT; 957 pElement = IntGetFormatElement(pWinStaObj, uSourceFmt); 958 break; 959 960 default: 961 ASSERT(FALSE); 962 } 963 } 964 965 if (pElement && IS_DATA_DELAYED(pElement) && pWinStaObj->spwndClipOwner) 966 { 967 /* Send WM_RENDERFORMAT message */ 968 pWinStaObj->fInDelayedRendering = TRUE; 969 co_IntSendMessage(UserHMGetHandle(pWinStaObj->spwndClipOwner), WM_RENDERFORMAT, (WPARAM)uSourceFmt, 0); 970 pWinStaObj->fInDelayedRendering = FALSE; 971 972 /* Data should be in clipboard now */ 973 pElement = IntGetFormatElement(pWinStaObj, uSourceFmt); 974 } 975 976 if (!pElement || IS_DATA_DELAYED(pElement)) 977 goto cleanup; 978 979 _SEH2_TRY 980 { 981 ProbeForWrite(pgcd, sizeof(*pgcd), 1); 982 pgcd->uFmtRet = pElement->fmt; 983 pgcd->fGlobalHandle = pElement->fGlobalHandle; 984 985 /* Text and bitmap needs more data */ 986 if (fmt == CF_TEXT) 987 { 988 PCLIP pLocaleEl; 989 990 pLocaleEl = IntGetFormatElement(pWinStaObj, CF_LOCALE); 991 if (pLocaleEl && !IS_DATA_DELAYED(pLocaleEl)) 992 pgcd->hLocale = pLocaleEl->hData; 993 } 994 else if (fmt == CF_BITMAP) 995 { 996 PCLIP pPaletteEl; 997 998 pPaletteEl = IntGetFormatElement(pWinStaObj, CF_PALETTE); 999 if (pPaletteEl && !IS_DATA_DELAYED(pPaletteEl)) 1000 pgcd->hPalette = pPaletteEl->hData; 1001 } 1002 1003 hRet = pElement->hData; 1004 } 1005 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1006 { 1007 SetLastNtError(_SEH2_GetExceptionCode()); 1008 } 1009 _SEH2_END; 1010 1011 cleanup: 1012 if (pWinStaObj) 1013 ObDereferenceObject(pWinStaObj); 1014 1015 UserLeave(); 1016 1017 TRACE("NtUserGetClipboardData returns %p\n", hRet); 1018 1019 return hRet; 1020 } 1021 1022 HANDLE NTAPI 1023 UserSetClipboardData(UINT fmt, HANDLE hData, PSETCLIPBDATA scd) 1024 { 1025 HANDLE hRet = NULL; 1026 PWINSTATION_OBJECT pWinStaObj; 1027 1028 pWinStaObj = IntGetWinStaForCbAccess(); 1029 if (!pWinStaObj) 1030 goto cleanup; 1031 1032 if (!fmt || !pWinStaObj->ptiClipLock) 1033 { 1034 ERR("Access denied!\n"); 1035 EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN); 1036 goto cleanup; 1037 } 1038 1039 if (scd->fIncSerialNumber) 1040 pWinStaObj->iClipSerialNumber++; 1041 1042 /* Is it a delayed rendering? */ 1043 if (hData) 1044 { 1045 /* Is it a bitmap? */ 1046 if (fmt == CF_BITMAP) 1047 { 1048 /* Make bitmap public */ 1049 GreSetObjectOwner(hData, GDI_OBJ_HMGR_PUBLIC); 1050 } 1051 1052 /* Save data in the clipboard */ 1053 IntAddFormatedData(pWinStaObj, fmt, hData, scd->fGlobalHandle, FALSE); 1054 TRACE("hData stored\n"); 1055 1056 /* If the serial number was increased, increase also the sequence number */ 1057 if (scd->fIncSerialNumber) 1058 pWinStaObj->iClipSequenceNumber++; 1059 1060 pWinStaObj->fClipboardChanged = TRUE; 1061 1062 /* Note: Synthesized formats are added in NtUserCloseClipboard */ 1063 } 1064 else 1065 { 1066 /* This is a delayed rendering */ 1067 IntAddFormatedData(pWinStaObj, fmt, DATA_DELAYED, FALSE, FALSE); 1068 TRACE("SetClipboardData delayed format: %u\n", fmt); 1069 } 1070 1071 /* Return hData on success */ 1072 hRet = hData; 1073 1074 cleanup: 1075 TRACE("NtUserSetClipboardData returns: %p\n", hRet); 1076 1077 if (pWinStaObj) 1078 ObDereferenceObject(pWinStaObj); 1079 1080 return hRet; 1081 } 1082 1083 HANDLE APIENTRY 1084 NtUserSetClipboardData(UINT fmt, HANDLE hData, PSETCLIPBDATA pUnsafeScd) 1085 { 1086 SETCLIPBDATA scd; 1087 HANDLE hRet; 1088 1089 TRACE("NtUserSetClipboardData(%x %p %p)\n", fmt, hData, pUnsafeScd); 1090 1091 _SEH2_TRY 1092 { 1093 ProbeForRead(pUnsafeScd, sizeof(*pUnsafeScd), 1); 1094 RtlCopyMemory(&scd, pUnsafeScd, sizeof(scd)); 1095 } 1096 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1097 { 1098 SetLastNtError(_SEH2_GetExceptionCode()); 1099 _SEH2_YIELD(return NULL;) 1100 } 1101 _SEH2_END 1102 1103 UserEnterExclusive(); 1104 1105 /* Call internal function */ 1106 hRet = UserSetClipboardData(fmt, hData, &scd); 1107 1108 UserLeave(); 1109 1110 return hRet; 1111 } 1112 1113 HWND APIENTRY 1114 NtUserSetClipboardViewer(HWND hWndNewViewer) 1115 { 1116 HWND hWndNext = NULL; 1117 PWINSTATION_OBJECT pWinStaObj; 1118 PWND pWindow; 1119 1120 UserEnterExclusive(); 1121 1122 pWinStaObj = IntGetWinStaForCbAccess(); 1123 if (!pWinStaObj) 1124 goto cleanup; 1125 1126 pWindow = UserGetWindowObject(hWndNewViewer); 1127 if (!pWindow) 1128 { 1129 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE); 1130 goto cleanup; 1131 } 1132 1133 /* Return previous viewer. New viever window should 1134 send messages to rest of the chain */ 1135 if (pWinStaObj->spwndClipViewer) 1136 hWndNext = UserHMGetHandle(pWinStaObj->spwndClipViewer); 1137 1138 /* Set new viewer window */ 1139 pWinStaObj->spwndClipViewer = pWindow; 1140 1141 /* Notify viewer windows in chain */ 1142 pWinStaObj->fClipboardChanged = FALSE; 1143 if (pWinStaObj->spwndClipViewer) 1144 { 1145 TRACE("Clipboard: sending WM_DRAWCLIPBOARD to %p\n", UserHMGetHandle(pWinStaObj->spwndClipViewer)); 1146 // For 32-bit applications this message is sent as a notification 1147 co_IntSendMessageNoWait(UserHMGetHandle(pWinStaObj->spwndClipViewer), WM_DRAWCLIPBOARD, 0, 0); 1148 } 1149 1150 cleanup: 1151 if (pWinStaObj) 1152 ObDereferenceObject(pWinStaObj); 1153 1154 UserLeave(); 1155 1156 return hWndNext; 1157 } 1158 1159 // Sequence number is incremented whenever the contents of the clipboard change 1160 // or the clipboard is emptied. If clipboard rendering is delayed, 1161 // the sequence number is not incremented until the changes are rendered. 1162 1163 DWORD APIENTRY 1164 NtUserGetClipboardSequenceNumber(VOID) 1165 { 1166 DWORD dwRet = 0; 1167 PWINSTATION_OBJECT pWinStaObj; 1168 1169 UserEnterShared(); 1170 1171 pWinStaObj = IntGetWinStaForCbAccess(); 1172 if (!pWinStaObj) 1173 goto cleanup; 1174 1175 /* Get windowstation sequence number */ 1176 dwRet = (DWORD)pWinStaObj->iClipSequenceNumber; 1177 1178 ObDereferenceObject(pWinStaObj); 1179 1180 cleanup: 1181 UserLeave(); 1182 1183 return dwRet; 1184 } 1185 1186 HANDLE APIENTRY 1187 NtUserConvertMemHandle( 1188 PVOID pData, 1189 DWORD cbData) 1190 { 1191 HANDLE hMem = NULL; 1192 PCLIPBOARDDATA pMemObj; 1193 1194 UserEnterExclusive(); 1195 1196 /* Create Clipboard data object */ 1197 pMemObj = UserCreateObject(gHandleTable, NULL, NULL, &hMem, TYPE_CLIPDATA, sizeof(CLIPBOARDDATA) + cbData); 1198 if (!pMemObj) 1199 goto cleanup; 1200 1201 pMemObj->cbData = cbData; 1202 1203 /* Copy data */ 1204 _SEH2_TRY 1205 { 1206 ProbeForRead(pData, cbData, 1); 1207 memcpy(pMemObj->Data, pData, cbData); 1208 } 1209 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1210 { 1211 pMemObj = NULL; 1212 } 1213 _SEH2_END; 1214 1215 /* Release the extra reference (UserCreateObject added 2 references) */ 1216 UserDereferenceObject(pMemObj); 1217 1218 /* If we failed to copy data, remove handle */ 1219 if (!pMemObj) 1220 { 1221 UserDeleteObject(hMem, TYPE_CLIPDATA); 1222 hMem = NULL; 1223 } 1224 1225 cleanup: 1226 UserLeave(); 1227 1228 return hMem; 1229 } 1230 1231 NTSTATUS APIENTRY 1232 NtUserCreateLocalMemHandle( 1233 HANDLE hMem, 1234 PVOID pData, 1235 DWORD cbData, 1236 DWORD *pcbData) 1237 { 1238 PCLIPBOARDDATA pMemObj; 1239 NTSTATUS Status = STATUS_SUCCESS; 1240 1241 UserEnterShared(); 1242 1243 /* Get Clipboard data object */ 1244 pMemObj = (PCLIPBOARDDATA)UserGetObject(gHandleTable, hMem, TYPE_CLIPDATA); 1245 if (!pMemObj) 1246 { 1247 Status = STATUS_INVALID_HANDLE; 1248 goto cleanup; 1249 } 1250 1251 /* Don't overrun */ 1252 if (cbData > pMemObj->cbData) 1253 cbData = pMemObj->cbData; 1254 1255 /* Copy data to usermode */ 1256 _SEH2_TRY 1257 { 1258 if (pcbData) 1259 { 1260 ProbeForWrite(pcbData, sizeof(*pcbData), 1); 1261 *pcbData = pMemObj->cbData; 1262 } 1263 1264 ProbeForWrite(pData, cbData, 1); 1265 memcpy(pData, pMemObj->Data, cbData); 1266 } 1267 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1268 { 1269 Status = _SEH2_GetExceptionCode(); 1270 } 1271 _SEH2_END; 1272 1273 cleanup: 1274 UserLeave(); 1275 1276 return Status; 1277 } 1278 1279 /* EOF */ 1280