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