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