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