user32: Retrieve clipboard data from the server.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2016-09-26 14:19:28 +09:00
parent c69b4995c5
commit 3044935b0e
7 changed files with 195 additions and 69 deletions

View file

@ -36,6 +36,8 @@
#endif
#include <string.h>
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
@ -162,6 +164,46 @@ static HANDLE marshal_data( UINT format, HANDLE handle, data_size_t *ret_size )
}
}
/* rebuild the target handle from the data received in GetClipboardData */
static HANDLE unmarshal_data( UINT format, void *data, data_size_t size )
{
HANDLE handle = GlobalReAlloc( data, size, 0 ); /* release unused space */
switch (format)
{
case CF_BITMAP:
{
BITMAP *bm = handle;
if (size < sizeof(*bm)) break;
if (size < bm->bmWidthBytes * abs( bm->bmHeight )) break;
if (bm->bmBits) break; /* DIB sections are not supported across processes */
bm->bmBits = bm + 1;
return CreateBitmapIndirect( bm );
}
case CF_DSPBITMAP: /* not supported across processes */
break;
case CF_PALETTE:
{
LOGPALETTE *pal = handle;
if (size < sizeof(*pal)) break;
if (size < offsetof( LOGPALETTE, palPalEntry[pal->palNumEntries] )) break;
return CreatePalette( pal );
}
case CF_ENHMETAFILE:
case CF_DSPENHMETAFILE:
return SetEnhMetaFileBits( size, handle );
case CF_METAFILEPICT:
case CF_DSPMETAFILEPICT:
{
METAFILEPICT *mf = handle;
if (size <= sizeof(*mf)) break;
mf->hMF = SetMetaFileBitsEx( size - sizeof(*mf), (BYTE *)(mf + 1) );
return handle;
}
}
return handle;
}
/* formats that can be synthesized are: CF_TEXT, CF_OEMTEXT, CF_UNICODETEXT,
CF_BITMAP, CF_DIB, CF_DIBV5, CF_ENHMETAFILE, CF_METAFILEPICT */
@ -501,23 +543,6 @@ static HANDLE render_synthesized_format( UINT format, UINT from )
return data;
}
/**************************************************************************
* get_clipboard_flags
*/
static UINT get_clipboard_flags(void)
{
UINT ret = 0;
SERVER_START_REQ( set_clipboard_info )
{
if (!wine_server_call_err( req )) ret = reply->flags;
}
SERVER_END_REQ;
return ret;
}
/**************************************************************************
* CLIPBOARD_ReleaseOwner
*/
@ -542,10 +567,6 @@ void CLIPBOARD_ReleaseOwner( HWND hwnd )
}
/**************************************************************************
* WIN32 Clipboard implementation
**************************************************************************/
/**************************************************************************
* RegisterClipboardFormatW (USER32.@)
*/
@ -643,11 +664,8 @@ BOOL WINAPI CloseClipboard(void)
if (!ret) return FALSE;
if (bCBHasChanged)
{
USER_Driver->pEndClipboardUpdate();
bCBHasChanged = FALSE;
}
bCBHasChanged = FALSE;
if (viewer) SendNotifyMessageW( viewer, WM_DRAWCLIPBOARD, (WPARAM)owner, 0 );
return TRUE;
}
@ -674,7 +692,6 @@ BOOL WINAPI EmptyClipboard(void)
if (ret)
{
USER_Driver->pEmptyClipboard();
bCBHasChanged = TRUE;
memset( synthesized_formats, 0, sizeof(synthesized_formats) );
}
@ -817,7 +834,7 @@ HANDLE WINAPI SetClipboardData( UINT format, HANDLE data )
}
SERVER_END_REQ;
if (ret && USER_Driver->pSetClipboardData( format, data, TRUE ))
if (ret)
{
bCBHasChanged = TRUE;
if (format < CF_MAX) synthesized_formats[format] = 0;
@ -931,23 +948,57 @@ BOOL WINAPI GetUpdatedClipboardFormats( UINT *formats, UINT size, UINT *out_size
*/
HANDLE WINAPI GetClipboardData( UINT format )
{
HANDLE data = 0;
NTSTATUS status;
HWND owner;
HANDLE data;
UINT size = 1024;
BOOL render = TRUE;
TRACE( "%s\n", debugstr_format( format ));
if (format < CF_MAX && synthesized_formats[format])
return render_synthesized_format( format, synthesized_formats[format] );
if (!(get_clipboard_flags() & CB_OPEN))
for (;;)
{
WARN("Clipboard not opened by calling task.\n");
SetLastError(ERROR_CLIPBOARD_NOT_OPEN);
if (!(data = GlobalAlloc( GMEM_FIXED, size ))) return 0;
SERVER_START_REQ( get_clipboard_data )
{
req->format = format;
wine_server_set_reply( req, data, size );
status = wine_server_call( req );
size = reply->total;
owner = wine_server_ptr_handle( reply->owner );
}
SERVER_END_REQ;
if (!status && size)
{
data = unmarshal_data( format, data, size );
TRACE( "%s returning %p\n", debugstr_format( format ), data );
return data;
}
GlobalFree( data );
if (status == STATUS_BUFFER_OVERFLOW) continue; /* retry with the new size */
if (status)
{
SetLastError( RtlNtStatusToDosError( status ));
TRACE( "%s error %08x\n", debugstr_format( format ), status );
return 0;
}
if (render) /* try rendering it */
{
render = FALSE;
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;
}
if (format < CF_MAX && synthesized_formats[format])
data = render_synthesized_format( format, synthesized_formats[format] );
else
data = USER_Driver->pGetClipboardData( format );
TRACE( "returning %p\n", data );
return data;
}

View file

@ -1762,16 +1762,16 @@ static void test_handles( HWND hwnd )
todo_wine ok( is_freed( hmoveable ), "expected freed mem %p\n", hmoveable );
data = GetClipboardData( CF_TEXT );
todo_wine ok( is_fixed( data ), "expected fixed mem %p\n", data );
ok( is_fixed( data ), "expected fixed mem %p\n", data );
data = GetClipboardData( format_id );
todo_wine ok( is_fixed( data ), "expected fixed mem %p\n", data );
ok( is_fixed( data ), "expected fixed mem %p\n", data );
data = GetClipboardData( CF_GDIOBJFIRST + 3 );
todo_wine ok( is_fixed( data ), "expected fixed mem %p\n", data );
ok( is_fixed( data ), "expected fixed mem %p\n", data );
data = GetClipboardData( CF_PRIVATEFIRST + 7 );
todo_wine ok( is_fixed( data ), "expected fixed mem %p\n", data );
ok( is_fixed( data ), "expected fixed mem %p\n", data );
data = GetClipboardData( format_id2 );
ok( is_fixed( data ), "expected fixed mem %p\n", data );
@ -1782,7 +1782,7 @@ static void test_handles( HWND hwnd )
ok( GlobalSize( data ) == 17, "wrong size %lu\n", GlobalSize( data ));
data = GetClipboardData( 0xdeadbabe );
todo_wine ok( is_fixed( data ), "expected fixed mem %p\n", data );
ok( is_fixed( data ), "expected fixed mem %p\n", data );
ok( GlobalSize( data ) == 23, "wrong size %lu\n", GlobalSize( data ));
data = GetClipboardData( 0xdeadfade );
@ -1937,69 +1937,69 @@ static void test_handles_process( const char *str )
h = GetClipboardData( CF_TEXT );
todo_wine_if( !h ) ok( is_fixed( h ), "expected fixed mem %p\n", h );
ptr = GlobalLock( h );
if (ptr) todo_wine ok( !strcmp( str, ptr ), "wrong data '%.5s'\n", ptr );
ok( !strcmp( str, ptr ), "wrong data '%.5s'\n", ptr );
GlobalUnlock( h );
h = GetClipboardData( format_id );
todo_wine ok( is_fixed( h ), "expected fixed mem %p\n", h );
ok( is_fixed( h ), "expected fixed mem %p\n", h );
ptr = GlobalLock( h );
if (ptr) ok( !strcmp( str, ptr ), "wrong data '%.5s'\n", ptr );
GlobalUnlock( h );
h = GetClipboardData( CF_GDIOBJFIRST + 3 );
todo_wine_if( !h ) ok( is_fixed( h ), "expected fixed mem %p\n", h );
ptr = GlobalLock( h );
if (ptr) todo_wine ok( !strcmp( str, ptr ), "wrong data '%.5s'\n", ptr );
ok( !strcmp( str, ptr ), "wrong data '%.5s'\n", ptr );
GlobalUnlock( h );
trace( "gdiobj %p\n", h );
h = GetClipboardData( CF_PRIVATEFIRST + 7 );
todo_wine_if( !h ) ok( is_fixed( h ), "expected fixed mem %p\n", h );
ptr = GlobalLock( h );
if (ptr) todo_wine ok( !strcmp( str, ptr ), "wrong data '%.5s'\n", ptr );
ok( !strcmp( str, ptr ), "wrong data '%.5s'\n", ptr );
GlobalUnlock( h );
trace( "private %p\n", h );
h = GetClipboardData( CF_BITMAP );
todo_wine ok( GetObjectType( h ) == OBJ_BITMAP, "expected bitmap %p\n", h );
todo_wine ok( GetObjectW( h, sizeof(bm), &bm ) == sizeof(bm), "GetObject %p failed\n", h );
todo_wine ok( bm.bmWidth == 13 && bm.bmHeight == 17, "wrong bitmap %ux%u\n", bm.bmWidth, bm.bmHeight );
ok( GetObjectType( h ) == OBJ_BITMAP, "expected bitmap %p\n", h );
ok( GetObjectW( h, sizeof(bm), &bm ) == sizeof(bm), "GetObject %p failed\n", h );
ok( bm.bmWidth == 13 && bm.bmHeight == 17, "wrong bitmap %ux%u\n", bm.bmWidth, bm.bmHeight );
trace( "bitmap %p\n", h );
h = GetClipboardData( CF_DSPBITMAP );
ok( !GetObjectType( h ), "expected invalid object %p\n", h );
trace( "bitmap2 %p\n", h );
h = GetClipboardData( CF_PALETTE );
todo_wine ok( GetObjectType( h ) == OBJ_PAL, "expected palette %p\n", h );
todo_wine ok( GetPaletteEntries( h, 0, 1, &entry ) == 1, "GetPaletteEntries %p failed\n", h );
todo_wine ok( entry.peRed == 0x12 && entry.peGreen == 0x34 && entry.peBlue == 0x56,
ok( GetObjectType( h ) == OBJ_PAL, "expected palette %p\n", h );
ok( GetPaletteEntries( h, 0, 1, &entry ) == 1, "GetPaletteEntries %p failed\n", h );
ok( entry.peRed == 0x12 && entry.peGreen == 0x34 && entry.peBlue == 0x56,
"wrong color %02x,%02x,%02x\n", entry.peRed, entry.peGreen, entry.peBlue );
trace( "palette %p\n", h );
h = GetClipboardData( CF_METAFILEPICT );
todo_wine ok( is_fixed( h ), "expected fixed mem %p\n", h );
ok( is_fixed( h ), "expected fixed mem %p\n", h );
if (h)
ok( GetObjectType( ((METAFILEPICT *)h)->hMF ) == OBJ_METAFILE,
"wrong object %p\n", ((METAFILEPICT *)h)->hMF );
trace( "metafile %p\n", h );
h = GetClipboardData( CF_DSPMETAFILEPICT );
todo_wine ok( is_fixed( h ), "expected fixed mem %p\n", h );
ok( is_fixed( h ), "expected fixed mem %p\n", h );
if (h)
ok( GetObjectType( ((METAFILEPICT *)h)->hMF ) == OBJ_METAFILE,
"wrong object %p\n", ((METAFILEPICT *)h)->hMF );
trace( "metafile2 %p\n", h );
h = GetClipboardData( CF_ENHMETAFILE );
todo_wine ok( GetObjectType( h ) == OBJ_ENHMETAFILE, "expected enhmetafile %p\n", h );
todo_wine ok( GetEnhMetaFileBits( h, sizeof(buffer), buffer ) > sizeof(ENHMETAHEADER),
ok( GetObjectType( h ) == OBJ_ENHMETAFILE, "expected enhmetafile %p\n", h );
ok( GetEnhMetaFileBits( h, sizeof(buffer), buffer ) > sizeof(ENHMETAHEADER),
"GetEnhMetaFileBits failed on %p\n", h );
todo_wine ok( ((ENHMETAHEADER *)buffer)->nRecords == 3,
ok( ((ENHMETAHEADER *)buffer)->nRecords == 3,
"wrong records %u\n", ((ENHMETAHEADER *)buffer)->nRecords );
trace( "enhmetafile %p\n", h );
h = GetClipboardData( CF_DSPENHMETAFILE );
todo_wine ok( GetObjectType( h ) == OBJ_ENHMETAFILE, "expected enhmetafile %p\n", h );
todo_wine ok( GetEnhMetaFileBits( h, sizeof(buffer), buffer ) > sizeof(ENHMETAHEADER),
ok( GetObjectType( h ) == OBJ_ENHMETAFILE, "expected enhmetafile %p\n", h );
ok( GetEnhMetaFileBits( h, sizeof(buffer), buffer ) > sizeof(ENHMETAHEADER),
"GetEnhMetaFileBits failed on %p\n", h );
todo_wine ok( ((ENHMETAHEADER *)buffer)->nRecords == 3,
ok( ((ENHMETAHEADER *)buffer)->nRecords == 3,
"wrong records %u\n", ((ENHMETAHEADER *)buffer)->nRecords );
trace( "enhmetafile2 %p\n", h );
h = GetClipboardData( CF_DIB );
todo_wine ok( is_fixed( h ), "expected fixed mem %p\n", h );
ok( is_fixed( h ), "expected fixed mem %p\n", h );
h = GetClipboardData( CF_DIBV5 );
todo_wine ok( is_fixed( h ), "expected fixed mem %p\n", h );
ok( is_fixed( h ), "expected fixed mem %p\n", h );
r = CloseClipboard();
ok( r, "gle %d\n", GetLastError() );
}
@ -2109,15 +2109,15 @@ static void test_data_handles(void)
ok( is_moveable( text ), "expected moveable mem %p\n", text );
h = GetClipboardData( CF_TEXT );
todo_wine ok( is_fixed( h ), "expected fixed mem %p\n", h );
ok( is_fixed( h ), "expected fixed mem %p\n", h );
ok( is_moveable( text ), "expected moveable mem %p\n", text );
ptr = GlobalLock( h );
if (ptr) todo_wine ok( !strcmp( ptr, "foobar" ), "wrong data '%.8s'\n", ptr );
ok( !strcmp( ptr, "foobar" ), "wrong data '%.8s'\n", ptr );
GlobalUnlock( h );
r = EmptyClipboard();
ok( r, "gle %d\n", GetLastError() );
todo_wine ok( is_fixed( h ), "expected free mem %p\n", h );
ok( is_fixed( h ), "expected free mem %p\n", h );
ok( is_freed( text ) || broken( is_moveable(text) ), /* w2003, w2008 */
"expected free mem %p\n", text );
r = CloseClipboard();

View file

@ -4540,6 +4540,21 @@ struct set_clipboard_data_reply
struct get_clipboard_data_request
{
struct request_header __header;
unsigned int format;
};
struct get_clipboard_data_reply
{
struct reply_header __header;
user_handle_t owner;
data_size_t total;
/* VARARG(data,bytes); */
};
struct get_clipboard_formats_request
{
struct request_header __header;
@ -5772,6 +5787,7 @@ enum request
REQ_set_clipboard_info,
REQ_empty_clipboard,
REQ_set_clipboard_data,
REQ_get_clipboard_data,
REQ_get_clipboard_formats,
REQ_enum_clipboard_formats,
REQ_release_clipboard,
@ -6062,6 +6078,7 @@ union generic_request
struct set_clipboard_info_request set_clipboard_info_request;
struct empty_clipboard_request empty_clipboard_request;
struct set_clipboard_data_request set_clipboard_data_request;
struct get_clipboard_data_request get_clipboard_data_request;
struct get_clipboard_formats_request get_clipboard_formats_request;
struct enum_clipboard_formats_request enum_clipboard_formats_request;
struct release_clipboard_request release_clipboard_request;
@ -6350,6 +6367,7 @@ union generic_reply
struct set_clipboard_info_reply set_clipboard_info_reply;
struct empty_clipboard_reply empty_clipboard_reply;
struct set_clipboard_data_reply set_clipboard_data_reply;
struct get_clipboard_data_reply get_clipboard_data_reply;
struct get_clipboard_formats_reply get_clipboard_formats_reply;
struct enum_clipboard_formats_reply enum_clipboard_formats_reply;
struct release_clipboard_reply release_clipboard_reply;
@ -6416,6 +6434,6 @@ union generic_reply
struct terminate_job_reply terminate_job_reply;
};
#define SERVER_PROTOCOL_VERSION 519
#define SERVER_PROTOCOL_VERSION 520
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */

View file

@ -411,6 +411,31 @@ DECL_HANDLER(set_clipboard_data)
}
/* fetch a data format from the clipboard */
DECL_HANDLER(get_clipboard_data)
{
struct clip_format *format;
struct clipboard *clipboard = get_process_clipboard();
if (!clipboard) return;
if (clipboard->open_thread != current)
{
set_win32_error( ERROR_CLIPBOARD_NOT_OPEN );
return;
}
if (!(format = get_format( clipboard, req->format )))
{
set_error( STATUS_OBJECT_NAME_NOT_FOUND );
return;
}
reply->total = format->size;
if (!format->data) reply->owner = clipboard->owner_win;
if (format->size <= get_reply_max_size()) set_reply_data( format->data, format->size );
else set_error( STATUS_BUFFER_OVERFLOW );
}
/* retrieve a list of available formats */
DECL_HANDLER(get_clipboard_formats)
{

View file

@ -3206,6 +3206,16 @@ enum caret_state
@END
/* Fetch a data format from the clipboard */
@REQ(get_clipboard_data)
unsigned int format; /* clipboard format of the data */
@REPLY
user_handle_t owner; /* clipboard owner for delayed-rendered formats */
data_size_t total; /* total data size */
VARARG(data,bytes); /* data contents */
@END
/* Retrieve a list of available formats */
@REQ(get_clipboard_formats)
unsigned int format; /* specific format to query, return all if 0 */

View file

@ -331,6 +331,7 @@ DECL_HANDLER(close_clipboard);
DECL_HANDLER(set_clipboard_info);
DECL_HANDLER(empty_clipboard);
DECL_HANDLER(set_clipboard_data);
DECL_HANDLER(get_clipboard_data);
DECL_HANDLER(get_clipboard_formats);
DECL_HANDLER(enum_clipboard_formats);
DECL_HANDLER(release_clipboard);
@ -620,6 +621,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
(req_handler)req_set_clipboard_info,
(req_handler)req_empty_clipboard,
(req_handler)req_set_clipboard_data,
(req_handler)req_get_clipboard_data,
(req_handler)req_get_clipboard_formats,
(req_handler)req_enum_clipboard_formats,
(req_handler)req_release_clipboard,
@ -2050,6 +2052,11 @@ C_ASSERT( sizeof(struct set_clipboard_info_reply) == 32 );
C_ASSERT( sizeof(struct empty_clipboard_request) == 16 );
C_ASSERT( FIELD_OFFSET(struct set_clipboard_data_request, format) == 12 );
C_ASSERT( sizeof(struct set_clipboard_data_request) == 16 );
C_ASSERT( FIELD_OFFSET(struct get_clipboard_data_request, format) == 12 );
C_ASSERT( sizeof(struct get_clipboard_data_request) == 16 );
C_ASSERT( FIELD_OFFSET(struct get_clipboard_data_reply, owner) == 8 );
C_ASSERT( FIELD_OFFSET(struct get_clipboard_data_reply, total) == 12 );
C_ASSERT( sizeof(struct get_clipboard_data_reply) == 16 );
C_ASSERT( FIELD_OFFSET(struct get_clipboard_formats_request, format) == 12 );
C_ASSERT( sizeof(struct get_clipboard_formats_request) == 16 );
C_ASSERT( FIELD_OFFSET(struct get_clipboard_formats_reply, count) == 8 );

View file

@ -3779,6 +3779,18 @@ static void dump_set_clipboard_data_request( const struct set_clipboard_data_req
dump_varargs_bytes( ", data=", cur_size );
}
static void dump_get_clipboard_data_request( const struct get_clipboard_data_request *req )
{
fprintf( stderr, " format=%08x", req->format );
}
static void dump_get_clipboard_data_reply( const struct get_clipboard_data_reply *req )
{
fprintf( stderr, " owner=%08x", req->owner );
fprintf( stderr, ", total=%u", req->total );
dump_varargs_bytes( ", data=", cur_size );
}
static void dump_get_clipboard_formats_request( const struct get_clipboard_formats_request *req )
{
fprintf( stderr, " format=%08x", req->format );
@ -4673,6 +4685,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_set_clipboard_info_request,
(dump_func)dump_empty_clipboard_request,
(dump_func)dump_set_clipboard_data_request,
(dump_func)dump_get_clipboard_data_request,
(dump_func)dump_get_clipboard_formats_request,
(dump_func)dump_enum_clipboard_formats_request,
(dump_func)dump_release_clipboard_request,
@ -4959,6 +4972,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_set_clipboard_info_reply,
NULL,
NULL,
(dump_func)dump_get_clipboard_data_reply,
(dump_func)dump_get_clipboard_formats_reply,
(dump_func)dump_enum_clipboard_formats_reply,
(dump_func)dump_release_clipboard_reply,
@ -5245,6 +5259,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
"set_clipboard_info",
"empty_clipboard",
"set_clipboard_data",
"get_clipboard_data",
"get_clipboard_formats",
"enum_clipboard_formats",
"release_clipboard",