- Merge aicom-network-fixes up to r36740
[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, PVOID pBuffer)
602 {
603 HANDLE ret = NULL;
604
605 UserEnterShared();
606
607 if (intIsClipboardOpenByMe())
608 {
609 /* when Unknown1 is zero, we returns to user32 the data size */
610 if (!pBuffer)
611 {
612 PCLIPBOARDELEMENT data = intIsFormatAvailable(uFormat);
613
614 if (data)
615 {
616 /* format exists in clipboard */
617 if (data->size == DATA_DELAYED_RENDER)
618 {
619 /* tell owner what data needs to be rendered */
620 if (ClipboardOwnerWindow)
621 {
622 ASSERT(ClipboardOwnerWindow->hSelf);
623 co_IntSendMessage(ClipboardOwnerWindow->hSelf, WM_RENDERFORMAT, (WPARAM)uFormat, 0);
624 data = intIsFormatAvailable(uFormat);
625 ASSERT(data->size);
626 ret = (HANDLE)(ULONG_PTR)data->size;
627 }
628 }
629 else
630 {
631 if (data->size == DATA_SYNTHESIZED_RENDER)
632 {
633 data->size = synthesizeData(uFormat);
634 }
635
636 }
637 ret = (HANDLE)(ULONG_PTR)data->size;
638 }
639 else
640 {
641 /* there is no data in this format */
642 //ret = (HANDLE)FALSE;
643 }
644 }
645 else
646 {
647 PCLIPBOARDELEMENT data = intIsFormatAvailable(uFormat);
648
649 if (data)
650 {
651 if (data->size == DATA_DELAYED_RENDER)
652 {
653 // we rendered it in 1st call of getclipboard data
654 }
655 else
656 {
657 if (data->size == DATA_SYNTHESIZED_RENDER)
658 {
659 if (uFormat == CF_BITMAP)
660 {
661 /* BITMAP & METAFILEs returns a GDI handle */
662 PCLIPBOARDELEMENT data = intIsFormatAvailable(CF_DIB);
663 if (data)
664 {
665 ret = renderBITMAPfromDIB(data->hData);
666 }
667 }
668 else
669 {
670 ret = (HANDLE)pBuffer;
671
672 _SEH_TRY
673 {
674 ProbeForWrite(pBuffer, synthesizedDataSize, 1);
675 memcpy(pBuffer, (PCHAR)synthesizedData, synthesizedDataSize);
676 }
677 _SEH_HANDLE
678 {
679 ret = NULL;
680 }
681 _SEH_END
682
683 freeSynthesizedData();
684 }
685 }
686 else
687 {
688 ret = (HANDLE)pBuffer;
689
690 _SEH_TRY
691 {
692 ProbeForWrite(pBuffer, data->size, 1);
693 memcpy(pBuffer, (PCHAR)data->hData, data->size);
694 }
695 _SEH_HANDLE
696 {
697 ret = NULL;
698 }
699 _SEH_END
700 }
701 }
702
703 }
704
705 }
706 }
707 else
708 {
709 SetLastWin32Error(ERROR_CLIPBOARD_NOT_OPEN);
710 }
711
712 UserLeave();
713
714 return ret;
715 }
716
717 INT STDCALL
718 NtUserGetClipboardFormatName(UINT format, PUNICODE_STRING FormatName,
719 INT cchMaxCount)
720 {
721 UNICODE_STRING sFormatName;
722 INT ret = 0;
723
724 /* if the format is built-in we fail */
725 if (format < 0xc000)
726 {
727 /* registetrated formats are >= 0xc000 */
728 return 0;
729 }
730
731 if((cchMaxCount < 1) || !FormatName)
732 {
733 SetLastWin32Error(ERROR_INVALID_PARAMETER);
734 return 0;
735 }
736
737 _SEH_TRY
738 {
739 ProbeForWriteUnicodeString(FormatName);
740 sFormatName = *(volatile UNICODE_STRING *)FormatName;
741 ProbeForWrite(sFormatName.Buffer, sFormatName.MaximumLength, 1);
742
743 ret = IntGetAtomName((RTL_ATOM)format, sFormatName.Buffer, cchMaxCount * sizeof(WCHAR));
744
745 if (ret >= 0)
746 {
747 ret = ret / sizeof(WCHAR);
748 sFormatName.Length = ret;
749 }
750 else
751 {
752 ret = 0;
753 }
754 }
755 _SEH_HANDLE
756 {
757 SetLastNtError(_SEH_GetExceptionCode());
758 }
759 _SEH_END;
760
761 return ret;
762 }
763
764 HWND STDCALL
765 NtUserGetClipboardOwner(VOID)
766 {
767 HWND ret = NULL;
768
769 UserEnterShared();
770
771 if (ClipboardOwnerWindow)
772 {
773 ret = ClipboardOwnerWindow->hSelf;
774 }
775
776 UserLeave();
777
778 return ret;
779 }
780
781 HWND STDCALL
782 NtUserGetClipboardViewer(VOID)
783 {
784 HWND ret = NULL;
785
786 UserEnterShared();
787
788 if (WindowsChain)
789 {
790 ret = WindowsChain->window->hSelf;
791 }
792
793 UserLeave();
794
795 return ret;
796 }
797
798 INT STDCALL
799 NtUserGetPriorityClipboardFormat(UINT *paFormatPriorityList, INT cFormats)
800 {
801 INT i;
802 UINT *priorityList;
803 INT ret = 0;
804
805 UserEnterExclusive();
806
807 _SEH_TRY
808 {
809 if (IntCountClipboardFormats() == 0)
810 {
811 ret = 0;
812 }
813 else
814 {
815 ProbeForRead(paFormatPriorityList, cFormats, sizeof(UINT));
816
817 priorityList = paFormatPriorityList;
818
819 ret = -1;
820
821 for (i = 0; i < cFormats; i++)
822 {
823 if (intIsFormatAvailable(priorityList[i]))
824 {
825 ret = priorityList[i];
826 break;
827 }
828 }
829
830 }
831 }
832 _SEH_HANDLE
833 {
834 SetLastNtError(_SEH_GetExceptionCode());
835 }
836 _SEH_END;
837
838 UserLeave();
839
840 return ret;
841
842 }
843
844 BOOL STDCALL
845 NtUserIsClipboardFormatAvailable(UINT format)
846 {
847 BOOL ret = FALSE;
848
849 UserEnterShared();
850
851 ret = (intIsFormatAvailable(format) != NULL);
852
853 UserLeave();
854
855 return ret;
856 }
857
858
859
860 HANDLE STDCALL
861 NtUserSetClipboardData(UINT uFormat, HANDLE hMem, DWORD size)
862 {
863 HANDLE hCBData = NULL;
864 UNICODE_STRING unicodeString;
865 OEM_STRING oemString;
866 ANSI_STRING ansiString;
867
868 UserEnterExclusive();
869
870 /* to place data here the we need to be the owner */
871 if (ClipboardOwnerThread == PsGetCurrentThreadWin32Thread())
872 {
873 PCLIPBOARDELEMENT data = intIsFormatAvailable(uFormat);
874 if (data)
875 {
876
877 if (data->size == DATA_DELAYED_RENDER)
878 {
879 intRemoveFormatedData(uFormat);
880 }
881 else
882 {
883 // we already have this format on clipboard
884 goto exit_setCB;
885 }
886 }
887
888 if (hMem)
889 {
890 _SEH_TRY
891 {
892 ProbeForRead(hMem, size, 1);
893 }
894 _SEH_HANDLE
895 {
896 SetLastNtError(_SEH_GetExceptionCode());
897 _SEH_YIELD(goto exit_setCB);
898 }
899 _SEH_END;
900
901 if (intIsClipboardOpenByMe())
902 {
903 delayedRender = FALSE;
904 }
905
906 if (!canSinthesize(uFormat))
907 {
908 hCBData = ExAllocatePool(PagedPool, size);
909 memcpy(hCBData, hMem, size);
910 intAddFormatedData(uFormat, hCBData, size);
911 DPRINT1("Data stored\n");
912 }
913
914 sendDrawClipboardMsg = TRUE;
915 recentlySetClipboard = TRUE;
916 lastEnumClipboardFormats = uFormat;
917
918 /* conversions */
919 switch (uFormat)
920 {
921 case CF_TEXT:
922 {
923 //TODO : sinthesize CF_UNICODETEXT & CF_OEMTEXT
924 // CF_TEXT -> CF_UNICODETEXT
925 ansiString.Buffer = hCBData;
926 ansiString.Length = size;
927 RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE);
928 intAddFormatedData(CF_UNICODETEXT, unicodeString.Buffer, unicodeString.Length * sizeof(WCHAR));
929 // CF_TEXT -> CF_OEMTEXT
930 RtlUnicodeStringToOemString(&oemString, &unicodeString, TRUE);
931 intAddFormatedData(CF_OEMTEXT, oemString.Buffer, oemString.Length);
932 //HKCU\Control Panel\International\Locale
933 //intAddFormatedData(CF_LOCALE, oemString.Buffer, oemString.Length);
934 break;
935 }
936 case CF_UNICODETEXT:
937 {
938 //TODO : sinthesize CF_TEXT & CF_OEMTEXT
939 //CF_UNICODETEXT -> CF_TEXT
940 unicodeString.Buffer = hCBData;
941 unicodeString.Length = size;
942 RtlUnicodeStringToAnsiString(&ansiString, &unicodeString, TRUE);
943 intAddFormatedData(CF_TEXT, ansiString.Buffer, ansiString.Length);
944 //CF_UNICODETEXT -> CF_OEMTEXT
945 RtlUnicodeStringToOemString(&oemString, &unicodeString, TRUE);
946 intAddFormatedData(CF_OEMTEXT, oemString.Buffer, oemString.Length);
947 break;
948 }
949 case CF_OEMTEXT:
950 {
951 //TODO : sinthesize CF_TEXT & CF_UNICODETEXT
952 //CF_OEMTEXT -> CF_UNICODETEXT
953 oemString.Buffer = hCBData;
954 oemString.Length = size;
955 RtlOemStringToUnicodeString(&unicodeString, &oemString, TRUE);
956 intAddFormatedData(CF_UNICODETEXT, unicodeString.Buffer, unicodeString.Length * sizeof(WCHAR));
957 //CF_OEMTEXT -> CF_TEXT
958 RtlUnicodeStringToAnsiString(&ansiString, &unicodeString, TRUE);
959 intAddFormatedData(CF_TEXT, ansiString.Buffer, ansiString.Length);
960 break;
961 }
962 case CF_BITMAP:
963 {
964 // we need to render the DIB or DIBV5 format as soon as possible
965 // because pallette information may change
966
967 HDC hdc;
968 INT ret;
969 BITMAP bm;
970 BITMAPINFO bi;
971 BITMAPOBJ *BitmapObj;
972
973 hdc = UserGetDCEx(NULL, NULL, DCX_USESTYLE);
974
975
976 BitmapObj = BITMAPOBJ_LockBitmap(hMem);
977 BITMAP_GetObject(BitmapObj, sizeof(BITMAP), (LPSTR)&bm);
978 if(BitmapObj)
979 {
980 BITMAPOBJ_UnlockBitmap(BitmapObj);
981 }
982
983 bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
984 bi.bmiHeader.biWidth = bm.bmWidth;
985 bi.bmiHeader.biHeight = bm.bmHeight;
986 bi.bmiHeader.biPlanes = 1;
987 bi.bmiHeader.biBitCount = bm.bmPlanes * bm.bmBitsPixel;
988 bi.bmiHeader.biCompression = BI_RGB;
989 bi.bmiHeader.biSizeImage = 0;
990 bi.bmiHeader.biXPelsPerMeter = 0;
991 bi.bmiHeader.biYPelsPerMeter = 0;
992 bi.bmiHeader.biClrUsed = 0;
993
994 ret = NtGdiGetDIBitsInternal(hdc, hMem, 0, bm.bmHeight, NULL, &bi, DIB_RGB_COLORS, 0, 0);
995
996 size = bi.bmiHeader.biSizeImage + sizeof(BITMAPINFOHEADER);
997
998 hCBData = ExAllocatePool(PagedPool, size);
999 memcpy(hCBData, &bi, sizeof(BITMAPINFOHEADER));
1000
1001 ret = NtGdiGetDIBitsInternal(hdc, hMem, 0, bm.bmHeight, (LPBYTE)hCBData + sizeof(BITMAPINFOHEADER), &bi, DIB_RGB_COLORS, 0, 0);
1002
1003 UserReleaseDC(NULL, hdc, FALSE);
1004
1005 intAddFormatedData(CF_DIB, hCBData, size);
1006 intAddFormatedData(CF_BITMAP, 0, DATA_SYNTHESIZED_RENDER);
1007 // intAddFormatedData(CF_DIBV5, hCBData, size);
1008
1009 break;
1010 }
1011 case CF_DIB:
1012 {
1013 intAddFormatedData(CF_BITMAP, 0, DATA_SYNTHESIZED_RENDER);
1014 // intAddFormatedData(CF_DIBV5, hCBData, size);
1015 /* investigate */
1016 // intAddFormatedData(CF_PALETTE, hCBData, size);
1017 break;
1018 }
1019 case CF_DIBV5:
1020 // intAddFormatedData(CF_BITMAP, hCBData, size);
1021 // intAddFormatedData(CF_PALETTE, hCBData, size);
1022 // intAddFormatedData(CF_DIB, hCBData, size);
1023 break;
1024 case CF_ENHMETAFILE:
1025 // intAddFormatedData(CF_METAFILEPICT, hCBData, size);
1026 break;
1027 case CF_METAFILEPICT:
1028 // intAddFormatedData(CF_ENHMETAFILE, hCBData, size);
1029 break;
1030 }
1031
1032 }
1033 else
1034 {
1035 // the window provides data in the specified format
1036 delayedRender = TRUE;
1037 sendDrawClipboardMsg = TRUE;
1038 intAddFormatedData(uFormat, NULL, 0);
1039 DPRINT1("SetClipboardData delayed format: %d\n", uFormat);
1040 }
1041
1042
1043 }
1044
1045 exit_setCB:
1046
1047 UserLeave();
1048
1049 return hMem;
1050 }
1051
1052 HWND STDCALL
1053 NtUserSetClipboardViewer(HWND hWndNewViewer)
1054 {
1055 HWND ret = NULL;
1056 PCLIPBOARDCHAINELEMENT newWC = NULL;
1057 PWINDOW_OBJECT window;
1058
1059 UserEnterExclusive();
1060
1061 window = UserGetWindowObject(hWndNewViewer);
1062
1063 if (window)
1064 {
1065 if ((newWC = IntAddWindowToChain(window)))
1066 {
1067 if (newWC)
1068 {
1069 // newWC->next may be NULL if we are the first window in the chain
1070 if (newWC->next)
1071 {
1072 // return the next HWND available window in the chain
1073 ret = newWC->next->window->hSelf;
1074 }
1075 }
1076 }
1077 }
1078
1079 UserLeave();
1080
1081 return ret;
1082 }
1083
1084 UINT STDCALL
1085 IntEnumClipboardFormats(UINT uFormat)
1086 {
1087 UINT ret = 0;
1088
1089 if (intIsClipboardOpenByMe())
1090 {
1091 if (uFormat == 0)
1092 {
1093 if (recentlySetClipboard)
1094 {
1095 ret = lastEnumClipboardFormats;
1096 }
1097 else
1098 {
1099 /* return the first available format */
1100 if (ClipboardData)
1101 {
1102 ret = ClipboardData->format;
1103 }
1104 }
1105 }
1106 else
1107 {
1108 if (recentlySetClipboard)
1109 {
1110 ret = 0;
1111 }
1112 else
1113 {
1114 /* querying nextt available format */
1115 PCLIPBOARDELEMENT data = intIsFormatAvailable(uFormat);
1116
1117 if (data)
1118 {
1119 if (data->next)
1120 {
1121 ret = data->next->format;
1122 }
1123 else
1124 {
1125 /* reached the end */
1126 ret = 0;
1127 }
1128 }
1129 }
1130
1131 }
1132 }
1133 else
1134 {
1135 SetLastWin32Error(ERROR_CLIPBOARD_NOT_OPEN);
1136 }
1137
1138 return ret;
1139 }
1140
1141 // This number is incremented whenever the contents of the clipboard change
1142 // or the clipboard is emptied.
1143 // If clipboard rendering is delayed,
1144 // the sequence number is not incremented until the changes are rendered.
1145 VOID FASTCALL
1146 IntIncrementSequenceNumber(VOID)
1147 {
1148
1149 USE_WINSTA
1150
1151 WINSTA_ClipboardSequenceNumber++;
1152
1153 }
1154
1155 DWORD STDCALL
1156 NtUserGetClipboardSequenceNumber(VOID)
1157 {
1158 //windowstation sequence number
1159 //if no WINSTA_ACCESSCLIPBOARD access to the window station,
1160 //the function returns zero.
1161 DWORD sn;
1162
1163 HWINSTA WinSta;
1164 PWINSTATION_OBJECT WinStaObj;
1165 NTSTATUS Status;
1166
1167 WinSta = UserGetProcessWindowStation();
1168
1169 Status = IntValidateWindowStationHandle(WinSta, UserMode, WINSTA_ACCESSCLIPBOARD, &WinStaObj);
1170
1171 if (!NT_SUCCESS(Status))
1172 {
1173 DPRINT1("No WINSTA_ACCESSCLIPBOARD access\n");
1174 SetLastNtError(Status);
1175 return 0;
1176 }
1177
1178 sn = WinStaObj->ClipboardSequenceNumber;
1179
1180 ObDereferenceObject(WinStaObj);
1181
1182 //local copy
1183 //sn = ClipboardSequenceNumber;
1184
1185 return sn;
1186 }
1187
1188
1189 /**************** VISTA FUNCTIONS******************/
1190
1191 BOOL STDCALL NtUserAddClipboardFormatListener(
1192 HWND hwnd
1193 )
1194 {
1195 UNIMPLEMENTED;
1196 return FALSE;
1197 }
1198
1199 BOOL STDCALL NtUserRemoveClipboardFormatListener(
1200 HWND hwnd
1201 )
1202 {
1203 UNIMPLEMENTED;
1204 return FALSE;
1205 }
1206
1207 BOOL STDCALL NtUserGetUpdatedClipboardFormats(
1208 PUINT lpuiFormats,
1209 UINT cFormats,
1210 PUINT pcFormatsOut
1211 )
1212 {
1213 UNIMPLEMENTED;
1214 return FALSE;
1215 }
1216
1217 /* EOF */