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