ucrtbase: Add support for r-value demangling in unDName.
[wine.git] / dlls / user32 / clipboard.c
blobffeb03d443579b53d726d82f60aa366656cd68b9
1 /*
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
26 #include <assert.h>
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #include <sys/types.h>
30 #include <fcntl.h>
31 #include <string.h>
33 #include "ntstatus.h"
34 #define WIN32_NO_STATUS
35 #include "windef.h"
36 #include "winbase.h"
37 #include "winnls.h"
38 #include "wingdi.h"
39 #include "winuser.h"
40 #include "winerror.h"
41 #include "user_private.h"
42 #include "win.h"
44 #include "wine/list.h"
45 #include "wine/server.h"
46 #include "wine/debug.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(clipboard);
51 struct cached_format
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 =
65 0, 0, &clipboard_cs,
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 */
72 struct metafile_pict
74 LONG mm;
75 LONG xExt;
76 LONG yExt;
77 BYTE bits[1];
80 /* get a debug string for a format id */
81 static const char *debugstr_format( UINT id )
83 WCHAR buffer[256];
84 DWORD le = GetLastError();
85 BOOL r = NtUserGetClipboardFormatName( id, buffer, 256 );
86 SetLastError(le);
88 if (r)
89 return wine_dbg_sprintf( "%04x %s", id, debugstr_w(buffer) );
91 switch (id)
93 #define BUILTIN(id) case id: return #id;
94 BUILTIN(CF_TEXT)
95 BUILTIN(CF_BITMAP)
96 BUILTIN(CF_METAFILEPICT)
97 BUILTIN(CF_SYLK)
98 BUILTIN(CF_DIF)
99 BUILTIN(CF_TIFF)
100 BUILTIN(CF_OEMTEXT)
101 BUILTIN(CF_DIB)
102 BUILTIN(CF_PALETTE)
103 BUILTIN(CF_PENDATA)
104 BUILTIN(CF_RIFF)
105 BUILTIN(CF_WAVE)
106 BUILTIN(CF_UNICODETEXT)
107 BUILTIN(CF_ENHMETAFILE)
108 BUILTIN(CF_HDROP)
109 BUILTIN(CF_LOCALE)
110 BUILTIN(CF_DIBV5)
111 BUILTIN(CF_OWNERDISPLAY)
112 BUILTIN(CF_DSPTEXT)
113 BUILTIN(CF_DSPBITMAP)
114 BUILTIN(CF_DSPMETAFILEPICT)
115 BUILTIN(CF_DSPENHMETAFILE)
116 #undef BUILTIN
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 )
124 SIZE_T size;
126 switch (format)
128 case CF_BITMAP:
129 case CF_DSPBITMAP:
131 BITMAP bitmap, *bm;
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;
136 *bm = bitmap;
137 GetBitmapBits( handle, size, bm + 1 );
138 return bm;
140 case CF_PALETTE:
142 LOGPALETTE *pal;
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 );
149 return pal;
151 case CF_ENHMETAFILE:
152 case CF_DSPENHMETAFILE:
154 BYTE *ret;
155 if (!(size = GetEnhMetaFileBits( handle, 0, NULL ))) return 0;
156 if (!(ret = GlobalAlloc( GMEM_FIXED, size ))) return 0;
157 GetEnhMetaFileBits( handle, size, ret );
158 *ret_size = size;
159 return ret;
161 case CF_METAFILEPICT:
162 case CF_DSPMETAFILEPICT:
164 METAFILEPICT *mf;
165 struct metafile_pict *mfbits;
166 if (!(mf = GlobalLock( handle ))) return 0;
167 if (!(size = GetMetaFileBitsEx( mf->hMF, 0, NULL )))
169 GlobalUnlock( handle );
170 return 0;
172 *ret_size = offsetof( struct metafile_pict, bits[size] );
173 if (!(mfbits = GlobalAlloc( GMEM_FIXED, *ret_size )))
175 GlobalUnlock( handle );
176 return 0;
178 mfbits->mm = mf->mm;
179 mfbits->xExt = mf->xExt;
180 mfbits->yExt = mf->yExt;
181 GetMetaFileBitsEx( mf->hMF, size, mfbits->bits );
182 GlobalUnlock( handle );
183 return mfbits;
185 case CF_UNICODETEXT:
187 WCHAR *ptr;
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 );
193 *ret_size = size;
194 return handle;
196 case CF_TEXT:
197 case CF_OEMTEXT:
199 char *ptr;
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 );
205 *ret_size = size;
206 return handle;
208 default:
209 if (!(size = GlobalSize( handle ))) return 0;
210 if ((data_size_t)size != size) return 0;
211 *ret_size = size;
212 return handle;
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 */
221 switch (format)
223 case CF_BITMAP:
225 BITMAP *bm = handle;
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 */
229 bm->bmBits = bm + 1;
230 return CreateBitmapIndirect( bm );
232 case CF_DSPBITMAP: /* not supported across processes */
233 break;
234 case CF_PALETTE:
236 LOGPALETTE *pal = handle;
237 if (size < sizeof(*pal)) break;
238 if (size < offsetof( LOGPALETTE, palPalEntry[pal->palNumEntries] )) break;
239 return CreatePalette( pal );
241 case CF_ENHMETAFILE:
242 case CF_DSPENHMETAFILE:
243 return SetEnhMetaFileBits( size, handle );
244 case CF_METAFILEPICT:
245 case CF_DSPMETAFILEPICT:
247 METAFILEPICT mf;
248 struct metafile_pict *mfbits = handle;
249 if (size <= sizeof(*mfbits)) break;
250 mf.mm = mfbits->mm;
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;
255 return handle;
258 return handle;
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;
268 return NULL;
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 )
275 if (cache)
277 if (seqno == cache->seqno) /* we can reuse the cached data */
279 GlobalFree( 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) )))
290 GlobalFree( data );
291 return 0;
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 )
303 void *ptr;
305 switch (cache->format)
307 case CF_BITMAP:
308 case CF_DSPBITMAP:
309 case CF_PALETTE:
310 DeleteObject( cache->handle );
311 break;
312 case CF_ENHMETAFILE:
313 case CF_DSPENHMETAFILE:
314 DeleteEnhMetaFile( cache->handle );
315 break;
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 );
324 break;
325 default:
326 GlobalFree( cache->handle );
327 break;
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)
342 case CF_BITMAP:
343 case CF_DSPBITMAP:
344 case CF_PALETTE:
345 case CF_ENHMETAFILE:
346 case CF_DSPENHMETAFILE:
347 case CF_METAFILEPICT:
348 case CF_DSPMETAFILEPICT:
349 continue;
350 default:
351 free_cached_data( cache );
352 break;
357 /* free all the data in the cache */
358 static void free_cached_formats(void)
360 struct list *ptr;
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)
370 HANDLE data;
371 LCID lcid = GetUserDefaultLCID();
373 if ((data = GetClipboardData( CF_LOCALE )))
375 LCID *ptr = GlobalLock( data );
376 if (ptr)
378 if (GlobalSize( data ) >= sizeof(*ptr)) lcid = *ptr;
379 GlobalUnlock( data );
382 return lcid;
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;
389 UINT ret;
391 if (!GetLocaleInfoW( lcid, type | LOCALE_RETURN_NUMBER, (LPWSTR)&ret, sizeof(ret)/sizeof(WCHAR) ))
392 ret = (format == CF_TEXT) ? CP_ACP : CP_OEMCP;
393 return ret;
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 )
399 void *src;
400 WCHAR *srcW = NULL;
401 HANDLE ret = 0;
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 );
414 src = srcW;
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 );
424 done:
425 HeapFree( GetProcessHeap(), 0, srcW );
426 GlobalUnlock( data );
427 return ret;
430 /* render synthesized Unicode text based on the contents of the 'from' format */
431 static HANDLE render_synthesized_textW( HANDLE data, UINT from )
433 char *src;
434 HANDLE ret = 0;
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 );
446 return ret;
449 /* render a synthesized bitmap based on the DIB clipboard data */
450 static HANDLE render_synthesized_bitmap( HANDLE data, UINT from )
452 BITMAPINFO *bmi;
453 HANDLE ret = 0;
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 );
464 ReleaseDC( 0, hdc );
465 return ret;
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;
473 HANDLE ret = 0;
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 );
491 else
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 );
502 goto done;
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 );
520 done:
521 ReleaseDC( 0, hdc );
522 return ret;
525 /* render a synthesized metafile based on the enhmetafile clipboard data */
526 static HANDLE render_synthesized_metafile( HANDLE data )
528 HANDLE ret = 0;
529 UINT size;
530 void *bits;
531 METAFILEPICT *pict;
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 );
552 ReleaseDC( 0, hdc );
553 return ret;
556 /* render a synthesized enhmetafile based on the metafile clipboard data */
557 static HANDLE render_synthesized_enhmetafile( HANDLE data )
559 METAFILEPICT *pict;
560 HANDLE ret = 0;
561 UINT size;
562 void *bits;
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 );
575 return ret;
578 /* render a synthesized format */
579 static HANDLE render_synthesized_format( UINT format, UINT from )
581 HANDLE data = GetClipboardData( from );
583 if (!data) return 0;
584 TRACE( "rendering %s from %s\n", debugstr_format( format ), debugstr_format( from ));
586 switch (format)
588 case CF_TEXT:
589 case CF_OEMTEXT:
590 data = render_synthesized_textA( data, format, from );
591 break;
592 case CF_UNICODETEXT:
593 data = render_synthesized_textW( data, from );
594 break;
595 case CF_BITMAP:
596 data = render_synthesized_bitmap( data, from );
597 break;
598 case CF_DIB:
599 case CF_DIBV5:
600 data = render_synthesized_dib( data, format, from );
601 break;
602 case CF_METAFILEPICT:
603 data = render_synthesized_metafile( data );
604 break;
605 case CF_ENHMETAFILE:
606 data = render_synthesized_enhmetafile( data );
607 break;
608 default:
609 assert( 0 );
611 if (data)
613 TRACE( "adding %s %p\n", debugstr_format( format ), data );
614 SetClipboardData( format, data );
616 return 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 );
637 SERVER_END_REQ;
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 )
676 BOOL ret;
677 HWND owner;
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 );
691 SERVER_END_REQ;
693 if (ret && !WIN_IsCurrentProcess( owner )) invalidate_memory_formats();
695 LeaveCriticalSection( &clipboard_cs );
696 return ret;
700 /**************************************************************************
701 * CloseClipboard (USER32.@)
703 BOOL WINAPI CloseClipboard(void)
705 HWND viewer = 0, owner = 0;
706 BOOL ret;
708 TRACE( "\n" );
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 );
718 SERVER_END_REQ;
720 if (viewer) SendNotifyMessageW( viewer, WM_DRAWCLIPBOARD, (WPARAM)owner, 0 );
721 return ret;
725 /**************************************************************************
726 * EmptyClipboard (USER32.@)
727 * Empties and acquires ownership of the clipboard
729 BOOL WINAPI EmptyClipboard(void)
731 BOOL ret;
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 );
744 SERVER_END_REQ;
746 if (ret) free_cached_formats();
748 LeaveCriticalSection( &clipboard_cs );
749 return ret;
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 );
769 SERVER_END_REQ;
771 if (hwnd) SendNotifyMessageW( hwnd, WM_DRAWCLIPBOARD, (WPARAM)owner, 0 );
773 TRACE( "%p returning %p\n", hwnd, prev );
774 return prev;
778 /**************************************************************************
779 * ChangeClipboardChain (USER32.@)
781 BOOL WINAPI ChangeClipboardChain( HWND hwnd, HWND next )
783 NTSTATUS status;
784 HWND viewer;
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 );
795 SERVER_END_REQ;
797 if (status == STATUS_PENDING)
798 return !SendMessageW( viewer, WM_CHANGECBCHAIN, (WPARAM)hwnd, (LPARAM)next );
800 if (status) SetLastError( RtlNtStatusToDosError( status ));
801 return !status;
805 /**************************************************************************
806 * SetClipboardData (USER32.@)
808 HANDLE WINAPI SetClipboardData( UINT format, HANDLE data )
810 struct cached_format *cache = NULL;
811 void *ptr = 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 );
818 if (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;
839 SERVER_END_REQ;
841 if (!status)
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 );
848 retval = data;
850 else HeapFree( GetProcessHeap(), 0, cache );
852 LeaveCriticalSection( &clipboard_cs );
854 done:
855 if (ptr) GlobalUnlock( handle );
856 if (handle != data) GlobalFree( handle );
857 if (status) SetLastError( RtlNtStatusToDosError( status ));
858 return retval;
862 /**************************************************************************
863 * EnumClipboardFormats (USER32.@)
865 UINT WINAPI EnumClipboardFormats( UINT format )
867 UINT ret = 0;
869 SERVER_START_REQ( enum_clipboard_formats )
871 req->previous = format;
872 if (!wine_server_call_err( req ))
874 ret = reply->format;
875 SetLastError( ERROR_SUCCESS );
878 SERVER_END_REQ;
880 TRACE( "%s -> %s\n", debugstr_format( format ), debugstr_format( ret ));
881 return ret;
885 /**************************************************************************
886 * GetClipboardData (USER32.@)
888 HANDLE WINAPI GetClipboardData( UINT format )
890 struct cached_format *cache;
891 NTSTATUS status;
892 UINT from, data_seqno;
893 HWND owner;
894 HANDLE data;
895 UINT size = 1024;
896 BOOL render = TRUE;
898 for (;;)
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;
909 if (cache)
911 req->cached = 1;
912 req->seqno = cache->seqno;
914 wine_server_set_reply( req, data, size );
915 status = wine_server_call( req );
916 from = reply->from;
917 size = reply->total;
918 data_seqno = reply->seqno;
919 owner = wine_server_ptr_handle( reply->owner );
921 SERVER_END_REQ;
923 if (!status && size)
925 data = cache_data( format, data, size, data_seqno, cache );
926 LeaveCriticalSection( &clipboard_cs );
927 TRACE( "%s returning %p\n", debugstr_format( format ), data );
928 return data;
930 LeaveCriticalSection( &clipboard_cs );
931 GlobalFree( data );
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 */
935 if (status)
937 SetLastError( RtlNtStatusToDosError( status ));
938 TRACE( "%s error %08x\n", debugstr_format( format ), status );
939 return 0;
941 if (render) /* try rendering it */
943 render = FALSE;
944 if (from)
946 render_synthesized_format( format, from );
947 continue;
949 else if (owner)
951 TRACE( "%s sending WM_RENDERFORMAT to %p\n", debugstr_format( format ), owner );
952 SendMessageW( owner, WM_RENDERFORMAT, format, 0 );
953 continue;
956 TRACE( "%s returning 0\n", debugstr_format( format ));
957 return 0;