2 * WIN32 clipboard implementation
4 * Copyright 1994 Martin Ayotte
5 * Copyright 1996 Alex Korobka
6 * Copyright 1999 Noel Borthwick
7 * Copyright 2003 Ulrich Czekalla for CodeWeavers
8 * Copyright 2016 Alexandre Julliard
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include <sys/types.h>
34 #define WIN32_NO_STATUS
41 #include "user_private.h"
44 #include "wine/list.h"
45 #include "wine/server.h"
46 #include "wine/debug.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(clipboard
);
53 struct list entry
; /* entry in cache list */
54 UINT format
; /* format id */
55 UINT seqno
; /* sequence number when the data was set */
56 HANDLE handle
; /* original data handle */
59 static struct list cached_formats
= LIST_INIT( cached_formats
);
60 static struct list formats_to_free
= LIST_INIT( formats_to_free
);
62 static CRITICAL_SECTION clipboard_cs
;
63 static CRITICAL_SECTION_DEBUG critsect_debug
=
66 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
67 0, 0, { (DWORD_PTR
)(__FILE__
": clipboard_cs") }
69 static CRITICAL_SECTION clipboard_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
71 /* platform-independent version of METAFILEPICT */
80 /* get a debug string for a format id */
81 static const char *debugstr_format( UINT id
)
84 DWORD le
= GetLastError();
85 BOOL r
= NtUserGetClipboardFormatName( id
, buffer
, 256 );
89 return wine_dbg_sprintf( "%04x %s", id
, debugstr_w(buffer
) );
93 #define BUILTIN(id) case id: return #id;
96 BUILTIN(CF_METAFILEPICT
)
106 BUILTIN(CF_UNICODETEXT
)
107 BUILTIN(CF_ENHMETAFILE
)
111 BUILTIN(CF_OWNERDISPLAY
)
113 BUILTIN(CF_DSPBITMAP
)
114 BUILTIN(CF_DSPMETAFILEPICT
)
115 BUILTIN(CF_DSPENHMETAFILE
)
117 default: return wine_dbg_sprintf( "%04x", id
);
121 /* build the data to send to the server in SetClipboardData */
122 static HANDLE
marshal_data( UINT format
, HANDLE handle
, data_size_t
*ret_size
)
132 if (!GetObjectW( handle
, sizeof(bitmap
), &bitmap
)) return 0;
133 size
= abs( bitmap
.bmHeight
) * ((((bitmap
.bmWidth
* bitmap
.bmBitsPixel
) + 15) >> 3) & ~1);
134 *ret_size
= sizeof(bitmap
) + size
;
135 if (!(bm
= GlobalAlloc( GMEM_FIXED
, *ret_size
))) return 0;
137 GetBitmapBits( handle
, size
, bm
+ 1 );
143 if (!(size
= GetPaletteEntries( handle
, 0, 0, NULL
))) return 0;
144 *ret_size
= offsetof( LOGPALETTE
, palPalEntry
[size
] );
145 if (!(pal
= GlobalAlloc( GMEM_FIXED
, *ret_size
))) return 0;
146 pal
->palVersion
= 0x300;
147 pal
->palNumEntries
= size
;
148 GetPaletteEntries( handle
, 0, size
, pal
->palPalEntry
);
152 case CF_DSPENHMETAFILE
:
155 if (!(size
= GetEnhMetaFileBits( handle
, 0, NULL
))) return 0;
156 if (!(ret
= GlobalAlloc( GMEM_FIXED
, size
))) return 0;
157 GetEnhMetaFileBits( handle
, size
, ret
);
161 case CF_METAFILEPICT
:
162 case CF_DSPMETAFILEPICT
:
165 struct metafile_pict
*mfbits
;
166 if (!(mf
= GlobalLock( handle
))) return 0;
167 if (!(size
= GetMetaFileBitsEx( mf
->hMF
, 0, NULL
)))
169 GlobalUnlock( handle
);
172 *ret_size
= offsetof( struct metafile_pict
, bits
[size
] );
173 if (!(mfbits
= GlobalAlloc( GMEM_FIXED
, *ret_size
)))
175 GlobalUnlock( handle
);
179 mfbits
->xExt
= mf
->xExt
;
180 mfbits
->yExt
= mf
->yExt
;
181 GetMetaFileBitsEx( mf
->hMF
, size
, mfbits
->bits
);
182 GlobalUnlock( handle
);
188 if (!(size
= GlobalSize( handle
))) return 0;
189 if ((data_size_t
)size
!= size
) return 0;
190 if (!(ptr
= GlobalLock( handle
))) return 0;
191 ptr
[(size
+ 1) / sizeof(WCHAR
) - 1] = 0; /* enforce null-termination */
192 GlobalUnlock( handle
);
200 if (!(size
= GlobalSize( handle
))) return 0;
201 if ((data_size_t
)size
!= size
) return 0;
202 if (!(ptr
= GlobalLock( handle
))) return 0;
203 ptr
[size
- 1] = 0; /* enforce null-termination */
204 GlobalUnlock( handle
);
209 if (!(size
= GlobalSize( handle
))) return 0;
210 if ((data_size_t
)size
!= size
) return 0;
216 /* rebuild the target handle from the data received in GetClipboardData */
217 static HANDLE
unmarshal_data( UINT format
, void *data
, data_size_t size
)
219 HANDLE handle
= GlobalReAlloc( data
, size
, 0 ); /* release unused space */
226 if (size
< sizeof(*bm
)) break;
227 if (size
< bm
->bmWidthBytes
* abs( bm
->bmHeight
)) break;
228 if (bm
->bmBits
) break; /* DIB sections are not supported across processes */
230 return CreateBitmapIndirect( bm
);
232 case CF_DSPBITMAP
: /* not supported across processes */
236 LOGPALETTE
*pal
= handle
;
237 if (size
< sizeof(*pal
)) break;
238 if (size
< offsetof( LOGPALETTE
, palPalEntry
[pal
->palNumEntries
] )) break;
239 return CreatePalette( pal
);
242 case CF_DSPENHMETAFILE
:
243 return SetEnhMetaFileBits( size
, handle
);
244 case CF_METAFILEPICT
:
245 case CF_DSPMETAFILEPICT
:
248 struct metafile_pict
*mfbits
= handle
;
249 if (size
<= sizeof(*mfbits
)) break;
251 mf
.xExt
= mfbits
->xExt
;
252 mf
.yExt
= mfbits
->yExt
;
253 mf
.hMF
= SetMetaFileBitsEx( size
- offsetof( struct metafile_pict
, bits
), mfbits
->bits
);
254 *(METAFILEPICT
*)handle
= mf
;
261 /* retrieve a data format from the cache */
262 static struct cached_format
*get_cached_format( UINT format
)
264 struct cached_format
*cache
;
266 LIST_FOR_EACH_ENTRY( cache
, &cached_formats
, struct cached_format
, entry
)
267 if (cache
->format
== format
) return cache
;
271 /* store data in the cache, or reuse the existing one if available */
272 static HANDLE
cache_data( UINT format
, HANDLE data
, data_size_t size
, UINT seqno
,
273 struct cached_format
*cache
)
277 if (seqno
== cache
->seqno
) /* we can reuse the cached data */
280 return cache
->handle
;
282 /* cache entry is stale, remove it */
283 list_remove( &cache
->entry
);
284 list_add_tail( &formats_to_free
, &cache
->entry
);
287 /* allocate new cache entry */
288 if (!(cache
= HeapAlloc( GetProcessHeap(), 0, sizeof(*cache
) )))
293 cache
->format
= format
;
294 cache
->seqno
= seqno
;
295 cache
->handle
= unmarshal_data( format
, data
, size
);
296 list_add_tail( &cached_formats
, &cache
->entry
);
297 return cache
->handle
;
300 /* free a single cached format */
301 static void free_cached_data( struct cached_format
*cache
)
305 switch (cache
->format
)
310 DeleteObject( cache
->handle
);
313 case CF_DSPENHMETAFILE
:
314 DeleteEnhMetaFile( cache
->handle
);
316 case CF_METAFILEPICT
:
317 case CF_DSPMETAFILEPICT
:
318 if ((ptr
= GlobalLock( cache
->handle
)))
320 DeleteMetaFile( ((METAFILEPICT
*)ptr
)->hMF
);
321 GlobalUnlock( cache
->handle
);
323 GlobalFree( cache
->handle
);
326 GlobalFree( cache
->handle
);
329 list_remove( &cache
->entry
);
330 HeapFree( GetProcessHeap(), 0, cache
);
333 /* clear global memory formats; special types are freed on EmptyClipboard */
334 static void invalidate_memory_formats(void)
336 struct cached_format
*cache
, *next
;
338 LIST_FOR_EACH_ENTRY_SAFE( cache
, next
, &cached_formats
, struct cached_format
, entry
)
340 switch (cache
->format
)
346 case CF_DSPENHMETAFILE
:
347 case CF_METAFILEPICT
:
348 case CF_DSPMETAFILEPICT
:
351 free_cached_data( cache
);
357 /* free all the data in the cache */
358 static void free_cached_formats(void)
362 list_move_tail( &formats_to_free
, &cached_formats
);
363 while ((ptr
= list_head( &formats_to_free
)))
364 free_cached_data( LIST_ENTRY( ptr
, struct cached_format
, entry
));
367 /* get the clipboard locale stored in the CF_LOCALE format */
368 static LCID
get_clipboard_locale(void)
371 LCID lcid
= GetUserDefaultLCID();
373 if ((data
= GetClipboardData( CF_LOCALE
)))
375 LCID
*ptr
= GlobalLock( data
);
378 if (GlobalSize( data
) >= sizeof(*ptr
)) lcid
= *ptr
;
379 GlobalUnlock( data
);
385 /* get the codepage to use for text conversions in the specified format (CF_TEXT or CF_OEMTEXT) */
386 static UINT
get_format_codepage( LCID lcid
, UINT format
)
388 LCTYPE type
= (format
== CF_TEXT
) ? LOCALE_IDEFAULTANSICODEPAGE
: LOCALE_IDEFAULTCODEPAGE
;
391 if (!GetLocaleInfoW( lcid
, type
| LOCALE_RETURN_NUMBER
, (LPWSTR
)&ret
, sizeof(ret
)/sizeof(WCHAR
) ))
392 ret
= (format
== CF_TEXT
) ? CP_ACP
: CP_OEMCP
;
396 /* render synthesized ANSI text based on the contents of the 'from' format */
397 static HANDLE
render_synthesized_textA( HANDLE data
, UINT format
, UINT from
)
402 LCID lcid
= get_clipboard_locale();
403 UINT codepage
= get_format_codepage( lcid
, format
);
404 UINT len
, size
= GlobalSize( data
);
406 if (!(src
= GlobalLock( data
))) return 0;
408 if (from
!= CF_UNICODETEXT
) /* first convert incoming format to Unicode */
410 UINT from_codepage
= get_format_codepage( lcid
, from
);
411 len
= MultiByteToWideChar( from_codepage
, 0, src
, size
, NULL
, 0 );
412 if (!(srcW
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) ))) goto done
;
413 MultiByteToWideChar( from_codepage
, 0, src
, size
, srcW
, len
);
415 size
= len
* sizeof(WCHAR
);
418 if ((len
= WideCharToMultiByte( codepage
, 0, src
, size
/ sizeof(WCHAR
), NULL
, 0, NULL
, NULL
)))
420 if ((ret
= GlobalAlloc( GMEM_FIXED
, len
)))
421 WideCharToMultiByte( codepage
, 0, src
, size
/ sizeof(WCHAR
), ret
, len
, NULL
, NULL
);
425 HeapFree( GetProcessHeap(), 0, srcW
);
426 GlobalUnlock( data
);
430 /* render synthesized Unicode text based on the contents of the 'from' format */
431 static HANDLE
render_synthesized_textW( HANDLE data
, UINT from
)
435 UINT len
, size
= GlobalSize( data
);
436 UINT codepage
= get_format_codepage( get_clipboard_locale(), from
);
438 if (!(src
= GlobalLock( data
))) return 0;
440 if ((len
= MultiByteToWideChar( codepage
, 0, src
, size
, NULL
, 0 )))
442 if ((ret
= GlobalAlloc( GMEM_FIXED
, len
* sizeof(WCHAR
) )))
443 MultiByteToWideChar( codepage
, 0, src
, size
, ret
, len
);
445 GlobalUnlock( data
);
449 /* render a synthesized bitmap based on the DIB clipboard data */
450 static HANDLE
render_synthesized_bitmap( HANDLE data
, UINT from
)
454 HDC hdc
= GetDC( 0 );
456 if ((bmi
= GlobalLock( data
)))
458 /* FIXME: validate data size */
459 ret
= CreateDIBitmap( hdc
, &bmi
->bmiHeader
, CBM_INIT
,
460 (char *)bmi
+ bitmap_info_size( bmi
, DIB_RGB_COLORS
),
461 bmi
, DIB_RGB_COLORS
);
462 GlobalUnlock( data
);
468 /* render a synthesized DIB based on the clipboard data */
469 static HANDLE
render_synthesized_dib( HANDLE data
, UINT format
, UINT from
)
471 BITMAPINFO
*bmi
, *src
;
472 DWORD src_size
, header_size
, bits_size
;
474 HDC hdc
= GetDC( 0 );
476 if (from
== CF_BITMAP
)
478 BITMAPV5HEADER header
;
480 memset( &header
, 0, sizeof(header
) );
481 header
.bV5Size
= (format
== CF_DIBV5
) ? sizeof(BITMAPV5HEADER
) : sizeof(BITMAPINFOHEADER
);
482 if (!GetDIBits( hdc
, data
, 0, 0, NULL
, (BITMAPINFO
*)&header
, DIB_RGB_COLORS
)) goto done
;
484 header_size
= bitmap_info_size( (BITMAPINFO
*)&header
, DIB_RGB_COLORS
);
485 if (!(ret
= GlobalAlloc( GMEM_FIXED
, header_size
+ header
.bV5SizeImage
))) goto done
;
486 bmi
= (BITMAPINFO
*)ret
;
487 memset( bmi
, 0, header_size
);
488 memcpy( bmi
, &header
, header
.bV5Size
);
489 GetDIBits( hdc
, data
, 0, abs(header
.bV5Height
), (char *)bmi
+ header_size
, bmi
, DIB_RGB_COLORS
);
493 SIZE_T size
= GlobalSize( data
);
495 if (size
< sizeof(*bmi
)) goto done
;
496 if (!(src
= GlobalLock( data
))) goto done
;
498 src_size
= bitmap_info_size( src
, DIB_RGB_COLORS
);
499 if (size
<= src_size
)
501 GlobalUnlock( data
);
504 bits_size
= size
- src_size
;
505 header_size
= (format
== CF_DIBV5
) ? sizeof(BITMAPV5HEADER
) :
506 offsetof( BITMAPINFO
, bmiColors
[src
->bmiHeader
.biCompression
== BI_BITFIELDS
? 3 : 0] );
508 if ((ret
= GlobalAlloc( GMEM_FIXED
, header_size
+ bits_size
)))
510 bmi
= (BITMAPINFO
*)ret
;
511 memset( bmi
, 0, header_size
);
512 memcpy( bmi
, src
, min( header_size
, src_size
));
513 bmi
->bmiHeader
.biSize
= header_size
;
514 /* FIXME: convert colors according to DIBv5 color profile */
515 memcpy( (char *)bmi
+ header_size
, (char *)src
+ src_size
, bits_size
);
517 GlobalUnlock( data
);
525 /* render a synthesized metafile based on the enhmetafile clipboard data */
526 static HANDLE
render_synthesized_metafile( HANDLE data
)
532 ENHMETAHEADER header
;
533 HDC hdc
= GetDC( 0 );
535 size
= GetWinMetaFileBits( data
, 0, NULL
, MM_ISOTROPIC
, hdc
);
536 if ((bits
= HeapAlloc( GetProcessHeap(), 0, size
)))
538 if (GetEnhMetaFileHeader( data
, sizeof(header
), &header
) &&
539 GetWinMetaFileBits( data
, size
, bits
, MM_ISOTROPIC
, hdc
))
541 if ((ret
= GlobalAlloc( GMEM_FIXED
, sizeof(*pict
) )))
543 pict
= (METAFILEPICT
*)ret
;
544 pict
->mm
= MM_ISOTROPIC
;
545 pict
->xExt
= header
.rclFrame
.right
- header
.rclFrame
.left
;
546 pict
->yExt
= header
.rclFrame
.bottom
- header
.rclFrame
.top
;
547 pict
->hMF
= SetMetaFileBitsEx( size
, bits
);
550 HeapFree( GetProcessHeap(), 0, bits
);
556 /* render a synthesized enhmetafile based on the metafile clipboard data */
557 static HANDLE
render_synthesized_enhmetafile( HANDLE data
)
564 if (!(pict
= GlobalLock( data
))) return 0;
566 size
= GetMetaFileBitsEx( pict
->hMF
, 0, NULL
);
567 if ((bits
= HeapAlloc( GetProcessHeap(), 0, size
)))
569 GetMetaFileBitsEx( pict
->hMF
, size
, bits
);
570 ret
= SetWinMetaFileBits( size
, bits
, NULL
, pict
);
571 HeapFree( GetProcessHeap(), 0, bits
);
574 GlobalUnlock( data
);
578 /* render a synthesized format */
579 static HANDLE
render_synthesized_format( UINT format
, UINT from
)
581 HANDLE data
= GetClipboardData( from
);
584 TRACE( "rendering %s from %s\n", debugstr_format( format
), debugstr_format( from
));
590 data
= render_synthesized_textA( data
, format
, from
);
593 data
= render_synthesized_textW( data
, from
);
596 data
= render_synthesized_bitmap( data
, from
);
600 data
= render_synthesized_dib( data
, format
, from
);
602 case CF_METAFILEPICT
:
603 data
= render_synthesized_metafile( data
);
606 data
= render_synthesized_enhmetafile( data
);
613 TRACE( "adding %s %p\n", debugstr_format( format
), data
);
614 SetClipboardData( format
, data
);
619 /**************************************************************************
620 * CLIPBOARD_ReleaseOwner
622 void CLIPBOARD_ReleaseOwner( HWND hwnd
)
624 HWND viewer
= 0, owner
= 0;
626 SendMessageW( hwnd
, WM_RENDERALLFORMATS
, 0, 0 );
628 SERVER_START_REQ( release_clipboard
)
630 req
->owner
= wine_server_user_handle( hwnd
);
631 if (!wine_server_call( req
))
633 viewer
= wine_server_ptr_handle( reply
->viewer
);
634 owner
= wine_server_ptr_handle( reply
->owner
);
639 if (viewer
) SendNotifyMessageW( viewer
, WM_DRAWCLIPBOARD
, (WPARAM
)owner
, 0 );
643 /**************************************************************************
644 * RegisterClipboardFormatW (USER32.@)
646 UINT WINAPI
RegisterClipboardFormatW( LPCWSTR name
)
648 return GlobalAddAtomW( name
);
652 /**************************************************************************
653 * RegisterClipboardFormatA (USER32.@)
655 UINT WINAPI
RegisterClipboardFormatA( LPCSTR name
)
657 return GlobalAddAtomA( name
);
661 /**************************************************************************
662 * GetClipboardFormatNameA (USER32.@)
664 INT WINAPI
GetClipboardFormatNameA( UINT format
, LPSTR buffer
, INT maxlen
)
666 if (format
< MAXINTATOM
|| format
> 0xffff) return 0;
667 return GlobalGetAtomNameA( format
, buffer
, maxlen
);
671 /**************************************************************************
672 * OpenClipboard (USER32.@)
674 BOOL WINAPI
OpenClipboard( HWND hwnd
)
679 TRACE( "%p\n", hwnd
);
681 USER_Driver
->pUpdateClipboard();
683 EnterCriticalSection( &clipboard_cs
);
685 SERVER_START_REQ( open_clipboard
)
687 req
->window
= wine_server_user_handle( hwnd
);
688 ret
= !wine_server_call_err( req
);
689 owner
= wine_server_ptr_handle( reply
->owner
);
693 if (ret
&& !WIN_IsCurrentProcess( owner
)) invalidate_memory_formats();
695 LeaveCriticalSection( &clipboard_cs
);
700 /**************************************************************************
701 * CloseClipboard (USER32.@)
703 BOOL WINAPI
CloseClipboard(void)
705 HWND viewer
= 0, owner
= 0;
710 SERVER_START_REQ( close_clipboard
)
712 if ((ret
= !wine_server_call_err( req
)))
714 viewer
= wine_server_ptr_handle( reply
->viewer
);
715 owner
= wine_server_ptr_handle( reply
->owner
);
720 if (viewer
) SendNotifyMessageW( viewer
, WM_DRAWCLIPBOARD
, (WPARAM
)owner
, 0 );
725 /**************************************************************************
726 * EmptyClipboard (USER32.@)
727 * Empties and acquires ownership of the clipboard
729 BOOL WINAPI
EmptyClipboard(void)
732 HWND owner
= NtUserGetClipboardOwner();
734 TRACE( "owner %p\n", owner
);
736 if (owner
) SendMessageTimeoutW( owner
, WM_DESTROYCLIPBOARD
, 0, 0, SMTO_ABORTIFHUNG
, 5000, NULL
);
738 EnterCriticalSection( &clipboard_cs
);
740 SERVER_START_REQ( empty_clipboard
)
742 ret
= !wine_server_call_err( req
);
746 if (ret
) free_cached_formats();
748 LeaveCriticalSection( &clipboard_cs
);
753 /**************************************************************************
754 * SetClipboardViewer (USER32.@)
756 HWND WINAPI
SetClipboardViewer( HWND hwnd
)
758 HWND prev
= 0, owner
= 0;
760 SERVER_START_REQ( set_clipboard_viewer
)
762 req
->viewer
= wine_server_user_handle( hwnd
);
763 if (!wine_server_call_err( req
))
765 prev
= wine_server_ptr_handle( reply
->old_viewer
);
766 owner
= wine_server_ptr_handle( reply
->owner
);
771 if (hwnd
) SendNotifyMessageW( hwnd
, WM_DRAWCLIPBOARD
, (WPARAM
)owner
, 0 );
773 TRACE( "%p returning %p\n", hwnd
, prev
);
778 /**************************************************************************
779 * ChangeClipboardChain (USER32.@)
781 BOOL WINAPI
ChangeClipboardChain( HWND hwnd
, HWND next
)
786 if (!hwnd
) return FALSE
;
788 SERVER_START_REQ( set_clipboard_viewer
)
790 req
->viewer
= wine_server_user_handle( next
);
791 req
->previous
= wine_server_user_handle( hwnd
);
792 status
= wine_server_call( req
);
793 viewer
= wine_server_ptr_handle( reply
->old_viewer
);
797 if (status
== STATUS_PENDING
)
798 return !SendMessageW( viewer
, WM_CHANGECBCHAIN
, (WPARAM
)hwnd
, (LPARAM
)next
);
800 if (status
) SetLastError( RtlNtStatusToDosError( status
));
805 /**************************************************************************
806 * SetClipboardData (USER32.@)
808 HANDLE WINAPI
SetClipboardData( UINT format
, HANDLE data
)
810 struct cached_format
*cache
= NULL
;
812 data_size_t size
= 0;
813 HANDLE handle
= data
, retval
= 0;
814 NTSTATUS status
= STATUS_SUCCESS
;
816 TRACE( "%s %p\n", debugstr_format( format
), data
);
820 if (!(handle
= marshal_data( format
, data
, &size
))) return 0;
821 if (!(ptr
= GlobalLock( handle
))) goto done
;
822 if (!(cache
= HeapAlloc( GetProcessHeap(), 0, sizeof(*cache
) ))) goto done
;
823 cache
->format
= format
;
824 cache
->handle
= data
;
827 EnterCriticalSection( &clipboard_cs
);
829 SERVER_START_REQ( set_clipboard_data
)
831 req
->format
= format
;
832 req
->lcid
= GetUserDefaultLCID();
833 wine_server_add_data( req
, ptr
, size
);
834 if (!(status
= wine_server_call( req
)))
836 if (cache
) cache
->seqno
= reply
->seqno
;
843 /* free the previous entry if any */
844 struct cached_format
*prev
;
846 if ((prev
= get_cached_format( format
))) free_cached_data( prev
);
847 if (cache
) list_add_tail( &cached_formats
, &cache
->entry
);
850 else HeapFree( GetProcessHeap(), 0, cache
);
852 LeaveCriticalSection( &clipboard_cs
);
855 if (ptr
) GlobalUnlock( handle
);
856 if (handle
!= data
) GlobalFree( handle
);
857 if (status
) SetLastError( RtlNtStatusToDosError( status
));
862 /**************************************************************************
863 * EnumClipboardFormats (USER32.@)
865 UINT WINAPI
EnumClipboardFormats( UINT format
)
869 SERVER_START_REQ( enum_clipboard_formats
)
871 req
->previous
= format
;
872 if (!wine_server_call_err( req
))
875 SetLastError( ERROR_SUCCESS
);
880 TRACE( "%s -> %s\n", debugstr_format( format
), debugstr_format( ret
));
885 /**************************************************************************
886 * GetClipboardData (USER32.@)
888 HANDLE WINAPI
GetClipboardData( UINT format
)
890 struct cached_format
*cache
;
892 UINT from
, data_seqno
;
900 if (!(data
= GlobalAlloc( GMEM_FIXED
, size
))) return 0;
902 EnterCriticalSection( &clipboard_cs
);
903 cache
= get_cached_format( format
);
905 SERVER_START_REQ( get_clipboard_data
)
907 req
->format
= format
;
908 req
->render
= render
;
912 req
->seqno
= cache
->seqno
;
914 wine_server_set_reply( req
, data
, size
);
915 status
= wine_server_call( req
);
918 data_seqno
= reply
->seqno
;
919 owner
= wine_server_ptr_handle( reply
->owner
);
925 data
= cache_data( format
, data
, size
, data_seqno
, cache
);
926 LeaveCriticalSection( &clipboard_cs
);
927 TRACE( "%s returning %p\n", debugstr_format( format
), data
);
930 LeaveCriticalSection( &clipboard_cs
);
933 if (status
== STATUS_BUFFER_OVERFLOW
) continue; /* retry with the new size */
934 if (status
== STATUS_OBJECT_NAME_NOT_FOUND
) return 0; /* no such format */
937 SetLastError( RtlNtStatusToDosError( status
));
938 TRACE( "%s error %08x\n", debugstr_format( format
), status
);
941 if (render
) /* try rendering it */
946 render_synthesized_format( format
, from
);
951 TRACE( "%s sending WM_RENDERFORMAT to %p\n", debugstr_format( format
), owner
);
952 SendMessageW( owner
, WM_RENDERFORMAT
, format
, 0 );
956 TRACE( "%s returning 0\n", debugstr_format( format
));