win32u: Move clipboard data management from user32.

Signed-off-by: Jacek Caban <jacek@codeweavers.com>
Signed-off-by: Huw Davies <huw@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Jacek Caban 2022-04-25 16:59:16 +02:00 committed by Alexandre Julliard
parent cad4adedaa
commit eba0a51002
8 changed files with 384 additions and 263 deletions

View file

@ -48,17 +48,6 @@
WINE_DEFAULT_DEBUG_CHANNEL(clipboard); WINE_DEFAULT_DEBUG_CHANNEL(clipboard);
struct cached_format
{
struct list entry; /* entry in cache list */
UINT format; /* format id */
UINT seqno; /* sequence number when the data was set */
HANDLE handle; /* original data handle */
};
static struct list cached_formats = LIST_INIT( cached_formats );
static struct list formats_to_free = LIST_INIT( formats_to_free );
static CRITICAL_SECTION clipboard_cs; static CRITICAL_SECTION clipboard_cs;
static CRITICAL_SECTION_DEBUG critsect_debug = static CRITICAL_SECTION_DEBUG critsect_debug =
{ {
@ -119,7 +108,7 @@ static const char *debugstr_format( UINT id )
} }
/* build the data to send to the server in SetClipboardData */ /* build the data to send to the server in SetClipboardData */
static HANDLE marshal_data( UINT format, HANDLE handle, data_size_t *ret_size ) static HANDLE marshal_data( UINT format, HANDLE handle, size_t *ret_size )
{ {
SIZE_T size; SIZE_T size;
@ -258,110 +247,35 @@ static HANDLE unmarshal_data( UINT format, void *data, data_size_t size )
return handle; return handle;
} }
/* retrieve a data format from the cache */
static struct cached_format *get_cached_format( UINT format )
{
struct cached_format *cache;
LIST_FOR_EACH_ENTRY( cache, &cached_formats, struct cached_format, entry )
if (cache->format == format) return cache;
return NULL;
}
/* store data in the cache, or reuse the existing one if available */
static HANDLE cache_data( UINT format, HANDLE data, data_size_t size, UINT seqno,
struct cached_format *cache )
{
if (cache)
{
if (seqno == cache->seqno) /* we can reuse the cached data */
{
GlobalFree( data );
return cache->handle;
}
/* cache entry is stale, remove it */
list_remove( &cache->entry );
list_add_tail( &formats_to_free, &cache->entry );
}
/* allocate new cache entry */
if (!(cache = HeapAlloc( GetProcessHeap(), 0, sizeof(*cache) )))
{
GlobalFree( data );
return 0;
}
cache->format = format;
cache->seqno = seqno;
cache->handle = unmarshal_data( format, data, size );
list_add_tail( &cached_formats, &cache->entry );
return cache->handle;
}
/* free a single cached format */ /* free a single cached format */
static void free_cached_data( struct cached_format *cache ) void free_cached_data( UINT format, HANDLE handle )
{ {
void *ptr; void *ptr;
switch (cache->format) switch (format)
{ {
case CF_BITMAP: case CF_BITMAP:
case CF_DSPBITMAP: case CF_DSPBITMAP:
case CF_PALETTE: case CF_PALETTE:
DeleteObject( cache->handle ); DeleteObject( handle );
break; break;
case CF_ENHMETAFILE: case CF_ENHMETAFILE:
case CF_DSPENHMETAFILE: case CF_DSPENHMETAFILE:
DeleteEnhMetaFile( cache->handle ); DeleteEnhMetaFile( handle );
break; break;
case CF_METAFILEPICT: case CF_METAFILEPICT:
case CF_DSPMETAFILEPICT: case CF_DSPMETAFILEPICT:
if ((ptr = GlobalLock( cache->handle ))) if ((ptr = GlobalLock( handle )))
{ {
DeleteMetaFile( ((METAFILEPICT *)ptr)->hMF ); DeleteMetaFile( ((METAFILEPICT *)ptr)->hMF );
GlobalUnlock( cache->handle ); GlobalUnlock( handle );
} }
GlobalFree( cache->handle ); GlobalFree( handle );
break; break;
default: default:
GlobalFree( cache->handle ); GlobalFree( handle );
break; break;
} }
list_remove( &cache->entry );
HeapFree( GetProcessHeap(), 0, cache );
}
/* clear global memory formats; special types are freed on EmptyClipboard */
static void invalidate_memory_formats(void)
{
struct cached_format *cache, *next;
LIST_FOR_EACH_ENTRY_SAFE( cache, next, &cached_formats, struct cached_format, entry )
{
switch (cache->format)
{
case CF_BITMAP:
case CF_DSPBITMAP:
case CF_PALETTE:
case CF_ENHMETAFILE:
case CF_DSPENHMETAFILE:
case CF_METAFILEPICT:
case CF_DSPMETAFILEPICT:
continue;
default:
free_cached_data( cache );
break;
}
}
}
/* free all the data in the cache */
static void free_cached_formats(void)
{
struct list *ptr;
list_move_tail( &formats_to_free, &cached_formats );
while ((ptr = list_head( &formats_to_free )))
free_cached_data( LIST_ENTRY( ptr, struct cached_format, entry ));
} }
/* get the clipboard locale stored in the CF_LOCALE format */ /* get the clipboard locale stored in the CF_LOCALE format */
@ -576,7 +490,7 @@ static HANDLE render_synthesized_enhmetafile( HANDLE data )
} }
/* render a synthesized format */ /* render a synthesized format */
static HANDLE render_synthesized_format( UINT format, UINT from ) HANDLE render_synthesized_format( UINT format, UINT from )
{ {
HANDLE data = GetClipboardData( from ); HANDLE data = GetClipboardData( from );
@ -650,55 +564,7 @@ INT WINAPI GetClipboardFormatNameA( UINT format, LPSTR buffer, INT maxlen )
*/ */
BOOL WINAPI OpenClipboard( HWND hwnd ) BOOL WINAPI OpenClipboard( HWND hwnd )
{ {
BOOL ret; return NtUserOpenClipboard( hwnd, 0 );
HWND owner;
TRACE( "%p\n", hwnd );
NtUserCallNoParam( NtUserUpdateClipboard );
EnterCriticalSection( &clipboard_cs );
SERVER_START_REQ( open_clipboard )
{
req->window = wine_server_user_handle( hwnd );
ret = !wine_server_call_err( req );
owner = wine_server_ptr_handle( reply->owner );
}
SERVER_END_REQ;
if (ret && !WIN_IsCurrentProcess( owner )) invalidate_memory_formats();
LeaveCriticalSection( &clipboard_cs );
return ret;
}
/**************************************************************************
* EmptyClipboard (USER32.@)
* Empties and acquires ownership of the clipboard
*/
BOOL WINAPI EmptyClipboard(void)
{
BOOL ret;
HWND owner = NtUserGetClipboardOwner();
TRACE( "owner %p\n", owner );
if (owner) SendMessageTimeoutW( owner, WM_DESTROYCLIPBOARD, 0, 0, SMTO_ABORTIFHUNG, 5000, NULL );
EnterCriticalSection( &clipboard_cs );
SERVER_START_REQ( empty_clipboard )
{
ret = !wine_server_call_err( req );
}
SERVER_END_REQ;
if (ret) free_cached_formats();
LeaveCriticalSection( &clipboard_cs );
return ret;
} }
@ -707,55 +573,28 @@ BOOL WINAPI EmptyClipboard(void)
*/ */
HANDLE WINAPI SetClipboardData( UINT format, HANDLE data ) HANDLE WINAPI SetClipboardData( UINT format, HANDLE data )
{ {
struct cached_format *cache = NULL; struct set_clipboard_params params = { .size = 0 };
void *ptr = NULL; HANDLE handle = data;
data_size_t size = 0; NTSTATUS status;
HANDLE handle = data, retval = 0;
NTSTATUS status = STATUS_SUCCESS;
TRACE( "%s %p\n", debugstr_format( format ), data ); TRACE( "%s %p\n", debugstr_format( format ), data );
if (data) if (data)
{ {
if (!(handle = marshal_data( format, data, &size ))) return 0; if (!(handle = marshal_data( format, data, &params.size ))) return 0;
if (!(ptr = GlobalLock( handle ))) goto done; if (!(params.data = GlobalLock( handle ))) return 0;
if (!(cache = HeapAlloc( GetProcessHeap(), 0, sizeof(*cache) ))) goto done;
cache->format = format;
cache->handle = data;
} }
EnterCriticalSection( &clipboard_cs ); status = NtUserSetClipboardData( format, data, &params );
SERVER_START_REQ( set_clipboard_data ) if (params.data) GlobalUnlock( handle );
{
req->format = format;
req->lcid = GetUserDefaultLCID();
wine_server_add_data( req, ptr, size );
if (!(status = wine_server_call( req )))
{
if (cache) cache->seqno = reply->seqno;
}
}
SERVER_END_REQ;
if (!status)
{
/* free the previous entry if any */
struct cached_format *prev;
if ((prev = get_cached_format( format ))) free_cached_data( prev );
if (cache) list_add_tail( &cached_formats, &cache->entry );
retval = data;
}
else HeapFree( GetProcessHeap(), 0, cache );
LeaveCriticalSection( &clipboard_cs );
done:
if (ptr) GlobalUnlock( handle );
if (handle != data) GlobalFree( handle ); if (handle != data) GlobalFree( handle );
if (status) SetLastError( RtlNtStatusToDosError( status )); if (status)
return retval; {
SetLastError( RtlNtStatusToDosError( status ));
return 0;
}
return data;
} }
@ -773,73 +612,34 @@ UINT WINAPI EnumClipboardFormats( UINT format )
*/ */
HANDLE WINAPI GetClipboardData( UINT format ) HANDLE WINAPI GetClipboardData( UINT format )
{ {
struct cached_format *cache; struct get_clipboard_params params = { .data_size = 1024 };
NTSTATUS status; HANDLE ret = 0;
UINT from, data_seqno;
HWND owner;
HANDLE data;
UINT size = 1024;
BOOL render = TRUE;
for (;;) EnterCriticalSection( &clipboard_cs );
while (params.data_size)
{ {
if (!(data = GlobalAlloc( GMEM_FIXED, size ))) return 0; params.size = params.data_size;
params.data_size = 0;
EnterCriticalSection( &clipboard_cs ); if (!(params.data = GlobalAlloc( GMEM_FIXED, params.size ))) break;
cache = get_cached_format( format ); ret = NtUserGetClipboardData( format, &params );
if (ret) break;
SERVER_START_REQ( get_clipboard_data ) if (params.data_size == ~0) /* needs unmarshaling */
{ {
req->format = format; struct set_clipboard_params set_params = { .cache_only = TRUE, .seqno = params.seqno };
req->render = render;
if (cache)
{
req->cached = 1;
req->seqno = cache->seqno;
}
wine_server_set_reply( req, data, size );
status = wine_server_call( req );
from = reply->from;
size = reply->total;
data_seqno = reply->seqno;
owner = wine_server_ptr_handle( reply->owner );
}
SERVER_END_REQ;
if (!status && size) ret = unmarshal_data( format, params.data, params.size );
{ if (!NtUserSetClipboardData( format, ret, &set_params )) break;
data = cache_data( format, data, size, data_seqno, cache );
LeaveCriticalSection( &clipboard_cs );
TRACE( "%s returning %p\n", debugstr_format( format ), data );
return data;
}
LeaveCriticalSection( &clipboard_cs );
GlobalFree( data );
if (status == STATUS_BUFFER_OVERFLOW) continue; /* retry with the new size */ /* data changed, retry */
if (status == STATUS_OBJECT_NAME_NOT_FOUND) return 0; /* no such format */ free_cached_data( format, ret );
if (status) ret = 0;
{ params.data_size = 1024;
SetLastError( RtlNtStatusToDosError( status )); continue;
TRACE( "%s error %08x\n", debugstr_format( format ), status );
return 0;
} }
if (render) /* try rendering it */ GlobalFree( params.data );
{
render = FALSE;
if (from)
{
render_synthesized_format( format, from );
continue;
}
else if (owner)
{
TRACE( "%s sending WM_RENDERFORMAT to %p\n", debugstr_format( format ), owner );
SendMessageW( owner, WM_RENDERFORMAT, format, 0 );
continue;
}
}
TRACE( "%s returning 0\n", debugstr_format( format ));
return 0;
} }
LeaveCriticalSection( &clipboard_cs );
return ret;
} }

View file

@ -3134,7 +3134,7 @@ static void EDIT_WM_Copy(EDITSTATE *es)
TRACE("%s\n", debugstr_w(dst)); TRACE("%s\n", debugstr_w(dst));
GlobalUnlock(hdst); GlobalUnlock(hdst);
OpenClipboard(es->hwndSelf); OpenClipboard(es->hwndSelf);
EmptyClipboard(); NtUserEmptyClipboard();
SetClipboardData(CF_UNICODETEXT, hdst); SetClipboardData(CF_UNICODETEXT, hdst);
NtUserCloseClipboard(); NtUserCloseClipboard();
} }

