9d0cde95eb93910400417b1e041c73bf605979cb
[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 */
9
10 #include <win32k.h>
11
12 DBG_DEFAULT_CHANNEL(UserClipbrd);
13
14 #define DATA_DELAYED_RENDER 0
15 #define DATA_SYNTHESIZED_RENDER -1
16
17 PTHREADINFO ClipboardThread;
18 PTHREADINFO ClipboardOwnerThread;
19 PWND ClipboardWindow;
20 PWND ClipboardViewerWindow;
21 PWND ClipboardOwnerWindow;
22 BOOL sendDrawClipboardMsg;
23 BOOL recentlySetClipboard;
24 BOOL delayedRender;
25 UINT lastEnumClipboardFormats;
26 DWORD ClipboardSequenceNumber = 0;
27
28 PCLIPBOARDCHAINELEMENT WindowsChain = NULL;
29 PCLIPBOARDELEMENT ClipboardData = NULL;
30
31 PCHAR synthesizedData;
32 DWORD synthesizedDataSize;
33
34
35 /*==============================================================*/
36
37 /* return the pointer to the prev window of the finded window,
38 if NULL does not exists in the chain */
39 PCLIPBOARDCHAINELEMENT FASTCALL
40 IntIsWindowInChain(PWND window)
41 {
42 PCLIPBOARDCHAINELEMENT wce = WindowsChain;
43
44 while (wce)
45 {
46 if (wce->window == window)
47 {
48 break;
49 }
50 wce = wce->next;
51 }
52
53 return wce;
54 }
55
56 VOID FASTCALL printChain(VOID)
57 {
58 /*test*/
59 PCLIPBOARDCHAINELEMENT wce2 = WindowsChain;
60 while (wce2)
61 {
62 ERR("chain: %p\n", wce2->window->head.h);
63 wce2 = wce2->next;
64 }
65 }
66
67 /* the new window always have to be the first in the chain */
68 PCLIPBOARDCHAINELEMENT FASTCALL
69 IntAddWindowToChain(PWND window)
70 {
71 PCLIPBOARDCHAINELEMENT wce = NULL;
72
73 if (!IntIsWindowInChain(window))
74 {
75 wce = WindowsChain;
76
77 wce = ExAllocatePoolWithTag(PagedPool, sizeof(CLIPBOARDCHAINELEMENT), USERTAG_CLIPBOARD);
78 if (wce == NULL)
79 {
80 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
81 goto exit_addChain;
82 }
83
84 wce->window = window;
85 wce->next = WindowsChain;
86
87 WindowsChain = wce;
88
89 //printChain();
90 }
91 exit_addChain:
92
93 /* return the next window to beremoved later */
94 return wce;
95 }
96
97 PCLIPBOARDCHAINELEMENT FASTCALL
98 IntRemoveWindowFromChain(PWND window)
99 {
100 PCLIPBOARDCHAINELEMENT wce = WindowsChain;
101 PCLIPBOARDCHAINELEMENT *link = &WindowsChain;
102
103 if (IntIsWindowInChain(window))
104 {
105 while (wce != NULL)
106 {
107 if (wce->window == window)
108 {
109 *link = wce->next;
110 break;
111 }
112
113 link = &wce->next;
114 wce = wce->next;
115 }
116
117 //printChain();
118
119 return wce;
120 }
121 else
122 {
123 return NULL;
124 }
125 }
126
127
128 /*==============================================================*/
129 /* if format exists, returns a non zero value (pointing to format object) */
130 PCLIPBOARDELEMENT FASTCALL
131 intIsFormatAvailable(UINT format)
132 {
133 PCLIPBOARDELEMENT ret = NULL;
134 PCLIPBOARDELEMENT ce = ClipboardData;
135
136 while(ce)
137 {
138 if (ce->format == format)
139 {
140 ret = ce;
141 break;
142 }
143 ce = ce->next;
144 }
145 return ret;
146 }
147
148 /* counts how many distinct format were are in the clipboard */
149 DWORD FASTCALL
150 IntCountClipboardFormats(VOID)
151 {
152 DWORD ret = 0;
153 PCLIPBOARDELEMENT ce = ClipboardData;
154
155 while(ce)
156 {
157 ret++;
158 ce = ce->next;
159 }
160 return ret;
161 }
162
163 /* adds a new format and data to the clipboard */
164 PCLIPBOARDELEMENT FASTCALL
165 intAddFormatedData(UINT format, HANDLE hData, DWORD size)
166 {
167 PCLIPBOARDELEMENT ce = NULL;
168
169 ce = ExAllocatePoolWithTag(PagedPool, sizeof(CLIPBOARDELEMENT), USERTAG_CLIPBOARD);
170 if (ce == NULL)
171 {
172 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
173 }
174 else
175 {
176 ce->format = format;
177 ce->size = size;
178 ce->hData = hData;
179 ce->next = ClipboardData;
180
181 ClipboardData = ce;
182
183 IntIncrementSequenceNumber();
184 }
185
186 return ce;
187 }
188
189 /* removes a format and its data from the clipboard */
190 BOOL FASTCALL
191 intRemoveFormatedData(UINT format)
192 {
193 BOOL ret = FALSE;
194 PCLIPBOARDELEMENT ce = ClipboardData;
195 PCLIPBOARDELEMENT *link = &ClipboardData;
196
197 if (intIsFormatAvailable(format))
198 {
199 while (ce != NULL)
200 {
201 if (ce->format == format)
202 {
203 *link = ce->next;
204 break;
205 }
206
207 link = &ce->next;
208 ce = ce->next;
209 }
210
211 if (ce->hData)
212 {
213 ExFreePool(ce->hData);
214 }
215 ExFreePool(ce);
216 ret = TRUE;
217 }
218
219 return ret;
220 }
221
222 VOID FASTCALL
223 IntEmptyClipboardData(VOID)
224 {
225 PCLIPBOARDELEMENT ce = ClipboardData;
226 PCLIPBOARDELEMENT tmp;
227
228 while(ce)
229 {
230 tmp = ce->next;
231 if (ce->hData)
232 {
233 ExFreePool(ce->hData);
234 }
235 ExFreePool(ce);
236 ce = tmp;
237 }
238
239 ClipboardData = NULL;
240 }
241
242 /*==============================================================*/
243
244 HANDLE FASTCALL
245 renderBITMAPfromDIB(LPBYTE pDIB)
246 {
247 HDC hdc;
248 HBITMAP hbitmap;
249 PBITMAPINFO pBmi, pConvertedBmi = NULL;
250 NTSTATUS Status ;
251 UINT offset = 0; /* Stupid compiler */
252
253 pBmi = (BITMAPINFO*)pDIB;
254
255 //hdc = UserGetDCEx(NULL, NULL, DCX_USESTYLE);
256 hdc = UserGetDCEx(ClipboardWindow, NULL, DCX_USESTYLE);
257
258 /* Probe it */
259 _SEH2_TRY
260 {
261 ProbeForRead(&pBmi->bmiHeader.biSize, sizeof(DWORD), 1);
262 ProbeForRead(pBmi, pBmi->bmiHeader.biSize, 1);
263 ProbeForRead(pBmi, DIB_BitmapInfoSize(pBmi, DIB_RGB_COLORS), 1);
264 pConvertedBmi = DIB_ConvertBitmapInfo(pBmi, DIB_RGB_COLORS);
265 if(!pConvertedBmi)
266 {
267 Status = STATUS_INVALID_PARAMETER;
268 }
269 else
270 {
271 offset = DIB_BitmapInfoSize((BITMAPINFO*)pBmi, DIB_RGB_COLORS);
272 ProbeForRead(pDIB + offset, pConvertedBmi->bmiHeader.biSizeImage, 1);
273 }
274 }
275 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
276 {
277 Status = _SEH2_GetExceptionCode();
278 }
279 _SEH2_END
280
281 if(!NT_SUCCESS(Status))
282 {
283 UserReleaseDC(ClipboardWindow, hdc, FALSE);
284 return NULL;
285 }
286
287 hbitmap = GreCreateDIBitmapInternal(hdc,
288 pConvertedBmi->bmiHeader.biWidth,
289 pConvertedBmi->bmiHeader.biHeight,
290 CBM_INIT,
291 pDIB+offset,
292 pConvertedBmi,
293 DIB_RGB_COLORS,
294 0,
295 0);
296 //UserReleaseDC(NULL, hdc, FALSE);
297 UserReleaseDC(ClipboardWindow, hdc, FALSE);
298
299 DIB_FreeConvertedBitmapInfo(pConvertedBmi, pBmi);
300
301 return hbitmap;
302 }
303
304 BOOL FASTCALL
305 canSinthesize(UINT format)
306 {
307 BOOL ret = FALSE;
308
309 switch(format)
310 {
311 case CF_BITMAP:
312 case CF_METAFILEPICT:
313 ret = TRUE;
314 }
315
316 return ret;
317 }
318
319 /* returns the size of the sinthesized data */
320 DWORD FASTCALL
321 synthesizeData(UINT format)
322 {
323 DWORD ret = 0;
324
325 synthesizedData = NULL;
326 synthesizedDataSize = 0;
327
328 if (!canSinthesize(format))
329 {
330 return 0;
331 }
332
333 switch (format)
334 {
335 case CF_BITMAP:
336 {
337 break;
338 }
339
340 case CF_METAFILEPICT:
341 {
342 break;
343 }
344 }
345
346 ret = 1;
347
348 return ret;
349 }
350
351 VOID FASTCALL
352 freeSynthesizedData(VOID)
353 {
354 ExFreePool(synthesizedData);
355 }
356
357 /*==============================================================*/
358
359 BOOL FASTCALL
360 intIsClipboardOpenByMe(VOID)
361 {
362 /* check if we open the clipboard */
363 if (ClipboardThread && ClipboardThread == PsGetCurrentThreadWin32Thread())
364 {
365 /* yes, we got a thread and its the same that opens the clipboard */
366 return TRUE;
367
368 }
369 /* will fail if not thread (closed) or not open by me*/
370 return FALSE;
371 }
372
373 /* IntClipboardFreeWindow it's called when a window was destroyed */
374 VOID FASTCALL
375 IntClipboardFreeWindow(PWND window)
376 {
377 /* called from co_UserFreeWindow in window.c */
378 /* check if clipboard is not locked by this window, if yes, unlock it */
379 if (ClipboardThread == PsGetCurrentThreadWin32Thread())
380 {
381 /* the window that opens the clipboard was destroyed */
382 ClipboardThread = NULL;
383 ClipboardWindow = NULL;
384 //TODO: free clipboard
385 }
386 if (window == ClipboardOwnerWindow)
387 {
388 /* the owner window was destroyed */
389 ClipboardOwnerWindow = NULL;
390 ClipboardOwnerThread = NULL;
391 }
392 /* remove window from window chain */
393 if (IntIsWindowInChain(window))
394 {
395 PCLIPBOARDCHAINELEMENT w = IntRemoveWindowFromChain(window);
396 if (w)
397 {
398 ExFreePool(w);
399 }
400 }
401 }
402
403 BOOL APIENTRY
404 NtUserOpenClipboard(HWND hWnd, DWORD Unknown1)
405 {
406
407 PWND Window;
408 BOOL ret = FALSE;
409
410 UserEnterExclusive();
411
412 sendDrawClipboardMsg = FALSE;
413 recentlySetClipboard = FALSE;
414
415 if (ClipboardThread)
416 {
417 /* clipboard is already open */
418 if (ClipboardThread == PsGetCurrentThreadWin32Thread())
419 {
420 if (ClipboardOwnerWindow)
421 {
422 if (ClipboardOwnerWindow->head.h == hWnd)
423 {
424 ret = TRUE;
425 }
426 }
427 else
428 {
429 if (hWnd == NULL)
430 {
431 ret = TRUE;
432 }
433 }
434 }
435 }
436 else
437 {
438
439 if (hWnd != NULL)
440 {
441 Window = UserGetWindowObject(hWnd);
442
443 if (Window != NULL)
444 {
445 ClipboardWindow = Window;
446 ClipboardThread = PsGetCurrentThreadWin32Thread();
447 ret = TRUE;
448 }
449 else
450 {
451 ClipboardWindow = NULL;
452 ClipboardThread = NULL;
453 ClipboardOwnerWindow = NULL;
454 ClipboardOwnerThread = NULL;
455 }
456 }
457 else
458 {
459 ClipboardWindow = NULL;
460 ClipboardThread = PsGetCurrentThreadWin32Thread();
461 ret = TRUE;
462 }
463 }
464
465 UserLeave();
466
467 return ret;
468 }
469
470 BOOL APIENTRY
471 NtUserCloseClipboard(VOID)
472 {
473 BOOL ret = FALSE;
474
475 UserEnterExclusive();
476
477 if (intIsClipboardOpenByMe())
478 {
479 ClipboardWindow = NULL;
480 ClipboardThread = NULL;
481 ret = TRUE;
482 }
483 else
484 {
485 EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN);
486 }
487
488 recentlySetClipboard = FALSE;
489
490 UserLeave();
491
492 if (sendDrawClipboardMsg && WindowsChain)
493 {
494 /* only send message to the first window in the chain, then they'll do the chain */
495 /* commented because it makes a crash in co_MsqSendMessage
496 ASSERT(WindowsChain->window);
497 ASSERT(WindowsChain->window->hSelf);
498 ERR("Clipboard: sending WM_DRAWCLIPBOARD to %p\n", WindowsChain->window->hSelf);
499 co_IntSendMessage(WindowsChain->window->hSelf, WM_DRAWCLIPBOARD, 0, 0);
500 */
501 }
502
503 return ret;
504 }
505
506 HWND APIENTRY
507 NtUserGetOpenClipboardWindow(VOID)
508 {
509 HWND ret = NULL;
510
511 UserEnterShared();
512
513 if (ClipboardWindow)
514 {
515 ret = ClipboardWindow->head.h;
516 }
517
518 UserLeave();
519
520 return ret;
521 }
522
523 BOOL APIENTRY
524 NtUserChangeClipboardChain(HWND hWndRemove, HWND hWndNewNext)
525 {
526 BOOL ret = FALSE;
527 PCLIPBOARDCHAINELEMENT w = NULL;
528 PWND removeWindow;
529 UserEnterExclusive();
530
531 removeWindow = UserGetWindowObject(hWndRemove);
532
533 if (removeWindow)
534 {
535 if ((ret = !!IntIsWindowInChain(removeWindow)))
536 {
537 w = IntRemoveWindowFromChain(removeWindow);
538 if (w)
539 {
540 ExFreePool(w);
541 }
542 }
543 }
544
545 if (ret && WindowsChain)
546 {
547 // only send message to the first window in the chain,
548 // then they do the chain
549
550 /* WindowsChain->window may be NULL */
551 LPARAM lparam = WindowsChain->window == NULL ? 0 : (LPARAM)WindowsChain->window->head.h;
552 ERR("Message: WM_CHANGECBCHAIN to %p", WindowsChain->window->head.h);
553 co_IntSendMessage(WindowsChain->window->head.h, WM_CHANGECBCHAIN, (WPARAM)hWndRemove, lparam);
554 }
555
556 UserLeave();
557
558 return ret;
559 }
560
561 DWORD APIENTRY
562 NtUserCountClipboardFormats(VOID)
563 {
564 DWORD ret = 0;
565
566 if (ClipboardData)
567 {
568 ret = IntCountClipboardFormats();
569 }
570
571 return ret;
572 }
573
574 DWORD APIENTRY
575 NtUserEmptyClipboard(VOID)
576 {
577 BOOL ret = FALSE;
578
579 UserEnterExclusive();
580
581 if (intIsClipboardOpenByMe())
582 {
583 if (ClipboardData)
584 {
585 IntEmptyClipboardData();
586 }
587
588 ClipboardOwnerWindow = ClipboardWindow;
589 ClipboardOwnerThread = ClipboardThread;
590
591 IntIncrementSequenceNumber();
592
593 ret = TRUE;
594 }
595 else
596 {
597 EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN);
598 }
599
600 if (ret && ClipboardOwnerWindow)
601 {
602 TRACE("Clipboard: WM_DESTROYCLIPBOARD to %p", ClipboardOwnerWindow->head.h);
603 co_IntSendMessageNoWait( ClipboardOwnerWindow->head.h, WM_DESTROYCLIPBOARD, 0, 0);
604 }
605
606 UserLeave();
607
608 return ret;
609 }
610
611 HANDLE APIENTRY
612 NtUserGetClipboardData(UINT uFormat, PVOID pBuffer)
613 {
614 HANDLE ret = NULL;
615
616 UserEnterShared();
617
618 if (intIsClipboardOpenByMe())
619 {
620 /* when Unknown1 is zero, we returns to user32 the data size */
621 if (!pBuffer)
622 {
623 PCLIPBOARDELEMENT data = intIsFormatAvailable(uFormat);
624
625 if (data)
626 {
627 /* format exists in clipboard */
628 if (data->size == DATA_DELAYED_RENDER)
629 {
630 /* tell owner what data needs to be rendered */
631 if (ClipboardOwnerWindow)
632 {
633 ASSERT(ClipboardOwnerWindow->head.h);
634 co_IntSendMessage(ClipboardOwnerWindow->head.h, WM_RENDERFORMAT, (WPARAM)uFormat, 0);
635 data = intIsFormatAvailable(uFormat);
636 ASSERT(data->size);
637 ret = (HANDLE)(ULONG_PTR)data->size;
638 }
639 }
640 else
641 {
642 if (data->size == DATA_SYNTHESIZED_RENDER)
643 {
644 data->size = synthesizeData(uFormat);
645 }
646
647 }
648 ret = (HANDLE)(ULONG_PTR)data->size;
649 }
650 else
651 {
652 /* there is no data in this format */
653 //ret = (HANDLE)FALSE;
654 }
655 }
656 else
657 {
658 PCLIPBOARDELEMENT data = intIsFormatAvailable(uFormat);
659
660 if (data)
661 {
662 if (data->size == DATA_DELAYED_RENDER)
663 {
664 // we rendered it in 1st call of getclipboard data
665 }
666 else
667 {
668 if (data->size == DATA_SYNTHESIZED_RENDER)
669 {
670 if (uFormat == CF_BITMAP)
671 {
672 /* BITMAP & METAFILEs returns a GDI handle */
673 PCLIPBOARDELEMENT data = intIsFormatAvailable(CF_DIB);
674 if (data)
675 {
676 ret = renderBITMAPfromDIB(data->hData);
677 }
678 }
679 else
680 {
681 ret = (HANDLE)pBuffer;
682
683 _SEH2_TRY
684 {
685 ProbeForWrite(pBuffer, synthesizedDataSize, 1);
686 memcpy(pBuffer, (PCHAR)synthesizedData, synthesizedDataSize);
687 }
688 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
689 {
690 ret = NULL;
691 }
692 _SEH2_END
693
694 freeSynthesizedData();
695 }
696 }
697 else
698 {
699 ret = (HANDLE)pBuffer;
700
701 _SEH2_TRY
702 {
703 ProbeForWrite(pBuffer, data->size, 1);
704 memcpy(pBuffer, (PCHAR)data->hData, data->size);
705 }
706 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
707 {
708 ret = NULL;
709 }
710 _SEH2_END
711 }
712 }
713
714 }
715
716 }
717 }
718 else
719 {
720 EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN);
721 }
722
723 UserLeave();
724
725 return ret;
726 }
727
728 INT APIENTRY
729 NtUserGetClipboardFormatName(UINT format, PUNICODE_STRING FormatName,
730 INT cchMaxCount)
731 {
732 UNICODE_STRING sFormatName;
733 INT ret = 0;
734
735 /* if the format is built-in we fail */
736 if (format < 0xc000)
737 {
738 /* registetrated formats are >= 0xc000 */
739 return 0;
740 }
741
742 if((cchMaxCount < 1) || !FormatName)
743 {
744 EngSetLastError(ERROR_INVALID_PARAMETER);
745 return 0;
746 }
747
748 _SEH2_TRY
749 {
750 ProbeForWriteUnicodeString(FormatName);
751 sFormatName = *(volatile UNICODE_STRING *)FormatName;
752 ProbeForWrite(sFormatName.Buffer, sFormatName.MaximumLength, 1);
753
754 ret = IntGetAtomName((RTL_ATOM)format, sFormatName.Buffer, cchMaxCount * sizeof(WCHAR));
755
756 if (ret >= 0)
757 {
758 ret = ret / sizeof(WCHAR);
759 sFormatName.Length = ret;
760 }
761 else
762 {
763 ret = 0;
764 }
765 }
766 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
767 {
768 SetLastNtError(_SEH2_GetExceptionCode());
769 }
770 _SEH2_END;
771
772 return ret;
773 }
774
775 HWND APIENTRY
776 NtUserGetClipboardOwner(VOID)
777 {
778 HWND ret = NULL;
779
780 UserEnterShared();
781
782 if (ClipboardOwnerWindow)
783 {
784 ret = ClipboardOwnerWindow->head.h;
785 }
786
787 UserLeave();
788
789 return ret;
790 }
791
792 HWND APIENTRY
793 NtUserGetClipboardViewer(VOID)
794 {
795 HWND ret = NULL;
796
797 UserEnterShared();
798
799 if (WindowsChain)
800 {
801 ret = WindowsChain->window->head.h;
802 }
803
804 UserLeave();
805
806 return ret;
807 }
808
809 INT APIENTRY
810 NtUserGetPriorityClipboardFormat(UINT *paFormatPriorityList, INT cFormats)
811 {
812 INT i;
813 UINT *priorityList;
814 INT ret = 0;
815
816 UserEnterExclusive();
817
818 _SEH2_TRY
819 {
820 if (IntCountClipboardFormats() == 0)
821 {
822 ret = 0;
823 }
824 else
825 {
826 ProbeForRead(paFormatPriorityList, cFormats, sizeof(UINT));
827
828 priorityList = paFormatPriorityList;
829
830 ret = -1;
831
832 for (i = 0; i < cFormats; i++)
833 {
834 if (intIsFormatAvailable(priorityList[i]))
835 {
836 ret = priorityList[i];
837 break;
838 }
839 }
840
841 }
842 }
843 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
844 {
845 SetLastNtError(_SEH2_GetExceptionCode());
846 }
847 _SEH2_END;
848
849 UserLeave();
850
851 return ret;
852
853 }
854
855 BOOL APIENTRY
856 NtUserIsClipboardFormatAvailable(UINT format)
857 {
858 BOOL ret = FALSE;
859
860 UserEnterShared();
861
862 ret = (intIsFormatAvailable(format) != NULL);
863
864 UserLeave();
865
866 return ret;
867 }
868
869
870
871 HANDLE APIENTRY
872 NtUserSetClipboardData(UINT uFormat, HANDLE hMem, DWORD size)
873 {
874 HANDLE hCBData = NULL;
875 UNICODE_STRING unicodeString;
876 OEM_STRING oemString;
877 ANSI_STRING ansiString;
878
879 UserEnterExclusive();
880
881 /* to place data here the we need to be the owner */
882 if (ClipboardOwnerThread == PsGetCurrentThreadWin32Thread())
883 {
884 PCLIPBOARDELEMENT data = intIsFormatAvailable(uFormat);
885 if (data)
886 {
887
888 if (data->size == DATA_DELAYED_RENDER)
889 {
890 intRemoveFormatedData(uFormat);
891 }
892 else
893 {
894 // we already have this format on clipboard
895 goto exit_setCB;
896 }
897 }
898
899 if (hMem)
900 {
901 _SEH2_TRY
902 {
903 ProbeForRead(hMem, size, 1);
904 }
905 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
906 {
907 SetLastNtError(_SEH2_GetExceptionCode());
908 _SEH2_YIELD(goto exit_setCB);
909 }
910 _SEH2_END;
911
912 if (intIsClipboardOpenByMe())
913 {
914 delayedRender = FALSE;
915 }
916
917 if (!canSinthesize(uFormat))
918 {
919 hCBData = ExAllocatePoolWithTag(PagedPool, size, USERTAG_CLIPBOARD);
920 memcpy(hCBData, hMem, size);
921 intAddFormatedData(uFormat, hCBData, size);
922 ERR("Data stored\n");
923 }
924
925 sendDrawClipboardMsg = TRUE;
926 recentlySetClipboard = TRUE;
927 lastEnumClipboardFormats = uFormat;
928
929 /* conversions */
930 switch (uFormat)
931 {
932 case CF_TEXT:
933 {
934 //TODO : sinthesize CF_UNICODETEXT & CF_OEMTEXT
935 // CF_TEXT -> CF_UNICODETEXT
936 ansiString.Buffer = hCBData;
937 ansiString.Length = size;
938 RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE);
939 intAddFormatedData(CF_UNICODETEXT, unicodeString.Buffer, unicodeString.Length * sizeof(WCHAR));
940 // CF_TEXT -> CF_OEMTEXT
941 RtlUnicodeStringToOemString(&oemString, &unicodeString, TRUE);
942 intAddFormatedData(CF_OEMTEXT, oemString.Buffer, oemString.Length);
943 //HKCU\Control Panel\International\Locale
944 //intAddFormatedData(CF_LOCALE, oemString.Buffer, oemString.Length);
945 break;
946 }
947 case CF_UNICODETEXT:
948 {
949 //TODO : sinthesize CF_TEXT & CF_OEMTEXT
950 //CF_UNICODETEXT -> CF_TEXT
951 unicodeString.Buffer = hCBData;
952 unicodeString.Length = size;
953 RtlUnicodeStringToAnsiString(&ansiString, &unicodeString, TRUE);
954 intAddFormatedData(CF_TEXT, ansiString.Buffer, ansiString.Length);
955 //CF_UNICODETEXT -> CF_OEMTEXT
956 RtlUnicodeStringToOemString(&oemString, &unicodeString, TRUE);
957 intAddFormatedData(CF_OEMTEXT, oemString.Buffer, oemString.Length);
958 break;
959 }
960 case CF_OEMTEXT:
961 {
962 //TODO : sinthesize CF_TEXT & CF_UNICODETEXT
963 //CF_OEMTEXT -> CF_UNICODETEXT
964 oemString.Buffer = hCBData;
965 oemString.Length = size;
966 RtlOemStringToUnicodeString(&unicodeString, &oemString, TRUE);
967 intAddFormatedData(CF_UNICODETEXT, unicodeString.Buffer, unicodeString.Length * sizeof(WCHAR));
968 //CF_OEMTEXT -> CF_TEXT
969 RtlUnicodeStringToAnsiString(&ansiString, &unicodeString, TRUE);
970 intAddFormatedData(CF_TEXT, ansiString.Buffer, ansiString.Length);
971 break;
972 }
973 case CF_BITMAP:
974 {
975 // we need to render the DIB or DIBV5 format as soon as possible
976 // because pallette information may change
977
978 HDC hdc;
979 BITMAP bm;
980 BITMAPINFO bi;
981 SURFACE *psurf;
982
983 hdc = UserGetDCEx(NULL, NULL, DCX_USESTYLE);
984
985
986 psurf = SURFACE_ShareLockSurface(hMem);
987 BITMAP_GetObject(psurf, sizeof(BITMAP), (PVOID)&bm);
988 if(psurf)
989 {
990 SURFACE_ShareUnlockSurface(psurf);
991 }
992
993 bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
994 bi.bmiHeader.biWidth = bm.bmWidth;
995 bi.bmiHeader.biHeight = bm.bmHeight;
996 bi.bmiHeader.biPlanes = 1;
997 bi.bmiHeader.biBitCount = bm.bmPlanes * bm.bmBitsPixel;
998 bi.bmiHeader.biCompression = BI_RGB;
999 bi.bmiHeader.biSizeImage = 0;
1000 bi.bmiHeader.biXPelsPerMeter = 0;
1001 bi.bmiHeader.biYPelsPerMeter = 0;
1002 bi.bmiHeader.biClrUsed = 0;
1003
1004 NtGdiGetDIBitsInternal(hdc, hMem, 0, bm.bmHeight, NULL, &bi, DIB_RGB_COLORS, 0, 0);
1005
1006 size = bi.bmiHeader.biSizeImage + sizeof(BITMAPINFOHEADER);
1007
1008 hCBData = ExAllocatePoolWithTag(PagedPool, size, USERTAG_CLIPBOARD);
1009 memcpy(hCBData, &bi, sizeof(BITMAPINFOHEADER));
1010
1011 NtGdiGetDIBitsInternal(hdc, hMem, 0, bm.bmHeight, (LPBYTE)hCBData + sizeof(BITMAPINFOHEADER), &bi, DIB_RGB_COLORS, 0, 0);
1012
1013 UserReleaseDC(NULL, hdc, FALSE);
1014
1015 intAddFormatedData(CF_DIB, hCBData, size);
1016 intAddFormatedData(CF_BITMAP, 0, DATA_SYNTHESIZED_RENDER);
1017 // intAddFormatedData(CF_DIBV5, hCBData, size);
1018
1019 break;
1020 }
1021 case CF_DIB:
1022 {
1023 intAddFormatedData(CF_BITMAP, 0, DATA_SYNTHESIZED_RENDER);
1024 // intAddFormatedData(CF_DIBV5, hCBData, size);
1025 /* investigate */
1026 // intAddFormatedData(CF_PALETTE, hCBData, size);
1027 break;
1028 }
1029 case CF_DIBV5:
1030 // intAddFormatedData(CF_BITMAP, hCBData, size);
1031 // intAddFormatedData(CF_PALETTE, hCBData, size);
1032 // intAddFormatedData(CF_DIB, hCBData, size);
1033 break;
1034 case CF_ENHMETAFILE:
1035 // intAddFormatedData(CF_METAFILEPICT, hCBData, size);
1036 break;
1037 case CF_METAFILEPICT:
1038 // intAddFormatedData(CF_ENHMETAFILE, hCBData, size);
1039 break;
1040 }
1041
1042 }
1043 else
1044 {
1045 // the window provides data in the specified format
1046 delayedRender = TRUE;
1047 sendDrawClipboardMsg = TRUE;
1048 intAddFormatedData(uFormat, NULL, 0);
1049 ERR("SetClipboardData delayed format: %d\n", uFormat);
1050 }
1051
1052
1053 }
1054
1055 exit_setCB:
1056
1057 UserLeave();
1058
1059 return hMem;
1060 }
1061
1062 HWND APIENTRY
1063 NtUserSetClipboardViewer(HWND hWndNewViewer)
1064 {
1065 HWND ret = NULL;
1066 PCLIPBOARDCHAINELEMENT newWC = NULL;
1067 PWND window;
1068
1069 UserEnterExclusive();
1070
1071 window = UserGetWindowObject(hWndNewViewer);
1072
1073 if (window)
1074 {
1075 if ((newWC = IntAddWindowToChain(window)))
1076 {
1077 if (newWC)
1078 {
1079 // newWC->next may be NULL if we are the first window in the chain
1080 if (newWC->next)
1081 {
1082 // return the next HWND available window in the chain
1083 ret = newWC->next->window->head.h;
1084 }
1085 }
1086 }
1087 }
1088
1089 UserLeave();
1090
1091 return ret;
1092 }
1093
1094 UINT APIENTRY
1095 IntEnumClipboardFormats(UINT uFormat)
1096 {
1097 UINT ret = 0;
1098
1099 if (intIsClipboardOpenByMe())
1100 {
1101 if (uFormat == 0)
1102 {
1103 if (recentlySetClipboard)
1104 {
1105 ret = lastEnumClipboardFormats;
1106 }
1107 else
1108 {
1109 /* return the first available format */
1110 if (ClipboardData)
1111 {
1112 ret = ClipboardData->format;
1113 }
1114 }
1115 }
1116 else
1117 {
1118 if (recentlySetClipboard)
1119 {
1120 ret = 0;
1121 }
1122 else
1123 {
1124 /* querying nextt available format */
1125 PCLIPBOARDELEMENT data = intIsFormatAvailable(uFormat);
1126
1127 if (data)
1128 {
1129 if (data->next)
1130 {
1131 ret = data->next->format;
1132 }
1133 else
1134 {
1135 /* reached the end */
1136 ret = 0;
1137 }
1138 }
1139 }
1140
1141 }
1142 }
1143 else
1144 {
1145 EngSetLastError(ERROR_CLIPBOARD_NOT_OPEN);
1146 }
1147
1148 return ret;
1149 }
1150
1151 // This number is incremented whenever the contents of the clipboard change
1152 // or the clipboard is emptied.
1153 // If clipboard rendering is delayed,
1154 // the sequence number is not incremented until the changes are rendered.
1155 VOID FASTCALL
1156 IntIncrementSequenceNumber(VOID)
1157 {
1158 PTHREADINFO pti;
1159 PWINSTATION_OBJECT WinStaObj;
1160
1161 pti = PsGetCurrentThreadWin32Thread();
1162 WinStaObj = pti->rpdesk->rpwinstaParent;
1163
1164 WinStaObj->Clipboard->ClipboardSequenceNumber++;
1165 }
1166
1167 DWORD APIENTRY
1168 NtUserGetClipboardSequenceNumber(VOID)
1169 {
1170 //windowstation sequence number
1171 //if no WINSTA_ACCESSCLIPBOARD access to the window station,
1172 //the function returns zero.
1173 DWORD sn;
1174
1175 HWINSTA WinSta;
1176 PWINSTATION_OBJECT WinStaObj;
1177 NTSTATUS Status;
1178
1179 WinSta = UserGetProcessWindowStation();
1180
1181 Status = IntValidateWindowStationHandle(WinSta, KernelMode, WINSTA_ACCESSCLIPBOARD, &WinStaObj);
1182
1183 if (!NT_SUCCESS(Status))
1184 {
1185 ERR("No WINSTA_ACCESSCLIPBOARD access\n");
1186 SetLastNtError(Status);
1187 return 0;
1188 }
1189
1190 sn = WinStaObj->ClipboardSequenceNumber;
1191
1192 ObDereferenceObject(WinStaObj);
1193
1194 //local copy
1195 //sn = ClipboardSequenceNumber;
1196
1197 return sn;
1198 }
1199
1200 /* EOF */