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