user32: Synthesize text clipboard formats on the user32 side.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
b1e8ed3e3b
commit
8865f4a4ec
|
@ -1336,17 +1336,14 @@ static void test_nonole_clipboard(void)
|
|||
hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
|
||||
ok(hr == S_OK, "got %08x\n", hr); /* User32 adds some synthesised formats */
|
||||
|
||||
todo_wine ok(fmt.cfFormat == CF_LOCALE, "cf %04x\n", fmt.cfFormat);
|
||||
if(fmt.cfFormat == CF_LOCALE)
|
||||
{
|
||||
ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
|
||||
ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
|
||||
ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
|
||||
ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
|
||||
ok(fmt.cfFormat == CF_LOCALE, "cf %04x\n", fmt.cfFormat);
|
||||
ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
|
||||
ok(fmt.dwAspect == DVASPECT_CONTENT, "aspect %x\n", fmt.dwAspect);
|
||||
ok(fmt.lindex == -1, "lindex %d\n", fmt.lindex);
|
||||
todo_wine ok(fmt.tymed == (TYMED_ISTREAM | TYMED_HGLOBAL), "tymed %x\n", fmt.tymed);
|
||||
|
||||
hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
|
||||
ok(hr == S_OK, "got %08x\n", hr);
|
||||
}
|
||||
hr = IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL);
|
||||
ok(hr == S_OK, "got %08x\n", hr);
|
||||
|
||||
ok(fmt.cfFormat == CF_OEMTEXT, "cf %04x\n", fmt.cfFormat);
|
||||
ok(fmt.ptd == NULL, "ptd %p\n", fmt.ptd);
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "config.h"
|
||||
#include "wine/port.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
|
@ -61,6 +62,162 @@ WINE_DEFAULT_DEBUG_CHANNEL(clipboard);
|
|||
static BOOL bCBHasChanged = FALSE;
|
||||
|
||||
|
||||
/* formats that can be synthesized are: CF_TEXT, CF_OEMTEXT, CF_UNICODETEXT,
|
||||
CF_BITMAP, CF_DIB, CF_DIBV5, CF_ENHMETAFILE, CF_METAFILEPICT */
|
||||
|
||||
static UINT synthesized_formats[CF_MAX];
|
||||
|
||||
/* add a synthesized format to the list */
|
||||
static void add_synthesized_format( UINT format, UINT from )
|
||||
{
|
||||
assert( format < CF_MAX );
|
||||
SetClipboardData( format, 0 );
|
||||
synthesized_formats[format] = from;
|
||||
}
|
||||
|
||||
/* store the current locale in the CF_LOCALE format */
|
||||
static void set_clipboard_locale(void)
|
||||
{
|
||||
HANDLE data = GlobalAlloc( GMEM_FIXED, sizeof(LCID) );
|
||||
|
||||
if (!data) return;
|
||||
*(LCID *)data = GetUserDefaultLCID();
|
||||
SetClipboardData( CF_LOCALE, data );
|
||||
TRACE( "added CF_LOCALE\n" );
|
||||
}
|
||||
|
||||
/* get the clipboard locale stored in the CF_LOCALE format */
|
||||
static LCID get_clipboard_locale(void)
|
||||
{
|
||||
HANDLE data;
|
||||
LCID lcid = GetUserDefaultLCID();
|
||||
|
||||
if ((data = GetClipboardData( CF_LOCALE )))
|
||||
{
|
||||
LCID *ptr = GlobalLock( data );
|
||||
if (ptr && GlobalSize( data ) >= sizeof(*ptr)) lcid = *ptr;
|
||||
GlobalUnlock( data );
|
||||
}
|
||||
return lcid;
|
||||
}
|
||||
|
||||
/* get the codepage to use for text conversions in the specified format (CF_TEXT or CF_OEMTEXT) */
|
||||
static UINT get_format_codepage( LCID lcid, UINT format )
|
||||
{
|
||||
LCTYPE type = (format == CF_TEXT) ? LOCALE_IDEFAULTANSICODEPAGE : LOCALE_IDEFAULTCODEPAGE;
|
||||
UINT ret;
|
||||
|
||||
if (!GetLocaleInfoW( lcid, type | LOCALE_RETURN_NUMBER, (LPWSTR)&ret, sizeof(ret)/sizeof(WCHAR) ))
|
||||
ret = (format == CF_TEXT) ? CP_ACP : CP_OEMCP;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* add synthesized text formats based on what is already in the clipboard */
|
||||
static void add_synthesized_text(void)
|
||||
{
|
||||
BOOL has_text = IsClipboardFormatAvailable( CF_TEXT );
|
||||
BOOL has_oemtext = IsClipboardFormatAvailable( CF_OEMTEXT );
|
||||
BOOL has_unicode = IsClipboardFormatAvailable( CF_UNICODETEXT );
|
||||
|
||||
if (!has_text && !has_oemtext && !has_unicode) return; /* no text, nothing to do */
|
||||
|
||||
if (!IsClipboardFormatAvailable( CF_LOCALE )) set_clipboard_locale();
|
||||
|
||||
if (has_unicode)
|
||||
{
|
||||
if (!has_text) add_synthesized_format( CF_TEXT, CF_UNICODETEXT );
|
||||
if (!has_oemtext) add_synthesized_format( CF_OEMTEXT, CF_UNICODETEXT );
|
||||
}
|
||||
else if (has_text)
|
||||
{
|
||||
if (!has_oemtext) add_synthesized_format( CF_OEMTEXT, CF_TEXT );
|
||||
if (!has_unicode) add_synthesized_format( CF_UNICODETEXT, CF_TEXT );
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!has_text) add_synthesized_format( CF_TEXT, CF_OEMTEXT );
|
||||
if (!has_unicode) add_synthesized_format( CF_UNICODETEXT, CF_OEMTEXT );
|
||||
}
|
||||
}
|
||||
|
||||
/* render synthesized ANSI text based on the contents of the 'from' format */
|
||||
static HANDLE render_synthesized_textA( HANDLE data, UINT format, UINT from )
|
||||
{
|
||||
void *src;
|
||||
WCHAR *srcW = NULL;
|
||||
HANDLE ret = 0;
|
||||
LCID lcid = get_clipboard_locale();
|
||||
UINT codepage = get_format_codepage( lcid, format );
|
||||
UINT len, size = GlobalSize( data );
|
||||
|
||||
if (!(src = GlobalLock( data ))) return 0;
|
||||
|
||||
if (from != CF_UNICODETEXT) /* first convert incoming format to Unicode */
|
||||
{
|
||||
UINT from_codepage = get_format_codepage( lcid, from );
|
||||
len = MultiByteToWideChar( from_codepage, 0, src, size, NULL, 0 );
|
||||
if (!(srcW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) goto done;
|
||||
MultiByteToWideChar( from_codepage, 0, src, size, srcW, len );
|
||||
src = srcW;
|
||||
size = len * sizeof(WCHAR);
|
||||
}
|
||||
|
||||
len = WideCharToMultiByte( codepage, 0, src, size / sizeof(WCHAR), NULL, 0, NULL, NULL );
|
||||
if ((ret = GlobalAlloc( GMEM_FIXED, len )))
|
||||
WideCharToMultiByte( codepage, 0, src, size / sizeof(WCHAR), ret, len, NULL, NULL );
|
||||
|
||||
done:
|
||||
HeapFree( GetProcessHeap(), 0, srcW );
|
||||
GlobalUnlock( data );
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* render synthesized Unicode text based on the contents of the 'from' format */
|
||||
static HANDLE render_synthesized_textW( HANDLE data, UINT from )
|
||||
{
|
||||
char *src;
|
||||
HANDLE ret;
|
||||
UINT len, size = GlobalSize( data );
|
||||
UINT codepage = get_format_codepage( get_clipboard_locale(), from );
|
||||
|
||||
if (!(src = GlobalLock( data ))) return 0;
|
||||
|
||||
len = MultiByteToWideChar( codepage, 0, src, size, NULL, 0 );
|
||||
if ((ret = GlobalAlloc( GMEM_FIXED, len * sizeof(WCHAR) )))
|
||||
MultiByteToWideChar( codepage, 0, src, size, ret, len );
|
||||
|
||||
GlobalUnlock( data );
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* render a synthesized format */
|
||||
static HANDLE render_synthesized_format( UINT format, UINT from )
|
||||
{
|
||||
HANDLE data = GetClipboardData( from );
|
||||
|
||||
if (!data) return 0;
|
||||
TRACE( "rendering %04x from %04x\n", format, from );
|
||||
|
||||
switch (format)
|
||||
{
|
||||
case CF_TEXT:
|
||||
case CF_OEMTEXT:
|
||||
data = render_synthesized_textA( data, format, from );
|
||||
break;
|
||||
case CF_UNICODETEXT:
|
||||
data = render_synthesized_textW( data, from );
|
||||
break;
|
||||
default:
|
||||
assert( 0 );
|
||||
}
|
||||
if (data)
|
||||
{
|
||||
TRACE( "adding %04x %p\n", format, data );
|
||||
SetClipboardData( format, data );
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* get_clipboard_flags
|
||||
*/
|
||||
|
@ -154,7 +311,11 @@ BOOL WINAPI OpenClipboard( HWND hwnd )
|
|||
req->window = wine_server_user_handle( hwnd );
|
||||
if ((ret = !wine_server_call_err( req )))
|
||||
{
|
||||
if (!reply->owner) bCBHasChanged = FALSE;
|
||||
if (!reply->owner)
|
||||
{
|
||||
bCBHasChanged = FALSE;
|
||||
memset( synthesized_formats, 0, sizeof(synthesized_formats) );
|
||||
}
|
||||
}
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
|
@ -173,6 +334,12 @@ BOOL WINAPI CloseClipboard(void)
|
|||
|
||||
TRACE("() Changed=%d\n", bCBHasChanged);
|
||||
|
||||
if (bCBHasChanged)
|
||||
{
|
||||
memset( synthesized_formats, 0, sizeof(synthesized_formats) );
|
||||
add_synthesized_text();
|
||||
}
|
||||
|
||||
SERVER_START_REQ( close_clipboard )
|
||||
{
|
||||
req->changed = bCBHasChanged;
|
||||
|
@ -219,6 +386,7 @@ BOOL WINAPI EmptyClipboard(void)
|
|||
{
|
||||
USER_Driver->pEmptyClipboard();
|
||||
bCBHasChanged = TRUE;
|
||||
memset( synthesized_formats, 0, sizeof(synthesized_formats) );
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -337,14 +505,14 @@ BOOL WINAPI ChangeClipboardChain( HWND hwnd, HWND next )
|
|||
/**************************************************************************
|
||||
* SetClipboardData (USER32.@)
|
||||
*/
|
||||
HANDLE WINAPI SetClipboardData(UINT wFormat, HANDLE hData)
|
||||
HANDLE WINAPI SetClipboardData( UINT format, HANDLE data )
|
||||
{
|
||||
HANDLE hResult = 0;
|
||||
UINT flags;
|
||||
|
||||
TRACE("(%04X, %p) !\n", wFormat, hData);
|
||||
TRACE( "%04x %p\n", format, data );
|
||||
|
||||
if (!wFormat)
|
||||
if (!format)
|
||||
{
|
||||
SetLastError( ERROR_CLIPBOARD_NOT_OPEN );
|
||||
return 0;
|
||||
|
@ -357,10 +525,11 @@ HANDLE WINAPI SetClipboardData(UINT wFormat, HANDLE hData)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (USER_Driver->pSetClipboardData(wFormat, hData, flags & CB_OWNER))
|
||||
if (USER_Driver->pSetClipboardData( format, data, flags & CB_OWNER))
|
||||
{
|
||||
hResult = hData;
|
||||
hResult = data;
|
||||
bCBHasChanged = TRUE;
|
||||
if (format < CF_MAX) synthesized_formats[format] = 0;
|
||||
}
|
||||
|
||||
return hResult;
|
||||
|
@ -439,11 +608,11 @@ BOOL WINAPI GetUpdatedClipboardFormats( UINT *formats, UINT size, UINT *out_size
|
|||
/**************************************************************************
|
||||
* GetClipboardData (USER32.@)
|
||||
*/
|
||||
HANDLE WINAPI GetClipboardData(UINT wFormat)
|
||||
HANDLE WINAPI GetClipboardData( UINT format )
|
||||
{
|
||||
HANDLE hData = 0;
|
||||
HANDLE data = 0;
|
||||
|
||||
TRACE("%04x\n", wFormat);
|
||||
TRACE( "%04x\n", format );
|
||||
|
||||
if (!(get_clipboard_flags() & CB_OPEN))
|
||||
{
|
||||
|
@ -451,11 +620,13 @@ HANDLE WINAPI GetClipboardData(UINT wFormat)
|
|||
SetLastError(ERROR_CLIPBOARD_NOT_OPEN);
|
||||
return 0;
|
||||
}
|
||||
if (format < CF_MAX && synthesized_formats[format])
|
||||
data = render_synthesized_format( format, synthesized_formats[format] );
|
||||
else
|
||||
data = USER_Driver->pGetClipboardData( format );
|
||||
|
||||
hData = USER_Driver->pGetClipboardData( wFormat );
|
||||
|
||||
TRACE("returning %p\n", hData);
|
||||
return hData;
|
||||
TRACE( "returning %p\n", data );
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -588,9 +588,9 @@ static void test_synthesized(void)
|
|||
UINT todo;
|
||||
} tests[] =
|
||||
{
|
||||
/* 0 */ { CF_TEXT, { CF_TEXT, CF_LOCALE, CF_OEMTEXT, CF_UNICODETEXT }, 1 << 1 },
|
||||
{ CF_OEMTEXT, { CF_OEMTEXT, CF_LOCALE, CF_TEXT, CF_UNICODETEXT }, 1 << 1 },
|
||||
{ CF_UNICODETEXT, { CF_UNICODETEXT, CF_LOCALE, CF_TEXT, CF_OEMTEXT }, 1 << 1 },
|
||||
/* 0 */ { CF_TEXT, { CF_TEXT, CF_LOCALE, CF_OEMTEXT, CF_UNICODETEXT }},
|
||||
{ CF_OEMTEXT, { CF_OEMTEXT, CF_LOCALE, CF_TEXT, CF_UNICODETEXT }},
|
||||
{ CF_UNICODETEXT, { CF_UNICODETEXT, CF_LOCALE, CF_TEXT, CF_OEMTEXT }},
|
||||
{ CF_ENHMETAFILE, { CF_ENHMETAFILE, CF_METAFILEPICT }},
|
||||
{ CF_METAFILEPICT, { CF_METAFILEPICT, CF_ENHMETAFILE }},
|
||||
/* 5 */ { CF_BITMAP, { CF_BITMAP, CF_DIB, CF_DIBV5 }, 1 << 2 },
|
||||
|
@ -623,11 +623,11 @@ static void test_synthesized(void)
|
|||
ok(r, "gle %d\n", GetLastError());
|
||||
|
||||
count = CountClipboardFormats();
|
||||
todo_wine ok( count == 6, "count %u\n", count );
|
||||
ok( count == 6, "count %u\n", count );
|
||||
r = IsClipboardFormatAvailable( CF_TEXT );
|
||||
ok( r, "CF_TEXT not available err %d\n", GetLastError());
|
||||
r = IsClipboardFormatAvailable( CF_LOCALE );
|
||||
todo_wine ok( r, "CF_LOCALE not available err %d\n", GetLastError());
|
||||
ok( r, "CF_LOCALE not available err %d\n", GetLastError());
|
||||
r = IsClipboardFormatAvailable( CF_OEMTEXT );
|
||||
ok( r, "CF_OEMTEXT not available err %d\n", GetLastError());
|
||||
r = IsClipboardFormatAvailable( CF_UNICODETEXT );
|
||||
|
@ -650,13 +650,11 @@ static void test_synthesized(void)
|
|||
ok(data != NULL, "couldn't get data, cf %08x\n", cf);
|
||||
|
||||
cf = EnumClipboardFormats(cf);
|
||||
todo_wine ok(cf == CF_LOCALE, "cf %08x\n", cf);
|
||||
if(cf == CF_LOCALE)
|
||||
{
|
||||
data = GetClipboardData(cf);
|
||||
ok(data != NULL, "couldn't get data, cf %08x\n", cf);
|
||||
cf = EnumClipboardFormats(cf);
|
||||
}
|
||||
ok(cf == CF_LOCALE, "cf %08x\n", cf);
|
||||
data = GetClipboardData(cf);
|
||||
ok(data != NULL, "couldn't get data, cf %08x\n", cf);
|
||||
|
||||
cf = EnumClipboardFormats(cf);
|
||||
ok(cf == CF_OEMTEXT, "cf %08x\n", cf);
|
||||
data = GetClipboardData(cf);
|
||||
ok(data != NULL, "couldn't get data, cf %08x\n", cf);
|
||||
|
@ -690,8 +688,8 @@ static void test_synthesized(void)
|
|||
cf = EnumClipboardFormats(cf);
|
||||
ok( cf == CF_OEMTEXT, "cf %08x\n", cf );
|
||||
cf = EnumClipboardFormats(cf);
|
||||
todo_wine ok( cf == CF_LOCALE, "cf %08x\n", cf );
|
||||
if (cf == CF_LOCALE) cf = EnumClipboardFormats( cf );
|
||||
ok( cf == CF_LOCALE, "cf %08x\n", cf );
|
||||
cf = EnumClipboardFormats( cf );
|
||||
ok( cf == 0, "cf %08x\n", cf );
|
||||
|
||||
r = EmptyClipboard();
|
||||
|
@ -1696,7 +1694,7 @@ static void test_handles( HWND hwnd )
|
|||
data = GetClipboardData( CF_UNICODETEXT );
|
||||
ok( is_fixed( data ), "expected fixed mem %p\n", data );
|
||||
data = GetClipboardData( CF_LOCALE );
|
||||
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_BITMAP );
|
||||
ok( data == bitmap, "expected bitmap %p\n", data );
|
||||
data = GetClipboardData( CF_PALETTE );
|
||||
|
@ -1964,11 +1962,11 @@ static void test_GetUpdatedClipboardFormats(void)
|
|||
memset( formats, 0xcc, sizeof(formats) );
|
||||
r = pGetUpdatedClipboardFormats( formats, 256, &count );
|
||||
ok( r, "gle %d\n", GetLastError() );
|
||||
todo_wine ok( count == 4, "wrong count %u\n", count );
|
||||
ok( count == 4, "wrong count %u\n", count );
|
||||
ok( formats[0] == CF_UNICODETEXT, "wrong format %u\n", formats[0] );
|
||||
ok( formats[1] == CF_TEXT, "wrong format %u\n", formats[1] );
|
||||
todo_wine ok( formats[2] == CF_LOCALE, "wrong format %u\n", formats[2] );
|
||||
todo_wine ok( formats[3] == CF_OEMTEXT, "wrong format %u\n", formats[3] );
|
||||
ok( formats[2] == CF_LOCALE, "wrong format %u\n", formats[2] );
|
||||
ok( formats[3] == CF_OEMTEXT, "wrong format %u\n", formats[3] );
|
||||
ok( formats[4] == 0xcccccccc, "wrong format %u\n", formats[4] );
|
||||
|
||||
count = 0xdeadbeef;
|
||||
|
@ -1976,20 +1974,20 @@ static void test_GetUpdatedClipboardFormats(void)
|
|||
r = pGetUpdatedClipboardFormats( formats, 2, &count );
|
||||
ok( !r, "gle %d\n", GetLastError() );
|
||||
ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "wrong error %u\n", GetLastError() );
|
||||
todo_wine ok( count == 4, "wrong count %u\n", count );
|
||||
ok( count == 4, "wrong count %u\n", count );
|
||||
ok( formats[0] == 0xcccccccc, "wrong format %u\n", formats[0] );
|
||||
|
||||
count = 0xdeadbeef;
|
||||
r = pGetUpdatedClipboardFormats( NULL, 256, &count );
|
||||
ok( !r, "gle %d\n", GetLastError() );
|
||||
ok( GetLastError() == ERROR_NOACCESS, "wrong error %u\n", GetLastError() );
|
||||
todo_wine ok( count == 4, "wrong count %u\n", count );
|
||||
ok( count == 4, "wrong count %u\n", count );
|
||||
|
||||
count = 0xdeadbeef;
|
||||
r = pGetUpdatedClipboardFormats( NULL, 256, &count );
|
||||
ok( !r, "gle %d\n", GetLastError() );
|
||||
ok( GetLastError() == ERROR_NOACCESS, "wrong error %u\n", GetLastError() );
|
||||
todo_wine ok( count == 4, "wrong count %u\n", count );
|
||||
ok( count == 4, "wrong count %u\n", count );
|
||||
}
|
||||
|
||||
START_TEST(clipboard)
|
||||
|
|
Loading…
Reference in New Issue