View file

@ -202,7 +202,7 @@
@ stdcall DrawTextExW(long wstr long ptr long ptr) @ stdcall DrawTextExW(long wstr long ptr long ptr)
@ stdcall DrawTextW(long wstr long ptr long) @ stdcall DrawTextW(long wstr long ptr long)
@ stdcall EditWndProc(long long long long) EditWndProcA @ stdcall EditWndProc(long long long long) EditWndProcA
@ stdcall EmptyClipboard() @ stdcall EmptyClipboard() NtUserEmptyClipboard
@ stdcall EnableMenuItem(long long long) NtUserEnableMenuItem @ stdcall EnableMenuItem(long long long) NtUserEnableMenuItem
@ stdcall EnableMouseInPointer(long) @ stdcall EnableMouseInPointer(long)
@ stdcall EnableNonClientDpiScaling(long) @ stdcall EnableNonClientDpiScaling(long)

View file

@ -184,6 +184,20 @@ static const struct user_callbacks user_funcs =
unregister_imm, unregister_imm,
}; };
static NTSTATUS WINAPI User32FreeCachedClipboardData( const struct free_cached_data_params *params,
ULONG size )
{
free_cached_data( params->format, params->handle );
return 0;
}
static NTSTATUS WINAPI User32RenderSsynthesizedFormat( const struct render_synthesized_format_params *params,
ULONG size )
{
render_synthesized_format( params->format, params->from );
return 0;
}
static BOOL WINAPI User32LoadDriver( const WCHAR *path, ULONG size ) static BOOL WINAPI User32LoadDriver( const WCHAR *path, ULONG size )
{ {
return LoadLibraryW( path ) != NULL; return LoadLibraryW( path ) != NULL;
@ -196,7 +210,9 @@ static const void *kernel_callback_table[NtUserCallCount] =
User32CallWinEventHook, User32CallWinEventHook,
User32CallWindowProc, User32CallWindowProc,
User32CallWindowsHook, User32CallWindowsHook,
User32FreeCachedClipboardData,
User32LoadDriver, User32LoadDriver,
User32RenderSsynthesizedFormat,
}; };

