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 memset(&bmiBuffer
, 0, sizeof(bmiBuffer
));
164 pbmi
->bmiHeader
.biSize
= sizeof(bmiBuffer
.bmih
);
165 iResult
= GreGetDIBitsInternal(hdc
,
179 /* Get the size for a full BITMAPINFO */
180 cjInfoSize
= DIB_BitmapInfoSize(pbmi
, DIB_RGB_COLORS
);
182 /* Calculate the size of the clipboard data, which is a packed DIB */
183 cjDataSize
= cjInfoSize
+ pbmi
->bmiHeader
.biSizeImage
;
185 /* Create the clipboard data */
186 pClipboardData
= (PCLIPBOARDDATA
)UserCreateObject(gHandleTable
,
191 sizeof(CLIPBOARDDATA
) + cjDataSize
);
197 /* Set the data size */
198 pClipboardData
->cbData
= cjDataSize
;
200 /* Copy the BITMAPINFOHEADER */
201 memcpy(pClipboardData
->Data
, pbmi
, sizeof(BITMAPINFOHEADER
));
203 /* Get the bitmap bits and the color table */
204 iResult
= GreGetDIBitsInternal(hdc
,
207 abs(pbmi
->bmiHeader
.biHeight
),
208 (LPBYTE
)pClipboardData
->Data
+ cjInfoSize
,
209 (LPBITMAPINFO
)pClipboardData
->Data
,
211 pbmi
->bmiHeader
.biSizeImage
,
214 /* Add the clipboard data */
215 IntAddFormatedData(pWinStaObj
, CF_DIB
, hMem
, TRUE
, TRUE
);
217 /* Release the extra reference (UserCreateObject added 2 references) */
218 UserDereferenceObject(pClipboardData
);
221 UserReleaseDC(NULL
, hdc
, FALSE
);
225 IntSynthesizeBitmap(PWINSTATION_OBJECT pWinStaObj
, PCLIP pBmEl
)
228 PBITMAPINFO pBmi
, pConvertedBmi
= NULL
;
230 PCLIPBOARDDATA pMemObj
;
234 TRACE("IntSynthesizeBitmap(%p, %p)\n", pWinStaObj
, pBmEl
);
236 pDibEl
= IntGetFormatElement(pWinStaObj
, CF_DIB
);
237 ASSERT(pDibEl
&& !IS_DATA_SYNTHESIZED(pDibEl
));
238 if (!pDibEl
->fGlobalHandle
)
241 pMemObj
= (PCLIPBOARDDATA
)UserGetObject(gHandleTable
, pDibEl
->hData
, TYPE_CLIPDATA
);
245 pBmi
= (BITMAPINFO
*)pMemObj
->Data
;
247 if (pMemObj
->cbData
< sizeof(DWORD
) && pMemObj
->cbData
< pBmi
->bmiHeader
.biSize
)
250 pConvertedBmi
= DIB_ConvertBitmapInfo(pBmi
, DIB_RGB_COLORS
);
254 Offset
= DIB_BitmapInfoSize(pBmi
, DIB_RGB_COLORS
);
256 hdc
= UserGetDCEx(NULL
, NULL
, DCX_USESTYLE
);
260 hBm
= GreCreateDIBitmapInternal(hdc
,
261 pConvertedBmi
->bmiHeader
.biWidth
,
262 pConvertedBmi
->bmiHeader
.biHeight
,
264 pMemObj
->Data
+ Offset
,
268 pMemObj
->cbData
- Offset
,
273 GreSetObjectOwner(hBm
, GDI_OBJ_HMGR_PUBLIC
);
279 UserReleaseDC(NULL
, hdc
, FALSE
);
282 DIB_FreeConvertedBitmapInfo(pConvertedBmi
, pBmi
, -1);
286 IntAddSynthesizedFormats(PWINSTATION_OBJECT pWinStaObj
)
288 BOOL bHaveText
, bHaveUniText
, bHaveOemText
, bHaveLocale
, bHaveBm
, bHaveDib
;
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
);
297 /* Add CF_LOCALE format if we have CF_TEXT */
298 if (!bHaveLocale
&& bHaveText
)
300 PCLIPBOARDDATA pMemObj
;
303 pMemObj
= (PCLIPBOARDDATA
)UserCreateObject(gHandleTable
, NULL
, NULL
, &hMem
, TYPE_CLIPDATA
,
304 sizeof(CLIPBOARDDATA
) + sizeof(LCID
));
307 pMemObj
->cbData
= sizeof(LCID
);
308 *((LCID
*)pMemObj
->Data
) = NtCurrentTeb()->CurrentLocale
;
309 IntAddFormatedData(pWinStaObj
, CF_LOCALE
, hMem
, TRUE
, TRUE
);
311 /* Release the extra reference (UserCreateObject added 2 references) */
312 UserDereferenceObject(pMemObj
);
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
);
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
);
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
);
328 /* Add CF_BITMAP. Note: it is synthesized on demand */
329 if (!bHaveBm
&& bHaveDib
)
330 IntAddFormatedData(pWinStaObj
, CF_BITMAP
, DATA_SYNTH_KRNL
, FALSE
, TRUE
);
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
);
339 UserEmptyClipboardData(PWINSTATION_OBJECT pWinSta
)
344 for (i
= 0; i
< pWinSta
->cNumClipFormats
; ++i
)
346 pElement
= &pWinSta
->pClipBase
[i
];
347 IntFreeElementData(pElement
);
350 if (pWinSta
->pClipBase
)
351 ExFreePoolWithTag(pWinSta
->pClipBase
, USERTAG_CLIPBOARD
);
353 pWinSta
->pClipBase
= NULL
;
354 pWinSta
->cNumClipFormats
= 0;
357 /* UserClipboardRelease is called from IntSendDestroyMsg in window.c */
359 UserClipboardRelease(PWND pWindow
)
361 PWINSTATION_OBJECT pWinStaObj
;
363 pWinStaObj
= IntGetWinStaForCbAccess();
367 co_IntSendMessage(pWinStaObj
->spwndClipOwner
->head
.h
, WM_RENDERALLFORMATS
, 0, 0);
369 /* If the window being destroyed is the current clipboard owner... */
370 if (pWindow
== pWinStaObj
->spwndClipOwner
)
372 /* ... make it release the clipboard */
373 pWinStaObj
->spwndClipOwner
= NULL
;
376 if (pWinStaObj
->fClipboardChanged
)
378 /* Add synthesized formats - they are rendered later */
379 IntAddSynthesizedFormats(pWinStaObj
);
381 /* Notify viewer windows in chain */
382 pWinStaObj
->fClipboardChanged
= FALSE
;
383 if (pWinStaObj
->spwndClipViewer
)
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);
391 ObDereferenceObject(pWinStaObj
);
394 /* UserClipboardFreeWindow is called from co_UserFreeWindow in window.c */
396 UserClipboardFreeWindow(PWND pWindow
)
398 PWINSTATION_OBJECT pWinStaObj
;
400 pWinStaObj
= IntGetWinStaForCbAccess();
404 if (pWindow
== pWinStaObj
->spwndClipOwner
)
406 /* The owner window was destroyed */
407 pWinStaObj
->spwndClipOwner
= NULL
;
410 /* Check if clipboard is not locked by this window, if yes, unlock it */
411 if (pWindow
== pWinStaObj
->spwndClipOpen
)
413 /* The window that opens the clipboard was destroyed */
414 pWinStaObj
->spwndClipOpen
= NULL
;
415 pWinStaObj
->ptiClipLock
= NULL
;
417 /* Remove window from window chain */
418 if (pWindow
== pWinStaObj
->spwndClipViewer
)
419 pWinStaObj
->spwndClipViewer
= NULL
;
421 ObDereferenceObject(pWinStaObj
);
425 UserEnumClipboardFormats(UINT fmt
)
429 PWINSTATION_OBJECT pWinStaObj
;
431 pWinStaObj
= IntGetWinStaForCbAccess();
435 /* Check if the clipboard has been opened */
436 if (!IntIsClipboardOpenByMe(pWinStaObj
))
438 EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN
);
444 /* Return first format */
445 if (pWinStaObj
->pClipBase
)
446 Ret
= pWinStaObj
->pClipBase
[0].fmt
;
450 /* Return next format */
451 pElement
= IntGetFormatElement(pWinStaObj
, fmt
);
452 if (pElement
!= NULL
)
455 if (pElement
< &pWinStaObj
->pClipBase
[pWinStaObj
->cNumClipFormats
])
464 ObDereferenceObject(pWinStaObj
);
470 UserOpenClipboard(HWND hWnd
)
474 PWINSTATION_OBJECT pWinStaObj
= NULL
;
478 pWindow
= UserGetWindowObject(hWnd
);
483 pWinStaObj
= IntGetWinStaForCbAccess();
487 /* Check if we already opened the clipboard */
488 if ((pWindow
== pWinStaObj
->spwndClipOpen
) && IntIsClipboardOpenByMe(pWinStaObj
))
494 /* If the clipboard was already opened by somebody else, bail out */
495 if ((pWindow
!= pWinStaObj
->spwndClipOpen
) && pWinStaObj
->ptiClipLock
)
497 ERR("Access denied!\n");
498 EngSetLastError(ERROR_ACCESS_DENIED
);
502 /* Open the clipboard */
503 pWinStaObj
->spwndClipOpen
= pWindow
;
504 pWinStaObj
->ptiClipLock
= PsGetCurrentThreadWin32Thread();
509 ObDereferenceObject(pWinStaObj
);
515 NtUserOpenClipboard(HWND hWnd
, DWORD Unknown1
)
519 UserEnterExclusive();
520 bRet
= UserOpenClipboard(hWnd
);
527 UserCloseClipboard(VOID
)
530 PWINSTATION_OBJECT pWinStaObj
;
532 pWinStaObj
= IntGetWinStaForCbAccess();
536 /* Check if the clipboard has been opened */
537 if (!IntIsClipboardOpenByMe(pWinStaObj
))
539 EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN
);
543 /* Clipboard is no longer open */
544 pWinStaObj
->spwndClipOpen
= NULL
;
545 pWinStaObj
->ptiClipLock
= NULL
;
548 if (pWinStaObj
->fClipboardChanged
)
550 /* Add synthesized formats - they are rendered later */
551 IntAddSynthesizedFormats(pWinStaObj
);
553 /* Notify viewer windows in chain */
554 pWinStaObj
->fClipboardChanged
= FALSE
;
555 if (pWinStaObj
->spwndClipViewer
)
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);
565 ObDereferenceObject(pWinStaObj
);
571 NtUserCloseClipboard(VOID
)
575 UserEnterExclusive();
576 bRet
= UserCloseClipboard();
583 NtUserGetOpenClipboardWindow(VOID
)
586 PWINSTATION_OBJECT pWinStaObj
;
590 pWinStaObj
= IntGetWinStaForCbAccess();
594 if (pWinStaObj
->spwndClipOpen
)
595 hWnd
= pWinStaObj
->spwndClipOpen
->head
.h
;
597 ObDereferenceObject(pWinStaObj
);
606 NtUserChangeClipboardChain(HWND hWndRemove
, HWND hWndNewNext
)
610 PWINSTATION_OBJECT pWinStaObj
;
612 TRACE("NtUserChangeClipboardChain(%p, %p)\n", hWndRemove
, hWndNewNext
);
614 UserEnterExclusive();
616 pWinStaObj
= IntGetWinStaForCbAccess();
620 pWindowRemove
= UserGetWindowObject(hWndRemove
);
622 if (pWindowRemove
&& pWinStaObj
->spwndClipViewer
)
624 if (pWindowRemove
== pWinStaObj
->spwndClipViewer
)
625 pWinStaObj
->spwndClipViewer
= UserGetWindowObject(hWndNewNext
);
627 if (pWinStaObj
->spwndClipViewer
)
628 bRet
= (BOOL
)co_IntSendMessage(pWinStaObj
->spwndClipViewer
->head
.h
, WM_CHANGECBCHAIN
, (WPARAM
)hWndRemove
, (LPARAM
)hWndNewNext
);
631 ObDereferenceObject(pWinStaObj
);
640 NtUserCountClipboardFormats(VOID
)
643 PWINSTATION_OBJECT pWinStaObj
;
647 pWinStaObj
= IntGetWinStaForCbAccess();
651 cFormats
= pWinStaObj
->cNumClipFormats
;
653 ObDereferenceObject(pWinStaObj
);
662 UserEmptyClipboard(VOID
)
665 PWINSTATION_OBJECT pWinStaObj
;
667 pWinStaObj
= IntGetWinStaForCbAccess();
671 /* Check if the clipboard has been opened */
672 if (!IntIsClipboardOpenByMe(pWinStaObj
))
674 EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN
);
678 UserEmptyClipboardData(pWinStaObj
);
680 if (pWinStaObj
->spwndClipOwner
)
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);
687 pWinStaObj
->spwndClipOwner
= pWinStaObj
->spwndClipOpen
;
689 pWinStaObj
->iClipSerialNumber
++;
690 pWinStaObj
->iClipSequenceNumber
++;
691 pWinStaObj
->fClipboardChanged
= TRUE
;
692 pWinStaObj
->fInDelayedRendering
= FALSE
;
698 ObDereferenceObject(pWinStaObj
);
704 NtUserEmptyClipboard(VOID
)
708 TRACE("NtUserEmptyClipboard()\n");
710 UserEnterExclusive();
711 bRet
= UserEmptyClipboard();
718 NtUserGetClipboardFormatName(UINT fmt
, LPWSTR lpszFormatName
, INT cchMaxCount
)
724 /* If the format is built-in we fail */
725 if (fmt
< 0xc000 || fmt
> 0xffff)
727 /* Registetrated formats are >= 0xc000 */
731 if (cchMaxCount
< 1 || !lpszFormatName
)
733 EngSetLastError(ERROR_INVALID_PARAMETER
);
739 ProbeForWrite(lpszFormatName
, cchMaxCount
* sizeof(WCHAR
), 1);
741 iRet
= IntGetAtomName((RTL_ATOM
)fmt
,
743 cchMaxCount
* sizeof(WCHAR
));
744 iRet
/= sizeof(WCHAR
);
746 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
748 SetLastNtError(_SEH2_GetExceptionCode());
759 NtUserGetClipboardOwner(VOID
)
762 PWINSTATION_OBJECT pWinStaObj
;
766 pWinStaObj
= IntGetWinStaForCbAccess();
770 if (pWinStaObj
->spwndClipOwner
)
771 hWnd
= pWinStaObj
->spwndClipOwner
->head
.h
;
773 ObDereferenceObject(pWinStaObj
);
782 NtUserGetClipboardViewer(VOID
)
785 PWINSTATION_OBJECT pWinStaObj
;
789 pWinStaObj
= IntGetWinStaForCbAccess();
793 if (pWinStaObj
->spwndClipViewer
)
794 hWnd
= pWinStaObj
->spwndClipViewer
->head
.h
;
796 ObDereferenceObject(pWinStaObj
);
805 NtUserGetPriorityClipboardFormat(UINT
*paFormatPriorityList
, INT cFormats
)
808 PWINSTATION_OBJECT pWinStaObj
;
812 pWinStaObj
= IntGetWinStaForCbAccess();
816 if (pWinStaObj
->pClipBase
== NULL
)
824 ProbeForRead(paFormatPriorityList
, cFormats
* sizeof(UINT
), sizeof(UINT
));
828 for (i
= 0; i
< cFormats
; ++i
)
830 if (IntIsFormatAvailable(pWinStaObj
, paFormatPriorityList
[i
]))
832 iRet
= paFormatPriorityList
[i
];
837 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
839 SetLastNtError(_SEH2_GetExceptionCode());
844 ObDereferenceObject(pWinStaObj
);
854 NtUserIsClipboardFormatAvailable(UINT fmt
)
857 PWINSTATION_OBJECT pWinStaObj
;
859 TRACE("NtUserIsClipboardFormatAvailable(%x)\n", fmt
);
863 pWinStaObj
= IntGetWinStaForCbAccess();
867 if (IntIsFormatAvailable(pWinStaObj
, fmt
))
870 ObDereferenceObject(pWinStaObj
);
879 NtUserGetClipboardData(UINT fmt
, PGETCLIPBDATA pgcd
)
883 PWINSTATION_OBJECT pWinStaObj
;
885 TRACE("NtUserGetClipboardData(%x, %p)\n", fmt
, pgcd
);
889 pWinStaObj
= IntGetWinStaForCbAccess();
893 /* Check if the clipboard has been opened */
894 if (!IntIsClipboardOpenByMe(pWinStaObj
))
896 EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN
);
900 pElement
= IntGetFormatElement(pWinStaObj
, fmt
);
901 if (pElement
&& IS_DATA_DELAYED(pElement
) && pWinStaObj
->spwndClipOwner
)
903 /* Send WM_RENDERFORMAT message */
904 pWinStaObj
->fInDelayedRendering
= TRUE
;
905 co_IntSendMessage(pWinStaObj
->spwndClipOwner
->head
.h
, WM_RENDERFORMAT
, (WPARAM
)fmt
, 0);
906 pWinStaObj
->fInDelayedRendering
= FALSE
;
908 /* Data should be in clipboard now */
909 pElement
= IntGetFormatElement(pWinStaObj
, fmt
);
912 if (!pElement
|| IS_DATA_DELAYED(pElement
))
915 if (IS_DATA_SYNTHESIZED(pElement
))
917 /* Note: Data is synthesized in usermode */
918 /* TODO: Add more formats */
924 pElement
= IntGetFormatElement(pWinStaObj
, CF_UNICODETEXT
);
925 if (IS_DATA_SYNTHESIZED(pElement
))
926 pElement
= IntGetFormatElement(pWinStaObj
, CF_TEXT
);
927 if (IS_DATA_SYNTHESIZED(pElement
))
928 pElement
= IntGetFormatElement(pWinStaObj
, CF_OEMTEXT
);
931 IntSynthesizeBitmap(pWinStaObj
, pElement
);
940 ProbeForWrite(pgcd
, sizeof(*pgcd
), 1);
941 pgcd
->uFmtRet
= pElement
->fmt
;
942 pgcd
->fGlobalHandle
= pElement
->fGlobalHandle
;
944 /* Text and bitmap needs more data */
949 pLocaleEl
= IntGetFormatElement(pWinStaObj
, CF_LOCALE
);
950 if (pLocaleEl
&& !IS_DATA_DELAYED(pLocaleEl
))
951 pgcd
->hLocale
= pLocaleEl
->hData
;
953 else if (fmt
== CF_BITMAP
)
957 pPaletteEl
= IntGetFormatElement(pWinStaObj
, CF_PALETTE
);
958 if (pPaletteEl
&& !IS_DATA_DELAYED(pPaletteEl
))
959 pgcd
->hPalette
= pPaletteEl
->hData
;
962 hRet
= pElement
->hData
;
964 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
966 SetLastNtError(_SEH2_GetExceptionCode());
972 ObDereferenceObject(pWinStaObj
);
976 TRACE("NtUserGetClipboardData returns %p\n", hRet
);
982 UserSetClipboardData(UINT fmt
, HANDLE hData
, PSETCLIPBDATA scd
)
985 PWINSTATION_OBJECT pWinStaObj
;
987 pWinStaObj
= IntGetWinStaForCbAccess();
991 if (!fmt
|| !pWinStaObj
->ptiClipLock
)
993 ERR("Access denied!\n");
994 EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN
);
998 if (scd
->fIncSerialNumber
)
999 pWinStaObj
->iClipSerialNumber
++;
1001 /* Is it a delayed rendering? */
1004 /* Is it a bitmap? */
1005 if (fmt
== CF_BITMAP
)
1007 /* Make bitmap public */
1008 GreSetObjectOwner(hData
, GDI_OBJ_HMGR_PUBLIC
);
1011 /* Save data in the clipboard */
1012 IntAddFormatedData(pWinStaObj
, fmt
, hData
, scd
->fGlobalHandle
, FALSE
);
1013 TRACE("hData stored\n");
1015 /* If the serial number was increased, increase also the sequence number */
1016 if (scd
->fIncSerialNumber
)
1017 pWinStaObj
->iClipSequenceNumber
++;
1019 pWinStaObj
->fClipboardChanged
= TRUE
;
1021 /* Note: Synthesized formats are added in NtUserCloseClipboard */
1025 /* This is a delayed rendering */
1026 IntAddFormatedData(pWinStaObj
, fmt
, DATA_DELAYED
, FALSE
, FALSE
);
1027 TRACE("SetClipboardData delayed format: %u\n", fmt
);
1030 /* Return hData on success */
1034 TRACE("NtUserSetClipboardData returns: %p\n", hRet
);
1037 ObDereferenceObject(pWinStaObj
);
1043 NtUserSetClipboardData(UINT fmt
, HANDLE hData
, PSETCLIPBDATA pUnsafeScd
)
1048 TRACE("NtUserSetClipboardData(%x %p %p)\n", fmt
, hData
, pUnsafeScd
);
1052 ProbeForRead(pUnsafeScd
, sizeof(*pUnsafeScd
), 1);
1053 RtlCopyMemory(&scd
, pUnsafeScd
, sizeof(scd
));
1055 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1057 SetLastNtError(_SEH2_GetExceptionCode());
1058 _SEH2_YIELD(return NULL
;)
1062 UserEnterExclusive();
1064 /* Call internal function */
1065 hRet
= UserSetClipboardData(fmt
, hData
, &scd
);
1073 NtUserSetClipboardViewer(HWND hWndNewViewer
)
1075 HWND hWndNext
= NULL
;
1076 PWINSTATION_OBJECT pWinStaObj
;
1079 UserEnterExclusive();
1081 pWinStaObj
= IntGetWinStaForCbAccess();
1085 pWindow
= UserGetWindowObject(hWndNewViewer
);
1088 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
1092 /* Return previous viewer. New viever window should
1093 send messages to rest of the chain */
1094 if (pWinStaObj
->spwndClipViewer
)
1095 hWndNext
= pWinStaObj
->spwndClipViewer
->head
.h
;
1097 /* Set new viewer window */
1098 pWinStaObj
->spwndClipViewer
= pWindow
;
1100 /* Notify viewer windows in chain */
1101 pWinStaObj
->fClipboardChanged
= FALSE
;
1102 if (pWinStaObj
->spwndClipViewer
)
1104 TRACE("Clipboard: sending WM_DRAWCLIPBOARD to %p\n", pWinStaObj
->spwndClipViewer
->head
.h
);
1105 // For 32-bit applications this message is sent as a notification
1106 co_IntSendMessageNoWait(pWinStaObj
->spwndClipViewer
->head
.h
, WM_DRAWCLIPBOARD
, 0, 0);
1111 ObDereferenceObject(pWinStaObj
);
1118 // Sequence number is incremented whenever the contents of the clipboard change
1119 // or the clipboard is emptied. If clipboard rendering is delayed,
1120 // the sequence number is not incremented until the changes are rendered.
1123 NtUserGetClipboardSequenceNumber(VOID
)
1126 PWINSTATION_OBJECT pWinStaObj
;
1130 pWinStaObj
= IntGetWinStaForCbAccess();
1134 /* Get windowstation sequence number */
1135 dwRet
= (DWORD
)pWinStaObj
->iClipSequenceNumber
;
1137 ObDereferenceObject(pWinStaObj
);
1146 NtUserConvertMemHandle(
1151 PCLIPBOARDDATA pMemObj
;
1153 UserEnterExclusive();
1155 /* Create Clipboard data object */
1156 pMemObj
= UserCreateObject(gHandleTable
, NULL
, NULL
, &hMem
, TYPE_CLIPDATA
, sizeof(CLIPBOARDDATA
) + cbData
);
1160 pMemObj
->cbData
= cbData
;
1165 ProbeForRead(pData
, cbData
, 1);
1166 memcpy(pMemObj
->Data
, pData
, cbData
);
1168 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1174 /* Release the extra reference (UserCreateObject added 2 references) */
1175 UserDereferenceObject(pMemObj
);
1177 /* If we failed to copy data, remove handle */
1180 UserDeleteObject(hMem
, TYPE_CLIPDATA
);
1191 NtUserCreateLocalMemHandle(
1197 PCLIPBOARDDATA pMemObj
;
1198 NTSTATUS Status
= STATUS_SUCCESS
;
1202 /* Get Clipboard data object */
1203 pMemObj
= (PCLIPBOARDDATA
)UserGetObject(gHandleTable
, hMem
, TYPE_CLIPDATA
);
1206 Status
= STATUS_INVALID_HANDLE
;
1211 if (cbData
> pMemObj
->cbData
)
1212 cbData
= pMemObj
->cbData
;
1214 /* Copy data to usermode */
1219 ProbeForWrite(pcbData
, sizeof(*pcbData
), 1);
1220 *pcbData
= pMemObj
->cbData
;
1223 ProbeForWrite(pData
, cbData
, 1);
1224 memcpy(pData
, pMemObj
->Data
, cbData
);
1226 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1228 Status
= _SEH2_GetExceptionCode();