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
27 #include "user_private.h"
29 #include "wine/server.h"
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(clipboard
);
35 static CRITICAL_SECTION clipboard_cs
;
36 static CRITICAL_SECTION_DEBUG critsect_debug
=
39 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
40 0, 0, { (DWORD_PTR
)(__FILE__
": clipboard_cs") }
42 static CRITICAL_SECTION clipboard_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
44 /* platform-independent version of METAFILEPICT */
53 /* get a debug string for a format id */
54 static const char *debugstr_format( UINT id
)
57 DWORD le
= GetLastError();
58 BOOL r
= NtUserGetClipboardFormatName( id
, buffer
, 256 );
62 return wine_dbg_sprintf( "%04x %s", id
, debugstr_w(buffer
) );
66 #define BUILTIN(id) case id: return #id;
69 BUILTIN(CF_METAFILEPICT
)
79 BUILTIN(CF_UNICODETEXT
)
80 BUILTIN(CF_ENHMETAFILE
)
84 BUILTIN(CF_OWNERDISPLAY
)
87 BUILTIN(CF_DSPMETAFILEPICT
)
88 BUILTIN(CF_DSPENHMETAFILE
)
90 default: return wine_dbg_sprintf( "%04x", id
);
94 /* build the data to send to the server in SetClipboardData */
95 static HANDLE
marshal_data( UINT format
, HANDLE handle
, size_t *ret_size
)
105 if (!GetObjectW( handle
, sizeof(bitmap
), &bitmap
)) return 0;
106 size
= abs( bitmap
.bmHeight
) * ((((bitmap
.bmWidth
* bitmap
.bmBitsPixel
) + 15) >> 3) & ~1);
107 *ret_size
= sizeof(bitmap
) + size
;
108 if (!(bm
= GlobalAlloc( GMEM_FIXED
, *ret_size
))) return 0;
110 GetBitmapBits( handle
, size
, bm
+ 1 );
116 if (!(size
= GetPaletteEntries( handle
, 0, 0, NULL
))) return 0;
117 *ret_size
= offsetof( LOGPALETTE
, palPalEntry
[size
] );
118 if (!(pal
= GlobalAlloc( GMEM_FIXED
, *ret_size
))) return 0;
119 pal
->palVersion
= 0x300;
120 pal
->palNumEntries
= size
;
121 GetPaletteEntries( handle
, 0, size
, pal
->palPalEntry
);
125 case CF_DSPENHMETAFILE
:
128 if (!(size
= GetEnhMetaFileBits( handle
, 0, NULL
))) return 0;
129 if (!(ret
= GlobalAlloc( GMEM_FIXED
, size
))) return 0;
130 GetEnhMetaFileBits( handle
, size
, ret
);
134 case CF_METAFILEPICT
:
135 case CF_DSPMETAFILEPICT
:
138 struct metafile_pict
*mfbits
;
139 if (!(mf
= GlobalLock( handle
))) return 0;
140 if (!(size
= GetMetaFileBitsEx( mf
->hMF
, 0, NULL
)))
142 GlobalUnlock( handle
);
145 *ret_size
= offsetof( struct metafile_pict
, bits
[size
] );
146 if (!(mfbits
= GlobalAlloc( GMEM_FIXED
, *ret_size
)))
148 GlobalUnlock( handle
);
152 mfbits
->xExt
= mf
->xExt
;
153 mfbits
->yExt
= mf
->yExt
;
154 GetMetaFileBitsEx( mf
->hMF
, size
, mfbits
->bits
);
155 GlobalUnlock( handle
);
161 if (!(size
= GlobalSize( handle
))) return 0;
162 if ((data_size_t
)size
!= size
) return 0;
163 if (size
< sizeof(WCHAR
)) return 0;
164 if (!(ptr
= GlobalLock( handle
))) return 0;
165 /* enforce nul-termination the Windows way: ignoring alignment */
166 *((WCHAR
*)(ptr
+ size
) - 1) = 0;
167 GlobalUnlock( handle
);
175 if (!(size
= GlobalSize( handle
))) return 0;
176 if ((data_size_t
)size
!= size
) return 0;
177 if (!(ptr
= GlobalLock( handle
))) return 0;
178 ptr
[size
- 1] = 0; /* enforce null-termination */
179 GlobalUnlock( handle
);
184 if (!(size
= GlobalSize( handle
))) return 0;
185 if ((data_size_t
)size
!= size
) return 0;
191 /* rebuild the target handle from the data received in GetClipboardData */
192 static HANDLE
unmarshal_data( UINT format
, void *data
, data_size_t size
)
194 HANDLE handle
= GlobalReAlloc( data
, size
, GMEM_MOVEABLE
); /* release unused space */
201 if (size
< sizeof(*bm
)) break;
202 if (size
< bm
->bmWidthBytes
* abs( bm
->bmHeight
)) break;
203 if (bm
->bmBits
) break; /* DIB sections are not supported across processes */
205 return CreateBitmapIndirect( bm
);
207 case CF_DSPBITMAP
: /* not supported across processes */
211 LOGPALETTE
*pal
= handle
;
212 if (size
< sizeof(*pal
)) break;
213 if (size
< offsetof( LOGPALETTE
, palPalEntry
[pal
->palNumEntries
] )) break;
214 return CreatePalette( pal
);
217 case CF_DSPENHMETAFILE
:
218 return SetEnhMetaFileBits( size
, handle
);
219 case CF_METAFILEPICT
:
220 case CF_DSPMETAFILEPICT
:
223 struct metafile_pict
*mfbits
= handle
;
224 if (size
<= sizeof(*mfbits
)) break;
226 mf
.xExt
= mfbits
->xExt
;
227 mf
.yExt
= mfbits
->yExt
;
228 mf
.hMF
= SetMetaFileBitsEx( size
- offsetof( struct metafile_pict
, bits
), mfbits
->bits
);
229 *(METAFILEPICT
*)handle
= mf
;
236 /* free a single cached format */
237 void free_cached_data( UINT format
, HANDLE handle
)
246 DeleteObject( handle
);
249 case CF_DSPENHMETAFILE
:
250 DeleteEnhMetaFile( handle
);
252 case CF_METAFILEPICT
:
253 case CF_DSPMETAFILEPICT
:
254 if ((ptr
= GlobalLock( handle
)))
256 DeleteMetaFile( ((METAFILEPICT
*)ptr
)->hMF
);
257 GlobalUnlock( handle
);
259 GlobalFree( handle
);
262 GlobalFree( handle
);
267 /* get the clipboard locale stored in the CF_LOCALE format */
268 static LCID
get_clipboard_locale(void)
271 LCID lcid
= GetUserDefaultLCID();
273 if ((data
= GetClipboardData( CF_LOCALE
)))
275 LCID
*ptr
= GlobalLock( data
);
278 if (GlobalSize( data
) >= sizeof(*ptr
)) lcid
= *ptr
;
279 GlobalUnlock( data
);
285 /* get the codepage to use for text conversions in the specified format (CF_TEXT or CF_OEMTEXT) */
286 static UINT
get_format_codepage( LCID lcid
, UINT format
)
288 LCTYPE type
= (format
== CF_TEXT
) ? LOCALE_IDEFAULTANSICODEPAGE
: LOCALE_IDEFAULTCODEPAGE
;
291 if (!GetLocaleInfoW( lcid
, type
| LOCALE_RETURN_NUMBER
, (LPWSTR
)&ret
, sizeof(ret
)/sizeof(WCHAR
) ))
292 ret
= (format
== CF_TEXT
) ? CP_ACP
: CP_OEMCP
;
296 /* render synthesized ANSI text based on the contents of the 'from' format */
297 static HANDLE
render_synthesized_textA( HANDLE data
, UINT format
, UINT from
)
302 LCID lcid
= get_clipboard_locale();
303 UINT codepage
= get_format_codepage( lcid
, format
);
304 UINT len
, size
= GlobalSize( data
);
306 if (!(src
= GlobalLock( data
))) return 0;
308 if (from
!= CF_UNICODETEXT
) /* first convert incoming format to Unicode */
310 UINT from_codepage
= get_format_codepage( lcid
, from
);
311 len
= MultiByteToWideChar( from_codepage
, 0, src
, size
, NULL
, 0 );
312 if (!(srcW
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) ))) goto done
;
313 MultiByteToWideChar( from_codepage
, 0, src
, size
, srcW
, len
);
315 size
= len
* sizeof(WCHAR
);
318 if ((len
= WideCharToMultiByte( codepage
, 0, src
, size
/ sizeof(WCHAR
), NULL
, 0, NULL
, NULL
)))
320 if ((ret
= GlobalAlloc( GMEM_FIXED
, len
)))
321 WideCharToMultiByte( codepage
, 0, src
, size
/ sizeof(WCHAR
), ret
, len
, NULL
, NULL
);
325 HeapFree( GetProcessHeap(), 0, srcW
);
326 GlobalUnlock( data
);
330 /* render synthesized Unicode text based on the contents of the 'from' format */
331 static HANDLE
render_synthesized_textW( HANDLE data
, UINT from
)
335 UINT len
, size
= GlobalSize( data
);
336 UINT codepage
= get_format_codepage( get_clipboard_locale(), from
);
338 if (!(src
= GlobalLock( data
))) return 0;
340 if ((len
= MultiByteToWideChar( codepage
, 0, src
, size
, NULL
, 0 )))
342 if ((ret
= GlobalAlloc( GMEM_FIXED
, len
* sizeof(WCHAR
) )))
343 MultiByteToWideChar( codepage
, 0, src
, size
, ret
, len
);
345 GlobalUnlock( data
);
349 /* render a synthesized bitmap based on the DIB clipboard data */
350 static HANDLE
render_synthesized_bitmap( HANDLE data
, UINT from
)
354 HDC hdc
= NtUserGetDC( 0 );
356 if ((bmi
= GlobalLock( data
)))
358 /* FIXME: validate data size */
359 ret
= CreateDIBitmap( hdc
, &bmi
->bmiHeader
, CBM_INIT
,
360 (char *)bmi
+ bitmap_info_size( bmi
, DIB_RGB_COLORS
),
361 bmi
, DIB_RGB_COLORS
);
362 GlobalUnlock( data
);
364 NtUserReleaseDC( 0, hdc
);
368 /* render a synthesized DIB based on the clipboard data */
369 static HANDLE
render_synthesized_dib( HANDLE data
, UINT format
, UINT from
)
371 BITMAPINFO
*bmi
, *src
;
372 DWORD src_size
, header_size
, bits_size
;
374 HDC hdc
= NtUserGetDC( 0 );
376 if (from
== CF_BITMAP
)
378 BITMAPV5HEADER header
;
380 memset( &header
, 0, sizeof(header
) );
381 header
.bV5Size
= (format
== CF_DIBV5
) ? sizeof(BITMAPV5HEADER
) : sizeof(BITMAPINFOHEADER
);
382 if (!GetDIBits( hdc
, data
, 0, 0, NULL
, (BITMAPINFO
*)&header
, DIB_RGB_COLORS
)) goto done
;
384 header_size
= bitmap_info_size( (BITMAPINFO
*)&header
, DIB_RGB_COLORS
);
385 if (!(ret
= GlobalAlloc( GMEM_FIXED
, header_size
+ header
.bV5SizeImage
))) goto done
;
386 bmi
= (BITMAPINFO
*)ret
;
387 memset( bmi
, 0, header_size
);
388 memcpy( bmi
, &header
, header
.bV5Size
);
389 GetDIBits( hdc
, data
, 0, abs(header
.bV5Height
), (char *)bmi
+ header_size
, bmi
, DIB_RGB_COLORS
);
393 SIZE_T size
= GlobalSize( data
);
395 if (size
< sizeof(*bmi
)) goto done
;
396 if (!(src
= GlobalLock( data
))) goto done
;
398 src_size
= bitmap_info_size( src
, DIB_RGB_COLORS
);
399 if (size
<= src_size
)
401 GlobalUnlock( data
);
404 bits_size
= size
- src_size
;
405 header_size
= (format
== CF_DIBV5
) ? sizeof(BITMAPV5HEADER
) :
406 offsetof( BITMAPINFO
, bmiColors
[src
->bmiHeader
.biCompression
== BI_BITFIELDS
? 3 : 0] );
408 if ((ret
= GlobalAlloc( GMEM_FIXED
, header_size
+ bits_size
)))
410 bmi
= (BITMAPINFO
*)ret
;
411 memset( bmi
, 0, header_size
);
412 memcpy( bmi
, src
, min( header_size
, src_size
));
413 bmi
->bmiHeader
.biSize
= header_size
;
414 /* FIXME: convert colors according to DIBv5 color profile */
415 memcpy( (char *)bmi
+ header_size
, (char *)src
+ src_size
, bits_size
);
417 GlobalUnlock( data
);
421 NtUserReleaseDC( 0, hdc
);
425 /* render a synthesized metafile based on the enhmetafile clipboard data */
426 static HANDLE
render_synthesized_metafile( HANDLE data
)
432 ENHMETAHEADER header
;
433 HDC hdc
= NtUserGetDC( 0 );
435 size
= GetWinMetaFileBits( data
, 0, NULL
, MM_ISOTROPIC
, hdc
);
436 if ((bits
= HeapAlloc( GetProcessHeap(), 0, size
)))
438 if (GetEnhMetaFileHeader( data
, sizeof(header
), &header
) &&
439 GetWinMetaFileBits( data
, size
, bits
, MM_ISOTROPIC
, hdc
))
441 if ((ret
= GlobalAlloc( GMEM_FIXED
, sizeof(*pict
) )))
443 pict
= (METAFILEPICT
*)ret
;
444 pict
->mm
= MM_ISOTROPIC
;
445 pict
->xExt
= header
.rclFrame
.right
- header
.rclFrame
.left
;
446 pict
->yExt
= header
.rclFrame
.bottom
- header
.rclFrame
.top
;
447 pict
->hMF
= SetMetaFileBitsEx( size
, bits
);
450 HeapFree( GetProcessHeap(), 0, bits
);
452 NtUserReleaseDC( 0, hdc
);
456 /* render a synthesized enhmetafile based on the metafile clipboard data */
457 static HANDLE
render_synthesized_enhmetafile( HANDLE data
)
464 if (!(pict
= GlobalLock( data
))) return 0;
466 size
= GetMetaFileBitsEx( pict
->hMF
, 0, NULL
);
467 if ((bits
= HeapAlloc( GetProcessHeap(), 0, size
)))
469 GetMetaFileBitsEx( pict
->hMF
, size
, bits
);
470 ret
= SetWinMetaFileBits( size
, bits
, NULL
, pict
);
471 HeapFree( GetProcessHeap(), 0, bits
);
474 GlobalUnlock( data
);
478 /* render a synthesized format */
479 HANDLE
render_synthesized_format( UINT format
, UINT from
)
481 HANDLE data
= GetClipboardData( from
);
484 TRACE( "rendering %s from %s\n", debugstr_format( format
), debugstr_format( from
));
490 data
= render_synthesized_textA( data
, format
, from
);
493 data
= render_synthesized_textW( data
, from
);
496 data
= render_synthesized_bitmap( data
, from
);
500 data
= render_synthesized_dib( data
, format
, from
);
502 case CF_METAFILEPICT
:
503 data
= render_synthesized_metafile( data
);
506 data
= render_synthesized_enhmetafile( data
);
513 TRACE( "adding %s %p\n", debugstr_format( format
), data
);
514 SetClipboardData( format
, data
);
520 /**************************************************************************
521 * RegisterClipboardFormatW (USER32.@)
523 UINT WINAPI
RegisterClipboardFormatW( LPCWSTR name
)
525 return GlobalAddAtomW( name
);
529 /**************************************************************************
530 * RegisterClipboardFormatA (USER32.@)
532 UINT WINAPI
RegisterClipboardFormatA( LPCSTR name
)
534 return GlobalAddAtomA( name
);
538 /**************************************************************************
539 * GetClipboardFormatNameA (USER32.@)
541 INT WINAPI
GetClipboardFormatNameA( UINT format
, LPSTR buffer
, INT maxlen
)
543 if (format
< MAXINTATOM
|| format
> 0xffff) return 0;
544 return GlobalGetAtomNameA( format
, buffer
, maxlen
);
548 /**************************************************************************
549 * OpenClipboard (USER32.@)
551 BOOL WINAPI
OpenClipboard( HWND hwnd
)
553 return NtUserOpenClipboard( hwnd
, 0 );
557 /**************************************************************************
558 * SetClipboardData (USER32.@)
560 HANDLE WINAPI
SetClipboardData( UINT format
, HANDLE data
)
562 struct set_clipboard_params params
= { .size
= 0 };
563 HANDLE handle
= data
;
566 TRACE( "%s %p\n", debugstr_format( format
), data
);
570 if (!(handle
= marshal_data( format
, data
, ¶ms
.size
))) return 0;
571 if (!(params
.data
= GlobalLock( handle
))) return 0;
574 status
= NtUserSetClipboardData( format
, data
, ¶ms
);
576 if (params
.data
) GlobalUnlock( handle
);
577 if (handle
!= data
) GlobalFree( handle
);
580 SetLastError( RtlNtStatusToDosError( status
));
587 /**************************************************************************
588 * EnumClipboardFormats (USER32.@)
590 UINT WINAPI
EnumClipboardFormats( UINT format
)
592 return NtUserEnumClipboardFormats( format
);
596 /**************************************************************************
597 * GetClipboardData (USER32.@)
599 HANDLE WINAPI
GetClipboardData( UINT format
)
601 struct get_clipboard_params params
= { .data_size
= 1024 };
604 EnterCriticalSection( &clipboard_cs
);
606 while (params
.data_size
)
608 params
.size
= params
.data_size
;
609 params
.data_size
= 0;
610 if (!(params
.data
= GlobalAlloc( GMEM_FIXED
, params
.size
))) break;
611 ret
= NtUserGetClipboardData( format
, ¶ms
);
613 if (params
.data_size
== ~0) /* needs unmarshaling */
615 struct set_clipboard_params set_params
= { .cache_only
= TRUE
, .seqno
= params
.seqno
};
617 ret
= unmarshal_data( format
, params
.data
, params
.size
);
618 if (!NtUserSetClipboardData( format
, ret
, &set_params
)) break;
620 /* data changed, retry */
621 free_cached_data( format
, ret
);
623 params
.data_size
= 1024;
626 GlobalFree( params
.data
);
629 LeaveCriticalSection( &clipboard_cs
);