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
27 #include "wine/port.h"
32 #include <sys/types.h>
40 #define WIN32_NO_STATUS
46 #include "user_private.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
);
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
=
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 */
86 /* get a debug string for a format id */
87 static const char *debugstr_format( UINT id
)
91 if (GetClipboardFormatNameW( id
, buffer
, 256 ))
92 return wine_dbg_sprintf( "%04x %s", id
, debugstr_w(buffer
) );
96 #define BUILTIN(id) case id: return #id;
99 BUILTIN(CF_METAFILEPICT
)
109 BUILTIN(CF_UNICODETEXT
)
110 BUILTIN(CF_ENHMETAFILE
)
114 BUILTIN(CF_OWNERDISPLAY
)
116 BUILTIN(CF_DSPBITMAP
)
117 BUILTIN(CF_DSPMETAFILEPICT
)
118 BUILTIN(CF_DSPENHMETAFILE
)
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
)
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;
140 GetBitmapBits( handle
, size
, bm
+ 1 );
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
);
155 case CF_DSPENHMETAFILE
:
158 if (!(size
= GetEnhMetaFileBits( handle
, 0, NULL
))) return 0;
159 if (!(ret
= GlobalAlloc( GMEM_FIXED
, size
))) return 0;
160 GetEnhMetaFileBits( handle
, size
, ret
);
164 case CF_METAFILEPICT
:
165 case CF_DSPMETAFILEPICT
:
168 struct metafile_pict
*mfbits
;
169 if (!(mf
= GlobalLock( handle
))) return 0;
170 if (!(size
= GetMetaFileBitsEx( mf
->hMF
, 0, NULL
)))
172 GlobalUnlock( handle
);
175 *ret_size
= offsetof( struct metafile_pict
, bits
[size
] );
176 if (!(mfbits
= GlobalAlloc( GMEM_FIXED
, *ret_size
)))
178 GlobalUnlock( handle
);
182 mfbits
->xExt
= mf
->xExt
;
183 mfbits
->yExt
= mf
->yExt
;
184 GetMetaFileBitsEx( mf
->hMF
, size
, mfbits
->bits
);
185 GlobalUnlock( handle
);
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
);
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
);
212 if (!(size
= GlobalSize( handle
))) return 0;
213 if ((data_size_t
)size
!= size
) return 0;
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 */
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 */
233 return CreateBitmapIndirect( bm
);
235 case CF_DSPBITMAP
: /* not supported across processes */
239 LOGPALETTE
*pal
= handle
;
240 if (size
< sizeof(*pal
)) break;
241 if (size
< offsetof( LOGPALETTE
, palPalEntry
[pal
->palNumEntries
] )) break;
242 return CreatePalette( pal
);
245 case CF_DSPENHMETAFILE
:
246 return SetEnhMetaFileBits( size
, handle
);
247 case CF_METAFILEPICT
:
248 case CF_DSPMETAFILEPICT
:
251 struct metafile_pict
*mfbits
= handle
;
252 if (size
<= sizeof(*mfbits
)) break;
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
;
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
;
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
)
280 if (seqno
== cache
->seqno
) /* we can reuse the cached 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
) )))
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
)
308 switch (cache
->format
)
313 DeleteObject( cache
->handle
);
316 case CF_DSPENHMETAFILE
:
317 DeleteEnhMetaFile( cache
->handle
);
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
);
329 GlobalFree( cache
->handle
);
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
)
349 case CF_DSPENHMETAFILE
:
350 case CF_METAFILEPICT
:
351 case CF_DSPMETAFILEPICT
:
354 free_cached_data( cache
);
360 /* free all the data in the cache */
361 static void free_cached_formats(void)
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)
374 LCID lcid
= GetUserDefaultLCID();
376 if ((data
= GetClipboardData( CF_LOCALE
)))
378 LCID
*ptr
= GlobalLock( data
);
381 if (GlobalSize( data
) >= sizeof(*ptr
)) lcid
= *ptr
;
382 GlobalUnlock( data
);
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
;
394 if (!GetLocaleInfoW( lcid
, type
| LOCALE_RETURN_NUMBER
, (LPWSTR
)&ret
, sizeof(ret
)/sizeof(WCHAR
) ))
395 ret
= (format
== CF_TEXT
) ? CP_ACP
: CP_OEMCP
;
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
)
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
);
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
);
428 HeapFree( GetProcessHeap(), 0, srcW
);
429 GlobalUnlock( data
);
433 /* render synthesized Unicode text based on the contents of the 'from' format */
434 static HANDLE
render_synthesized_textW( HANDLE data
, UINT from
)
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
);
452 /* render a synthesized bitmap based on the DIB clipboard data */
453 static HANDLE
render_synthesized_bitmap( HANDLE data
, UINT from
)
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
);
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
;
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
);
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
);
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
);
528 /* render a synthesized metafile based on the enhmetafile clipboard data */
529 static HANDLE
render_synthesized_metafile( HANDLE data
)
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
);
559 /* render a synthesized enhmetafile based on the metafile clipboard data */
560 static HANDLE
render_synthesized_enhmetafile( HANDLE data
)
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
);
581 /* render a synthesized format */
582 static HANDLE
render_synthesized_format( UINT format
, UINT from
)
584 HANDLE data
= GetClipboardData( from
);
587 TRACE( "rendering %s from %s\n", debugstr_format( format
), debugstr_format( from
));
593 data
= render_synthesized_textA( data
, format
, from
);
596 data
= render_synthesized_textW( data
, from
);
599 data
= render_synthesized_bitmap( data
, from
);
603 data
= render_synthesized_dib( data
, format
, from
);
605 case CF_METAFILEPICT
:
606 data
= render_synthesized_metafile( data
);
609 data
= render_synthesized_enhmetafile( data
);
616 TRACE( "adding %s %p\n", debugstr_format( format
), data
);
617 SetClipboardData( format
, 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
);
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
)
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
);
706 if (ret
&& !WIN_IsCurrentProcess( owner
)) invalidate_memory_formats();
708 LeaveCriticalSection( &clipboard_cs
);
713 /**************************************************************************
714 * CloseClipboard (USER32.@)
716 BOOL WINAPI
CloseClipboard(void)
718 HWND viewer
= 0, owner
= 0;
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
);
733 if (viewer
) SendNotifyMessageW( viewer
, WM_DRAWCLIPBOARD
, (WPARAM
)owner
, 0 );
738 /**************************************************************************
739 * EmptyClipboard (USER32.@)
740 * Empties and acquires ownership of the clipboard
742 BOOL WINAPI
EmptyClipboard(void)
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
);
759 if (ret
) free_cached_formats();
761 LeaveCriticalSection( &clipboard_cs
);
766 /**************************************************************************
767 * GetClipboardOwner (USER32.@)
769 HWND WINAPI
GetClipboardOwner(void)
773 SERVER_START_REQ( get_clipboard_info
)
775 if (!wine_server_call_err( req
)) hWndOwner
= wine_server_ptr_handle( reply
->owner
);
779 TRACE( "returning %p\n", hWndOwner
);
785 /**************************************************************************
786 * GetOpenClipboardWindow (USER32.@)
788 HWND WINAPI
GetOpenClipboardWindow(void)
792 SERVER_START_REQ( get_clipboard_info
)
794 if (!wine_server_call_err( req
)) hWndOpen
= wine_server_ptr_handle( reply
->window
);
798 TRACE( "returning %p\n", 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
);
822 if (hwnd
) SendNotifyMessageW( hwnd
, WM_DRAWCLIPBOARD
, (WPARAM
)owner
, 0 );
824 TRACE( "%p returning %p\n", hwnd
, prev
);
829 /**************************************************************************
830 * GetClipboardViewer (USER32.@)
832 HWND WINAPI
GetClipboardViewer(void)
836 SERVER_START_REQ( get_clipboard_info
)
838 if (!wine_server_call_err( req
)) hWndViewer
= wine_server_ptr_handle( reply
->viewer
);
842 TRACE( "returning %p\n", hWndViewer
);
848 /**************************************************************************
849 * ChangeClipboardChain (USER32.@)
851 BOOL WINAPI
ChangeClipboardChain( HWND hwnd
, HWND next
)
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
);
867 if (status
== STATUS_PENDING
)
868 return !SendMessageW( viewer
, WM_CHANGECBCHAIN
, (WPARAM
)hwnd
, (LPARAM
)next
);
870 if (status
) SetLastError( RtlNtStatusToDosError( status
));
875 /**************************************************************************
876 * SetClipboardData (USER32.@)
878 HANDLE WINAPI
SetClipboardData( UINT format
, HANDLE data
)
880 struct cached_format
*cache
= 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
);
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
;
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
);
920 else HeapFree( GetProcessHeap(), 0, cache
);
922 LeaveCriticalSection( &clipboard_cs
);
925 if (ptr
) GlobalUnlock( handle
);
926 if (handle
!= data
) GlobalFree( handle
);
927 if (status
) SetLastError( RtlNtStatusToDosError( status
));
932 /**************************************************************************
933 * CountClipboardFormats (USER32.@)
935 INT WINAPI
CountClipboardFormats(void)
939 USER_Driver
->pUpdateClipboard();
941 SERVER_START_REQ( get_clipboard_formats
)
943 wine_server_call( req
);
944 count
= reply
->count
;
948 TRACE("returning %d\n", count
);
953 /**************************************************************************
954 * EnumClipboardFormats (USER32.@)
956 UINT WINAPI
EnumClipboardFormats( UINT format
)
960 SERVER_START_REQ( enum_clipboard_formats
)
962 req
->previous
= format
;
963 if (!wine_server_call_err( req
))
966 SetLastError( ERROR_SUCCESS
);
971 TRACE( "%s -> %s\n", debugstr_format( format
), debugstr_format( ret
));
976 /**************************************************************************
977 * IsClipboardFormatAvailable (USER32.@)
979 BOOL WINAPI
IsClipboardFormatAvailable( UINT format
)
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);
993 TRACE( "%s -> %u\n", debugstr_format( format
), ret
);
998 /**************************************************************************
999 * GetUpdatedClipboardFormats (USER32.@)
1001 BOOL WINAPI
GetUpdatedClipboardFormats( UINT
*formats
, UINT size
, UINT
*out_size
)
1007 SetLastError( ERROR_NOACCESS
);
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
;
1021 TRACE( "%p %u returning %u formats, ret %u\n", formats
, size
, *out_size
, ret
);
1022 if (!ret
&& !formats
&& *out_size
) SetLastError( ERROR_NOACCESS
);
1027 /**************************************************************************
1028 * GetClipboardData (USER32.@)
1030 HANDLE WINAPI
GetClipboardData( UINT format
)
1032 struct cached_format
*cache
;
1034 UINT from
, data_seqno
;
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 req
->render
= render
;
1054 req
->seqno
= cache
->seqno
;
1056 wine_server_set_reply( req
, data
, size
);
1057 status
= wine_server_call( req
);
1059 size
= reply
->total
;
1060 data_seqno
= reply
->seqno
;
1061 owner
= wine_server_ptr_handle( reply
->owner
);
1065 if (!status
&& size
)
1067 data
= cache_data( format
, data
, size
, data_seqno
, cache
);
1068 LeaveCriticalSection( &clipboard_cs
);
1069 TRACE( "%s returning %p\n", debugstr_format( format
), data
);
1072 LeaveCriticalSection( &clipboard_cs
);
1075 if (status
== STATUS_BUFFER_OVERFLOW
) continue; /* retry with the new size */
1078 SetLastError( RtlNtStatusToDosError( status
));
1079 TRACE( "%s error %08x\n", debugstr_format( format
), status
);
1082 if (render
) /* try rendering it */
1087 render_synthesized_format( format
, from
);
1092 TRACE( "%s sending WM_RENDERFORMAT to %p\n", debugstr_format( format
), owner
);
1093 SendMessageW( owner
, WM_RENDERFORMAT
, format
, 0 );
1097 TRACE( "%s returning 0\n", debugstr_format( format
));
1103 /**************************************************************************
1104 * GetPriorityClipboardFormat (USER32.@)
1106 INT WINAPI
GetPriorityClipboardFormat(UINT
*list
, INT nCount
)
1110 TRACE( "%p %u\n", list
, nCount
);
1112 if(CountClipboardFormats() == 0)
1115 for (i
= 0; i
< nCount
; i
++)
1116 if (IsClipboardFormatAvailable(list
[i
]))
1123 /**************************************************************************
1124 * GetClipboardSequenceNumber (USER32.@)
1126 DWORD WINAPI
GetClipboardSequenceNumber(VOID
)
1130 SERVER_START_REQ( get_clipboard_info
)
1132 if (!wine_server_call_err( req
)) seqno
= reply
->seqno
;
1136 TRACE( "returning %u\n", seqno
);
1140 /**************************************************************************
1141 * AddClipboardFormatListener (USER32.@)
1143 BOOL WINAPI
AddClipboardFormatListener(HWND hwnd
)
1147 SERVER_START_REQ( add_clipboard_listener
)
1149 req
->window
= wine_server_user_handle( hwnd
);
1150 ret
= !wine_server_call_err( req
);
1156 /**************************************************************************
1157 * RemoveClipboardFormatListener (USER32.@)
1159 BOOL WINAPI
RemoveClipboardFormatListener(HWND hwnd
)
1163 SERVER_START_REQ( remove_clipboard_listener
)
1165 req
->window
= wine_server_user_handle( hwnd
);
1166 ret
= !wine_server_call_err( req
);