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