mshtml: Implement onprogress for XMLHttpRequest.
[wine.git] / dlls / user32 / clipboard.c
blob7e5a3e0b022a2ff36bde486919c17bc70be72661
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 <stdarg.h>
28 #include <stdlib.h>
29 #include <sys/types.h>
30 #include <fcntl.h>
31 #include <string.h>
33 #include "ntstatus.h"
34 #define WIN32_NO_STATUS
35 #include "windef.h"
36 #include "winbase.h"
37 #include "winnls.h"
38 #include "wingdi.h"
39 #include "winuser.h"
40 #include "winerror.h"
41 #include "user_private.h"
42 #include "win.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 =
54 0, 0, &clipboard_cs,
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 */
61 struct metafile_pict
63 LONG mm;
64 LONG xExt;
65 LONG yExt;
66 BYTE bits[1];
69 /* get a debug string for a format id */
70 static const char *debugstr_format( UINT id )
72 WCHAR buffer[256];
73 DWORD le = GetLastError();
74 BOOL r = NtUserGetClipboardFormatName( id, buffer, 256 );
75 SetLastError(le);
77 if (r)
78 return wine_dbg_sprintf( "%04x %s", id, debugstr_w(buffer) );
80 switch (id)
82 #define BUILTIN(id) case id: return #id;
83 BUILTIN(CF_TEXT)
84 BUILTIN(CF_BITMAP)
85 BUILTIN(CF_METAFILEPICT)
86 BUILTIN(CF_SYLK)
87 BUILTIN(CF_DIF)
88 BUILTIN(CF_TIFF)
89 BUILTIN(CF_OEMTEXT)
90 BUILTIN(CF_DIB)
91 BUILTIN(CF_PALETTE)
92 BUILTIN(CF_PENDATA)
93 BUILTIN(CF_RIFF)
94 BUILTIN(CF_WAVE)
95 BUILTIN(CF_UNICODETEXT)
96 BUILTIN(CF_ENHMETAFILE)
97 BUILTIN(CF_HDROP)
98 BUILTIN(CF_LOCALE)
99 BUILTIN(CF_DIBV5)
100 BUILTIN(CF_OWNERDISPLAY)
101 BUILTIN(CF_DSPTEXT)
102 BUILTIN(CF_DSPBITMAP)
103 BUILTIN(CF_DSPMETAFILEPICT)
104 BUILTIN(CF_DSPENHMETAFILE)
105 #undef BUILTIN
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 )
113 SIZE_T size;
115 switch (format)
117 case CF_BITMAP:
118 case CF_DSPBITMAP:
120 BITMAP bitmap, *bm;
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;
125 *bm = bitmap;
126 GetBitmapBits( handle, size, bm + 1 );
127 return bm;
129 case CF_PALETTE:
131 LOGPALETTE *pal;
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 );
138 return pal;
140 case CF_ENHMETAFILE:
141 case CF_DSPENHMETAFILE:
143 BYTE *ret;
144 if (!(size = GetEnhMetaFileBits( handle, 0, NULL ))) return 0;
145 if (!(ret = GlobalAlloc( GMEM_FIXED, size ))) return 0;
146 GetEnhMetaFileBits( handle, size, ret );
147 *ret_size = size;
148 return ret;
150 case CF_METAFILEPICT:
151 case CF_DSPMETAFILEPICT:
153 METAFILEPICT *mf;
154 struct metafile_pict *mfbits;
155 if (!(mf = GlobalLock( handle ))) return 0;
156 if (!(size = GetMetaFileBitsEx( mf->hMF, 0, NULL )))
158 GlobalUnlock( handle );
159 return 0;
161 *ret_size = offsetof( struct metafile_pict, bits[size] );
162 if (!(mfbits = GlobalAlloc( GMEM_FIXED, *ret_size )))
164 GlobalUnlock( handle );
165 return 0;
167 mfbits->mm = mf->mm;
168 mfbits->xExt = mf->xExt;
169 mfbits->yExt = mf->yExt;
170 GetMetaFileBitsEx( mf->hMF, size, mfbits->bits );
171 GlobalUnlock( handle );
172 return mfbits;
174 case CF_UNICODETEXT:
176 WCHAR *ptr;
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 );
182 *ret_size = size;
183 return handle;
185 case CF_TEXT:
186 case CF_OEMTEXT:
188 char *ptr;
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 );
194 *ret_size = size;
195 return handle;
197 default:
198 if (!(size = GlobalSize( handle ))) return 0;
199 if ((data_size_t)size != size) return 0;
200 *ret_size = size;
201 return handle;
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 */
210 switch (format)
212 case CF_BITMAP:
214 BITMAP *bm = handle;
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 */
218 bm->bmBits = bm + 1;
219 return CreateBitmapIndirect( bm );
221 case CF_DSPBITMAP: /* not supported across processes */
222 break;
223 case CF_PALETTE:
225 LOGPALETTE *pal = handle;
226 if (size < sizeof(*pal)) break;
227 if (size < offsetof( LOGPALETTE, palPalEntry[pal->palNumEntries] )) break;
228 return CreatePalette( pal );
230 case CF_ENHMETAFILE:
231 case CF_DSPENHMETAFILE:
232 return SetEnhMetaFileBits( size, handle );
233 case CF_METAFILEPICT:
234 case CF_DSPMETAFILEPICT:
236 METAFILEPICT mf;
237 struct metafile_pict *mfbits = handle;
238 if (size <= sizeof(*mfbits)) break;
239 mf.mm = mfbits->mm;
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;
244 return handle;
247 return handle;
250 /* free a single cached format */
251 void free_cached_data( UINT format, HANDLE handle )
253 void *ptr;
255 switch (format)
257 case CF_BITMAP:
258 case CF_DSPBITMAP:
259 case CF_PALETTE:
260 DeleteObject( handle );
261 break;
262 case CF_ENHMETAFILE:
263 case CF_DSPENHMETAFILE:
264 DeleteEnhMetaFile( handle );
265 break;
266 case CF_METAFILEPICT:
267 case CF_DSPMETAFILEPICT:
268 if ((ptr = GlobalLock( handle )))
270 DeleteMetaFile( ((METAFILEPICT *)ptr)->hMF );
271 GlobalUnlock( handle );
273 GlobalFree( handle );
274 break;
275 default:
276 GlobalFree( handle );
277 break;
281 /* get the clipboard locale stored in the CF_LOCALE format */
282 static LCID get_clipboard_locale(void)
284 HANDLE data;
285 LCID lcid = GetUserDefaultLCID();
287 if ((data = GetClipboardData( CF_LOCALE )))
289 LCID *ptr = GlobalLock( data );
290 if (ptr)
292 if (GlobalSize( data ) >= sizeof(*ptr)) lcid = *ptr;
293 GlobalUnlock( data );
296 return lcid;
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;
303 UINT ret;
305 if (!GetLocaleInfoW( lcid, type | LOCALE_RETURN_NUMBER, (LPWSTR)&ret, sizeof(ret)/sizeof(WCHAR) ))
306 ret = (format == CF_TEXT) ? CP_ACP : CP_OEMCP;
307 return ret;
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 )
313 void *src;
314 WCHAR *srcW = NULL;
315 HANDLE ret = 0;
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 );
328 src = srcW;
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 );
338 done:
339 HeapFree( GetProcessHeap(), 0, srcW );
340 GlobalUnlock( data );
341 return ret;
344 /* render synthesized Unicode text based on the contents of the 'from' format */
345 static HANDLE render_synthesized_textW( HANDLE data, UINT from )
347 char *src;
348 HANDLE ret = 0;
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 );
360 return ret;
363 /* render a synthesized bitmap based on the DIB clipboard data */
364 static HANDLE render_synthesized_bitmap( HANDLE data, UINT from )
366 BITMAPINFO *bmi;
367 HANDLE ret = 0;
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 );
379 return ret;
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;
387 HANDLE ret = 0;
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 );
405 else
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 );
416 goto done;
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 );
434 done:
435 NtUserReleaseDC( 0, hdc );
436 return ret;
439 /* render a synthesized metafile based on the enhmetafile clipboard data */
440 static HANDLE render_synthesized_metafile( HANDLE data )
442 HANDLE ret = 0;
443 UINT size;
444 void *bits;
445 METAFILEPICT *pict;
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 );
467 return ret;
470 /* render a synthesized enhmetafile based on the metafile clipboard data */
471 static HANDLE render_synthesized_enhmetafile( HANDLE data )
473 METAFILEPICT *pict;
474 HANDLE ret = 0;
475 UINT size;
476 void *bits;
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 );
489 return ret;
492 /* render a synthesized format */
493 HANDLE render_synthesized_format( UINT format, UINT from )
495 HANDLE data = GetClipboardData( from );
497 if (!data) return 0;
498 TRACE( "rendering %s from %s\n", debugstr_format( format ), debugstr_format( from ));
500 switch (format)
502 case CF_TEXT:
503 case CF_OEMTEXT:
504 data = render_synthesized_textA( data, format, from );
505 break;
506 case CF_UNICODETEXT:
507 data = render_synthesized_textW( data, from );
508 break;
509 case CF_BITMAP:
510 data = render_synthesized_bitmap( data, from );
511 break;
512 case CF_DIB:
513 case CF_DIBV5:
514 data = render_synthesized_dib( data, format, from );
515 break;
516 case CF_METAFILEPICT:
517 data = render_synthesized_metafile( data );
518 break;
519 case CF_ENHMETAFILE:
520 data = render_synthesized_enhmetafile( data );
521 break;
522 default:
523 assert( 0 );
525 if (data)
527 TRACE( "adding %s %p\n", debugstr_format( format ), data );
528 SetClipboardData( format, data );
530 return 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;
578 NTSTATUS status;
580 TRACE( "%s %p\n", debugstr_format( format ), data );
582 if (data)
584 if (!(handle = marshal_data( format, data, &params.size ))) return 0;
585 if (!(params.data = GlobalLock( handle ))) return 0;
588 status = NtUserSetClipboardData( format, data, &params );
590 if (params.data) GlobalUnlock( handle );
591 if (handle != data) GlobalFree( handle );
592 if (status)
594 SetLastError( RtlNtStatusToDosError( status ));
595 return 0;
597 return data;
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 };
616 HANDLE ret = 0;
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, &params );
626 if (ret) break;
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 );
636 ret = 0;
637 params.data_size = 1024;
638 continue;
640 GlobalFree( params.data );
643 LeaveCriticalSection( &clipboard_cs );
644 return ret;