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