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>
12 DBG_DEFAULT_CHANNEL(UserClipbrd
);
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)
20 static PWINSTATION_OBJECT FASTCALL
21 IntGetWinStaForCbAccess(VOID
)
24 PWINSTATION_OBJECT pWinStaObj
;
27 hWinSta
= UserGetProcessWindowStation();
28 Status
= IntValidateWindowStationHandle(hWinSta
, UserMode
, WINSTA_ACCESSCLIPBOARD
, &pWinStaObj
, 0);
29 if (!NT_SUCCESS(Status
))
31 ERR("Cannot open winsta\n");
32 SetLastNtError(Status
);
39 /* If format exists, returns a non-null value (pointing to formated object) */
41 IntGetFormatElement(PWINSTATION_OBJECT pWinStaObj
, UINT fmt
)
45 for (i
= 0; i
< pWinStaObj
->cNumClipFormats
; ++i
)
47 if (pWinStaObj
->pClipBase
[i
].fmt
== fmt
)
48 return &pWinStaObj
->pClipBase
[i
];
55 IntIsFormatAvailable(PWINSTATION_OBJECT pWinStaObj
, UINT fmt
)
57 return IntGetFormatElement(pWinStaObj
, fmt
) != NULL
;
61 IntFreeElementData(PCLIP pElement
)
63 if (!IS_DATA_DELAYED(pElement
) &&
64 !IS_DATA_SYNTHESIZED(pElement
))
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
)
71 GreSetObjectOwner(pElement
->hData
, GDI_OBJ_HMGR_POWNED
);
72 GreDeleteObject(pElement
->hData
);
77 /* Adds a new format and data to the clipboard */
79 IntAddFormatedData(PWINSTATION_OBJECT pWinStaObj
, UINT fmt
, HANDLE hData
, BOOLEAN fGlobalHandle
, BOOL bEnd
)
81 PCLIP pElement
= NULL
;
83 /* Use existing entry with specified format */
85 pElement
= IntGetFormatElement(pWinStaObj
, fmt
);
87 /* Put new entry at the end if nothing was found */
90 /* Allocate bigger clipboard if needed. We could use lists but Windows uses array */
91 if (pWinStaObj
->cNumClipFormats
% 4 == 0)
95 /* Allocate new clipboard */
96 pNewClip
= ExAllocatePoolWithTag(PagedPool
,
97 (pWinStaObj
->cNumClipFormats
+ 4) * sizeof(CLIP
),
101 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
106 memcpy(pNewClip
, pWinStaObj
->pClipBase
, pWinStaObj
->cNumClipFormats
* sizeof(CLIP
));
108 /* Free old clipboard */
109 if (pWinStaObj
->pClipBase
)
110 ExFreePoolWithTag(pWinStaObj
->pClipBase
, USERTAG_CLIPBOARD
);
113 pWinStaObj
->pClipBase
= pNewClip
;
116 /* New element is at the end */
117 pElement
= &pWinStaObj
->pClipBase
[pWinStaObj
->cNumClipFormats
];
119 pWinStaObj
->cNumClipFormats
++;
122 IntFreeElementData(pElement
);
124 pElement
->hData
= hData
;
125 pElement
->fGlobalHandle
= fGlobalHandle
;
131 IntIsClipboardOpenByMe(PWINSTATION_OBJECT pWinSta
)
133 /* Check if the current thread has opened the clipboard */
134 return (pWinSta
->ptiClipLock
&&
135 pWinSta
->ptiClipLock
== PsGetCurrentThreadWin32Thread());
140 PWINSTATION_OBJECT pWinStaObj
,
144 ULONG cjInfoSize
, cjDataSize
;
145 PCLIPBOARDDATA pClipboardData
;
150 BITMAPINFOHEADER bmih
;
151 RGBQUAD rgbColors
[256];
153 PBITMAPINFO pbmi
= (PBITMAPINFO
)&bmiBuffer
;
155 /* Get the display DC */
156 hdc
= UserGetDCEx(NULL
, NULL
, DCX_USESTYLE
);
162 /* Get information about the bitmap format */
163 pbmi
->bmiHeader
.biSize
= sizeof(bmiBuffer
.bmih
);
164 iResult
= GreGetDIBitsInternal(hdc
,
178 /* Get the size for a full BITMAPINFO */
179 cjInfoSize
= DIB_BitmapInfoSize(pbmi
, DIB_RGB_COLORS
);
181 /* Calculate the size of the clipboard data, which is a packed DIB */
182 cjDataSize
= cjInfoSize
+ pbmi
->bmiHeader
.biSizeImage
;
184 /* Create the clipboard data */
185 pClipboardData
= (PCLIPBOARDDATA
)UserCreateObject(gHandleTable
,
190 sizeof(CLIPBOARDDATA
) + cjDataSize
);
196 /* Set the data size */
197 pClipboardData
->cbData
= cjDataSize
;
199 /* Copy the BITMAPINFOHEADER */
200 memcpy(pClipboardData
->Data
, pbmi
, sizeof(BITMAPINFOHEADER
));
202 /* Get the bitmap bits and the color table */
203 iResult
= GreGetDIBitsInternal(hdc
,
206 abs(pbmi
->bmiHeader
.biHeight
),
207 (LPBYTE
)pClipboardData
->Data
+ cjInfoSize
,
208 (LPBITMAPINFO
)pClipboardData
->Data
,
210 pbmi
->bmiHeader
.biSizeImage
,
213 /* Add the clipboard data */
214 IntAddFormatedData(pWinStaObj
, CF_DIB
, hMem
, TRUE
, TRUE
);
216 /* Release the extra reference (UserCreateObject added 2 references) */
217 UserDereferenceObject(pClipboardData
);
220 UserReleaseDC(NULL
, hdc
, FALSE
);
224 IntSynthesizeBitmap(PWINSTATION_OBJECT pWinStaObj
, PCLIP pBmEl
)
227 PBITMAPINFO pBmi
, pConvertedBmi
= NULL
;
229 PCLIPBOARDDATA pMemObj
;
233 TRACE("IntSynthesizeBitmap(%p, %p)\n", pWinStaObj
, pBmEl
);
235 pDibEl
= IntGetFormatElement(pWinStaObj
, CF_DIB
);
236 ASSERT(pDibEl
&& !IS_DATA_SYNTHESIZED(pDibEl
));
237 if (!pDibEl
->fGlobalHandle
)
240 pMemObj
= (PCLIPBOARDDATA
)UserGetObject(gHandleTable
, pDibEl
->hData
, TYPE_CLIPDATA
);
244 pBmi
= (BITMAPINFO
*)pMemObj
->Data
;
246 if (pMemObj
->cbData
< sizeof(DWORD
) && pMemObj
->cbData
< pBmi
->bmiHeader
.biSize
)
249 pConvertedBmi
= DIB_ConvertBitmapInfo(pBmi
, DIB_RGB_COLORS
);
253 Offset
= DIB_BitmapInfoSize(pBmi
, DIB_RGB_COLORS
);
255 hdc
= UserGetDCEx(NULL
, NULL
, DCX_USESTYLE
);
259 hBm
= GreCreateDIBitmapInternal(hdc
,
260 pConvertedBmi
->bmiHeader
.biWidth
,
261 pConvertedBmi
->bmiHeader
.biHeight
,
263 pMemObj
->Data
+ Offset
,
267 pMemObj
->cbData
- Offset
,
272 GreSetObjectOwner(hBm
, GDI_OBJ_HMGR_PUBLIC
);
278 UserReleaseDC(NULL
, hdc
, FALSE
);
281 DIB_FreeConvertedBitmapInfo(pConvertedBmi
, pBmi
, -1);
285 IntAddSynthesizedFormats(PWINSTATION_OBJECT pWinStaObj
)
287 BOOL bHaveText
, bHaveUniText
, bHaveOemText
, bHaveLocale
, bHaveBm
, bHaveDib
;
289 bHaveText
= IntIsFormatAvailable(pWinStaObj
, CF_TEXT
);
290 bHaveOemText
= IntIsFormatAvailable(pWinStaObj
, CF_OEMTEXT
);
291 bHaveUniText
= IntIsFormatAvailable(pWinStaObj
, CF_UNICODETEXT
);
292 bHaveLocale
= IntIsFormatAvailable(pWinStaObj
, CF_LOCALE
);
293 bHaveBm
= IntIsFormatAvailable(pWinStaObj
, CF_BITMAP
);
294 bHaveDib
= IntIsFormatAvailable(pWinStaObj
, CF_DIB
);
296 /* Add CF_LOCALE format if we have CF_TEXT */
297 if (!bHaveLocale
&& bHaveText
)
299 PCLIPBOARDDATA pMemObj
;
302 pMemObj
= (PCLIPBOARDDATA
)UserCreateObject(gHandleTable
, NULL
, NULL
, &hMem
, TYPE_CLIPDATA
,
303 sizeof(CLIPBOARDDATA
) + sizeof(LCID
));
306 pMemObj
->cbData
= sizeof(LCID
);
307 *((LCID
*)pMemObj
->Data
) = NtCurrentTeb()->CurrentLocale
;
308 IntAddFormatedData(pWinStaObj
, CF_LOCALE
, hMem
, TRUE
, TRUE
);
310 /* Release the extra reference (UserCreateObject added 2 references) */
311 UserDereferenceObject(pMemObj
);
315 /* Add CF_TEXT. Note: it is synthesized in user32.dll */
316 if (!bHaveText
&& (bHaveUniText
|| bHaveOemText
))
317 IntAddFormatedData(pWinStaObj
, CF_TEXT
, DATA_SYNTH_USER
, FALSE
, TRUE
);
319 /* Add CF_OEMTEXT. Note: it is synthesized in user32.dll */
320 if (!bHaveOemText
&& (bHaveUniText
|| bHaveText
))
321 IntAddFormatedData(pWinStaObj
, CF_OEMTEXT
, DATA_SYNTH_USER
, FALSE
, TRUE
);
323 /* Add CF_UNICODETEXT. Note: it is synthesized in user32.dll */
324 if (!bHaveUniText
&& (bHaveText
|| bHaveOemText
))
325 IntAddFormatedData(pWinStaObj
, CF_UNICODETEXT
, DATA_SYNTH_USER
, FALSE
, TRUE
);
327 /* Add CF_BITMAP. Note: it is synthesized on demand */
328 if (!bHaveBm
&& bHaveDib
)
329 IntAddFormatedData(pWinStaObj
, CF_BITMAP
, DATA_SYNTH_KRNL
, FALSE
, TRUE
);
331 /* Note: We need to render the DIB or DIBV5 format as soon as possible
332 because pallette information may change */
333 if (!bHaveDib
&& bHaveBm
)
334 IntSynthesizeDib(pWinStaObj
, IntGetFormatElement(pWinStaObj
, CF_BITMAP
)->hData
);
338 UserEmptyClipboardData(PWINSTATION_OBJECT pWinSta
)
343 for (i
= 0; i
< pWinSta
->cNumClipFormats
; ++i
)
345 pElement
= &pWinSta
->pClipBase
[i
];
346 IntFreeElementData(pElement
);
349 if (pWinSta
->pClipBase
)
350 ExFreePoolWithTag(pWinSta
->pClipBase
, USERTAG_CLIPBOARD
);
352 pWinSta
->pClipBase
= NULL
;
353 pWinSta
->cNumClipFormats
= 0;
356 /* UserClipboardRelease is called from IntSendDestroyMsg in window.c */
358 UserClipboardRelease(PWND pWindow
)
360 PWINSTATION_OBJECT pWinStaObj
;
362 pWinStaObj
= IntGetWinStaForCbAccess();
366 co_IntSendMessage(pWinStaObj
->spwndClipOwner
->head
.h
, WM_RENDERALLFORMATS
, 0, 0);
368 /* If the window being destroyed is the current clipboard owner... */
369 if (pWindow
== pWinStaObj
->spwndClipOwner
)
371 /* ... make it release the clipboard */
372 pWinStaObj
->spwndClipOwner
= NULL
;
375 if (pWinStaObj
->fClipboardChanged
)
377 /* Add synthesized formats - they are rendered later */
378 IntAddSynthesizedFormats(pWinStaObj
);
380 /* Notify viewer windows in chain */
381 pWinStaObj
->fClipboardChanged
= FALSE
;
382 if (pWinStaObj
->spwndClipViewer
)
384 TRACE("Clipboard: sending WM_DRAWCLIPBOARD to %p\n", pWinStaObj
->spwndClipViewer
->head
.h
);
385 // For 32-bit applications this message is sent as a notification
386 co_IntSendMessageNoWait(pWinStaObj
->spwndClipViewer
->head
.h
, WM_DRAWCLIPBOARD
, 0, 0);
390 ObDereferenceObject(pWinStaObj
);
393 /* UserClipboardFreeWindow is called from co_UserFreeWindow in window.c */
395 UserClipboardFreeWindow(PWND pWindow
)
397 PWINSTATION_OBJECT pWinStaObj
;
399 pWinStaObj
= IntGetWinStaForCbAccess();
403 if (pWindow
== pWinStaObj
->spwndClipOwner
)
405 /* The owner window was destroyed */
406 pWinStaObj
->spwndClipOwner
= NULL
;
409 /* Check if clipboard is not locked by this window, if yes, unlock it */
410 if (pWindow
== pWinStaObj
->spwndClipOpen
)
412 /* The window that opens the clipboard was destroyed */
413 pWinStaObj
->spwndClipOpen
= NULL
;
414 pWinStaObj
->ptiClipLock
= NULL
;
416 /* Remove window from window chain */
417 if (pWindow
== pWinStaObj
->spwndClipViewer
)
418 pWinStaObj
->spwndClipViewer
= NULL
;
420 ObDereferenceObject(pWinStaObj
);
424 UserEnumClipboardFormats(UINT fmt
)
428 PWINSTATION_OBJECT pWinStaObj
;
430 pWinStaObj
= IntGetWinStaForCbAccess();
434 /* Check if the clipboard has been opened */
435 if (!IntIsClipboardOpenByMe(pWinStaObj
))
437 EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN
);
443 /* Return first format */
444 if (pWinStaObj
->pClipBase
)
445 Ret
= pWinStaObj
->pClipBase
[0].fmt
;
449 /* Return next format */
450 pElement
= IntGetFormatElement(pWinStaObj
, fmt
);
451 if (pElement
!= NULL
)
454 if (pElement
< &pWinStaObj
->pClipBase
[pWinStaObj
->cNumClipFormats
])
463 ObDereferenceObject(pWinStaObj
);
469 UserOpenClipboard(HWND hWnd
)
473 PWINSTATION_OBJECT pWinStaObj
= NULL
;
477 pWindow
= UserGetWindowObject(hWnd
);
482 pWinStaObj
= IntGetWinStaForCbAccess();
486 /* Check if we already opened the clipboard */
487 if ((pWindow
== pWinStaObj
->spwndClipOpen
) && IntIsClipboardOpenByMe(pWinStaObj
))
493 /* If the clipboard was already opened by somebody else, bail out */
494 if ((pWindow
!= pWinStaObj
->spwndClipOpen
) && pWinStaObj
->ptiClipLock
)
496 ERR("Access denied!\n");
497 EngSetLastError(ERROR_ACCESS_DENIED
);
501 /* Open the clipboard */
502 pWinStaObj
->spwndClipOpen
= pWindow
;
503 pWinStaObj
->ptiClipLock
= PsGetCurrentThreadWin32Thread();
508 ObDereferenceObject(pWinStaObj
);
514 NtUserOpenClipboard(HWND hWnd
, DWORD Unknown1
)
518 UserEnterExclusive();
519 bRet
= UserOpenClipboard(hWnd
);
526 UserCloseClipboard(VOID
)
529 PWINSTATION_OBJECT pWinStaObj
;
531 pWinStaObj
= IntGetWinStaForCbAccess();
535 /* Check if the clipboard has been opened */
536 if (!IntIsClipboardOpenByMe(pWinStaObj
))
538 EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN
);
542 /* Clipboard is no longer open */
543 pWinStaObj
->spwndClipOpen
= NULL
;
544 pWinStaObj
->ptiClipLock
= NULL
;
547 if (pWinStaObj
->fClipboardChanged
)
549 /* Add synthesized formats - they are rendered later */
550 IntAddSynthesizedFormats(pWinStaObj
);
552 /* Notify viewer windows in chain */
553 pWinStaObj
->fClipboardChanged
= FALSE
;
554 if (pWinStaObj
->spwndClipViewer
)
556 TRACE("Clipboard: sending WM_DRAWCLIPBOARD to %p\n", pWinStaObj
->spwndClipViewer
->head
.h
);
557 // For 32-bit applications this message is sent as a notification
558 co_IntSendMessageNoWait(pWinStaObj
->spwndClipViewer
->head
.h
, WM_DRAWCLIPBOARD
, 0, 0);
564 ObDereferenceObject(pWinStaObj
);
570 NtUserCloseClipboard(VOID
)
574 UserEnterExclusive();
575 bRet
= UserCloseClipboard();
582 NtUserGetOpenClipboardWindow(VOID
)
585 PWINSTATION_OBJECT pWinStaObj
;
589 pWinStaObj
= IntGetWinStaForCbAccess();
593 if (pWinStaObj
->spwndClipOpen
)
594 hWnd
= pWinStaObj
->spwndClipOpen
->head
.h
;
596 ObDereferenceObject(pWinStaObj
);
605 NtUserChangeClipboardChain(HWND hWndRemove
, HWND hWndNewNext
)
609 PWINSTATION_OBJECT pWinStaObj
;
611 TRACE("NtUserChangeClipboardChain(%p, %p)\n", hWndRemove
, hWndNewNext
);
613 UserEnterExclusive();
615 pWinStaObj
= IntGetWinStaForCbAccess();
619 pWindowRemove
= UserGetWindowObject(hWndRemove
);
621 if (pWindowRemove
&& pWinStaObj
->spwndClipViewer
)
623 if (pWindowRemove
== pWinStaObj
->spwndClipViewer
)
624 pWinStaObj
->spwndClipViewer
= UserGetWindowObject(hWndNewNext
);
626 if (pWinStaObj
->spwndClipViewer
)
627 bRet
= (BOOL
)co_IntSendMessage(pWinStaObj
->spwndClipViewer
->head
.h
, WM_CHANGECBCHAIN
, (WPARAM
)hWndRemove
, (LPARAM
)hWndNewNext
);
630 ObDereferenceObject(pWinStaObj
);
639 NtUserCountClipboardFormats(VOID
)
642 PWINSTATION_OBJECT pWinStaObj
;
646 pWinStaObj
= IntGetWinStaForCbAccess();
650 cFormats
= pWinStaObj
->cNumClipFormats
;
652 ObDereferenceObject(pWinStaObj
);
661 UserEmptyClipboard(VOID
)
664 PWINSTATION_OBJECT pWinStaObj
;
666 pWinStaObj
= IntGetWinStaForCbAccess();
670 /* Check if the clipboard has been opened */
671 if (!IntIsClipboardOpenByMe(pWinStaObj
))
673 EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN
);
677 UserEmptyClipboardData(pWinStaObj
);
679 if (pWinStaObj
->spwndClipOwner
)
681 TRACE("Clipboard: WM_DESTROYCLIPBOARD to %p\n", pWinStaObj
->spwndClipOwner
->head
.h
);
682 // For 32-bit applications this message is sent as a notification
683 co_IntSendMessage(pWinStaObj
->spwndClipOwner
->head
.h
, WM_DESTROYCLIPBOARD
, 0, 0);
686 pWinStaObj
->spwndClipOwner
= pWinStaObj
->spwndClipOpen
;
688 pWinStaObj
->iClipSerialNumber
++;
689 pWinStaObj
->iClipSequenceNumber
++;
690 pWinStaObj
->fClipboardChanged
= TRUE
;
691 pWinStaObj
->fInDelayedRendering
= FALSE
;
697 ObDereferenceObject(pWinStaObj
);
703 NtUserEmptyClipboard(VOID
)
707 TRACE("NtUserEmptyClipboard()\n");
709 UserEnterExclusive();
710 bRet
= UserEmptyClipboard();
717 NtUserGetClipboardFormatName(UINT fmt
, LPWSTR lpszFormatName
, INT cchMaxCount
)
723 /* If the format is built-in we fail */
724 if (fmt
< 0xc000 || fmt
> 0xffff)
726 /* Registetrated formats are >= 0xc000 */
730 if (cchMaxCount
< 1 || !lpszFormatName
)
732 EngSetLastError(ERROR_INVALID_PARAMETER
);
738 ProbeForWrite(lpszFormatName
, cchMaxCount
* sizeof(WCHAR
), 1);
740 iRet
= IntGetAtomName((RTL_ATOM
)fmt
,
742 cchMaxCount
* sizeof(WCHAR
));
743 iRet
/= sizeof(WCHAR
);
745 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
747 SetLastNtError(_SEH2_GetExceptionCode());
758 NtUserGetClipboardOwner(VOID
)
761 PWINSTATION_OBJECT pWinStaObj
;
765 pWinStaObj
= IntGetWinStaForCbAccess();
769 if (pWinStaObj
->spwndClipOwner
)
770 hWnd
= pWinStaObj
->spwndClipOwner
->head
.h
;
772 ObDereferenceObject(pWinStaObj
);
781 NtUserGetClipboardViewer(VOID
)
784 PWINSTATION_OBJECT pWinStaObj
;
788 pWinStaObj
= IntGetWinStaForCbAccess();
792 if (pWinStaObj
->spwndClipViewer
)
793 hWnd
= pWinStaObj
->spwndClipViewer
->head
.h
;
795 ObDereferenceObject(pWinStaObj
);
804 NtUserGetPriorityClipboardFormat(UINT
*paFormatPriorityList
, INT cFormats
)
807 PWINSTATION_OBJECT pWinStaObj
;
811 pWinStaObj
= IntGetWinStaForCbAccess();
815 if (pWinStaObj
->pClipBase
== NULL
)
823 ProbeForRead(paFormatPriorityList
, cFormats
* sizeof(UINT
), sizeof(UINT
));
827 for (i
= 0; i
< cFormats
; ++i
)
829 if (IntIsFormatAvailable(pWinStaObj
, paFormatPriorityList
[i
]))
831 iRet
= paFormatPriorityList
[i
];
836 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
838 SetLastNtError(_SEH2_GetExceptionCode());
843 ObDereferenceObject(pWinStaObj
);
853 NtUserIsClipboardFormatAvailable(UINT fmt
)
856 PWINSTATION_OBJECT pWinStaObj
;
858 TRACE("NtUserIsClipboardFormatAvailable(%x)\n", fmt
);
862 pWinStaObj
= IntGetWinStaForCbAccess();
866 if (IntIsFormatAvailable(pWinStaObj
, fmt
))
869 ObDereferenceObject(pWinStaObj
);
878 NtUserGetClipboardData(UINT fmt
, PGETCLIPBDATA pgcd
)
882 PWINSTATION_OBJECT pWinStaObj
;
884 TRACE("NtUserGetClipboardData(%x, %p)\n", fmt
, pgcd
);
888 pWinStaObj
= IntGetWinStaForCbAccess();
892 /* Check if the clipboard has been opened */
893 if (!IntIsClipboardOpenByMe(pWinStaObj
))
895 EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN
);
899 pElement
= IntGetFormatElement(pWinStaObj
, fmt
);
900 if (pElement
&& IS_DATA_DELAYED(pElement
) && pWinStaObj
->spwndClipOwner
)
902 /* Send WM_RENDERFORMAT message */
903 pWinStaObj
->fInDelayedRendering
= TRUE
;
904 co_IntSendMessage(pWinStaObj
->spwndClipOwner
->head
.h
, WM_RENDERFORMAT
, (WPARAM
)fmt
, 0);
905 pWinStaObj
->fInDelayedRendering
= FALSE
;
907 /* Data should be in clipboard now */
908 pElement
= IntGetFormatElement(pWinStaObj
, fmt
);
911 if (!pElement
|| IS_DATA_DELAYED(pElement
))
914 if (IS_DATA_SYNTHESIZED(pElement
))
916 /* Note: Data is synthesized in usermode */
917 /* TODO: Add more formats */
923 pElement
= IntGetFormatElement(pWinStaObj
, CF_UNICODETEXT
);
924 if (IS_DATA_SYNTHESIZED(pElement
))
925 pElement
= IntGetFormatElement(pWinStaObj
, CF_TEXT
);
926 if (IS_DATA_SYNTHESIZED(pElement
))
927 pElement
= IntGetFormatElement(pWinStaObj
, CF_OEMTEXT
);
930 IntSynthesizeBitmap(pWinStaObj
, pElement
);
939 ProbeForWrite(pgcd
, sizeof(*pgcd
), 1);
940 pgcd
->uFmtRet
= pElement
->fmt
;
941 pgcd
->fGlobalHandle
= pElement
->fGlobalHandle
;
943 /* Text and bitmap needs more data */
948 pLocaleEl
= IntGetFormatElement(pWinStaObj
, CF_LOCALE
);
949 if (pLocaleEl
&& !IS_DATA_DELAYED(pLocaleEl
))
950 pgcd
->hLocale
= pLocaleEl
->hData
;
952 else if (fmt
== CF_BITMAP
)
956 pPaletteEl
= IntGetFormatElement(pWinStaObj
, CF_PALETTE
);
957 if (pPaletteEl
&& !IS_DATA_DELAYED(pPaletteEl
))
958 pgcd
->hPalette
= pPaletteEl
->hData
;
961 hRet
= pElement
->hData
;
963 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
965 SetLastNtError(_SEH2_GetExceptionCode());
971 ObDereferenceObject(pWinStaObj
);
975 TRACE("NtUserGetClipboardData returns %p\n", hRet
);
981 UserSetClipboardData(UINT fmt
, HANDLE hData
, PSETCLIPBDATA scd
)
984 PWINSTATION_OBJECT pWinStaObj
;
986 pWinStaObj
= IntGetWinStaForCbAccess();
990 if (!fmt
|| !pWinStaObj
->ptiClipLock
)
992 ERR("Access denied!\n");
993 EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN
);
997 if (scd
->fIncSerialNumber
)
998 pWinStaObj
->iClipSerialNumber
++;
1000 /* Is it a delayed rendering? */
1003 /* Is it a bitmap? */
1004 if (fmt
== CF_BITMAP
)
1006 /* Make bitmap public */
1007 GreSetObjectOwner(hData
, GDI_OBJ_HMGR_PUBLIC
);
1010 /* Save data in the clipboard */
1011 IntAddFormatedData(pWinStaObj
, fmt
, hData
, scd
->fGlobalHandle
, FALSE
);
1012 TRACE("hData stored\n");
1014 /* If the serial number was increased, increase also the sequence number */
1015 if (scd
->fIncSerialNumber
)
1016 pWinStaObj
->iClipSequenceNumber
++;
1018 pWinStaObj
->fClipboardChanged
= TRUE
;
1020 /* Note: Synthesized formats are added in NtUserCloseClipboard */
1024 /* This is a delayed rendering */
1025 IntAddFormatedData(pWinStaObj
, fmt
, DATA_DELAYED
, FALSE
, FALSE
);
1026 TRACE("SetClipboardData delayed format: %u\n", fmt
);
1029 /* Return hData on success */
1033 TRACE("NtUserSetClipboardData returns: %p\n", hRet
);
1036 ObDereferenceObject(pWinStaObj
);
1042 NtUserSetClipboardData(UINT fmt
, HANDLE hData
, PSETCLIPBDATA pUnsafeScd
)
1047 TRACE("NtUserSetClipboardData(%x %p %p)\n", fmt
, hData
, pUnsafeScd
);
1051 ProbeForRead(pUnsafeScd
, sizeof(*pUnsafeScd
), 1);
1052 RtlCopyMemory(&scd
, pUnsafeScd
, sizeof(scd
));
1054 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1056 SetLastNtError(_SEH2_GetExceptionCode());
1057 _SEH2_YIELD(return NULL
;)
1061 UserEnterExclusive();
1063 /* Call internal function */
1064 hRet
= UserSetClipboardData(fmt
, hData
, &scd
);
1072 NtUserSetClipboardViewer(HWND hWndNewViewer
)
1074 HWND hWndNext
= NULL
;
1075 PWINSTATION_OBJECT pWinStaObj
;
1078 UserEnterExclusive();
1080 pWinStaObj
= IntGetWinStaForCbAccess();
1084 pWindow
= UserGetWindowObject(hWndNewViewer
);
1087 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
1091 /* Return previous viewer. New viever window should
1092 send messages to rest of the chain */
1093 if (pWinStaObj
->spwndClipViewer
)
1094 hWndNext
= pWinStaObj
->spwndClipViewer
->head
.h
;
1096 /* Set new viewer window */
1097 pWinStaObj
->spwndClipViewer
= pWindow
;
1099 /* Notify viewer windows in chain */
1100 pWinStaObj
->fClipboardChanged
= FALSE
;
1101 if (pWinStaObj
->spwndClipViewer
)
1103 TRACE("Clipboard: sending WM_DRAWCLIPBOARD to %p\n", pWinStaObj
->spwndClipViewer
->head
.h
);
1104 // For 32-bit applications this message is sent as a notification
1105 co_IntSendMessageNoWait(pWinStaObj
->spwndClipViewer
->head
.h
, WM_DRAWCLIPBOARD
, 0, 0);
1110 ObDereferenceObject(pWinStaObj
);
1117 // Sequence number is incremented whenever the contents of the clipboard change
1118 // or the clipboard is emptied. If clipboard rendering is delayed,
1119 // the sequence number is not incremented until the changes are rendered.
1122 NtUserGetClipboardSequenceNumber(VOID
)
1125 PWINSTATION_OBJECT pWinStaObj
;
1129 pWinStaObj
= IntGetWinStaForCbAccess();
1133 /* Get windowstation sequence number */
1134 dwRet
= (DWORD
)pWinStaObj
->iClipSequenceNumber
;
1136 ObDereferenceObject(pWinStaObj
);
1145 NtUserConvertMemHandle(
1150 PCLIPBOARDDATA pMemObj
;
1152 UserEnterExclusive();
1154 /* Create Clipboard data object */
1155 pMemObj
= UserCreateObject(gHandleTable
, NULL
, NULL
, &hMem
, TYPE_CLIPDATA
, sizeof(CLIPBOARDDATA
) + cbData
);
1159 pMemObj
->cbData
= cbData
;
1164 ProbeForRead(pData
, cbData
, 1);
1165 memcpy(pMemObj
->Data
, pData
, cbData
);
1167 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1173 /* Release the extra reference (UserCreateObject added 2 references) */
1174 UserDereferenceObject(pMemObj
);
1176 /* If we failed to copy data, remove handle */
1179 UserDeleteObject(hMem
, TYPE_CLIPDATA
);
1190 NtUserCreateLocalMemHandle(
1196 PCLIPBOARDDATA pMemObj
;
1197 NTSTATUS Status
= STATUS_SUCCESS
;
1201 /* Get Clipboard data object */
1202 pMemObj
= (PCLIPBOARDDATA
)UserGetObject(gHandleTable
, hMem
, TYPE_CLIPDATA
);
1205 Status
= STATUS_INVALID_HANDLE
;
1210 if (cbData
> pMemObj
->cbData
)
1211 cbData
= pMemObj
->cbData
;
1213 /* Copy data to usermode */
1218 ProbeForWrite(pcbData
, sizeof(*pcbData
), 1);
1219 *pcbData
= pMemObj
->cbData
;
1222 ProbeForWrite(pData
, cbData
, 1);
1223 memcpy(pData
, pMemObj
->Data
, cbData
);
1225 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1227 Status
= _SEH2_GetExceptionCode();