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
32 #define WIN32_NO_STATUS
33 #include "win32u_private.h"
34 #include "ntgdi_private.h"
35 #include "ntuser_private.h"
36 #include "wine/server.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(clipboard
);
41 static pthread_mutex_t clipboard_mutex
= PTHREAD_MUTEX_INITIALIZER
;
45 struct list entry
; /* entry in cache list */
46 UINT format
; /* format id */
47 UINT seqno
; /* sequence number when the data was set */
48 HANDLE handle
; /* original data handle */
51 static struct list cached_formats
= LIST_INIT( cached_formats
);
52 static struct list formats_to_free
= LIST_INIT( formats_to_free
);
55 /* get a debug string for a format id */
56 static const char *debugstr_format( UINT id
)
59 DWORD le
= RtlGetLastWin32Error();
60 BOOL r
= NtUserGetClipboardFormatName( id
, buffer
, ARRAYSIZE(buffer
) );
61 RtlSetLastWin32Error(le
);
64 return wine_dbg_sprintf( "%04x %s", id
, debugstr_w(buffer
) );
68 #define BUILTIN(id) case id: return #id;
71 BUILTIN(CF_METAFILEPICT
)
81 BUILTIN(CF_UNICODETEXT
)
82 BUILTIN(CF_ENHMETAFILE
)
86 BUILTIN(CF_OWNERDISPLAY
)
89 BUILTIN(CF_DSPMETAFILEPICT
)
90 BUILTIN(CF_DSPENHMETAFILE
)
92 default: return wine_dbg_sprintf( "%04x", id
);
96 /* retrieve a data format from the cache */
97 static struct cached_format
*get_cached_format( UINT format
)
99 struct cached_format
*cache
;
101 LIST_FOR_EACH_ENTRY( cache
, &cached_formats
, struct cached_format
, entry
)
102 if (cache
->format
== format
) return cache
;
106 /* free a single cached format */
107 static void free_cached_data( struct cached_format
*cache
)
109 struct free_cached_data_params params
;
113 switch (cache
->format
)
117 make_gdi_object_system( cache
->handle
, FALSE
);
119 NtGdiDeleteObjectApp( cache
->handle
);
123 params
.format
= cache
->format
;
124 params
.handle
= cache
->handle
;
125 KeUserModeCallback( NtUserFreeCachedClipboardData
, ¶ms
, sizeof(params
),
126 &ret_ptr
, &ret_len
);
132 /* free all the data in the cache */
133 static void free_cached_formats( struct list
*list
)
137 while ((ptr
= list_head( list
)))
140 free_cached_data( LIST_ENTRY( ptr
, struct cached_format
, entry
));
144 /* clear global memory formats; special types are freed on EmptyClipboard */
145 static void invalidate_memory_formats( struct list
*free_list
)
147 struct cached_format
*cache
, *next
;
149 LIST_FOR_EACH_ENTRY_SAFE( cache
, next
, &cached_formats
, struct cached_format
, entry
)
151 switch (cache
->format
)
157 case CF_DSPENHMETAFILE
:
158 case CF_METAFILEPICT
:
159 case CF_DSPMETAFILEPICT
:
162 list_remove( &cache
->entry
);
163 list_add_tail( free_list
, &cache
->entry
);
169 /**************************************************************************
170 * NtUserOpenClipboard (win32u.@)
172 BOOL WINAPI
NtUserOpenClipboard( HWND hwnd
, ULONG unk
)
174 struct list free_list
= LIST_INIT( free_list
);
178 TRACE( "%p\n", hwnd
);
180 user_driver
->pUpdateClipboard();
182 pthread_mutex_lock( &clipboard_mutex
);
184 SERVER_START_REQ( open_clipboard
)
186 req
->window
= wine_server_user_handle( hwnd
);
187 ret
= !wine_server_call_err( req
);
188 owner
= wine_server_ptr_handle( reply
->owner
);
192 if (ret
&& !is_current_process_window( owner
)) invalidate_memory_formats( &free_list
);
194 pthread_mutex_unlock( &clipboard_mutex
);
195 free_cached_formats( &free_list
);
199 /**************************************************************************
200 * NtUserCloseClipboard (win32u.@)
202 BOOL WINAPI
NtUserCloseClipboard(void)
204 HWND viewer
= 0, owner
= 0;
209 SERVER_START_REQ( close_clipboard
)
211 if ((ret
= !wine_server_call_err( req
)))
213 viewer
= wine_server_ptr_handle( reply
->viewer
);
214 owner
= wine_server_ptr_handle( reply
->owner
);
219 if (viewer
) NtUserMessageCall( viewer
, WM_DRAWCLIPBOARD
, (WPARAM
)owner
, 0,
220 0, NtUserSendNotifyMessage
, FALSE
);
224 /**************************************************************************
225 * NtUserEmptyClipboard (win32u.@)
227 BOOL WINAPI
NtUserEmptyClipboard(void)
230 HWND owner
= NtUserGetClipboardOwner();
231 struct list free_list
= LIST_INIT( free_list
);
233 TRACE( "owner %p\n", owner
);
236 send_message_timeout( owner
, WM_DESTROYCLIPBOARD
, 0, 0, SMTO_ABORTIFHUNG
, 5000, FALSE
);
238 pthread_mutex_lock( &clipboard_mutex
);
240 SERVER_START_REQ( empty_clipboard
)
242 ret
= !wine_server_call_err( req
);
248 list_move_tail( &free_list
, &formats_to_free
);
249 list_move_tail( &free_list
, &cached_formats
);
252 pthread_mutex_unlock( &clipboard_mutex
);
253 free_cached_formats( &free_list
);
257 /**************************************************************************
258 * NtUserCountClipboardFormats (win32u.@)
260 INT WINAPI
NtUserCountClipboardFormats(void)
264 user_driver
->pUpdateClipboard();
266 SERVER_START_REQ( get_clipboard_formats
)
268 wine_server_call( req
);
269 count
= reply
->count
;
273 TRACE( "returning %d\n", count
);
277 /**************************************************************************
278 * NtUserIsClipboardFormatAvailable (win32u.@)
280 BOOL WINAPI
NtUserIsClipboardFormatAvailable( UINT format
)
284 if (!format
) return FALSE
;
286 user_driver
->pUpdateClipboard();
288 SERVER_START_REQ( get_clipboard_formats
)
290 req
->format
= format
;
291 if (!wine_server_call_err( req
)) ret
= (reply
->count
> 0);
294 TRACE( "%s -> %u\n", debugstr_format( format
), ret
);
298 /**************************************************************************
299 * NtUserGetUpdatedClipboardFormats (win32u.@)
301 BOOL WINAPI
NtUserGetUpdatedClipboardFormats( UINT
*formats
, UINT size
, UINT
*out_size
)
307 RtlSetLastWin32Error( ERROR_NOACCESS
);
311 user_driver
->pUpdateClipboard();
313 SERVER_START_REQ( get_clipboard_formats
)
315 if (formats
) wine_server_set_reply( req
, formats
, size
* sizeof(*formats
) );
316 ret
= !wine_server_call_err( req
);
317 *out_size
= reply
->count
;
321 TRACE( "%p %u returning %u formats, ret %u\n", formats
, size
, *out_size
, ret
);
322 if (!ret
&& !formats
&& *out_size
) RtlSetLastWin32Error( ERROR_NOACCESS
);
326 /**************************************************************************
327 * NtUserGetPriorityClipboardFormat (win32u.@)
329 INT WINAPI
NtUserGetPriorityClipboardFormat( UINT
*list
, INT count
)
333 TRACE( "%p %u\n", list
, count
);
335 if (NtUserCountClipboardFormats() == 0)
338 for (i
= 0; i
< count
; i
++)
339 if (NtUserIsClipboardFormatAvailable( list
[i
] ))
345 /**************************************************************************
346 * NtUserGetClipboardFormatName (win32u.@)
348 INT WINAPI
NtUserGetClipboardFormatName( UINT format
, WCHAR
*buffer
, INT maxlen
)
350 char buf
[sizeof(ATOM_BASIC_INFORMATION
) + MAX_ATOM_LEN
* sizeof(WCHAR
)];
351 ATOM_BASIC_INFORMATION
*abi
= (ATOM_BASIC_INFORMATION
*)buf
;
354 if (format
< MAXINTATOM
|| format
> 0xffff) return 0;
357 RtlSetLastWin32Error( ERROR_MORE_DATA
);
360 if (!set_ntstatus( NtQueryInformationAtom( format
, AtomBasicInformation
,
361 buf
, sizeof(buf
), NULL
)))
364 length
= min( abi
->NameLength
/ sizeof(WCHAR
), maxlen
- 1 );
365 if (length
) memcpy( buffer
, abi
->Name
, length
* sizeof(WCHAR
) );
370 /**************************************************************************
371 * NtUserGetClipboardOwner (win32u.@)
373 HWND WINAPI
NtUserGetClipboardOwner(void)
377 SERVER_START_REQ( get_clipboard_info
)
379 if (!wine_server_call_err( req
)) owner
= wine_server_ptr_handle( reply
->owner
);
383 TRACE( "returning %p\n", owner
);
387 /**************************************************************************
388 * NtUserSetClipboardViewer (win32u.@)
390 HWND WINAPI
NtUserSetClipboardViewer( HWND hwnd
)
392 HWND prev
= 0, owner
= 0;
394 SERVER_START_REQ( set_clipboard_viewer
)
396 req
->viewer
= wine_server_user_handle( hwnd
);
397 if (!wine_server_call_err( req
))
399 prev
= wine_server_ptr_handle( reply
->old_viewer
);
400 owner
= wine_server_ptr_handle( reply
->owner
);
406 NtUserMessageCall( hwnd
, WM_DRAWCLIPBOARD
, (WPARAM
)owner
, 0,
407 NULL
, NtUserSendNotifyMessage
, FALSE
);
409 TRACE( "%p returning %p\n", hwnd
, prev
);
413 /**************************************************************************
414 * NtUserGetClipboardViewer (win32u.@)
416 HWND WINAPI
NtUserGetClipboardViewer(void)
420 SERVER_START_REQ( get_clipboard_info
)
422 if (!wine_server_call_err( req
)) viewer
= wine_server_ptr_handle( reply
->viewer
);
426 TRACE( "returning %p\n", viewer
);
430 /**************************************************************************
431 * NtUserChangeClipboardChain (win32u.@)
433 BOOL WINAPI
NtUserChangeClipboardChain( HWND hwnd
, HWND next
)
438 if (!hwnd
) return FALSE
;
440 SERVER_START_REQ( set_clipboard_viewer
)
442 req
->viewer
= wine_server_user_handle( next
);
443 req
->previous
= wine_server_user_handle( hwnd
);
444 status
= wine_server_call( req
);
445 viewer
= wine_server_ptr_handle( reply
->old_viewer
);
449 if (status
== STATUS_PENDING
)
450 return !send_message( viewer
, WM_CHANGECBCHAIN
, (WPARAM
)hwnd
, (LPARAM
)next
);
452 if (status
) RtlSetLastWin32Error( RtlNtStatusToDosError( status
));
456 /**************************************************************************
457 * NtUserGetOpenClipboardWindow (win32u.@)
459 HWND WINAPI
NtUserGetOpenClipboardWindow(void)
463 SERVER_START_REQ( get_clipboard_info
)
465 if (!wine_server_call_err( req
)) window
= wine_server_ptr_handle( reply
->window
);
469 TRACE( "returning %p\n", window
);
473 /**************************************************************************
474 * NtUserGetClipboardSequenceNumber (win32u.@)
476 DWORD WINAPI
NtUserGetClipboardSequenceNumber(void)
478 unsigned int seqno
= 0;
480 SERVER_START_REQ( get_clipboard_info
)
482 if (!wine_server_call_err( req
)) seqno
= reply
->seqno
;
486 TRACE( "returning %u\n", seqno
);
490 /* see EnumClipboardFormats */
491 UINT
enum_clipboard_formats( UINT format
)
495 SERVER_START_REQ( enum_clipboard_formats
)
497 req
->previous
= format
;
498 if (!wine_server_call_err( req
))
501 RtlSetLastWin32Error( ERROR_SUCCESS
);
506 TRACE( "%s -> %s\n", debugstr_format( format
), debugstr_format( ret
));
510 /**************************************************************************
511 * NtUserAddClipboardFormatListener (win32u.@)
513 BOOL WINAPI
NtUserAddClipboardFormatListener( HWND hwnd
)
517 SERVER_START_REQ( add_clipboard_listener
)
519 req
->window
= wine_server_user_handle( hwnd
);
520 ret
= !wine_server_call_err( req
);
526 /**************************************************************************
527 * NtUserRemoveClipboardFormatListener (win32u.@)
529 BOOL WINAPI
NtUserRemoveClipboardFormatListener( HWND hwnd
)
533 SERVER_START_REQ( remove_clipboard_listener
)
535 req
->window
= wine_server_user_handle( hwnd
);
536 ret
= !wine_server_call_err( req
);
542 /**************************************************************************
543 * release_clipboard_owner
545 void release_clipboard_owner( HWND hwnd
)
547 HWND viewer
= 0, owner
= 0;
549 send_message( hwnd
, WM_RENDERALLFORMATS
, 0, 0 );
551 SERVER_START_REQ( release_clipboard
)
553 req
->owner
= wine_server_user_handle( hwnd
);
554 if (!wine_server_call( req
))
556 viewer
= wine_server_ptr_handle( reply
->viewer
);
557 owner
= wine_server_ptr_handle( reply
->owner
);
563 NtUserMessageCall( viewer
, WM_DRAWCLIPBOARD
, (WPARAM
)owner
, 0,
564 0, NtUserSendNotifyMessage
, FALSE
);
567 /**************************************************************************
568 * NtUserSetClipboardData (win32u.@)
570 NTSTATUS WINAPI
NtUserSetClipboardData( UINT format
, HANDLE data
, struct set_clipboard_params
*params
)
572 struct cached_format
*cache
= NULL
, *prev
= NULL
;
575 data_size_t size
= 0;
576 NTSTATUS status
= STATUS_SUCCESS
;
578 TRACE( "%s %p\n", debugstr_format( format
), data
);
580 if (params
->cache_only
)
582 pthread_mutex_lock( &clipboard_mutex
);
583 if ((cache
= get_cached_format( format
)) && cache
->seqno
== params
->seqno
)
584 cache
->handle
= data
;
586 status
= STATUS_UNSUCCESSFUL
;
587 pthread_mutex_unlock( &clipboard_mutex
);
597 if (!(cache
= malloc( sizeof(*cache
) ))) goto done
;
598 cache
->format
= format
;
599 cache
->handle
= data
;
602 if (format
== CF_BITMAP
|| format
== CF_PALETTE
)
604 make_gdi_object_system( cache
->handle
, TRUE
);
607 NtQueryDefaultLocale( TRUE
, &lcid
);
609 pthread_mutex_lock( &clipboard_mutex
);
611 SERVER_START_REQ( set_clipboard_data
)
613 req
->format
= format
;
615 wine_server_add_data( req
, ptr
, size
);
616 if (!(status
= wine_server_call( req
)))
618 if (cache
) cache
->seqno
= reply
->seqno
;
625 /* free the previous entry if any */
626 if ((prev
= get_cached_format( format
))) list_remove( &prev
->entry
);
627 if (cache
) list_add_tail( &cached_formats
, &cache
->entry
);
631 pthread_mutex_unlock( &clipboard_mutex
);
632 if (prev
) free_cached_data( prev
);
638 /**************************************************************************
639 * NtUserGetClipboardData (win32u.@)
641 HANDLE WINAPI
NtUserGetClipboardData( UINT format
, struct get_clipboard_params
*params
)
643 struct cached_format
*cache
= NULL
;
645 UINT from
, data_seqno
;
652 pthread_mutex_lock( &clipboard_mutex
);
654 if (!params
->data_only
) cache
= get_cached_format( format
);
656 SERVER_START_REQ( get_clipboard_data
)
658 req
->format
= format
;
659 req
->render
= render
;
660 if (cache
&& cache
->handle
)
663 req
->seqno
= cache
->seqno
;
665 wine_server_set_reply( req
, params
->data
, params
->size
);
666 status
= wine_server_call( req
);
669 data_seqno
= reply
->seqno
;
670 owner
= wine_server_ptr_handle( reply
->owner
);
680 if (cache
->handle
&& data_seqno
== cache
->seqno
) /* we can reuse the cached data */
682 HANDLE ret
= cache
->handle
;
683 pthread_mutex_unlock( &clipboard_mutex
);
684 TRACE( "%s returning %p\n", debugstr_format( format
), ret
);
688 /* cache entry is stale, remove it */
689 list_remove( &cache
->entry
);
690 list_add_tail( &formats_to_free
, &cache
->entry
);
693 if (params
->data_only
)
695 pthread_mutex_unlock( &clipboard_mutex
);
699 /* allocate new cache entry */
700 if (!(cache
= malloc( sizeof(*cache
) )))
702 pthread_mutex_unlock( &clipboard_mutex
);
706 cache
->format
= format
;
707 cache
->seqno
= data_seqno
;
708 cache
->handle
= NULL
;
709 params
->seqno
= cache
->seqno
;
710 list_add_tail( &cached_formats
, &cache
->entry
);
711 pthread_mutex_unlock( &clipboard_mutex
);
712 TRACE( "%s needs unmarshaling\n", debugstr_format( format
) );
713 params
->data_size
= ~0;
716 pthread_mutex_unlock( &clipboard_mutex
);
718 if (status
== STATUS_BUFFER_OVERFLOW
)
720 params
->data_size
= size
;
723 if (status
== STATUS_OBJECT_NAME_NOT_FOUND
)
725 RtlSetLastWin32Error( ERROR_NOT_FOUND
); /* no such format */
730 RtlSetLastWin32Error( RtlNtStatusToDosError( status
));
731 TRACE( "%s error %08x\n", debugstr_format( format
), status
);
734 if (render
) /* try rendering it */
739 struct render_synthesized_format_params params
= { .format
= format
, .from
= from
};
742 KeUserModeCallback( NtUserRenderSynthesizedFormat
, ¶ms
, sizeof(params
),
743 &ret_ptr
, &ret_len
);
748 TRACE( "%s sending WM_RENDERFORMAT to %p\n", debugstr_format( format
), owner
);
749 send_message( owner
, WM_RENDERFORMAT
, format
, 0 );
753 TRACE( "%s returning 0\n", debugstr_format( format
));