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