View file

@ -82,6 +82,8 @@ extern BOOL process_rawinput_message( MSG *msg, UINT hw_id,
const struct hardware_msg_data *msg_data ) DECLSPEC_HIDDEN; const struct hardware_msg_data *msg_data ) DECLSPEC_HIDDEN;
extern BOOL unpack_dde_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lparam, extern BOOL unpack_dde_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lparam,
void **buffer, size_t size ) DECLSPEC_HIDDEN; void **buffer, size_t size ) DECLSPEC_HIDDEN;
extern void free_cached_data( UINT format, HANDLE handle ) DECLSPEC_HIDDEN;
extern HANDLE render_synthesized_format( UINT format, UINT from ) DECLSPEC_HIDDEN;
extern void CLIPBOARD_ReleaseOwner( HWND hwnd ) DECLSPEC_HIDDEN; extern void CLIPBOARD_ReleaseOwner( HWND hwnd ) DECLSPEC_HIDDEN;
extern BOOL FOCUS_MouseActivate( HWND hwnd ) DECLSPEC_HIDDEN; extern BOOL FOCUS_MouseActivate( HWND hwnd ) DECLSPEC_HIDDEN;

View file

@ -27,6 +27,9 @@
#pragma makedep unix #pragma makedep unix
#endif #endif
#include <pthread.h>
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "win32u_private.h" #include "win32u_private.h"
#include "ntuser_private.h" #include "ntuser_private.h"
#include "wine/server.h" #include "wine/server.h"
@ -34,6 +37,19 @@
WINE_DEFAULT_DEBUG_CHANNEL(clipboard); WINE_DEFAULT_DEBUG_CHANNEL(clipboard);
static pthread_mutex_t clipboard_mutex = PTHREAD_MUTEX_INITIALIZER;
struct cached_format
{
struct list entry; /* entry in cache list */
UINT format; /* format id */
UINT seqno; /* sequence number when the data was set */
HANDLE handle; /* original data handle */
};
static struct list cached_formats = LIST_INIT( cached_formats );
static struct list formats_to_free = LIST_INIT( formats_to_free );
/* get a debug string for a format id */ /* get a debug string for a format id */
static const char *debugstr_format( UINT id ) static const char *debugstr_format( UINT id )
@ -76,13 +92,106 @@ static const char *debugstr_format( UINT id )
} }
} }
/* retrieve a data format from the cache */
static struct cached_format *get_cached_format( UINT format )
{
struct cached_format *cache;
LIST_FOR_EACH_ENTRY( cache, &cached_formats, struct cached_format, entry )
if (cache->format == format) return cache;
return NULL;
}
/* free a single cached format */
static void free_cached_data( struct cached_format *cache )
{
struct free_cached_data_params params;
void *ret_ptr;
ULONG ret_len;
switch (cache->format)
{
case CF_BITMAP:
case CF_DSPBITMAP:
case CF_PALETTE:
NtGdiDeleteObjectApp( cache->handle );
break;
default:
params.format = cache->format;
params.handle = cache->handle;
KeUserModeCallback( NtUserFreeCachedClipboardData, &params, sizeof(params),
&ret_ptr, &ret_len );
break;
}
free( cache );
}
/* free all the data in the cache */
static void free_cached_formats( struct list *list )
{
struct list *ptr;
while ((ptr = list_head( list )))
{
list_remove( ptr );
free_cached_data( LIST_ENTRY( ptr, struct cached_format, entry ));
}
}
/* clear global memory formats; special types are freed on EmptyClipboard */
static void invalidate_memory_formats( struct list *free_list )
{
struct cached_format *cache, *next;
LIST_FOR_EACH_ENTRY_SAFE( cache, next, &cached_formats, struct cached_format, entry )
{
switch (cache->format)
{
case CF_BITMAP:
case CF_DSPBITMAP:
case CF_PALETTE:
case CF_ENHMETAFILE:
case CF_DSPENHMETAFILE:
case CF_METAFILEPICT:
case CF_DSPMETAFILEPICT:
continue;
default:
list_remove( &cache->entry );
list_add_tail( free_list, &cache->entry );
break;
}
}
}
/************************************************************************** /**************************************************************************
* NtUserOpenClipboard (win32u.@) * NtUserOpenClipboard (win32u.@)
*/ */
BOOL WINAPI NtUserOpenClipboard( HWND hwnd, ULONG unk ) BOOL WINAPI NtUserOpenClipboard( HWND hwnd, ULONG unk )
{ {
FIXME( "\n" ); struct list free_list = LIST_INIT( free_list );
return FALSE; BOOL ret;
HWND owner;
TRACE( "%p\n", hwnd );
user_driver->pUpdateClipboard();
pthread_mutex_lock( &clipboard_mutex );
SERVER_START_REQ( open_clipboard )
{
req->window = wine_server_user_handle( hwnd );
ret = !wine_server_call_err( req );
owner = wine_server_ptr_handle( reply->owner );
}
SERVER_END_REQ;
if (ret && !is_current_process_window( owner )) invalidate_memory_formats( &free_list );
pthread_mutex_unlock( &clipboard_mutex );
free_cached_formats( &free_list );
return ret;
} }
/************************************************************************** /**************************************************************************
@ -115,8 +224,32 @@ BOOL WINAPI NtUserCloseClipboard(void)
*/ */
BOOL WINAPI NtUserEmptyClipboard(void) BOOL WINAPI NtUserEmptyClipboard(void)
{ {
FIXME( "\n" ); BOOL ret;
return FALSE; HWND owner = NtUserGetClipboardOwner();
struct list free_list = LIST_INIT( free_list );
TRACE( "owner %p\n", owner );
if (owner) send_message_timeout( owner, WM_DESTROYCLIPBOARD, 0, 0, SMTO_ABORTIFHUNG,
5000, NULL, FALSE );
pthread_mutex_lock( &clipboard_mutex );
SERVER_START_REQ( empty_clipboard )
{
ret = !wine_server_call_err( req );
}
SERVER_END_REQ;
if (ret)
{
list_move_tail( &free_list, &formats_to_free );
list_move_tail( &free_list, &cached_formats );
}
pthread_mutex_unlock( &clipboard_mutex );
free_cached_formats( &free_list );
return ret;
} }
/************************************************************************** /**************************************************************************
@ -432,10 +565,65 @@ void release_clipboard_owner( HWND hwnd )
/************************************************************************** /**************************************************************************
* NtUserSetClipboardData (win32u.@) * NtUserSetClipboardData (win32u.@)
*/ */
NTSTATUS WINAPI NtUserSetClipboardData( UINT format, HANDLE handle, struct set_clipboard_params *params ) NTSTATUS WINAPI NtUserSetClipboardData( UINT format, HANDLE data, struct set_clipboard_params *params )
{ {
FIXME( "\n" ); struct cached_format *cache = NULL, *prev = NULL;
return 0; void *ptr = NULL;
data_size_t size = 0;
NTSTATUS status = STATUS_SUCCESS;
TRACE( "%s %p\n", debugstr_format( format ), data );
if (params->cache_only)
{
pthread_mutex_lock( &clipboard_mutex );
if ((cache = get_cached_format( format )) && cache->seqno == params->seqno)
cache->handle = data;
else
status = STATUS_UNSUCCESSFUL;
pthread_mutex_unlock( &clipboard_mutex );
return status;
}
if (params->data)
{
ptr = params->data;
size = params->size;
if (data)
{
if (!(cache = malloc( sizeof(*cache) ))) goto done;
cache->format = format;
cache->handle = data;
}
}
pthread_mutex_lock( &clipboard_mutex );
SERVER_START_REQ( set_clipboard_data )
{
req->format = format;
NtQueryDefaultLocale( TRUE, &req->lcid );
wine_server_add_data( req, ptr, size );
if (!(status = wine_server_call( req )))
{
if (cache) cache->seqno = reply->seqno;
}
}
SERVER_END_REQ;
if (!status)
{
/* free the previous entry if any */
if ((prev = get_cached_format( format ))) list_remove( &prev->entry );
if (cache) list_add_tail( &cached_formats, &cache->entry );
}
else free( cache );
pthread_mutex_unlock( &clipboard_mutex );
if (prev) free_cached_data( prev );
done:
return status;
} }
/************************************************************************** /**************************************************************************
@ -443,6 +631,102 @@ NTSTATUS WINAPI NtUserSetClipboardData( UINT format, HANDLE handle, struct set_c
*/ */
HANDLE WINAPI NtUserGetClipboardData( UINT format, struct get_clipboard_params *params ) HANDLE WINAPI NtUserGetClipboardData( UINT format, struct get_clipboard_params *params )
{ {
FIXME( "\n" ); struct cached_format *cache;
return 0; NTSTATUS status;
UINT from, data_seqno;
size_t size;
HWND owner;
BOOL render = TRUE;
for (;;)
{
pthread_mutex_lock( &clipboard_mutex );
cache = get_cached_format( format );
SERVER_START_REQ( get_clipboard_data )
{
req->format = format;
req->render = render;
if (cache && cache->handle)
{
req->cached = 1;
req->seqno = cache->seqno;
}
wine_server_set_reply( req, params->data, params->size );
status = wine_server_call( req );
from = reply->from;
size = reply->total;
data_seqno = reply->seqno;
owner = wine_server_ptr_handle( reply->owner );
}
SERVER_END_REQ;
if (!status && size)
{
if (cache)
{
if (cache->handle && data_seqno == cache->seqno) /* we can reuse the cached data */
{
HANDLE ret = cache->handle;
pthread_mutex_unlock( &clipboard_mutex );
TRACE( "%s returning %p\n", debugstr_format( format ), ret );
return ret;
}
/* cache entry is stale, remove it */
list_remove( &cache->entry );
list_add_tail( &formats_to_free, &cache->entry );
}
/* allocate new cache entry */
if (!(cache = malloc( sizeof(*cache) ))) return 0;
cache->format = format;
cache->seqno = data_seqno;
cache->handle = NULL;
params->seqno = cache->seqno;
list_add_tail( &cached_formats, &cache->entry );
pthread_mutex_unlock( &clipboard_mutex );
TRACE( "%s needs unmarshaling\n", debugstr_format( format ) );
params->data_size = ~0;
params->size = size;
return 0;
}
pthread_mutex_unlock( &clipboard_mutex );
if (status == STATUS_BUFFER_OVERFLOW)
{
params->data_size = size;
return 0;
}
if (status == STATUS_OBJECT_NAME_NOT_FOUND) return 0; /* no such format */
if (status)
{
SetLastError( RtlNtStatusToDosError( status ));
TRACE( "%s error %08x\n", debugstr_format( format ), status );
return 0;
}
if (render) /* try rendering it */
{
render = FALSE;
if (from)
{
struct render_synthesized_format_params params = { .format = format, .from = from };
ULONG ret_len;
void *ret_ptr;
KeUserModeCallback( NtUserRenderSynthesizedFormat, &params, sizeof(params),
&ret_ptr, &ret_len );
continue;
}
if (owner)
{
TRACE( "%s sending WM_RENDERFORMAT to %p\n", debugstr_format( format ), owner );
send_message( owner, WM_RENDERFORMAT, format, 0 );
continue;
}
}
TRACE( "%s returning 0\n", debugstr_format( format ));
return 0;
}
} }

