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