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