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
29 #include <sys/types.h>
34 #define WIN32_NO_STATUS
41 #include "user_private.h"
44 #include "wine/list.h"
45 #include "wine/server.h"
46 #include "wine/debug.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(clipboard
);
51 static CRITICAL_SECTION clipboard_cs
;
52 static CRITICAL_SECTION_DEBUG critsect_debug
=
55 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
56 0, 0, { (DWORD_PTR
)(__FILE__
": clipboard_cs") }
58 static CRITICAL_SECTION clipboard_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
60 /* platform-independent version of METAFILEPICT */
69 /* get a debug string for a format id */
70 static const char *debugstr_format( UINT id
)
73 DWORD le
= GetLastError();
74 BOOL r
= NtUserGetClipboardFormatName( id
, buffer
, 256 );
78 return wine_dbg_sprintf( "%04x %s", id
, debugstr_w(buffer
) );
82 #define BUILTIN(id) case id: return #id;
85 BUILTIN(CF_METAFILEPICT
)
95 BUILTIN(CF_UNICODETEXT
)
96 BUILTIN(CF_ENHMETAFILE
)
100 BUILTIN(CF_OWNERDISPLAY
)
102 BUILTIN(CF_DSPBITMAP
)
103 BUILTIN(CF_DSPMETAFILEPICT
)
104 BUILTIN(CF_DSPENHMETAFILE
)
106 default: return wine_dbg_sprintf( "%04x", id
);
110 /* build the data to send to the server in SetClipboardData */
111 static HANDLE
marshal_data( UINT format
, HANDLE handle
, size_t *ret_size
)
121 if (!GetObjectW( handle
, sizeof(bitmap
), &bitmap
)) return 0;
122 size
= abs( bitmap
.bmHeight
) * ((((bitmap
.bmWidth
* bitmap
.bmBitsPixel
) + 15) >> 3) & ~1);
123 *ret_size
= sizeof(bitmap
) + size
;
124 if (!(bm
= GlobalAlloc( GMEM_FIXED
, *ret_size
))) return 0;
126 GetBitmapBits( handle
, size
, bm
+ 1 );
132 if (!(size
= GetPaletteEntries( handle
, 0, 0, NULL
))) return 0;
133 *ret_size
= offsetof( LOGPALETTE
, palPalEntry
[size
] );
134 if (!(pal
= GlobalAlloc( GMEM_FIXED
, *ret_size
))) return 0;
135 pal
->palVersion
= 0x300;
136 pal
->palNumEntries
= size
;
137 GetPaletteEntries( handle
, 0, size
, pal
->palPalEntry
);
141 case CF_DSPENHMETAFILE
:
144 if (!(size
= GetEnhMetaFileBits( handle
, 0, NULL
))) return 0;
145 if (!(ret
= GlobalAlloc( GMEM_FIXED
, size
))) return 0;
146 GetEnhMetaFileBits( handle
, size
, ret
);
150 case CF_METAFILEPICT
:
151 case CF_DSPMETAFILEPICT
:
154 struct metafile_pict
*mfbits
;
155 if (!(mf
= GlobalLock( handle
))) return 0;
156 if (!(size
= GetMetaFileBitsEx( mf
->hMF
, 0, NULL
)))
158 GlobalUnlock( handle
);
161 *ret_size
= offsetof( struct metafile_pict
, bits
[size
] );
162 if (!(mfbits
= GlobalAlloc( GMEM_FIXED
, *ret_size
)))
164 GlobalUnlock( handle
);
168 mfbits
->xExt
= mf
->xExt
;
169 mfbits
->yExt
= mf
->yExt
;
170 GetMetaFileBitsEx( mf
->hMF
, size
, mfbits
->bits
);
171 GlobalUnlock( handle
);
177 if (!(size
= GlobalSize( handle
))) return 0;
178 if ((data_size_t
)size
!= size
) return 0;
179 if (!(ptr
= GlobalLock( handle
))) return 0;
180 ptr
[(size
+ 1) / sizeof(WCHAR
) - 1] = 0; /* enforce null-termination */
181 GlobalUnlock( handle
);
189 if (!(size
= GlobalSize( handle
))) return 0;
190 if ((data_size_t
)size
!= size
) return 0;
191 if (!(ptr
= GlobalLock( handle
))) return 0;
192 ptr
[size
- 1] = 0; /* enforce null-termination */
193 GlobalUnlock( handle
);
198 if (!(size
= GlobalSize( handle
))) return 0;
199 if ((data_size_t
)size
!= size
) return 0;
205 /* rebuild the target handle from the data received in GetClipboardData */
206 static HANDLE
unmarshal_data( UINT format
, void *data
, data_size_t size
)
208 HANDLE handle
= GlobalReAlloc( data
, size
, 0 ); /* release unused space */
215 if (size
< sizeof(*bm
)) break;
216 if (size
< bm
->bmWidthBytes
* abs( bm
->bmHeight
)) break;
217 if (bm
->bmBits
) break; /* DIB sections are not supported across processes */
219 return CreateBitmapIndirect( bm
);
221 case CF_DSPBITMAP
: /* not supported across processes */
225 LOGPALETTE
*pal
= handle
;
226 if (size
< sizeof(*pal
)) break;
227 if (size
< offsetof( LOGPALETTE
, palPalEntry
[pal
->palNumEntries
] )) break;
228 return CreatePalette( pal
);
231 case CF_DSPENHMETAFILE
:
232 return SetEnhMetaFileBits( size
, handle
);
233 case CF_METAFILEPICT
:
234 case CF_DSPMETAFILEPICT
:
237 struct metafile_pict
*mfbits
= handle
;
238 if (size
<= sizeof(*mfbits
)) break;
240 mf
.xExt
= mfbits
->xExt
;
241 mf
.yExt
= mfbits
->yExt
;
242 mf
.hMF
= SetMetaFileBitsEx( size
- offsetof( struct metafile_pict
, bits
), mfbits
->bits
);
243 *(METAFILEPICT
*)handle
= mf
;
250 /* free a single cached format */
251 void free_cached_data( UINT format
, HANDLE handle
)
260 DeleteObject( handle
);
263 case CF_DSPENHMETAFILE
:
264 DeleteEnhMetaFile( handle
);
266 case CF_METAFILEPICT
:
267 case CF_DSPMETAFILEPICT
:
268 if ((ptr
= GlobalLock( handle
)))
270 DeleteMetaFile( ((METAFILEPICT
*)ptr
)->hMF
);
271 GlobalUnlock( handle
);
273 GlobalFree( handle
);
276 GlobalFree( handle
);
281 /* get the clipboard locale stored in the CF_LOCALE format */
282 static LCID
get_clipboard_locale(void)
285 LCID lcid
= GetUserDefaultLCID();
287 if ((data
= GetClipboardData( CF_LOCALE
)))
289 LCID
*ptr
= GlobalLock( data
);
292 if (GlobalSize( data
) >= sizeof(*ptr
)) lcid
= *ptr
;
293 GlobalUnlock( data
);
299 /* get the codepage to use for text conversions in the specified format (CF_TEXT or CF_OEMTEXT) */
300 static UINT
get_format_codepage( LCID lcid
, UINT format
)
302 LCTYPE type
= (format
== CF_TEXT
) ? LOCALE_IDEFAULTANSICODEPAGE
: LOCALE_IDEFAULTCODEPAGE
;
305 if (!GetLocaleInfoW( lcid
, type
| LOCALE_RETURN_NUMBER
, (LPWSTR
)&ret
, sizeof(ret
)/sizeof(WCHAR
) ))
306 ret
= (format
== CF_TEXT
) ? CP_ACP
: CP_OEMCP
;
310 /* render synthesized ANSI text based on the contents of the 'from' format */
311 static HANDLE
render_synthesized_textA( HANDLE data
, UINT format
, UINT from
)
316 LCID lcid
= get_clipboard_locale();
317 UINT codepage
= get_format_codepage( lcid
, format
);
318 UINT len
, size
= GlobalSize( data
);
320 if (!(src
= GlobalLock( data
))) return 0;
322 if (from
!= CF_UNICODETEXT
) /* first convert incoming format to Unicode */
324 UINT from_codepage
= get_format_codepage( lcid
, from
);
325 len
= MultiByteToWideChar( from_codepage
, 0, src
, size
, NULL
, 0 );
326 if (!(srcW
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) ))) goto done
;
327 MultiByteToWideChar( from_codepage
, 0, src
, size
, srcW
, len
);
329 size
= len
* sizeof(WCHAR
);
332 if ((len
= WideCharToMultiByte( codepage
, 0, src
, size
/ sizeof(WCHAR
), NULL
, 0, NULL
, NULL
)))
334 if ((ret
= GlobalAlloc( GMEM_FIXED
, len
)))
335 WideCharToMultiByte( codepage
, 0, src
, size
/ sizeof(WCHAR
), ret
, len
, NULL
, NULL
);
339 HeapFree( GetProcessHeap(), 0, srcW
);
340 GlobalUnlock( data
);
344 /* render synthesized Unicode text based on the contents of the 'from' format */
345 static HANDLE
render_synthesized_textW( HANDLE data
, UINT from
)
349 UINT len
, size
= GlobalSize( data
);
350 UINT codepage
= get_format_codepage( get_clipboard_locale(), from
);
352 if (!(src
= GlobalLock( data
))) return 0;
354 if ((len
= MultiByteToWideChar( codepage
, 0, src
, size
, NULL
, 0 )))
356 if ((ret
= GlobalAlloc( GMEM_FIXED
, len
* sizeof(WCHAR
) )))
357 MultiByteToWideChar( codepage
, 0, src
, size
, ret
, len
);
359 GlobalUnlock( data
);
363 /* render a synthesized bitmap based on the DIB clipboard data */
364 static HANDLE
render_synthesized_bitmap( HANDLE data
, UINT from
)
368 HDC hdc
= GetDC( 0 );
370 if ((bmi
= GlobalLock( data
)))
372 /* FIXME: validate data size */
373 ret
= CreateDIBitmap( hdc
, &bmi
->bmiHeader
, CBM_INIT
,
374 (char *)bmi
+ bitmap_info_size( bmi
, DIB_RGB_COLORS
),
375 bmi
, DIB_RGB_COLORS
);
376 GlobalUnlock( data
);
378 NtUserReleaseDC( 0, hdc
);
382 /* render a synthesized DIB based on the clipboard data */
383 static HANDLE
render_synthesized_dib( HANDLE data
, UINT format
, UINT from
)
385 BITMAPINFO
*bmi
, *src
;
386 DWORD src_size
, header_size
, bits_size
;
388 HDC hdc
= GetDC( 0 );
390 if (from
== CF_BITMAP
)
392 BITMAPV5HEADER header
;
394 memset( &header
, 0, sizeof(header
) );
395 header
.bV5Size
= (format
== CF_DIBV5
) ? sizeof(BITMAPV5HEADER
) : sizeof(BITMAPINFOHEADER
);
396 if (!GetDIBits( hdc
, data
, 0, 0, NULL
, (BITMAPINFO
*)&header
, DIB_RGB_COLORS
)) goto done
;
398 header_size
= bitmap_info_size( (BITMAPINFO
*)&header
, DIB_RGB_COLORS
);
399 if (!(ret
= GlobalAlloc( GMEM_FIXED
, header_size
+ header
.bV5SizeImage
))) goto done
;
400 bmi
= (BITMAPINFO
*)ret
;
401 memset( bmi
, 0, header_size
);
402 memcpy( bmi
, &header
, header
.bV5Size
);
403 GetDIBits( hdc
, data
, 0, abs(header
.bV5Height
), (char *)bmi
+ header_size
, bmi
, DIB_RGB_COLORS
);
407 SIZE_T size
= GlobalSize( data
);
409 if (size
< sizeof(*bmi
)) goto done
;
410 if (!(src
= GlobalLock( data
))) goto done
;
412 src_size
= bitmap_info_size( src
, DIB_RGB_COLORS
);
413 if (size
<= src_size
)
415 GlobalUnlock( data
);
418 bits_size
= size
- src_size
;
419 header_size
= (format
== CF_DIBV5
) ? sizeof(BITMAPV5HEADER
) :
420 offsetof( BITMAPINFO
, bmiColors
[src
->bmiHeader
.biCompression
== BI_BITFIELDS
? 3 : 0] );
422 if ((ret
= GlobalAlloc( GMEM_FIXED
, header_size
+ bits_size
)))
424 bmi
= (BITMAPINFO
*)ret
;
425 memset( bmi
, 0, header_size
);
426 memcpy( bmi
, src
, min( header_size
, src_size
));
427 bmi
->bmiHeader
.biSize
= header_size
;
428 /* FIXME: convert colors according to DIBv5 color profile */
429 memcpy( (char *)bmi
+ header_size
, (char *)src
+ src_size
, bits_size
);
431 GlobalUnlock( data
);
435 NtUserReleaseDC( 0, hdc
);
439 /* render a synthesized metafile based on the enhmetafile clipboard data */
440 static HANDLE
render_synthesized_metafile( HANDLE data
)
446 ENHMETAHEADER header
;
447 HDC hdc
= GetDC( 0 );
449 size
= GetWinMetaFileBits( data
, 0, NULL
, MM_ISOTROPIC
, hdc
);
450 if ((bits
= HeapAlloc( GetProcessHeap(), 0, size
)))
452 if (GetEnhMetaFileHeader( data
, sizeof(header
), &header
) &&
453 GetWinMetaFileBits( data
, size
, bits
, MM_ISOTROPIC
, hdc
))
455 if ((ret
= GlobalAlloc( GMEM_FIXED
, sizeof(*pict
) )))
457 pict
= (METAFILEPICT
*)ret
;
458 pict
->mm
= MM_ISOTROPIC
;
459 pict
->xExt
= header
.rclFrame
.right
- header
.rclFrame
.left
;
460 pict
->yExt
= header
.rclFrame
.bottom
- header
.rclFrame
.top
;
461 pict
->hMF
= SetMetaFileBitsEx( size
, bits
);
464 HeapFree( GetProcessHeap(), 0, bits
);
466 NtUserReleaseDC( 0, hdc
);
470 /* render a synthesized enhmetafile based on the metafile clipboard data */
471 static HANDLE
render_synthesized_enhmetafile( HANDLE data
)
478 if (!(pict
= GlobalLock( data
))) return 0;
480 size
= GetMetaFileBitsEx( pict
->hMF
, 0, NULL
);
481 if ((bits
= HeapAlloc( GetProcessHeap(), 0, size
)))
483 GetMetaFileBitsEx( pict
->hMF
, size
, bits
);
484 ret
= SetWinMetaFileBits( size
, bits
, NULL
, pict
);
485 HeapFree( GetProcessHeap(), 0, bits
);
488 GlobalUnlock( data
);
492 /* render a synthesized format */
493 HANDLE
render_synthesized_format( UINT format
, UINT from
)
495 HANDLE data
= GetClipboardData( from
);
498 TRACE( "rendering %s from %s\n", debugstr_format( format
), debugstr_format( from
));
504 data
= render_synthesized_textA( data
, format
, from
);
507 data
= render_synthesized_textW( data
, from
);
510 data
= render_synthesized_bitmap( data
, from
);
514 data
= render_synthesized_dib( data
, format
, from
);
516 case CF_METAFILEPICT
:
517 data
= render_synthesized_metafile( data
);
520 data
= render_synthesized_enhmetafile( data
);
527 TRACE( "adding %s %p\n", debugstr_format( format
), data
);
528 SetClipboardData( format
, data
);
534 /**************************************************************************
535 * RegisterClipboardFormatW (USER32.@)
537 UINT WINAPI
RegisterClipboardFormatW( LPCWSTR name
)
539 return GlobalAddAtomW( name
);
543 /**************************************************************************
544 * RegisterClipboardFormatA (USER32.@)
546 UINT WINAPI
RegisterClipboardFormatA( LPCSTR name
)
548 return GlobalAddAtomA( name
);
552 /**************************************************************************
553 * GetClipboardFormatNameA (USER32.@)
555 INT WINAPI
GetClipboardFormatNameA( UINT format
, LPSTR buffer
, INT maxlen
)
557 if (format
< MAXINTATOM
|| format
> 0xffff) return 0;
558 return GlobalGetAtomNameA( format
, buffer
, maxlen
);
562 /**************************************************************************
563 * OpenClipboard (USER32.@)
565 BOOL WINAPI
OpenClipboard( HWND hwnd
)
567 return NtUserOpenClipboard( hwnd
, 0 );
571 /**************************************************************************
572 * SetClipboardData (USER32.@)
574 HANDLE WINAPI
SetClipboardData( UINT format
, HANDLE data
)
576 struct set_clipboard_params params
= { .size
= 0 };
577 HANDLE handle
= data
;
580 TRACE( "%s %p\n", debugstr_format( format
), data
);
584 if (!(handle
= marshal_data( format
, data
, ¶ms
.size
))) return 0;
585 if (!(params
.data
= GlobalLock( handle
))) return 0;
588 status
= NtUserSetClipboardData( format
, data
, ¶ms
);
590 if (params
.data
) GlobalUnlock( handle
);
591 if (handle
!= data
) GlobalFree( handle
);
594 SetLastError( RtlNtStatusToDosError( status
));
601 /**************************************************************************
602 * EnumClipboardFormats (USER32.@)
604 UINT WINAPI
EnumClipboardFormats( UINT format
)
606 return NtUserEnumClipboardFormats( format
);
610 /**************************************************************************
611 * GetClipboardData (USER32.@)
613 HANDLE WINAPI
GetClipboardData( UINT format
)
615 struct get_clipboard_params params
= { .data_size
= 1024 };
618 EnterCriticalSection( &clipboard_cs
);
620 while (params
.data_size
)
622 params
.size
= params
.data_size
;
623 params
.data_size
= 0;
624 if (!(params
.data
= GlobalAlloc( GMEM_FIXED
, params
.size
))) break;
625 ret
= NtUserGetClipboardData( format
, ¶ms
);
627 if (params
.data_size
== ~0) /* needs unmarshaling */
629 struct set_clipboard_params set_params
= { .cache_only
= TRUE
, .seqno
= params
.seqno
};
631 ret
= unmarshal_data( format
, params
.data
, params
.size
);
632 if (!NtUserSetClipboardData( format
, ret
, &set_params
)) break;
634 /* data changed, retry */
635 free_cached_data( format
, ret
);
637 params
.data_size
= 1024;
640 GlobalFree( params
.data
);
643 LeaveCriticalSection( &clipboard_cs
);