include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / user32 / clipboard.c
blob72c7720dc17726cfd2f35b96893ffa6c6607a758
1 /*
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
26 #include <assert.h>
27 #include "user_private.h"
28 #include "winnls.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 =
38 0, 0, &clipboard_cs,
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 */
45 struct metafile_pict
47 LONG mm;
48 LONG xExt;
49 LONG yExt;
50 BYTE bits[1];
53 /* get a debug string for a format id */
54 static const char *debugstr_format( UINT id )
56 WCHAR buffer[256];
57 DWORD le = GetLastError();
58 BOOL r = NtUserGetClipboardFormatName( id, buffer, 256 );
59 SetLastError(le);
61 if (r)
62 return wine_dbg_sprintf( "%04x %s", id, debugstr_w(buffer) );
64 switch (id)
66 #define BUILTIN(id) case id: return #id;
67 BUILTIN(CF_TEXT)
68 BUILTIN(CF_BITMAP)
69 BUILTIN(CF_METAFILEPICT)
70 BUILTIN(CF_SYLK)
71 BUILTIN(CF_DIF)
72 BUILTIN(CF_TIFF)
73 BUILTIN(CF_OEMTEXT)
74 BUILTIN(CF_DIB)
75 BUILTIN(CF_PALETTE)
76 BUILTIN(CF_PENDATA)
77 BUILTIN(CF_RIFF)
78 BUILTIN(CF_WAVE)
79 BUILTIN(CF_UNICODETEXT)
80 BUILTIN(CF_ENHMETAFILE)
81 BUILTIN(CF_HDROP)
82 BUILTIN(CF_LOCALE)
83 BUILTIN(CF_DIBV5)
84 BUILTIN(CF_OWNERDISPLAY)
85 BUILTIN(CF_DSPTEXT)
86 BUILTIN(CF_DSPBITMAP)
87 BUILTIN(CF_DSPMETAFILEPICT)
88 BUILTIN(CF_DSPENHMETAFILE)
89 #undef BUILTIN
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 )
97 SIZE_T size;
99 switch (format)
101 case CF_BITMAP:
102 case CF_DSPBITMAP:
104 BITMAP bitmap, *bm;
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;
109 *bm = bitmap;
110 GetBitmapBits( handle, size, bm + 1 );
111 return bm;
113 case CF_PALETTE:
115 LOGPALETTE *pal;
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 );
122 return pal;
124 case CF_ENHMETAFILE:
125 case CF_DSPENHMETAFILE:
127 BYTE *ret;
128 if (!(size = GetEnhMetaFileBits( handle, 0, NULL ))) return 0;
129 if (!(ret = GlobalAlloc( GMEM_FIXED, size ))) return 0;
130 GetEnhMetaFileBits( handle, size, ret );
131 *ret_size = size;
132 return ret;
134 case CF_METAFILEPICT:
135 case CF_DSPMETAFILEPICT:
137 METAFILEPICT *mf;
138 struct metafile_pict *mfbits;
139 if (!(mf = GlobalLock( handle ))) return 0;
140 if (!(size = GetMetaFileBitsEx( mf->hMF, 0, NULL )))
142 GlobalUnlock( handle );
143 return 0;
145 *ret_size = offsetof( struct metafile_pict, bits[size] );
146 if (!(mfbits = GlobalAlloc( GMEM_FIXED, *ret_size )))
148 GlobalUnlock( handle );
149 return 0;
151 mfbits->mm = mf->mm;
152 mfbits->xExt = mf->xExt;
153 mfbits->yExt = mf->yExt;
154 GetMetaFileBitsEx( mf->hMF, size, mfbits->bits );
155 GlobalUnlock( handle );
156 return mfbits;
158 case CF_UNICODETEXT:
160 char *ptr;
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 );
168 *ret_size = size;
169 return handle;
171 case CF_TEXT:
172 case CF_OEMTEXT:
174 char *ptr;
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 );
180 *ret_size = size;
181 return handle;
183 default:
184 if (!(size = GlobalSize( handle ))) return 0;
185 if ((data_size_t)size != size) return 0;
186 *ret_size = size;
187 return handle;
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 */
196 switch (format)
198 case CF_BITMAP:
200 BITMAP *bm = handle;
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 */
204 bm->bmBits = bm + 1;
205 return CreateBitmapIndirect( bm );
207 case CF_DSPBITMAP: /* not supported across processes */
208 break;
209 case CF_PALETTE:
211 LOGPALETTE *pal = handle;
212 if (size < sizeof(*pal)) break;
213 if (size < offsetof( LOGPALETTE, palPalEntry[pal->palNumEntries] )) break;
214 return CreatePalette( pal );
216 case CF_ENHMETAFILE:
217 case CF_DSPENHMETAFILE:
218 return SetEnhMetaFileBits( size, handle );
219 case CF_METAFILEPICT:
220 case CF_DSPMETAFILEPICT:
222 METAFILEPICT mf;
223 struct metafile_pict *mfbits = handle;
224 if (size <= sizeof(*mfbits)) break;
225 mf.mm = mfbits->mm;
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;
230 return handle;
233 return handle;
236 /* free a single cached format */
237 void free_cached_data( UINT format, HANDLE handle )
239 void *ptr;
241 switch (format)
243 case CF_BITMAP:
244 case CF_DSPBITMAP:
245 case CF_PALETTE:
246 DeleteObject( handle );
247 break;
248 case CF_ENHMETAFILE:
249 case CF_DSPENHMETAFILE:
250 DeleteEnhMetaFile( handle );
251 break;
252 case CF_METAFILEPICT:
253 case CF_DSPMETAFILEPICT:
254 if ((ptr = GlobalLock( handle )))
256 DeleteMetaFile( ((METAFILEPICT *)ptr)->hMF );
257 GlobalUnlock( handle );
259 GlobalFree( handle );
260 break;
261 default:
262 GlobalFree( handle );
263 break;
267 /* get the clipboard locale stored in the CF_LOCALE format */
268 static LCID get_clipboard_locale(void)
270 HANDLE data;
271 LCID lcid = GetUserDefaultLCID();
273 if ((data = GetClipboardData( CF_LOCALE )))
275 LCID *ptr = GlobalLock( data );
276 if (ptr)
278 if (GlobalSize( data ) >= sizeof(*ptr)) lcid = *ptr;
279 GlobalUnlock( data );
282 return lcid;
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;
289 UINT ret;
291 if (!GetLocaleInfoW( lcid, type | LOCALE_RETURN_NUMBER, (LPWSTR)&ret, sizeof(ret)/sizeof(WCHAR) ))
292 ret = (format == CF_TEXT) ? CP_ACP : CP_OEMCP;
293 return ret;
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 )
299 void *src;
300 WCHAR *srcW = NULL;
301 HANDLE ret = 0;
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 );
314 src = srcW;
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 );
324 done:
325 HeapFree( GetProcessHeap(), 0, srcW );
326 GlobalUnlock( data );
327 return ret;
330 /* render synthesized Unicode text based on the contents of the 'from' format */
331 static HANDLE render_synthesized_textW( HANDLE data, UINT from )
333 char *src;
334 HANDLE ret = 0;
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 );
346 return ret;
349 /* render a synthesized bitmap based on the DIB clipboard data */
350 static HANDLE render_synthesized_bitmap( HANDLE data, UINT from )
352 BITMAPINFO *bmi;
353 HANDLE ret = 0;
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 );
365 return ret;
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;
373 HANDLE ret = 0;
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 );
391 else
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 );
402 goto done;
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 );
420 done:
421 NtUserReleaseDC( 0, hdc );
422 return ret;
425 /* render a synthesized metafile based on the enhmetafile clipboard data */
426 static HANDLE render_synthesized_metafile( HANDLE data )
428 HANDLE ret = 0;
429 UINT size;
430 void *bits;
431 METAFILEPICT *pict;
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 );
453 return ret;
456 /* render a synthesized enhmetafile based on the metafile clipboard data */
457 static HANDLE render_synthesized_enhmetafile( HANDLE data )
459 METAFILEPICT *pict;
460 HANDLE ret = 0;
461 UINT size;
462 void *bits;
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 );
475 return ret;
478 /* render a synthesized format */
479 HANDLE render_synthesized_format( UINT format, UINT from )
481 HANDLE data = GetClipboardData( from );
483 if (!data) return 0;
484 TRACE( "rendering %s from %s\n", debugstr_format( format ), debugstr_format( from ));
486 switch (format)
488 case CF_TEXT:
489 case CF_OEMTEXT:
490 data = render_synthesized_textA( data, format, from );
491 break;
492 case CF_UNICODETEXT:
493 data = render_synthesized_textW( data, from );
494 break;
495 case CF_BITMAP:
496 data = render_synthesized_bitmap( data, from );
497 break;
498 case CF_DIB:
499 case CF_DIBV5:
500 data = render_synthesized_dib( data, format, from );
501 break;
502 case CF_METAFILEPICT:
503 data = render_synthesized_metafile( data );
504 break;
505 case CF_ENHMETAFILE:
506 data = render_synthesized_enhmetafile( data );
507 break;
508 default:
509 assert( 0 );
511 if (data)
513 TRACE( "adding %s %p\n", debugstr_format( format ), data );
514 SetClipboardData( format, data );
516 return 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;
564 NTSTATUS status;
566 TRACE( "%s %p\n", debugstr_format( format ), data );
568 if (data)
570 if (!(handle = marshal_data( format, data, &params.size ))) return 0;
571 if (!(params.data = GlobalLock( handle ))) return 0;
574 status = NtUserSetClipboardData( format, data, &params );
576 if (params.data) GlobalUnlock( handle );
577 if (handle != data) GlobalFree( handle );
578 if (status)
580 SetLastError( RtlNtStatusToDosError( status ));
581 return 0;
583 return data;
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 };
602 HANDLE ret = 0;
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, &params );
612 if (ret) break;
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 );
622 ret = 0;
623 params.data_size = 1024;
624 continue;
626 GlobalFree( params.data );
629 LeaveCriticalSection( &clipboard_cs );
630 return ret;