View file

@ -4671,10 +4671,6 @@ ULONG_PTR WINAPI NtUserCallNoParam( ULONG code )
thread_detach(); thread_detach();
return 0; return 0;
case NtUserUpdateClipboard:
user_driver->pUpdateClipboard();
return 0;
default: default:
FIXME( "invalid code %u\n", code ); FIXME( "invalid code %u\n", code );
return 0; return 0;

View file

@ -32,7 +32,9 @@ enum
NtUserCallWinEventHook, NtUserCallWinEventHook,
NtUserCallWinProc, NtUserCallWinProc,
NtUserCallWindowsHook, NtUserCallWindowsHook,
NtUserFreeCachedClipboardData,
NtUserLoadDriver, NtUserLoadDriver,
NtUserRenderSynthesizedFormat,
/* win16 hooks */ /* win16 hooks */
NtUserCallFreeIcon, NtUserCallFreeIcon,
NtUserThunkLock, NtUserThunkLock,
@ -140,6 +142,20 @@ struct win_hook_params
WCHAR module[MAX_PATH]; WCHAR module[MAX_PATH];
}; };
/* NtUserFreeCachedClipboardData params */
struct free_cached_data_params
{
UINT format;
HANDLE handle;
};
/* NtUserRenderSynthesizedFormat params */
struct render_synthesized_format_params
{
UINT format;
UINT from;
};
/* process DPI awareness contexts */ /* process DPI awareness contexts */
#define NTUSER_DPI_UNAWARE 0x00006010 #define NTUSER_DPI_UNAWARE 0x00006010
#define NTUSER_DPI_SYSTEM_AWARE 0x00006011 #define NTUSER_DPI_SYSTEM_AWARE 0x00006011
@ -237,11 +253,19 @@ struct client_menu_name
/* NtUserGetClipboardData params, not compatible with Windows */ /* NtUserGetClipboardData params, not compatible with Windows */
struct get_clipboard_params struct get_clipboard_params
{ {
void *data;
size_t size;
size_t data_size;
UINT seqno;
}; };
/* NtUserSetClipboardData params, not compatible with Windows */ /* NtUserSetClipboardData params, not compatible with Windows */
struct set_clipboard_params struct set_clipboard_params
{ {
void *data;
size_t size;
BOOL cache_only;
UINT seqno;
}; };
/* internal messages codes */ /* internal messages codes */
@ -624,7 +648,6 @@ enum
/* temporary exports */ /* temporary exports */
NtUserExitingThread, NtUserExitingThread,
NtUserThreadDetach, NtUserThreadDetach,
NtUserUpdateClipboard,
}; };
static inline HWND NtUserGetDesktopWindow(void) static inline HWND NtUserGetDesktopWindow(void)