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