user32/tests: Add tests for disabled buttons receiving WM_LBUTTONUP.
[wine.git] / dlls / user32 / clipboard.c
blobd33459c00cc55974da081ab097dd53337a0f2c26
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 "config.h"
27 #include "wine/port.h"
29 #include <assert.h>
30 #include <stdarg.h>
31 #include <stdlib.h>
32 #include <sys/types.h>
33 #include <fcntl.h>
34 #ifdef HAVE_UNISTD_H
35 # include <unistd.h>
36 #endif
37 #include <string.h>
39 #include "ntstatus.h"
40 #define WIN32_NO_STATUS
41 #include "windef.h"
42 #include "winbase.h"
43 #include "wingdi.h"
44 #include "winuser.h"
45 #include "winerror.h"
46 #include "user_private.h"
47 #include "win.h"
49 #include "wine/list.h"
50 #include "wine/unicode.h"
51 #include "wine/server.h"
52 #include "wine/debug.h"
54 WINE_DEFAULT_DEBUG_CHANNEL(clipboard);
57 struct cached_format
59 struct list entry; /* entry in cache list */
60 UINT format; /* format id */
61 UINT seqno; /* sequence number when the data was set */
62 HANDLE handle; /* original data handle */
65 static struct list cached_formats = LIST_INIT( cached_formats );
66 static struct list formats_to_free = LIST_INIT( formats_to_free );
68 static CRITICAL_SECTION clipboard_cs;
69 static CRITICAL_SECTION_DEBUG critsect_debug =
71 0, 0, &clipboard_cs,
72 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
73 0, 0, { (DWORD_PTR)(__FILE__ ": clipboard_cs") }
75 static CRITICAL_SECTION clipboard_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
77 /* platform-independent version of METAFILEPICT */
78 struct metafile_pict
80 LONG mm;
81 LONG xExt;
82 LONG yExt;
83 BYTE bits[1];
86 /* get a debug string for a format id */
87 static const char *debugstr_format( UINT id )
89 WCHAR buffer[256];
91 if (GetClipboardFormatNameW( id, buffer, 256 ))
92 return wine_dbg_sprintf( "%04x %s", id, debugstr_w(buffer) );
94 switch (id)
96 #define BUILTIN(id) case id: return #id;
97 BUILTIN(CF_TEXT)
98 BUILTIN(CF_BITMAP)
99 BUILTIN(CF_METAFILEPICT)
100 BUILTIN(CF_SYLK)
101 BUILTIN(CF_DIF)
102 BUILTIN(CF_TIFF)
103 BUILTIN(CF_OEMTEXT)
104 BUILTIN(CF_DIB)
105 BUILTIN(CF_PALETTE)
106 BUILTIN(CF_PENDATA)
107 BUILTIN(CF_RIFF)
108 BUILTIN(CF_WAVE)
109 BUILTIN(CF_UNICODETEXT)
110 BUILTIN(CF_ENHMETAFILE)
111 BUILTIN(CF_HDROP)
112 BUILTIN(CF_LOCALE)
113 BUILTIN(CF_DIBV5)
114 BUILTIN(CF_OWNERDISPLAY)
115 BUILTIN(CF_DSPTEXT)
116 BUILTIN(CF_DSPBITMAP)
117 BUILTIN(CF_DSPMETAFILEPICT)
118 BUILTIN(CF_DSPENHMETAFILE)
119 #undef BUILTIN
120 default: return wine_dbg_sprintf( "%04x", id );
124 /* build the data to send to the server in SetClipboardData */
125 static HANDLE marshal_data( UINT format, HANDLE handle, data_size_t *ret_size )
127 SIZE_T size;
129 switch (format)
131 case CF_BITMAP:
132 case CF_DSPBITMAP:
134 BITMAP bitmap, *bm;
135 if (!GetObjectW( handle, sizeof(bitmap), &bitmap )) return 0;
136 size = abs( bitmap.bmHeight ) * ((((bitmap.bmWidth * bitmap.bmBitsPixel) + 15) >> 3) & ~1);
137 *ret_size = sizeof(bitmap) + size;
138 if (!(bm = GlobalAlloc( GMEM_FIXED, *ret_size ))) return 0;
139 *bm = bitmap;
140 GetBitmapBits( handle, size, bm + 1 );
141 return bm;
143 case CF_PALETTE:
145 LOGPALETTE *pal;
146 if (!(size = GetPaletteEntries( handle, 0, 0, NULL ))) return 0;
147 *ret_size = offsetof( LOGPALETTE, palPalEntry[size] );
148 if (!(pal = GlobalAlloc( GMEM_FIXED, *ret_size ))) return 0;
149 pal->palVersion = 0x300;
150 pal->palNumEntries = size;
151 GetPaletteEntries( handle, 0, size, pal->palPalEntry );
152 return pal;
154 case CF_ENHMETAFILE:
155 case CF_DSPENHMETAFILE:
157 BYTE *ret;
158 if (!(size = GetEnhMetaFileBits( handle, 0, NULL ))) return 0;
159 if (!(ret = GlobalAlloc( GMEM_FIXED, size ))) return 0;
160 GetEnhMetaFileBits( handle, size, ret );
161 *ret_size = size;
162 return ret;
164 case CF_METAFILEPICT:
165 case CF_DSPMETAFILEPICT:
167 METAFILEPICT *mf;
168 struct metafile_pict *mfbits;
169 if (!(mf = GlobalLock( handle ))) return 0;
170 if (!(size = GetMetaFileBitsEx( mf->hMF, 0, NULL )))
172 GlobalUnlock( handle );
173 return 0;
175 *ret_size = offsetof( struct metafile_pict, bits[size] );
176 if (!(mfbits = GlobalAlloc( GMEM_FIXED, *ret_size )))
178 GlobalUnlock( handle );
179 return 0;
181 mfbits->mm = mf->mm;
182 mfbits->xExt = mf->xExt;
183 mfbits->yExt = mf->yExt;
184 GetMetaFileBitsEx( mf->hMF, size, mfbits->bits );
185 GlobalUnlock( handle );
186 return mfbits;
188 case CF_UNICODETEXT:
190 WCHAR *ptr;
191 if (!(size = GlobalSize( handle ))) return 0;
192 if ((data_size_t)size != size) return 0;
193 if (!(ptr = GlobalLock( handle ))) return 0;
194 ptr[(size + 1) / sizeof(WCHAR) - 1] = 0; /* enforce null-termination */
195 GlobalUnlock( handle );
196 *ret_size = size;
197 return handle;
199 case CF_TEXT:
200 case CF_OEMTEXT:
202 char *ptr;
203 if (!(size = GlobalSize( handle ))) return 0;
204 if ((data_size_t)size != size) return 0;
205 if (!(ptr = GlobalLock( handle ))) return 0;
206 ptr[size - 1] = 0; /* enforce null-termination */
207 GlobalUnlock( handle );
208 *ret_size = size;
209 return handle;
211 default:
212 if (!(size = GlobalSize( handle ))) return 0;
213 if ((data_size_t)size != size) return 0;
214 *ret_size = size;
215 return handle;
219 /* rebuild the target handle from the data received in GetClipboardData */
220 static HANDLE unmarshal_data( UINT format, void *data, data_size_t size )
222 HANDLE handle = GlobalReAlloc( data, size, 0 ); /* release unused space */
224 switch (format)
226 case CF_BITMAP:
228 BITMAP *bm = handle;
229 if (size < sizeof(*bm)) break;
230 if (size < bm->bmWidthBytes * abs( bm->bmHeight )) break;
231 if (bm->bmBits) break; /* DIB sections are not supported across processes */
232 bm->bmBits = bm + 1;
233 return CreateBitmapIndirect( bm );
235 case CF_DSPBITMAP: /* not supported across processes */
236 break;
237 case CF_PALETTE:
239 LOGPALETTE *pal = handle;
240 if (size < sizeof(*pal)) break;
241 if (size < offsetof( LOGPALETTE, palPalEntry[pal->palNumEntries] )) break;
242 return CreatePalette( pal );
244 case CF_ENHMETAFILE:
245 case CF_DSPENHMETAFILE:
246 return SetEnhMetaFileBits( size, handle );
247 case CF_METAFILEPICT:
248 case CF_DSPMETAFILEPICT:
250 METAFILEPICT mf;
251 struct metafile_pict *mfbits = handle;
252 if (size <= sizeof(*mfbits)) break;
253 mf.mm = mfbits->mm;
254 mf.xExt = mfbits->xExt;
255 mf.yExt = mfbits->yExt;
256 mf.hMF = SetMetaFileBitsEx( size - offsetof( struct metafile_pict, bits ), mfbits->bits );
257 *(METAFILEPICT *)handle = mf;
258 return handle;
261 return handle;
264 /* retrieve a data format from the cache */
265 static struct cached_format *get_cached_format( UINT format )
267 struct cached_format *cache;
269 LIST_FOR_EACH_ENTRY( cache, &cached_formats, struct cached_format, entry )
270 if (cache->format == format) return cache;
271 return NULL;
274 /* store data in the cache, or reuse the existing one if available */
275 static HANDLE cache_data( UINT format, HANDLE data, data_size_t size, UINT seqno,
276 struct cached_format *cache )
278 if (cache)
280 if (seqno == cache->seqno) /* we can reuse the cached data */
282 GlobalFree( data );
283 return cache->handle;
285 /* cache entry is stale, remove it */
286 list_remove( &cache->entry );
287 list_add_tail( &formats_to_free, &cache->entry );
290 /* allocate new cache entry */
291 if (!(cache = HeapAlloc( GetProcessHeap(), 0, sizeof(*cache) )))
293 GlobalFree( data );
294 return 0;
296 cache->format = format;
297 cache->seqno = seqno;
298 cache->handle = unmarshal_data( format, data, size );
299 list_add_tail( &cached_formats, &cache->entry );
300 return cache->handle;
303 /* free a single cached format */
304 static void free_cached_data( struct cached_format *cache )
306 void *ptr;
308 switch (cache->format)
310 case CF_BITMAP:
311 case CF_DSPBITMAP:
312 case CF_PALETTE:
313 DeleteObject( cache->handle );
314 break;
315 case CF_ENHMETAFILE:
316 case CF_DSPENHMETAFILE:
317 DeleteEnhMetaFile( cache->handle );
318 break;
319 case CF_METAFILEPICT:
320 case CF_DSPMETAFILEPICT:
321 if ((ptr = GlobalLock( cache->handle )))
323 DeleteMetaFile( ((METAFILEPICT *)ptr)->hMF );
324 GlobalUnlock( cache->handle );
326 GlobalFree( cache->handle );
327 break;
328 default:
329 GlobalFree( cache->handle );
330 break;
332 list_remove( &cache->entry );
333 HeapFree( GetProcessHeap(), 0, cache );
336 /* clear global memory formats; special types are freed on EmptyClipboard */
337 static void invalidate_memory_formats(void)
339 struct cached_format *cache, *next;
341 LIST_FOR_EACH_ENTRY_SAFE( cache, next, &cached_formats, struct cached_format, entry )
343 switch (cache->format)
345 case CF_BITMAP:
346 case CF_DSPBITMAP:
347 case CF_PALETTE:
348 case CF_ENHMETAFILE:
349 case CF_DSPENHMETAFILE:
350 case CF_METAFILEPICT:
351 case CF_DSPMETAFILEPICT:
352 continue;
353 default:
354 free_cached_data( cache );
355 break;
360 /* free all the data in the cache */
361 static void free_cached_formats(void)
363 struct list *ptr;
365 list_move_tail( &formats_to_free, &cached_formats );
366 while ((ptr = list_head( &formats_to_free )))
367 free_cached_data( LIST_ENTRY( ptr, struct cached_format, entry ));
370 /* get the clipboard locale stored in the CF_LOCALE format */
371 static LCID get_clipboard_locale(void)
373 HANDLE data;
374 LCID lcid = GetUserDefaultLCID();
376 if ((data = GetClipboardData( CF_LOCALE )))
378 LCID *ptr = GlobalLock( data );
379 if (ptr)
381 if (GlobalSize( data ) >= sizeof(*ptr)) lcid = *ptr;
382 GlobalUnlock( data );
385 return lcid;
388 /* get the codepage to use for text conversions in the specified format (CF_TEXT or CF_OEMTEXT) */
389 static UINT get_format_codepage( LCID lcid, UINT format )
391 LCTYPE type = (format == CF_TEXT) ? LOCALE_IDEFAULTANSICODEPAGE : LOCALE_IDEFAULTCODEPAGE;
392 UINT ret;
394 if (!GetLocaleInfoW( lcid, type | LOCALE_RETURN_NUMBER, (LPWSTR)&ret, sizeof(ret)/sizeof(WCHAR) ))
395 ret = (format == CF_TEXT) ? CP_ACP : CP_OEMCP;
396 return ret;
399 /* render synthesized ANSI text based on the contents of the 'from' format */
400 static HANDLE render_synthesized_textA( HANDLE data, UINT format, UINT from )
402 void *src;
403 WCHAR *srcW = NULL;
404 HANDLE ret = 0;
405 LCID lcid = get_clipboard_locale();
406 UINT codepage = get_format_codepage( lcid, format );
407 UINT len, size = GlobalSize( data );
409 if (!(src = GlobalLock( data ))) return 0;
411 if (from != CF_UNICODETEXT) /* first convert incoming format to Unicode */
413 UINT from_codepage = get_format_codepage( lcid, from );
414 len = MultiByteToWideChar( from_codepage, 0, src, size, NULL, 0 );
415 if (!(srcW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) goto done;
416 MultiByteToWideChar( from_codepage, 0, src, size, srcW, len );
417 src = srcW;
418 size = len * sizeof(WCHAR);
421 if ((len = WideCharToMultiByte( codepage, 0, src, size / sizeof(WCHAR), NULL, 0, NULL, NULL )))
423 if ((ret = GlobalAlloc( GMEM_FIXED, len )))
424 WideCharToMultiByte( codepage, 0, src, size / sizeof(WCHAR), ret, len, NULL, NULL );
427 done:
428 HeapFree( GetProcessHeap(), 0, srcW );
429 GlobalUnlock( data );
430 return ret;
433 /* render synthesized Unicode text based on the contents of the 'from' format */
434 static HANDLE render_synthesized_textW( HANDLE data, UINT from )
436 char *src;
437 HANDLE ret = 0;
438 UINT len, size = GlobalSize( data );
439 UINT codepage = get_format_codepage( get_clipboard_locale(), from );
441 if (!(src = GlobalLock( data ))) return 0;
443 if ((len = MultiByteToWideChar( codepage, 0, src, size, NULL, 0 )))
445 if ((ret = GlobalAlloc( GMEM_FIXED, len * sizeof(WCHAR) )))
446 MultiByteToWideChar( codepage, 0, src, size, ret, len );
448 GlobalUnlock( data );
449 return ret;
452 /* render a synthesized bitmap based on the DIB clipboard data */
453 static HANDLE render_synthesized_bitmap( HANDLE data, UINT from )
455 BITMAPINFO *bmi;
456 HANDLE ret = 0;
457 HDC hdc = GetDC( 0 );
459 if ((bmi = GlobalLock( data )))
461 /* FIXME: validate data size */
462 ret = CreateDIBitmap( hdc, &bmi->bmiHeader, CBM_INIT,
463 (char *)bmi + bitmap_info_size( bmi, DIB_RGB_COLORS ),
464 bmi, DIB_RGB_COLORS );
465 GlobalUnlock( data );
467 ReleaseDC( 0, hdc );
468 return ret;
471 /* render a synthesized DIB based on the clipboard data */
472 static HANDLE render_synthesized_dib( HANDLE data, UINT format, UINT from )
474 BITMAPINFO *bmi, *src;
475 DWORD src_size, header_size, bits_size;
476 HANDLE ret = 0;
477 HDC hdc = GetDC( 0 );
479 if (from == CF_BITMAP)
481 BITMAPV5HEADER header;
483 memset( &header, 0, sizeof(header) );
484 header.bV5Size = (format == CF_DIBV5) ? sizeof(BITMAPV5HEADER) : sizeof(BITMAPINFOHEADER);
485 if (!GetDIBits( hdc, data, 0, 0, NULL, (BITMAPINFO *)&header, DIB_RGB_COLORS )) goto done;
487 header_size = bitmap_info_size( (BITMAPINFO *)&header, DIB_RGB_COLORS );
488 if (!(ret = GlobalAlloc( GMEM_FIXED, header_size + header.bV5SizeImage ))) goto done;
489 bmi = (BITMAPINFO *)ret;
490 memset( bmi, 0, header_size );
491 memcpy( bmi, &header, header.bV5Size );
492 GetDIBits( hdc, data, 0, abs(header.bV5Height), (char *)bmi + header_size, bmi, DIB_RGB_COLORS );
494 else
496 SIZE_T size = GlobalSize( data );
498 if (size < sizeof(*bmi)) goto done;
499 if (!(src = GlobalLock( data ))) goto done;
501 src_size = bitmap_info_size( src, DIB_RGB_COLORS );
502 if (size <= src_size)
504 GlobalUnlock( data );
505 goto done;
507 bits_size = size - src_size;
508 header_size = (format == CF_DIBV5) ? sizeof(BITMAPV5HEADER) :
509 offsetof( BITMAPINFO, bmiColors[src->bmiHeader.biCompression == BI_BITFIELDS ? 3 : 0] );
511 if ((ret = GlobalAlloc( GMEM_FIXED, header_size + bits_size )))
513 bmi = (BITMAPINFO *)ret;
514 memset( bmi, 0, header_size );
515 memcpy( bmi, src, min( header_size, src_size ));
516 bmi->bmiHeader.biSize = header_size;
517 /* FIXME: convert colors according to DIBv5 color profile */
518 memcpy( (char *)bmi + header_size, (char *)src + src_size, bits_size );
520 GlobalUnlock( data );
523 done:
524 ReleaseDC( 0, hdc );
525 return ret;
528 /* render a synthesized metafile based on the enhmetafile clipboard data */
529 static HANDLE render_synthesized_metafile( HANDLE data )
531 HANDLE ret = 0;
532 UINT size;
533 void *bits;
534 METAFILEPICT *pict;
535 ENHMETAHEADER header;
536 HDC hdc = GetDC( 0 );
538 size = GetWinMetaFileBits( data, 0, NULL, MM_ISOTROPIC, hdc );
539 if ((bits = HeapAlloc( GetProcessHeap(), 0, size )))
541 if (GetEnhMetaFileHeader( data, sizeof(header), &header ) &&
542 GetWinMetaFileBits( data, size, bits, MM_ISOTROPIC, hdc ))
544 if ((ret = GlobalAlloc( GMEM_FIXED, sizeof(*pict) )))
546 pict = (METAFILEPICT *)ret;
547 pict->mm = MM_ISOTROPIC;
548 pict->xExt = header.rclFrame.right - header.rclFrame.left;
549 pict->yExt = header.rclFrame.bottom - header.rclFrame.top;
550 pict->hMF = SetMetaFileBitsEx( size, bits );
553 HeapFree( GetProcessHeap(), 0, bits );
555 ReleaseDC( 0, hdc );
556 return ret;
559 /* render a synthesized enhmetafile based on the metafile clipboard data */
560 static HANDLE render_synthesized_enhmetafile( HANDLE data )
562 METAFILEPICT *pict;
563 HANDLE ret = 0;
564 UINT size;
565 void *bits;
567 if (!(pict = GlobalLock( data ))) return 0;
569 size = GetMetaFileBitsEx( pict->hMF, 0, NULL );
570 if ((bits = HeapAlloc( GetProcessHeap(), 0, size )))
572 GetMetaFileBitsEx( pict->hMF, size, bits );
573 ret = SetWinMetaFileBits( size, bits, NULL, pict );
574 HeapFree( GetProcessHeap(), 0, bits );
577 GlobalUnlock( data );
578 return ret;
581 /* render a synthesized format */
582 static HANDLE render_synthesized_format( UINT format, UINT from )
584 HANDLE data = GetClipboardData( from );
586 if (!data) return 0;
587 TRACE( "rendering %s from %s\n", debugstr_format( format ), debugstr_format( from ));
589 switch (format)
591 case CF_TEXT:
592 case CF_OEMTEXT:
593 data = render_synthesized_textA( data, format, from );
594 break;
595 case CF_UNICODETEXT:
596 data = render_synthesized_textW( data, from );
597 break;
598 case CF_BITMAP:
599 data = render_synthesized_bitmap( data, from );
600 break;
601 case CF_DIB:
602 case CF_DIBV5:
603 data = render_synthesized_dib( data, format, from );
604 break;
605 case CF_METAFILEPICT:
606 data = render_synthesized_metafile( data );
607 break;
608 case CF_ENHMETAFILE:
609 data = render_synthesized_enhmetafile( data );
610 break;
611 default:
612 assert( 0 );
614 if (data)
616 TRACE( "adding %s %p\n", debugstr_format( format ), data );
617 SetClipboardData( format, data );
619 return data;
622 /**************************************************************************
623 * CLIPBOARD_ReleaseOwner
625 void CLIPBOARD_ReleaseOwner( HWND hwnd )
627 HWND viewer = 0, owner = 0;
629 SendMessageW( hwnd, WM_RENDERALLFORMATS, 0, 0 );
631 SERVER_START_REQ( release_clipboard )
633 req->owner = wine_server_user_handle( hwnd );
634 if (!wine_server_call( req ))
636 viewer = wine_server_ptr_handle( reply->viewer );
637 owner = wine_server_ptr_handle( reply->owner );
640 SERVER_END_REQ;
642 if (viewer) SendNotifyMessageW( viewer, WM_DRAWCLIPBOARD, (WPARAM)owner, 0 );
646 /**************************************************************************
647 * RegisterClipboardFormatW (USER32.@)
649 UINT WINAPI RegisterClipboardFormatW( LPCWSTR name )
651 return GlobalAddAtomW( name );
655 /**************************************************************************
656 * RegisterClipboardFormatA (USER32.@)
658 UINT WINAPI RegisterClipboardFormatA( LPCSTR name )
660 return GlobalAddAtomA( name );
664 /**************************************************************************
665 * GetClipboardFormatNameW (USER32.@)
667 INT WINAPI GetClipboardFormatNameW( UINT format, LPWSTR buffer, INT maxlen )
669 if (format < MAXINTATOM || format > 0xffff) return 0;
670 return GlobalGetAtomNameW( format, buffer, maxlen );
674 /**************************************************************************
675 * GetClipboardFormatNameA (USER32.@)
677 INT WINAPI GetClipboardFormatNameA( UINT format, LPSTR buffer, INT maxlen )
679 if (format < MAXINTATOM || format > 0xffff) return 0;
680 return GlobalGetAtomNameA( format, buffer, maxlen );
684 /**************************************************************************
685 * OpenClipboard (USER32.@)
687 BOOL WINAPI OpenClipboard( HWND hwnd )
689 BOOL ret;
690 HWND owner;
692 TRACE( "%p\n", hwnd );
694 USER_Driver->pUpdateClipboard();
696 EnterCriticalSection( &clipboard_cs );
698 SERVER_START_REQ( open_clipboard )
700 req->window = wine_server_user_handle( hwnd );
701 ret = !wine_server_call_err( req );
702 owner = wine_server_ptr_handle( reply->owner );
704 SERVER_END_REQ;
706 if (ret && !WIN_IsCurrentProcess( owner )) invalidate_memory_formats();
708 LeaveCriticalSection( &clipboard_cs );
709 return ret;
713 /**************************************************************************
714 * CloseClipboard (USER32.@)
716 BOOL WINAPI CloseClipboard(void)
718 HWND viewer = 0, owner = 0;
719 BOOL ret;
721 TRACE( "\n" );
723 SERVER_START_REQ( close_clipboard )
725 if ((ret = !wine_server_call_err( req )))
727 viewer = wine_server_ptr_handle( reply->viewer );
728 owner = wine_server_ptr_handle( reply->owner );
731 SERVER_END_REQ;
733 if (viewer) SendNotifyMessageW( viewer, WM_DRAWCLIPBOARD, (WPARAM)owner, 0 );
734 return ret;
738 /**************************************************************************
739 * EmptyClipboard (USER32.@)
740 * Empties and acquires ownership of the clipboard
742 BOOL WINAPI EmptyClipboard(void)
744 BOOL ret;
745 HWND owner = GetClipboardOwner();
747 TRACE( "owner %p\n", owner );
749 if (owner) SendMessageTimeoutW( owner, WM_DESTROYCLIPBOARD, 0, 0, SMTO_ABORTIFHUNG, 5000, NULL );
751 EnterCriticalSection( &clipboard_cs );
753 SERVER_START_REQ( empty_clipboard )
755 ret = !wine_server_call_err( req );
757 SERVER_END_REQ;
759 if (ret) free_cached_formats();
761 LeaveCriticalSection( &clipboard_cs );
762 return ret;
766 /**************************************************************************
767 * GetClipboardOwner (USER32.@)
769 HWND WINAPI GetClipboardOwner(void)
771 HWND hWndOwner = 0;
773 SERVER_START_REQ( get_clipboard_info )
775 if (!wine_server_call_err( req )) hWndOwner = wine_server_ptr_handle( reply->owner );
777 SERVER_END_REQ;
779 TRACE( "returning %p\n", hWndOwner );
781 return hWndOwner;
785 /**************************************************************************
786 * GetOpenClipboardWindow (USER32.@)
788 HWND WINAPI GetOpenClipboardWindow(void)
790 HWND hWndOpen = 0;
792 SERVER_START_REQ( get_clipboard_info )
794 if (!wine_server_call_err( req )) hWndOpen = wine_server_ptr_handle( reply->window );
796 SERVER_END_REQ;
798 TRACE( "returning %p\n", hWndOpen );
800 return hWndOpen;
804 /**************************************************************************
805 * SetClipboardViewer (USER32.@)
807 HWND WINAPI SetClipboardViewer( HWND hwnd )
809 HWND prev = 0, owner = 0;
811 SERVER_START_REQ( set_clipboard_viewer )
813 req->viewer = wine_server_user_handle( hwnd );
814 if (!wine_server_call_err( req ))
816 prev = wine_server_ptr_handle( reply->old_viewer );
817 owner = wine_server_ptr_handle( reply->owner );
820 SERVER_END_REQ;
822 if (hwnd) SendNotifyMessageW( hwnd, WM_DRAWCLIPBOARD, (WPARAM)owner, 0 );
824 TRACE( "%p returning %p\n", hwnd, prev );
825 return prev;
829 /**************************************************************************
830 * GetClipboardViewer (USER32.@)
832 HWND WINAPI GetClipboardViewer(void)
834 HWND hWndViewer = 0;
836 SERVER_START_REQ( get_clipboard_info )
838 if (!wine_server_call_err( req )) hWndViewer = wine_server_ptr_handle( reply->viewer );
840 SERVER_END_REQ;
842 TRACE( "returning %p\n", hWndViewer );
844 return hWndViewer;
848 /**************************************************************************
849 * ChangeClipboardChain (USER32.@)
851 BOOL WINAPI ChangeClipboardChain( HWND hwnd, HWND next )
853 NTSTATUS status;
854 HWND viewer;
856 if (!hwnd) return FALSE;
858 SERVER_START_REQ( set_clipboard_viewer )
860 req->viewer = wine_server_user_handle( next );
861 req->previous = wine_server_user_handle( hwnd );
862 status = wine_server_call( req );
863 viewer = wine_server_ptr_handle( reply->old_viewer );
865 SERVER_END_REQ;
867 if (status == STATUS_PENDING)
868 return !SendMessageW( viewer, WM_CHANGECBCHAIN, (WPARAM)hwnd, (LPARAM)next );
870 if (status) SetLastError( RtlNtStatusToDosError( status ));
871 return !status;
875 /**************************************************************************
876 * SetClipboardData (USER32.@)
878 HANDLE WINAPI SetClipboardData( UINT format, HANDLE data )
880 struct cached_format *cache = NULL;
881 void *ptr = NULL;
882 data_size_t size = 0;
883 HANDLE handle = data, retval = 0;
884 NTSTATUS status = STATUS_SUCCESS;
886 TRACE( "%s %p\n", debugstr_format( format ), data );
888 if (data)
890 if (!(handle = marshal_data( format, data, &size ))) return 0;
891 if (!(ptr = GlobalLock( handle ))) goto done;
892 if (!(cache = HeapAlloc( GetProcessHeap(), 0, sizeof(*cache) ))) goto done;
893 cache->format = format;
894 cache->handle = data;
897 EnterCriticalSection( &clipboard_cs );
899 SERVER_START_REQ( set_clipboard_data )
901 req->format = format;
902 req->lcid = GetUserDefaultLCID();
903 wine_server_add_data( req, ptr, size );
904 if (!(status = wine_server_call( req )))
906 if (cache) cache->seqno = reply->seqno;
909 SERVER_END_REQ;
911 if (!status)
913 /* free the previous entry if any */
914 struct cached_format *prev;
916 if ((prev = get_cached_format( format ))) free_cached_data( prev );
917 if (cache) list_add_tail( &cached_formats, &cache->entry );
918 retval = data;
920 else HeapFree( GetProcessHeap(), 0, cache );
922 LeaveCriticalSection( &clipboard_cs );
924 done:
925 if (ptr) GlobalUnlock( handle );
926 if (handle != data) GlobalFree( handle );
927 if (status) SetLastError( RtlNtStatusToDosError( status ));
928 return retval;
932 /**************************************************************************
933 * CountClipboardFormats (USER32.@)
935 INT WINAPI CountClipboardFormats(void)
937 INT count = 0;
939 USER_Driver->pUpdateClipboard();
941 SERVER_START_REQ( get_clipboard_formats )
943 wine_server_call( req );
944 count = reply->count;
946 SERVER_END_REQ;
948 TRACE("returning %d\n", count);
949 return count;
953 /**************************************************************************
954 * EnumClipboardFormats (USER32.@)
956 UINT WINAPI EnumClipboardFormats( UINT format )
958 UINT ret = 0;
960 SERVER_START_REQ( enum_clipboard_formats )
962 req->previous = format;
963 if (!wine_server_call_err( req ))
965 ret = reply->format;
966 SetLastError( ERROR_SUCCESS );
969 SERVER_END_REQ;
971 TRACE( "%s -> %s\n", debugstr_format( format ), debugstr_format( ret ));
972 return ret;
976 /**************************************************************************
977 * IsClipboardFormatAvailable (USER32.@)
979 BOOL WINAPI IsClipboardFormatAvailable( UINT format )
981 BOOL ret = FALSE;
983 if (!format) return FALSE;
985 USER_Driver->pUpdateClipboard();
987 SERVER_START_REQ( get_clipboard_formats )
989 req->format = format;
990 if (!wine_server_call_err( req )) ret = (reply->count > 0);
992 SERVER_END_REQ;
993 TRACE( "%s -> %u\n", debugstr_format( format ), ret );
994 return ret;
998 /**************************************************************************
999 * GetUpdatedClipboardFormats (USER32.@)
1001 BOOL WINAPI GetUpdatedClipboardFormats( UINT *formats, UINT size, UINT *out_size )
1003 BOOL ret;
1005 if (!out_size)
1007 SetLastError( ERROR_NOACCESS );
1008 return FALSE;
1011 USER_Driver->pUpdateClipboard();
1013 SERVER_START_REQ( get_clipboard_formats )
1015 if (formats) wine_server_set_reply( req, formats, size * sizeof(*formats) );
1016 ret = !wine_server_call_err( req );
1017 *out_size = reply->count;
1019 SERVER_END_REQ;
1021 TRACE( "%p %u returning %u formats, ret %u\n", formats, size, *out_size, ret );
1022 if (!ret && !formats && *out_size) SetLastError( ERROR_NOACCESS );
1023 return ret;
1027 /**************************************************************************
1028 * GetClipboardData (USER32.@)
1030 HANDLE WINAPI GetClipboardData( UINT format )
1032 struct cached_format *cache;
1033 NTSTATUS status;
1034 UINT from, data_seqno;
1035 HWND owner;
1036 HANDLE data;
1037 UINT size = 1024;
1038 BOOL render = TRUE;
1040 for (;;)
1042 if (!(data = GlobalAlloc( GMEM_FIXED, size ))) return 0;
1044 EnterCriticalSection( &clipboard_cs );
1045 cache = get_cached_format( format );
1047 SERVER_START_REQ( get_clipboard_data )
1049 req->format = format;
1050 if (cache)
1052 req->cached = 1;
1053 req->seqno = cache->seqno;
1055 wine_server_set_reply( req, data, size );
1056 status = wine_server_call( req );
1057 from = reply->from;
1058 size = reply->total;
1059 data_seqno = reply->seqno;
1060 owner = wine_server_ptr_handle( reply->owner );
1062 SERVER_END_REQ;
1064 if (!status && size)
1066 data = cache_data( format, data, size, data_seqno, cache );
1067 LeaveCriticalSection( &clipboard_cs );
1068 TRACE( "%s returning %p\n", debugstr_format( format ), data );
1069 return data;
1071 LeaveCriticalSection( &clipboard_cs );
1072 GlobalFree( data );
1074 if (status == STATUS_BUFFER_OVERFLOW) continue; /* retry with the new size */
1075 if (status)
1077 SetLastError( RtlNtStatusToDosError( status ));
1078 TRACE( "%s error %08x\n", debugstr_format( format ), status );
1079 return 0;
1081 if (render) /* try rendering it */
1083 render = FALSE;
1084 if (owner)
1086 TRACE( "%s sending WM_RENDERFORMAT to %p\n", debugstr_format( format ), owner );
1087 SendMessageW( owner, WM_RENDERFORMAT, format, 0 );
1088 continue;
1090 if (from) return render_synthesized_format( format, from );
1092 TRACE( "%s returning 0\n", debugstr_format( format ));
1093 return 0;
1098 /**************************************************************************
1099 * GetPriorityClipboardFormat (USER32.@)
1101 INT WINAPI GetPriorityClipboardFormat(UINT *list, INT nCount)
1103 int i;
1105 TRACE( "%p %u\n", list, nCount );
1107 if(CountClipboardFormats() == 0)
1108 return 0;
1110 for (i = 0; i < nCount; i++)
1111 if (IsClipboardFormatAvailable(list[i]))
1112 return list[i];
1114 return -1;
1118 /**************************************************************************
1119 * GetClipboardSequenceNumber (USER32.@)
1121 DWORD WINAPI GetClipboardSequenceNumber(VOID)
1123 DWORD seqno = 0;
1125 SERVER_START_REQ( get_clipboard_info )
1127 if (!wine_server_call_err( req )) seqno = reply->seqno;
1129 SERVER_END_REQ;
1131 TRACE( "returning %u\n", seqno );
1132 return seqno;
1135 /**************************************************************************
1136 * AddClipboardFormatListener (USER32.@)
1138 BOOL WINAPI AddClipboardFormatListener(HWND hwnd)
1140 BOOL ret;
1142 SERVER_START_REQ( add_clipboard_listener )
1144 req->window = wine_server_user_handle( hwnd );
1145 ret = !wine_server_call_err( req );
1147 SERVER_END_REQ;
1148 return ret;
1151 /**************************************************************************
1152 * RemoveClipboardFormatListener (USER32.@)
1154 BOOL WINAPI RemoveClipboardFormatListener(HWND hwnd)
1156 BOOL ret;
1158 SERVER_START_REQ( remove_clipboard_listener )
1160 req->window = wine_server_user_handle( hwnd );
1161 ret = !wine_server_call_err( req );
1163 SERVER_END_REQ;
1164 return ret;