blob: 7d0510b6febc0dbf6211b7369c33b09079137e2e [file] [log] [blame]
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00001/*
Noel Borthwick29700671999-09-03 15:17:57 +00002 * WIN32 clipboard implementation
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00003 *
4 * Copyright 1994 Martin Ayotte
Alexandre Julliard1e9ac791996-06-06 18:38:27 +00005 * 1996 Alex Korobka
Noel Borthwick29700671999-09-03 15:17:57 +00006 * 1999 Noel Borthwick
7 *
Alexandre Julliard0799c1a2002-03-09 23:29:33 +00008 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
Noel Borthwick29700671999-09-03 15:17:57 +000022 * NOTES:
23 * This file contains the implementation for the WIN32 Clipboard API
24 * and Wine's internal clipboard cache.
25 * The actual contents of the clipboard are held in the clipboard cache.
26 * The internal implementation talks to a "clipboard driver" to fill or
27 * expose the cache to the native device. (Currently only the X11 and
28 * TTY clipboard driver are available)
Alexandre Julliard1e9ac791996-06-06 18:38:27 +000029 */
Alexandre Julliardfb9a9191994-03-01 19:48:04 +000030
Patrik Stridvalld016f812002-08-17 00:43:16 +000031#include "config.h"
Patrik Stridvall51e6c0c2002-08-31 19:04:14 +000032#include "wine/port.h"
Patrik Stridvalld016f812002-08-17 00:43:16 +000033
Alexandre Julliard8d24ae61994-04-05 21:42:43 +000034#include <stdlib.h>
Alexandre Julliardfb9a9191994-03-01 19:48:04 +000035#include <sys/types.h>
Alexandre Julliardfb9a9191994-03-01 19:48:04 +000036#include <fcntl.h>
Patrik Stridvalld016f812002-08-17 00:43:16 +000037#ifdef HAVE_UNISTD_H
38# include <unistd.h>
39#endif
Alexandre Julliard1e9ac791996-06-06 18:38:27 +000040#include <string.h>
François Gouget44a18222000-12-19 04:53:20 +000041
Jeremy Whited3e22d92000-02-10 19:03:02 +000042#include "windef.h"
François Gouget44a18222000-12-19 04:53:20 +000043#include "winbase.h"
Jeremy Whited3e22d92000-02-10 19:03:02 +000044#include "wingdi.h"
Marcus Meissner61afa331999-02-22 10:16:00 +000045#include "winuser.h"
Marcus Meissner219cfd81999-02-24 13:05:13 +000046#include "wine/winuser16.h"
Noel Borthwick29700671999-09-03 15:17:57 +000047#include "wine/winbase16.h"
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +000048#include "heap.h"
Alexandre Julliard42d20f92000-08-10 01:16:19 +000049#include "user.h"
Alexandre Julliard37a46392001-09-12 17:19:13 +000050#include "win.h"
Alexandre Julliard234bc241994-12-10 13:02:28 +000051#include "clipboard.h"
Patrik Stridvallcf07e102002-10-23 20:20:59 +000052
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000053#include "wine/debug.h"
Patrik Stridvallcf07e102002-10-23 20:20:59 +000054#include "wine/unicode.h"
Alexandre Julliardfb9a9191994-03-01 19:48:04 +000055
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000056WINE_DEFAULT_DEBUG_CHANNEL(clipboard);
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000057
Alexandre Julliard1e9ac791996-06-06 18:38:27 +000058#define CF_REGFORMATBASE 0xC000
59
Alexandre Julliarda8a422f2002-11-22 20:43:01 +000060#define HGDIOBJ_32(handle16) ((HGDIOBJ)(ULONG_PTR)(handle16))
61
Patrik Stridvalle35d6361998-12-07 09:13:40 +000062/**************************************************************************
Noel Borthwick29700671999-09-03 15:17:57 +000063 * Clipboard context global variables
Alexandre Julliard1e9ac791996-06-06 18:38:27 +000064 */
65
Alexandre Julliard7ef66af2002-11-22 04:47:10 +000066static DWORD ClipLock = 0;
Alexandre Julliarda3960291999-02-26 11:11:13 +000067static BOOL bCBHasChanged = FALSE;
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +000068
Alexandre Julliard37a46392001-09-12 17:19:13 +000069static HWND hWndClipWindow; /* window that last opened clipboard */
70static HWND hWndClipOwner; /* current clipboard owner */
Alexandre Julliard7ef66af2002-11-22 04:47:10 +000071static DWORD ClipOwner; /* clipboard owner's thread id */
Alexandre Julliard37a46392001-09-12 17:19:13 +000072static HWND hWndViewer; /* start of viewers chain */
Alexandre Julliard1e9ac791996-06-06 18:38:27 +000073
Noel Borthwick29700671999-09-03 15:17:57 +000074/* Clipboard cache initial data.
Gerard Patel9289a5d2000-12-22 23:26:18 +000075 * WARNING: This data ordering is dependent on the WINE_CLIPFORMAT structure
Noel Borthwick29700671999-09-03 15:17:57 +000076 * declared in clipboard.h
77 */
Dmitry Timoshkov1df0d362000-12-11 01:09:56 +000078WINE_CLIPFORMAT ClipFormats[] = {
Alexandre Julliard42d20f92000-08-10 01:16:19 +000079 { CF_TEXT, 1, 0, "Text", 0, 0, 0, 0, NULL, &ClipFormats[1]},
80 { CF_BITMAP, 1, 0, "Bitmap", 0, 0, 0, 0, &ClipFormats[0], &ClipFormats[2]},
81 { CF_METAFILEPICT, 1, 0, "MetaFile Picture", 0, 0, 0, 0, &ClipFormats[1], &ClipFormats[3]},
82 { CF_SYLK, 1, 0, "Sylk", 0, 0, 0, 0, &ClipFormats[2], &ClipFormats[4]},
83 { CF_DIF, 1, 0, "DIF", 0, 0, 0, 0, &ClipFormats[3], &ClipFormats[5]},
84 { CF_TIFF, 1, 0, "TIFF", 0, 0, 0, 0, &ClipFormats[4], &ClipFormats[6]},
85 { CF_OEMTEXT, 1, 0, "OEM Text", 0, 0, 0, 0, &ClipFormats[5], &ClipFormats[7]},
86 { CF_DIB, 1, 0, "DIB", 0, 0, 0, 0, &ClipFormats[6], &ClipFormats[8]},
87 { CF_PALETTE, 1, 0, "Palette", 0, 0, 0, 0, &ClipFormats[7], &ClipFormats[9]},
88 { CF_PENDATA, 1, 0, "PenData", 0, 0, 0, 0, &ClipFormats[8], &ClipFormats[10]},
89 { CF_RIFF, 1, 0, "RIFF", 0, 0, 0, 0, &ClipFormats[9], &ClipFormats[11]},
90 { CF_WAVE, 1, 0, "Wave", 0, 0, 0, 0, &ClipFormats[10], &ClipFormats[12]},
Dmitry Timoshkov1df0d362000-12-11 01:09:56 +000091 { CF_UNICODETEXT, 1, 0, "Unicode Text", 0, 0, 0, 0, &ClipFormats[11], &ClipFormats[13]},
92 { CF_OWNERDISPLAY, 1, 0, "Owner Display", 0, 0, 0, 0, &ClipFormats[12], &ClipFormats[14]},
93 { CF_DSPTEXT, 1, 0, "DSPText", 0, 0, 0, 0, &ClipFormats[13], &ClipFormats[15]},
94 { CF_DSPMETAFILEPICT, 1, 0, "DSPMetaFile Picture", 0, 0, 0, 0, &ClipFormats[14], &ClipFormats[16]},
95 { CF_DSPBITMAP, 1, 0, "DSPBitmap", 0, 0, 0, 0, &ClipFormats[15], &ClipFormats[17]},
Ulrich Czekalla651c5982002-08-27 19:19:49 +000096 { CF_HDROP, 1, 0, "HDROP", 0, 0, 0, 0, &ClipFormats[16], &ClipFormats[18]},
97 { CF_ENHMETAFILE, 1, 0, "Enhmetafile", 0, 0, 0, 0, &ClipFormats[17], NULL}
Alexandre Julliard42d20f92000-08-10 01:16:19 +000098};
Alexandre Julliardfb9a9191994-03-01 19:48:04 +000099
Noel Borthwick29700671999-09-03 15:17:57 +0000100
101/**************************************************************************
102 * Internal Clipboard implementation methods
103 **************************************************************************/
104
105
106/**************************************************************************
107 * CLIPBOARD_LookupFormat
108 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000109static LPWINE_CLIPFORMAT __lookup_format( LPWINE_CLIPFORMAT lpFormat, WORD wID )
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000110{
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000111 while(TRUE)
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000112 {
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000113 if (lpFormat == NULL ||
114 lpFormat->wFormatID == wID) break;
115 lpFormat = lpFormat->NextFormat;
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000116 }
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000117 return lpFormat;
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000118}
119
Noel Borthwick29700671999-09-03 15:17:57 +0000120LPWINE_CLIPFORMAT CLIPBOARD_LookupFormat( WORD wID )
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000121{
Noel Borthwick29700671999-09-03 15:17:57 +0000122 return __lookup_format( ClipFormats, wID );
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000123}
124
Noel Borthwick29700671999-09-03 15:17:57 +0000125/**************************************************************************
126 * CLIPBOARD_IsLocked
127 * Check if the clipboard cache is available to the caller
128 */
129BOOL CLIPBOARD_IsLocked()
130{
131 BOOL bIsLocked = TRUE;
Noel Borthwick29700671999-09-03 15:17:57 +0000132
133 /*
134 * The clipboard is available:
135 * 1. if the caller's task has opened the clipboard,
136 * or
137 * 2. if the caller is the clipboard owners task, AND is responding to a
138 * WM_RENDERFORMAT message.
139 */
Alexandre Julliard7ef66af2002-11-22 04:47:10 +0000140 if ( ClipLock == GetCurrentThreadId() )
Noel Borthwick29700671999-09-03 15:17:57 +0000141 bIsLocked = FALSE;
Vincent Béron9a624912002-05-31 23:06:46 +0000142
Alexandre Julliard7ef66af2002-11-22 04:47:10 +0000143 else if ( ClipOwner == GetCurrentThreadId() )
Noel Borthwick29700671999-09-03 15:17:57 +0000144 {
145 /* Check if we're currently executing inside a window procedure
146 * called in response to a WM_RENDERFORMAT message. A WM_RENDERFORMAT
147 * handler is not permitted to open the clipboard since it has been opened
148 * by another client. However the handler must have access to the
149 * clipboard in order to update data in response to this message.
150 */
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000151#if 0
Alexandre Julliard8afe6622001-07-26 20:12:22 +0000152 MESSAGEQUEUE *queue = QUEUE_Current();
Vincent Béron9a624912002-05-31 23:06:46 +0000153
Noel Borthwick29700671999-09-03 15:17:57 +0000154 if ( queue
155 && queue->smWaiting
156 && queue->smWaiting->msg == WM_RENDERFORMAT
157 && queue->smWaiting->hSrcQueue
158 )
159 bIsLocked = FALSE;
Alexandre Julliard51ab43b2001-05-18 22:51:56 +0000160#else
161 /* FIXME: queue check no longer possible */
162 bIsLocked = FALSE;
163#endif
Noel Borthwick29700671999-09-03 15:17:57 +0000164 }
165
166 return bIsLocked;
167}
168
169/**************************************************************************
170 * CLIPBOARD_ReleaseOwner
171 * Gives up ownership of the clipboard
172 */
173void CLIPBOARD_ReleaseOwner()
174{
175 hWndClipOwner = 0;
Alexandre Julliard7ef66af2002-11-22 04:47:10 +0000176 ClipOwner = 0;
Noel Borthwick29700671999-09-03 15:17:57 +0000177}
178
179/**************************************************************************
180 * CLIPBOARD_GlobalFreeProc
181 *
182 * This is a callback mechanism to allow HGLOBAL data to be released in
183 * the context of the process which allocated it. We post a WM_TIMER message
184 * to the owner window(in CLIPBOARD_DeleteRecord) and destroy the data(in idEvent)
185 * in this WndProc, which is invoked when the apps message loop calls DispatchMessage.
186 * This technique is discussed in Matt Pietrek's "Under the Hood".
187 * An article describing the same may be found in MSDN by searching for WM_TIMER.
188 * Note that this mechanism will probably stop working when WINE supports
189 * address space separation. When "queue events" are implemented in Wine we
190 * should switch to using that mechanism, since it is more robust and does not
191 * require a procedure address to be passed. See the SetWinEventHook API for
192 * more info on this.
193 */
194VOID CALLBACK CLIPBOARD_GlobalFreeProc( HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime )
195{
196 /* idEvent is the HGLOBAL to be deleted */
197 GlobalFree( (HGLOBAL)idEvent );
198}
Alexandre Julliard1e9ac791996-06-06 18:38:27 +0000199
200/**************************************************************************
201 * CLIPBOARD_DeleteRecord
202 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000203void CLIPBOARD_DeleteRecord(LPWINE_CLIPFORMAT lpFormat, BOOL bChange)
Alexandre Julliard1e9ac791996-06-06 18:38:27 +0000204{
Alexandre Julliard03468f71998-02-15 19:40:49 +0000205 if( (lpFormat->wFormatID >= CF_GDIOBJFIRST &&
Vincent Béron9a624912002-05-31 23:06:46 +0000206 lpFormat->wFormatID <= CF_GDIOBJLAST) || lpFormat->wFormatID == CF_BITMAP
Ulrich Czekalla6623b851999-10-23 14:10:04 +0000207 || lpFormat->wFormatID == CF_PALETTE)
Alexandre Julliard03468f71998-02-15 19:40:49 +0000208 {
Pascal Cuoq724f1901998-10-26 10:58:16 +0000209 if (lpFormat->hData32)
Alexandre Julliarda3960291999-02-26 11:11:13 +0000210 DeleteObject(lpFormat->hData32);
Pascal Cuoq724f1901998-10-26 10:58:16 +0000211 if (lpFormat->hData16)
Alexandre Julliarda8a422f2002-11-22 20:43:01 +0000212 DeleteObject(HGDIOBJ_32(lpFormat->hData16));
Alexandre Julliard03468f71998-02-15 19:40:49 +0000213 }
Pascal Cuoq724f1901998-10-26 10:58:16 +0000214 else if( lpFormat->wFormatID == CF_METAFILEPICT )
215 {
216 if (lpFormat->hData32)
217 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000218 DeleteMetaFile( ((METAFILEPICT *)GlobalLock( lpFormat->hData32 ))->hMF );
Noel Borthwick29700671999-09-03 15:17:57 +0000219 PostMessageA(hWndClipOwner, WM_TIMER,
220 (WPARAM)lpFormat->hData32, (LPARAM)CLIPBOARD_GlobalFreeProc);
Noel Borthwick83579c81999-07-24 12:18:04 +0000221 if (lpFormat->hDataSrc32)
Noel Borthwick29700671999-09-03 15:17:57 +0000222 {
223 /* Release lpFormat->hData32 in the context of the process which created it.
224 * See CLIPBOARD_GlobalFreeProc for more details about this technique.
225 * GlobalFree(lpFormat->hDataSrc32);
226 */
227 PostMessageA(hWndClipOwner, WM_TIMER,
228 (WPARAM)lpFormat->hDataSrc32, (LPARAM)CLIPBOARD_GlobalFreeProc);
229 }
Vincent Béron9a624912002-05-31 23:06:46 +0000230
Pascal Cuoq724f1901998-10-26 10:58:16 +0000231 if (lpFormat->hData16)
Vincent Béron9a624912002-05-31 23:06:46 +0000232 /* HMETAFILE16 and HMETAFILE32 are apparently the same thing,
Pascal Cuoq724f1901998-10-26 10:58:16 +0000233 and a shallow copy is enough to share a METAFILEPICT
234 structure between 16bit and 32bit clipboards. The MetaFile
235 should of course only be deleted once. */
236 GlobalFree16(lpFormat->hData16);
237 }
Noel Borthwick83579c81999-07-24 12:18:04 +0000238 if (lpFormat->hData16)
Pascal Cuoq724f1901998-10-26 10:58:16 +0000239 {
240 DeleteMetaFile16( ((METAFILEPICT16 *)GlobalLock16( lpFormat->hData16 ))->hMF );
241 GlobalFree16(lpFormat->hData16);
242 }
243 }
Vincent Béron9a624912002-05-31 23:06:46 +0000244 else
Pascal Cuoq724f1901998-10-26 10:58:16 +0000245 {
246 if (lpFormat->hData32)
Noel Borthwick29700671999-09-03 15:17:57 +0000247 {
248 /* Release lpFormat->hData32 in the context of the process which created it.
249 * See CLIPBOARD_GlobalFreeProc for more details about this technique.
250 * GlobalFree( lpFormat->hData32 );
251 */
252 PostMessageA(hWndClipOwner, WM_TIMER,
253 (WPARAM)lpFormat->hData32, (LPARAM)CLIPBOARD_GlobalFreeProc);
254 }
Noel Borthwick83579c81999-07-24 12:18:04 +0000255 if (lpFormat->hDataSrc32)
Noel Borthwick29700671999-09-03 15:17:57 +0000256 {
257 /* Release lpFormat->hData32 in the context of the process which created it.
258 * See CLIPBOARD_GlobalFreeProc for more details about this technique.
259 * GlobalFree(lpFormat->hDataSrc32);
260 */
261 PostMessageA(hWndClipOwner, WM_TIMER,
262 (WPARAM)lpFormat->hDataSrc32, (LPARAM)CLIPBOARD_GlobalFreeProc);
263 }
Pascal Cuoq724f1901998-10-26 10:58:16 +0000264 if (lpFormat->hData16)
265 GlobalFree16(lpFormat->hData16);
266 }
Alexandre Julliard1e9ac791996-06-06 18:38:27 +0000267
Vincent Béron9a624912002-05-31 23:06:46 +0000268 lpFormat->wDataPresent = 0;
Pascal Cuoq724f1901998-10-26 10:58:16 +0000269 lpFormat->hData16 = 0;
270 lpFormat->hData32 = 0;
Noel Borthwick29700671999-09-03 15:17:57 +0000271 lpFormat->hDataSrc32 = 0;
272 lpFormat->drvData = 0;
Alexandre Julliard1e9ac791996-06-06 18:38:27 +0000273
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000274 if( bChange ) bCBHasChanged = TRUE;
Alexandre Julliard1e9ac791996-06-06 18:38:27 +0000275}
276
277/**************************************************************************
Noel Borthwick29700671999-09-03 15:17:57 +0000278 * CLIPBOARD_EmptyCache
279 */
280void CLIPBOARD_EmptyCache( BOOL bChange )
281{
Vincent Béron9a624912002-05-31 23:06:46 +0000282 LPWINE_CLIPFORMAT lpFormat = ClipFormats;
Noel Borthwick29700671999-09-03 15:17:57 +0000283
284 while(lpFormat)
285 {
286 if ( lpFormat->wDataPresent || lpFormat->hData16 || lpFormat->hData32 )
287 CLIPBOARD_DeleteRecord( lpFormat, bChange );
288
289 lpFormat = lpFormat->NextFormat;
290 }
291}
292
293/**************************************************************************
Alexandre Julliard1e9ac791996-06-06 18:38:27 +0000294 * CLIPBOARD_IsPresent
295 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000296BOOL CLIPBOARD_IsPresent(WORD wFormat)
Alexandre Julliard1e9ac791996-06-06 18:38:27 +0000297{
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000298 /* special case */
299
Dmitry Timoshkov1df0d362000-12-11 01:09:56 +0000300 if( wFormat == CF_TEXT || wFormat == CF_OEMTEXT || wFormat == CF_UNICODETEXT )
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000301 return ClipFormats[CF_TEXT-1].wDataPresent ||
Dmitry Timoshkov1df0d362000-12-11 01:09:56 +0000302 ClipFormats[CF_OEMTEXT-1].wDataPresent ||
303 ClipFormats[CF_UNICODETEXT-1].wDataPresent;
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000304 else
305 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000306 LPWINE_CLIPFORMAT lpFormat = __lookup_format( ClipFormats, wFormat );
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000307 if( lpFormat ) return (lpFormat->wDataPresent);
308 }
309 return FALSE;
Alexandre Julliard1e9ac791996-06-06 18:38:27 +0000310}
311
312/**************************************************************************
Noel Borthwick29700671999-09-03 15:17:57 +0000313 * CLIPBOARD_IsCacheRendered
314 * Checks if any data needs to be rendered to the clipboard cache
315 * RETURNS:
316 * TRUE - All clipboard data is available in the cache
317 * FALSE - Some data is marked for delayed render and needs rendering
318 */
319BOOL CLIPBOARD_IsCacheRendered()
320{
321 LPWINE_CLIPFORMAT lpFormat = ClipFormats;
Vincent Béron9a624912002-05-31 23:06:46 +0000322
Noel Borthwick29700671999-09-03 15:17:57 +0000323 /* check if all formats were rendered */
324 while(lpFormat)
325 {
326 if( lpFormat->wDataPresent && !lpFormat->hData16 && !lpFormat->hData32 )
327 return FALSE;
Vincent Béron9a624912002-05-31 23:06:46 +0000328
Noel Borthwick29700671999-09-03 15:17:57 +0000329 lpFormat = lpFormat->NextFormat;
330 }
Vincent Béron9a624912002-05-31 23:06:46 +0000331
Noel Borthwick29700671999-09-03 15:17:57 +0000332 return TRUE;
333}
334
335
336/**************************************************************************
Noel Borthwick83579c81999-07-24 12:18:04 +0000337 * CLIPBOARD_IsMemoryObject
338 * Tests if the clipboard format specifies a memory object
339 */
340BOOL CLIPBOARD_IsMemoryObject( WORD wFormat )
341{
342 switch(wFormat)
343 {
344 case CF_BITMAP:
345 case CF_METAFILEPICT:
346 case CF_DSPTEXT:
347 case CF_ENHMETAFILE:
348 case CF_HDROP:
349 case CF_PALETTE:
350 case CF_PENDATA:
351 return FALSE;
352 default:
353 return TRUE;
354 }
355}
356
357/***********************************************************************
358 * CLIPBOARD_GlobalDupMem( HGLOBAL )
359 * Helper method to duplicate an HGLOBAL chunk of memory into shared memory
360 */
361HGLOBAL CLIPBOARD_GlobalDupMem( HGLOBAL hGlobalSrc )
362{
363 HGLOBAL hGlobalDest;
364 PVOID pGlobalSrc, pGlobalDest;
365 DWORD cBytes;
Vincent Béron9a624912002-05-31 23:06:46 +0000366
Noel Borthwick83579c81999-07-24 12:18:04 +0000367 if ( !hGlobalSrc )
368 return 0;
369
370 cBytes = GlobalSize(hGlobalSrc);
371 if ( 0 == cBytes )
372 return 0;
373
374 /* Turn on the DDESHARE and _MOVEABLE flags explicitly */
375 hGlobalDest = GlobalAlloc( GlobalFlags(hGlobalSrc) | GMEM_DDESHARE | GMEM_MOVEABLE,
376 cBytes );
377 if ( !hGlobalDest )
378 return 0;
Vincent Béron9a624912002-05-31 23:06:46 +0000379
Noel Borthwick83579c81999-07-24 12:18:04 +0000380 pGlobalSrc = GlobalLock(hGlobalSrc);
381 pGlobalDest = GlobalLock(hGlobalDest);
382 if ( !pGlobalSrc || !pGlobalDest )
383 return 0;
384
385 memcpy(pGlobalDest, pGlobalSrc, cBytes);
Vincent Béron9a624912002-05-31 23:06:46 +0000386
Noel Borthwick83579c81999-07-24 12:18:04 +0000387 GlobalUnlock(hGlobalSrc);
388 GlobalUnlock(hGlobalDest);
389
390 return hGlobalDest;
391}
392
393/**************************************************************************
Noel Borthwick29700671999-09-03 15:17:57 +0000394 * CLIPBOARD_GetFormatName
395 * Gets the format name associated with an ID
396 */
Ulrich Czekalla651c5982002-08-27 19:19:49 +0000397char * CLIPBOARD_GetFormatName(UINT wFormat, LPSTR buf, INT size)
Noel Borthwick29700671999-09-03 15:17:57 +0000398{
399 LPWINE_CLIPFORMAT lpFormat = __lookup_format( ClipFormats, wFormat );
Ulrich Czekalla651c5982002-08-27 19:19:49 +0000400
401 if (lpFormat)
402 {
403 if (buf)
404 {
405 strncpy(buf, lpFormat->Name, size);
406 CharLowerA(buf);
407 }
408
409 return lpFormat->Name;
410 }
411 else
412 return NULL;
Noel Borthwick29700671999-09-03 15:17:57 +0000413}
414
415
416/**************************************************************************
417 * CLIPBOARD_RenderFormat
418 */
419static BOOL CLIPBOARD_RenderFormat(LPWINE_CLIPFORMAT lpFormat)
420{
421 /*
422 * If WINE is not the selection owner, and the format is available
Gerard Patel9289a5d2000-12-22 23:26:18 +0000423 * we must ask the driver to render the data to the clipboard cache.
Noel Borthwick29700671999-09-03 15:17:57 +0000424 */
Gerard Patel9289a5d2000-12-22 23:26:18 +0000425 TRACE("enter format=%d\n", lpFormat->wFormatID);
Vincent Béron9a624912002-05-31 23:06:46 +0000426 if ( !USER_Driver.pIsSelectionOwner()
Alexandre Julliard42d20f92000-08-10 01:16:19 +0000427 && USER_Driver.pIsClipboardFormatAvailable( lpFormat->wFormatID ) )
Noel Borthwick29700671999-09-03 15:17:57 +0000428 {
Alexandre Julliard42d20f92000-08-10 01:16:19 +0000429 if ( !USER_Driver.pGetClipboardData( lpFormat->wFormatID ) )
Noel Borthwick29700671999-09-03 15:17:57 +0000430 return FALSE;
431 }
432 /*
433 * If Wine owns the clipboard, and the data is marked for delayed render,
434 * render it now.
435 */
436 else if( lpFormat->wDataPresent && !lpFormat->hData16 && !lpFormat->hData32 )
437 {
438 if( IsWindow(hWndClipOwner) )
439 {
440 /* Send a WM_RENDERFORMAT message to notify the owner to render the
441 * data requested into the clipboard.
442 */
443 TRACE("Sending WM_RENDERFORMAT message\n");
Alexandre Julliardcb25e252001-08-08 23:28:42 +0000444 SendMessageW( hWndClipOwner, WM_RENDERFORMAT, (WPARAM)lpFormat->wFormatID, 0 );
Noel Borthwick29700671999-09-03 15:17:57 +0000445 }
446 else
447 {
Alexandre Julliardaff7dda2002-11-22 21:22:14 +0000448 WARN("\thWndClipOwner (%p) is lost!\n", hWndClipOwner);
Noel Borthwick29700671999-09-03 15:17:57 +0000449 CLIPBOARD_ReleaseOwner();
450 lpFormat->wDataPresent = 0;
451 return FALSE;
452 }
453 }
454
455 return (lpFormat->hData16 || lpFormat->hData32) ? TRUE : FALSE;
456}
457
Dmitry Timoshkov1df0d362000-12-11 01:09:56 +0000458/**************************************************************************
459 * CLIPBOARD_ConvertText
460 * Returns number of required/converted characters - not bytes!
461 */
462static INT CLIPBOARD_ConvertText(WORD src_fmt, void const *src, INT src_size,
463 WORD dst_fmt, void *dst, INT dst_size)
464{
465 UINT cp;
466
467 if(src_fmt == CF_UNICODETEXT)
468 {
469 switch(dst_fmt)
470 {
471 case CF_TEXT:
472 cp = CP_ACP;
473 break;
474 case CF_OEMTEXT:
475 cp = CP_OEMCP;
476 break;
477 default:
478 return 0;
479 }
480 return WideCharToMultiByte(cp, 0, src, src_size, dst, dst_size, NULL, NULL);
481 }
482
483 if(dst_fmt == CF_UNICODETEXT)
484 {
485 switch(src_fmt)
486 {
487 case CF_TEXT:
488 cp = CP_ACP;
489 break;
490 case CF_OEMTEXT:
491 cp = CP_OEMCP;
492 break;
493 default:
494 return 0;
495 }
496 return MultiByteToWideChar(cp, 0, src, src_size, dst, dst_size);
497 }
498
499 if(!dst_size) return src_size;
500
501 if(dst_size > src_size) dst_size = src_size;
502
503 if(src_fmt == CF_TEXT )
504 CharToOemBuffA(src, dst, dst_size);
505 else
506 OemToCharBuffA(src, dst, dst_size);
507
508 return dst_size;
509}
Noel Borthwick29700671999-09-03 15:17:57 +0000510
511/**************************************************************************
512 * CLIPBOARD_RenderText
513 *
514 * Renders text to the clipboard buffer converting between UNIX and DOS formats.
515 *
516 * RETURNS: pointer to the WINE_CLIPFORMAT if successful, NULL otherwise
517 *
518 * FIXME: Should be a pair of driver functions that convert between OEM text and Windows.
519 *
520 */
521static LPWINE_CLIPFORMAT CLIPBOARD_RenderText( UINT wFormat )
522{
Vincent Béron9a624912002-05-31 23:06:46 +0000523 LPWINE_CLIPFORMAT lpSource = ClipFormats;
Gerard Patel9289a5d2000-12-22 23:26:18 +0000524 LPWINE_CLIPFORMAT lpTarget = NULL;
525 BOOL foundData = FALSE;
Vincent Béron9a624912002-05-31 23:06:46 +0000526
Aric Stewart039ae272001-02-12 19:16:05 +0000527 /* Asked for CF_TEXT */
528 if( wFormat == CF_TEXT)
Noel Borthwick29700671999-09-03 15:17:57 +0000529 {
Aric Stewart039ae272001-02-12 19:16:05 +0000530 if(ClipFormats[CF_TEXT-1].wDataPresent)
531 {
532 lpSource = &ClipFormats[CF_TEXT-1];
533 lpTarget = &ClipFormats[CF_TEXT-1];
534 foundData = TRUE;
535 TRACE("\t TEXT -> TEXT\n");
536 }
537 else if(ClipFormats[CF_UNICODETEXT-1].wDataPresent)
Dmitry Timoshkov1df0d362000-12-11 01:09:56 +0000538 {
539 /* Convert UNICODETEXT -> TEXT */
540 lpSource = &ClipFormats[CF_UNICODETEXT-1];
541 lpTarget = &ClipFormats[CF_TEXT-1];
Gerard Patel9289a5d2000-12-22 23:26:18 +0000542 foundData = TRUE;
Dmitry Timoshkov1df0d362000-12-11 01:09:56 +0000543 TRACE("\tUNICODETEXT -> TEXT\n");
544 }
545 else if(ClipFormats[CF_OEMTEXT-1].wDataPresent)
546 {
547 /* Convert OEMTEXT -> TEXT */
548 lpSource = &ClipFormats[CF_OEMTEXT-1];
549 lpTarget = &ClipFormats[CF_TEXT-1];
Gerard Patel9289a5d2000-12-22 23:26:18 +0000550 foundData = TRUE;
Dmitry Timoshkov1df0d362000-12-11 01:09:56 +0000551 TRACE("\tOEMTEXT -> TEXT\n");
552 }
Noel Borthwick29700671999-09-03 15:17:57 +0000553 }
Aric Stewart039ae272001-02-12 19:16:05 +0000554 /* Asked for CF_OEMTEXT */
555 else if( wFormat == CF_OEMTEXT)
Noel Borthwick29700671999-09-03 15:17:57 +0000556 {
Aric Stewart039ae272001-02-12 19:16:05 +0000557 if(ClipFormats[CF_OEMTEXT-1].wDataPresent)
558 {
559 lpSource = &ClipFormats[CF_OEMTEXT-1];
560 lpTarget = &ClipFormats[CF_OEMTEXT-1];
561 foundData = TRUE;
562 TRACE("\tOEMTEXT -> OEMTEXT\n");
563 }
564 else if(ClipFormats[CF_UNICODETEXT-1].wDataPresent)
Dmitry Timoshkov1df0d362000-12-11 01:09:56 +0000565 {
566 /* Convert UNICODETEXT -> OEMTEXT */
567 lpSource = &ClipFormats[CF_UNICODETEXT-1];
568 lpTarget = &ClipFormats[CF_OEMTEXT-1];
Gerard Patel9289a5d2000-12-22 23:26:18 +0000569 foundData = TRUE;
Dmitry Timoshkov1df0d362000-12-11 01:09:56 +0000570 TRACE("\tUNICODETEXT -> OEMTEXT\n");
571 }
572 else if(ClipFormats[CF_TEXT-1].wDataPresent)
573 {
574 /* Convert TEXT -> OEMTEXT */
575 lpSource = &ClipFormats[CF_TEXT-1];
576 lpTarget = &ClipFormats[CF_OEMTEXT-1];
Gerard Patel9289a5d2000-12-22 23:26:18 +0000577 foundData = TRUE;
Dmitry Timoshkov1df0d362000-12-11 01:09:56 +0000578 TRACE("\tTEXT -> OEMTEXT\n");
579 }
Dmitry Timoshkov1df0d362000-12-11 01:09:56 +0000580 }
Aric Stewart039ae272001-02-12 19:16:05 +0000581 /* Asked for CF_UNICODETEXT */
582 else if( wFormat == CF_UNICODETEXT )
Dmitry Timoshkov1df0d362000-12-11 01:09:56 +0000583 {
Aric Stewart039ae272001-02-12 19:16:05 +0000584 if(ClipFormats[CF_UNICODETEXT-1].wDataPresent)
585 {
586 lpSource = &ClipFormats[CF_UNICODETEXT-1];
587 lpTarget = &ClipFormats[CF_UNICODETEXT-1];
588 foundData = TRUE;
589 TRACE("\tUNICODETEXT -> UNICODETEXT\n");
590 }
591 else if(ClipFormats[CF_TEXT-1].wDataPresent)
Dmitry Timoshkov1df0d362000-12-11 01:09:56 +0000592 {
593 /* Convert TEXT -> UNICODETEXT */
594 lpSource = &ClipFormats[CF_TEXT-1];
595 lpTarget = &ClipFormats[CF_UNICODETEXT-1];
Gerard Patel9289a5d2000-12-22 23:26:18 +0000596 foundData = TRUE;
Dmitry Timoshkov1df0d362000-12-11 01:09:56 +0000597 TRACE("\tTEXT -> UNICODETEXT\n");
598 }
599 else if(ClipFormats[CF_OEMTEXT-1].wDataPresent)
600 {
601 /* Convert OEMTEXT -> UNICODETEXT */
602 lpSource = &ClipFormats[CF_OEMTEXT-1];
603 lpTarget = &ClipFormats[CF_UNICODETEXT-1];
Gerard Patel9289a5d2000-12-22 23:26:18 +0000604 foundData = TRUE;
Dmitry Timoshkov1df0d362000-12-11 01:09:56 +0000605 TRACE("\tOEMTEXT -> UNICODETEXT\n");
606 }
Noel Borthwick29700671999-09-03 15:17:57 +0000607 }
Gerard Patel9289a5d2000-12-22 23:26:18 +0000608 if (!foundData)
Vincent Béron9a624912002-05-31 23:06:46 +0000609 {
Gerard Patel9289a5d2000-12-22 23:26:18 +0000610 if ((wFormat == CF_TEXT) || (wFormat == CF_OEMTEXT))
611 {
612 lpSource = &ClipFormats[CF_UNICODETEXT-1];
613 lpTarget = __lookup_format( ClipFormats, wFormat );
614 }
615 else
616 {
617 lpSource = __lookup_format( ClipFormats, wFormat );
618 lpTarget = lpSource;
619 }
Noel Borthwick29700671999-09-03 15:17:57 +0000620 }
621
622 /* First render the source text format */
623 if ( !lpSource || !CLIPBOARD_RenderFormat(lpSource) ) return NULL;
624
625 /* Convert to the desired target text format, if necessary */
626 if( lpTarget != lpSource && !lpTarget->hData16 && !lpTarget->hData32 )
627 {
Dmitry Timoshkov1df0d362000-12-11 01:09:56 +0000628 INT src_chars, dst_chars, alloc_size;
Vincent Béron9a624912002-05-31 23:06:46 +0000629 LPCSTR lpstrS;
Noel Borthwick29700671999-09-03 15:17:57 +0000630 LPSTR lpstrT;
Vincent Béron9a624912002-05-31 23:06:46 +0000631
Noel Borthwick29700671999-09-03 15:17:57 +0000632 if (lpSource->hData32)
633 {
Noel Borthwick29700671999-09-03 15:17:57 +0000634 lpstrS = (LPSTR)GlobalLock(lpSource->hData32);
635 }
636 else
637 {
Noel Borthwick29700671999-09-03 15:17:57 +0000638 lpstrS = (LPSTR)GlobalLock16(lpSource->hData16);
639 }
Vincent Béron9a624912002-05-31 23:06:46 +0000640
Noel Borthwick29700671999-09-03 15:17:57 +0000641 if( !lpstrS ) return NULL;
Dmitry Timoshkov1df0d362000-12-11 01:09:56 +0000642
643 /* Text always NULL terminated */
644 if(lpSource->wFormatID == CF_UNICODETEXT)
Aric Stewart096c1ae2001-02-20 01:54:08 +0000645 src_chars = strlenW((LPCWSTR)lpstrS)+1;
Dmitry Timoshkov1df0d362000-12-11 01:09:56 +0000646 else
Aric Stewart096c1ae2001-02-20 01:54:08 +0000647 src_chars = strlen(lpstrS)+1;
Dmitry Timoshkov1df0d362000-12-11 01:09:56 +0000648
649 /* Calculate number of characters in the destination buffer */
650 dst_chars = CLIPBOARD_ConvertText(lpSource->wFormatID, lpstrS, src_chars,
651 lpTarget->wFormatID, NULL, 0);
652 if(!dst_chars) return NULL;
653
Noel Borthwick29700671999-09-03 15:17:57 +0000654 TRACE("\tconverting from '%s' to '%s', %i chars\n",
Dmitry Timoshkov1df0d362000-12-11 01:09:56 +0000655 lpSource->Name, lpTarget->Name, src_chars);
656
657 /* Convert characters to bytes */
658 if(lpTarget->wFormatID == CF_UNICODETEXT)
659 alloc_size = dst_chars * sizeof(WCHAR);
660 else
661 alloc_size = dst_chars;
662
663 lpTarget->hData32 = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE, alloc_size);
Noel Borthwick29700671999-09-03 15:17:57 +0000664 lpstrT = (LPSTR)GlobalLock(lpTarget->hData32);
Dmitry Timoshkov1df0d362000-12-11 01:09:56 +0000665
Noel Borthwick29700671999-09-03 15:17:57 +0000666 if( lpstrT )
667 {
Dmitry Timoshkov1df0d362000-12-11 01:09:56 +0000668 CLIPBOARD_ConvertText(lpSource->wFormatID, lpstrS, src_chars,
669 lpTarget->wFormatID, lpstrT, dst_chars);
Noel Borthwick29700671999-09-03 15:17:57 +0000670 GlobalUnlock(lpTarget->hData32);
671 }
672 else
673 lpTarget->hData32 = 0;
674
675 /* Unlock source */
676 if (lpSource->hData32)
677 GlobalUnlock(lpSource->hData32);
678 else
679 GlobalUnlock16(lpSource->hData16);
680 }
681
682 return (lpTarget->hData16 || lpTarget->hData32) ? lpTarget : NULL;
683}
684
685/**************************************************************************
Gerard Patel9289a5d2000-12-22 23:26:18 +0000686 * CLIPBOARD_EnumClipboardFormats (internal)
687 */
688static UINT CLIPBOARD_EnumClipboardFormats( UINT wFormat )
689{
690 LPWINE_CLIPFORMAT lpFormat = ClipFormats;
691 BOOL bFormatPresent;
692
693 if (wFormat == 0) /* start from the beginning */
694 lpFormat = ClipFormats;
695 else
696 {
697 /* walk up to the specified format record */
698
Vincent Béron9a624912002-05-31 23:06:46 +0000699 if( !(lpFormat = __lookup_format( lpFormat, wFormat )) )
Gerard Patel9289a5d2000-12-22 23:26:18 +0000700 return 0;
701 lpFormat = lpFormat->NextFormat; /* right */
702 }
703
Vincent Béron9a624912002-05-31 23:06:46 +0000704 while(TRUE)
Gerard Patel9289a5d2000-12-22 23:26:18 +0000705 {
706 if (lpFormat == NULL) return 0;
707
708 if(CLIPBOARD_IsPresent(lpFormat->wFormatID))
709 break;
710
711 /* Query the driver if not yet in the cache */
712 if (!USER_Driver.pIsSelectionOwner())
713 {
714 if(lpFormat->wFormatID == CF_UNICODETEXT ||
715 lpFormat->wFormatID == CF_TEXT ||
716 lpFormat->wFormatID == CF_OEMTEXT)
717 {
718 if(USER_Driver.pIsClipboardFormatAvailable(CF_UNICODETEXT) ||
719 USER_Driver.pIsClipboardFormatAvailable(CF_TEXT) ||
720 USER_Driver.pIsClipboardFormatAvailable(CF_OEMTEXT))
721 bFormatPresent = TRUE;
722 else
723 bFormatPresent = FALSE;
724 }
725 else
726 bFormatPresent = USER_Driver.pIsClipboardFormatAvailable(lpFormat->wFormatID);
727
728 if(bFormatPresent)
729 break;
730 }
731
732 lpFormat = lpFormat->NextFormat;
733 }
734
735 TRACE("Next available format %d\n", lpFormat->wFormatID);
736
737 return lpFormat->wFormatID;
738}
739
740
741/**************************************************************************
Vincent Béron9a624912002-05-31 23:06:46 +0000742 * WIN32 Clipboard implementation
Noel Borthwick29700671999-09-03 15:17:57 +0000743 **************************************************************************/
744
745/**************************************************************************
Patrik Stridvall2ece70e2000-12-22 01:38:01 +0000746 * OpenClipboard (USER32.@)
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000747 *
748 * Note: Netscape uses NULL hWnd to open the clipboard.
Alexandre Julliardf0cbfa01997-02-15 14:29:56 +0000749 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000750BOOL WINAPI OpenClipboard( HWND hWnd )
Alexandre Julliardf0cbfa01997-02-15 14:29:56 +0000751{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000752 BOOL bRet;
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000753
Alexandre Julliardaff7dda2002-11-22 21:22:14 +0000754 TRACE("(%p)...\n", hWnd);
Alexandre Julliard1e9ac791996-06-06 18:38:27 +0000755
Alexandre Julliard7ef66af2002-11-22 04:47:10 +0000756 if (!ClipLock)
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000757 {
Alexandre Julliard7ef66af2002-11-22 04:47:10 +0000758 ClipLock = GetCurrentThreadId();
Noel Borthwick29700671999-09-03 15:17:57 +0000759
760 /* Save current user of the clipboard */
Alexandre Julliard37a46392001-09-12 17:19:13 +0000761 hWndClipWindow = WIN_GetFullHandle( hWnd );
Noel Borthwick29700671999-09-03 15:17:57 +0000762 bCBHasChanged = FALSE;
763 bRet = TRUE;
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000764 }
765 else bRet = FALSE;
Alexandre Julliard1e9ac791996-06-06 18:38:27 +0000766
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000767 TRACE(" returning %i\n", bRet);
Alexandre Julliard1e9ac791996-06-06 18:38:27 +0000768 return bRet;
Alexandre Julliardfb9a9191994-03-01 19:48:04 +0000769}
770
771
772/**************************************************************************
Patrik Stridvall2ece70e2000-12-22 01:38:01 +0000773 * CloseClipboard (USER.138)
Alexandre Julliardfb9a9191994-03-01 19:48:04 +0000774 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000775BOOL16 WINAPI CloseClipboard16(void)
Alexandre Julliardf0cbfa01997-02-15 14:29:56 +0000776{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000777 return CloseClipboard();
Alexandre Julliardf0cbfa01997-02-15 14:29:56 +0000778}
779
780
781/**************************************************************************
Patrik Stridvall2ece70e2000-12-22 01:38:01 +0000782 * CloseClipboard (USER32.@)
Alexandre Julliardf0cbfa01997-02-15 14:29:56 +0000783 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000784BOOL WINAPI CloseClipboard(void)
Alexandre Julliardfb9a9191994-03-01 19:48:04 +0000785{
Noel Borthwick29700671999-09-03 15:17:57 +0000786 TRACE("()\n");
Alexandre Julliard1e9ac791996-06-06 18:38:27 +0000787
Alexandre Julliard7ef66af2002-11-22 04:47:10 +0000788 if (ClipLock == GetCurrentThreadId())
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000789 {
790 hWndClipWindow = 0;
Alexandre Julliard1e9ac791996-06-06 18:38:27 +0000791
Alexandre Julliardcb25e252001-08-08 23:28:42 +0000792 if (bCBHasChanged && hWndViewer) SendMessageW( hWndViewer, WM_DRAWCLIPBOARD, 0, 0 );
Alexandre Julliard7ef66af2002-11-22 04:47:10 +0000793 ClipLock = 0;
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000794 }
Alexandre Julliardfb9a9191994-03-01 19:48:04 +0000795 return TRUE;
796}
797
798
799/**************************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +0000800 * EmptyClipboard (USER.139)
Alexandre Julliardfb9a9191994-03-01 19:48:04 +0000801 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000802BOOL16 WINAPI EmptyClipboard16(void)
Alexandre Julliardf0cbfa01997-02-15 14:29:56 +0000803{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000804 return EmptyClipboard();
Alexandre Julliardf0cbfa01997-02-15 14:29:56 +0000805}
806
807
808/**************************************************************************
Patrik Stridvall2ece70e2000-12-22 01:38:01 +0000809 * EmptyClipboard (USER32.@)
Noel Borthwick29700671999-09-03 15:17:57 +0000810 * Empties and acquires ownership of the clipboard
Alexandre Julliardf0cbfa01997-02-15 14:29:56 +0000811 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000812BOOL WINAPI EmptyClipboard(void)
Alexandre Julliardfb9a9191994-03-01 19:48:04 +0000813{
Noel Borthwick29700671999-09-03 15:17:57 +0000814 TRACE("()\n");
Alexandre Julliard1e9ac791996-06-06 18:38:27 +0000815
Alexandre Julliard7ef66af2002-11-22 04:47:10 +0000816 if (ClipLock != GetCurrentThreadId())
Noel Borthwick29700671999-09-03 15:17:57 +0000817 {
Francois Gougete76218d2001-05-09 17:31:31 +0000818 WARN("Clipboard not opened by calling task!\n");
Noel Borthwick29700671999-09-03 15:17:57 +0000819 return FALSE;
820 }
Vincent Béron9a624912002-05-31 23:06:46 +0000821
Alexandre Julliard1e9ac791996-06-06 18:38:27 +0000822 /* destroy private objects */
823
Alexandre Julliardcb25e252001-08-08 23:28:42 +0000824 if (hWndClipOwner) SendMessageW( hWndClipOwner, WM_DESTROYCLIPBOARD, 0, 0 );
Alexandre Julliard1e9ac791996-06-06 18:38:27 +0000825
Noel Borthwick29700671999-09-03 15:17:57 +0000826 /* empty the cache */
827 CLIPBOARD_EmptyCache(TRUE);
Alexandre Julliard1e9ac791996-06-06 18:38:27 +0000828
Noel Borthwick29700671999-09-03 15:17:57 +0000829 /* Assign ownership of the clipboard to the current client */
Alexandre Julliard1e9ac791996-06-06 18:38:27 +0000830 hWndClipOwner = hWndClipWindow;
831
Noel Borthwick29700671999-09-03 15:17:57 +0000832 /* Save the current task */
Alexandre Julliard7ef66af2002-11-22 04:47:10 +0000833 ClipOwner = GetCurrentThreadId();
Vincent Béron9a624912002-05-31 23:06:46 +0000834
Noel Borthwick29700671999-09-03 15:17:57 +0000835 /* Tell the driver to acquire the selection */
Alexandre Julliard42d20f92000-08-10 01:16:19 +0000836 USER_Driver.pAcquireClipboard();
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000837
Alexandre Julliardfb9a9191994-03-01 19:48:04 +0000838 return TRUE;
839}
840
841
842/**************************************************************************
Patrik Stridvall2ece70e2000-12-22 01:38:01 +0000843 * GetClipboardOwner (USER32.@)
Noel Borthwick29700671999-09-03 15:17:57 +0000844 * FIXME: Can't return the owner if the clipbard is owned by an external app
Alexandre Julliardf0cbfa01997-02-15 14:29:56 +0000845 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000846HWND WINAPI GetClipboardOwner(void)
Alexandre Julliardf0cbfa01997-02-15 14:29:56 +0000847{
Noel Borthwick29700671999-09-03 15:17:57 +0000848 TRACE("()\n");
Alexandre Julliard1e9ac791996-06-06 18:38:27 +0000849 return hWndClipOwner;
Alexandre Julliardfb9a9191994-03-01 19:48:04 +0000850}
851
852
853/**************************************************************************
Patrik Stridvall2ece70e2000-12-22 01:38:01 +0000854 * SetClipboardData (USER.141)
Alexandre Julliardfb9a9191994-03-01 19:48:04 +0000855 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000856HANDLE16 WINAPI SetClipboardData16( UINT16 wFormat, HANDLE16 hData )
Alexandre Julliardfb9a9191994-03-01 19:48:04 +0000857{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000858 LPWINE_CLIPFORMAT lpFormat = __lookup_format( ClipFormats, wFormat );
Alexandre Julliard1e9ac791996-06-06 18:38:27 +0000859
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000860 TRACE("(%04X, %04x) !\n", wFormat, hData);
Alexandre Julliard1e9ac791996-06-06 18:38:27 +0000861
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000862 /* NOTE: If the hData is zero and current owner doesn't match
863 * the window that opened the clipboard then this application
Noel Borthwick29700671999-09-03 15:17:57 +0000864 * is screwed because WM_RENDERFORMAT will go to the owner.
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000865 * (to become the owner it must call EmptyClipboard() before
866 * adding new data).
867 */
868
Noel Borthwick29700671999-09-03 15:17:57 +0000869 if( CLIPBOARD_IsLocked() || !lpFormat ||
870 (!hData && (!hWndClipOwner || (hWndClipOwner != hWndClipWindow))) )
871 {
Juergen Schmied1c35dae2000-02-07 16:22:57 +0000872 WARN("Invalid hData or clipboard not opened by calling task!\n");
Noel Borthwick29700671999-09-03 15:17:57 +0000873 return 0;
874 }
Alexandre Julliard1e9ac791996-06-06 18:38:27 +0000875
Noel Borthwick29700671999-09-03 15:17:57 +0000876 /* Pass on the request to the driver */
Alexandre Julliard42d20f92000-08-10 01:16:19 +0000877 USER_Driver.pSetClipboardData(wFormat);
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000878
Vincent Béron9a624912002-05-31 23:06:46 +0000879 if ( lpFormat->wDataPresent || lpFormat->hData16 || lpFormat->hData32 )
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000880 {
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000881 CLIPBOARD_DeleteRecord(lpFormat, TRUE);
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000882
Dmitry Timoshkov1df0d362000-12-11 01:09:56 +0000883 /* delete existing CF_UNICODETEXT/CF_TEXT/CF_OEMTEXT aliases */
884 if(wFormat == CF_UNICODETEXT)
885 {
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000886 CLIPBOARD_DeleteRecord(&ClipFormats[CF_TEXT-1], TRUE);
Dmitry Timoshkov1df0d362000-12-11 01:09:56 +0000887 CLIPBOARD_DeleteRecord(&ClipFormats[CF_OEMTEXT-1], TRUE);
888 }
889 else if(wFormat == CF_TEXT)
890 {
891 CLIPBOARD_DeleteRecord(&ClipFormats[CF_UNICODETEXT-1], TRUE);
892 CLIPBOARD_DeleteRecord(&ClipFormats[CF_OEMTEXT-1], TRUE);
893 }
894 else if(wFormat == CF_OEMTEXT)
895 {
896 CLIPBOARD_DeleteRecord(&ClipFormats[CF_UNICODETEXT-1], TRUE);
897 CLIPBOARD_DeleteRecord(&ClipFormats[CF_TEXT-1], TRUE);
898 }
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000899 }
Alexandre Julliard1e9ac791996-06-06 18:38:27 +0000900
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000901 bCBHasChanged = TRUE;
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000902 lpFormat->wDataPresent = 1;
Pascal Cuoq724f1901998-10-26 10:58:16 +0000903 lpFormat->hData16 = hData; /* 0 is legal, see WM_RENDERFORMAT */
904 lpFormat->hData32 = 0;
Alexandre Julliard1e9ac791996-06-06 18:38:27 +0000905
Pascal Cuoq724f1901998-10-26 10:58:16 +0000906 return lpFormat->hData16;
Alexandre Julliardfb9a9191994-03-01 19:48:04 +0000907}
908
Alexandre Julliard21979011997-03-05 08:22:35 +0000909
910/**************************************************************************
Patrik Stridvall2ece70e2000-12-22 01:38:01 +0000911 * SetClipboardData (USER32.@)
Alexandre Julliard21979011997-03-05 08:22:35 +0000912 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000913HANDLE WINAPI SetClipboardData( UINT wFormat, HANDLE hData )
Alexandre Julliard21979011997-03-05 08:22:35 +0000914{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000915 LPWINE_CLIPFORMAT lpFormat = __lookup_format( ClipFormats, wFormat );
Pascal Cuoq724f1901998-10-26 10:58:16 +0000916
Alexandre Julliardaff7dda2002-11-22 21:22:14 +0000917 TRACE("(%08X, %p) !\n", wFormat, hData);
Pascal Cuoq724f1901998-10-26 10:58:16 +0000918
919 /* NOTE: If the hData is zero and current owner doesn't match
920 * the window that opened the clipboard then this application
Noel Borthwick29700671999-09-03 15:17:57 +0000921 * is screwed because WM_RENDERFORMAT will go to the owner.
Pascal Cuoq724f1901998-10-26 10:58:16 +0000922 * (to become the owner it must call EmptyClipboard() before
923 * adding new data).
924 */
925
Noel Borthwick29700671999-09-03 15:17:57 +0000926 if( CLIPBOARD_IsLocked() || !lpFormat ||
927 (!hData && (!hWndClipOwner || (hWndClipOwner != hWndClipWindow))) )
928 {
Juergen Schmied1c35dae2000-02-07 16:22:57 +0000929 WARN("Invalid hData or clipboard not opened by calling task!\n");
Noel Borthwick29700671999-09-03 15:17:57 +0000930 return 0;
931 }
Pascal Cuoq724f1901998-10-26 10:58:16 +0000932
Noel Borthwick29700671999-09-03 15:17:57 +0000933 /* Tell the driver to acquire the selection */
Alexandre Julliard42d20f92000-08-10 01:16:19 +0000934 USER_Driver.pAcquireClipboard();
Pascal Cuoq724f1901998-10-26 10:58:16 +0000935
Noel Borthwick29700671999-09-03 15:17:57 +0000936 if ( lpFormat->wDataPresent &&
937 (lpFormat->hData16 || lpFormat->hData32) )
Pascal Cuoq724f1901998-10-26 10:58:16 +0000938 {
939 CLIPBOARD_DeleteRecord(lpFormat, TRUE);
940
Dmitry Timoshkov1df0d362000-12-11 01:09:56 +0000941 /* delete existing CF_UNICODETEXT/CF_TEXT/CF_OEMTEXT aliases */
942 if(wFormat == CF_UNICODETEXT)
943 {
Pascal Cuoq724f1901998-10-26 10:58:16 +0000944 CLIPBOARD_DeleteRecord(&ClipFormats[CF_TEXT-1], TRUE);
Dmitry Timoshkov1df0d362000-12-11 01:09:56 +0000945 CLIPBOARD_DeleteRecord(&ClipFormats[CF_OEMTEXT-1], TRUE);
946 }
947 else if(wFormat == CF_TEXT)
948 {
949 CLIPBOARD_DeleteRecord(&ClipFormats[CF_UNICODETEXT-1], TRUE);
950 CLIPBOARD_DeleteRecord(&ClipFormats[CF_OEMTEXT-1], TRUE);
951 }
952 else if(wFormat == CF_OEMTEXT)
953 {
954 CLIPBOARD_DeleteRecord(&ClipFormats[CF_UNICODETEXT-1], TRUE);
955 CLIPBOARD_DeleteRecord(&ClipFormats[CF_TEXT-1], TRUE);
956 }
Pascal Cuoq724f1901998-10-26 10:58:16 +0000957 }
958
959 bCBHasChanged = TRUE;
960 lpFormat->wDataPresent = 1;
Noel Borthwick83579c81999-07-24 12:18:04 +0000961 lpFormat->hDataSrc32 = hData; /* Save the source handle */
962
963 /*
964 * Make a shared duplicate if the memory is not shared
965 * TODO: What should be done for non-memory objects
966 */
967 if ( CLIPBOARD_IsMemoryObject(wFormat) && hData && !(GlobalFlags(hData) & GMEM_DDESHARE) )
968 lpFormat->hData32 = CLIPBOARD_GlobalDupMem( hData );
969 else
Noel Borthwick29700671999-09-03 15:17:57 +0000970 lpFormat->hData32 = hData; /* 0 is legal, see WM_RENDERFORMAT */
Vincent Béron9a624912002-05-31 23:06:46 +0000971
Pascal Cuoq724f1901998-10-26 10:58:16 +0000972 lpFormat->hData16 = 0;
973
Noel Borthwick29700671999-09-03 15:17:57 +0000974 return lpFormat->hData32; /* Should we return lpFormat->hDataSrc32 */
Alexandre Julliard21979011997-03-05 08:22:35 +0000975}
976
977
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000978/**************************************************************************
Patrik Stridvall2ece70e2000-12-22 01:38:01 +0000979 * GetClipboardData (USER.142)
Alexandre Julliardfb9a9191994-03-01 19:48:04 +0000980 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000981HANDLE16 WINAPI GetClipboardData16( UINT16 wFormat )
Alexandre Julliardfb9a9191994-03-01 19:48:04 +0000982{
Vincent Béron9a624912002-05-31 23:06:46 +0000983 LPWINE_CLIPFORMAT lpRender = ClipFormats;
Alexandre Julliard1e9ac791996-06-06 18:38:27 +0000984
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000985 TRACE("(%04X)\n", wFormat);
Alexandre Julliard1e9ac791996-06-06 18:38:27 +0000986
Noel Borthwick29700671999-09-03 15:17:57 +0000987 if (CLIPBOARD_IsLocked())
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000988 {
Juergen Schmied1c35dae2000-02-07 16:22:57 +0000989 WARN("Clipboard not opened by calling task!\n");
Noel Borthwick29700671999-09-03 15:17:57 +0000990 return 0;
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000991 }
Noel Borthwick29700671999-09-03 15:17:57 +0000992
Dmitry Timoshkov1df0d362000-12-11 01:09:56 +0000993 if( wFormat == CF_UNICODETEXT || wFormat == CF_TEXT || wFormat == CF_OEMTEXT )
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000994 {
Noel Borthwick29700671999-09-03 15:17:57 +0000995 lpRender = CLIPBOARD_RenderText(wFormat);
996 if ( !lpRender ) return 0;
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000997 }
998 else
999 {
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00001000 lpRender = __lookup_format( ClipFormats, wFormat );
Noel Borthwick29700671999-09-03 15:17:57 +00001001 if( !lpRender || !CLIPBOARD_RenderFormat(lpRender) ) return 0;
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +00001002 }
Vincent Béron9a624912002-05-31 23:06:46 +00001003
Noel Borthwick29700671999-09-03 15:17:57 +00001004 /* Convert between 32 -> 16 bit data, if necessary */
Francis Beaudet56ab55d1999-10-24 20:22:24 +00001005 if( lpRender->hData32 && !lpRender->hData16
1006 && CLIPBOARD_IsMemoryObject(wFormat) )
Pascal Cuoq724f1901998-10-26 10:58:16 +00001007 {
1008 int size;
Noel Borthwick29700671999-09-03 15:17:57 +00001009 if( lpRender->wFormatID == CF_METAFILEPICT )
Pascal Cuoq724f1901998-10-26 10:58:16 +00001010 size = sizeof( METAFILEPICT16 );
1011 else
Noel Borthwickd05b7be1999-09-20 15:42:47 +00001012 size = GlobalSize(lpRender->hData32);
Vincent Béron9a624912002-05-31 23:06:46 +00001013
Noel Borthwick29700671999-09-03 15:17:57 +00001014 lpRender->hData16 = GlobalAlloc16(GMEM_ZEROINIT, size);
1015 if( !lpRender->hData16 )
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001016 ERR("(%04X) -- not enough memory in 16b heap\n", wFormat);
Pascal Cuoq724f1901998-10-26 10:58:16 +00001017 else
1018 {
Noel Borthwickd05b7be1999-09-20 15:42:47 +00001019 if( lpRender->wFormatID == CF_METAFILEPICT )
1020 {
1021 FIXME("\timplement function CopyMetaFilePict32to16\n");
1022 FIXME("\tin the appropriate file.\n");
1023 #ifdef SOMEONE_IMPLEMENTED_ME
Vincent Béron9a624912002-05-31 23:06:46 +00001024 CopyMetaFilePict32to16( GlobalLock16(lpRender->hData16),
Noel Borthwickd05b7be1999-09-20 15:42:47 +00001025 GlobalLock(lpRender->hData32) );
1026 #endif
1027 }
1028 else
1029 {
Vincent Béron9a624912002-05-31 23:06:46 +00001030 memcpy( GlobalLock16(lpRender->hData16),
1031 GlobalLock(lpRender->hData32),
Noel Borthwickd05b7be1999-09-20 15:42:47 +00001032 size );
1033 }
Noel Borthwick29700671999-09-03 15:17:57 +00001034 GlobalUnlock16(lpRender->hData16);
1035 GlobalUnlock(lpRender->hData32);
Pascal Cuoq724f1901998-10-26 10:58:16 +00001036 }
1037 }
1038
Vincent Béron9a624912002-05-31 23:06:46 +00001039 TRACE("\treturning %04x (type %i)\n",
Noel Borthwick29700671999-09-03 15:17:57 +00001040 lpRender->hData16, lpRender->wFormatID);
1041 return lpRender->hData16;
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00001042}
1043
1044
1045/**************************************************************************
Patrik Stridvall2ece70e2000-12-22 01:38:01 +00001046 * GetClipboardData (USER32.@)
Alexandre Julliard21979011997-03-05 08:22:35 +00001047 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001048HANDLE WINAPI GetClipboardData( UINT wFormat )
Alexandre Julliard21979011997-03-05 08:22:35 +00001049{
Vincent Béron9a624912002-05-31 23:06:46 +00001050 LPWINE_CLIPFORMAT lpRender = ClipFormats;
Pascal Cuoq724f1901998-10-26 10:58:16 +00001051
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001052 TRACE("(%08X)\n", wFormat);
Pascal Cuoq724f1901998-10-26 10:58:16 +00001053
Noel Borthwick29700671999-09-03 15:17:57 +00001054 if (CLIPBOARD_IsLocked())
Pascal Cuoq724f1901998-10-26 10:58:16 +00001055 {
Francois Gougete76218d2001-05-09 17:31:31 +00001056 WARN("Clipboard not opened by calling task!\n");
Noel Borthwick29700671999-09-03 15:17:57 +00001057 return 0;
Pascal Cuoq724f1901998-10-26 10:58:16 +00001058 }
Noel Borthwick29700671999-09-03 15:17:57 +00001059
Dmitry Timoshkov1df0d362000-12-11 01:09:56 +00001060 if( wFormat == CF_UNICODETEXT || wFormat == CF_TEXT || wFormat == CF_OEMTEXT )
Pascal Cuoq724f1901998-10-26 10:58:16 +00001061 {
Noel Borthwick29700671999-09-03 15:17:57 +00001062 lpRender = CLIPBOARD_RenderText(wFormat);
1063 if ( !lpRender ) return 0;
Pascal Cuoq724f1901998-10-26 10:58:16 +00001064 }
1065 else
1066 {
1067 lpRender = __lookup_format( ClipFormats, wFormat );
Noel Borthwick29700671999-09-03 15:17:57 +00001068 if( !lpRender || !CLIPBOARD_RenderFormat(lpRender) ) return 0;
Pascal Cuoq724f1901998-10-26 10:58:16 +00001069 }
Vincent Béron9a624912002-05-31 23:06:46 +00001070
Noel Borthwick29700671999-09-03 15:17:57 +00001071 /* Convert between 16 -> 32 bit data, if necessary */
Francis Beaudet56ab55d1999-10-24 20:22:24 +00001072 if( lpRender->hData16 && !lpRender->hData32
1073 && CLIPBOARD_IsMemoryObject(wFormat) )
Pascal Cuoq724f1901998-10-26 10:58:16 +00001074 {
1075 int size;
Noel Borthwick29700671999-09-03 15:17:57 +00001076 if( lpRender->wFormatID == CF_METAFILEPICT )
Alexandre Julliarda3960291999-02-26 11:11:13 +00001077 size = sizeof( METAFILEPICT );
Pascal Cuoq724f1901998-10-26 10:58:16 +00001078 else
Noel Borthwick29700671999-09-03 15:17:57 +00001079 size = GlobalSize16(lpRender->hData16);
1080 lpRender->hData32 = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE,
Noel Borthwick83579c81999-07-24 12:18:04 +00001081 size);
Noel Borthwick29700671999-09-03 15:17:57 +00001082 if( lpRender->wFormatID == CF_METAFILEPICT )
Pascal Cuoq724f1901998-10-26 10:58:16 +00001083 {
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001084 FIXME("\timplement function CopyMetaFilePict16to32\n");
1085 FIXME("\tin the appropriate file.\n");
Pascal Cuoq724f1901998-10-26 10:58:16 +00001086#ifdef SOMEONE_IMPLEMENTED_ME
Vincent Béron9a624912002-05-31 23:06:46 +00001087 CopyMetaFilePict16to32( GlobalLock16(lpRender->hData32),
Noel Borthwick29700671999-09-03 15:17:57 +00001088 GlobalLock(lpRender->hData16) );
Pascal Cuoq724f1901998-10-26 10:58:16 +00001089#endif
1090 }
1091 else
1092 {
Vincent Béron9a624912002-05-31 23:06:46 +00001093 memcpy( GlobalLock(lpRender->hData32),
1094 GlobalLock16(lpRender->hData16),
Pascal Cuoq724f1901998-10-26 10:58:16 +00001095 size );
1096 }
Noel Borthwick29700671999-09-03 15:17:57 +00001097 GlobalUnlock(lpRender->hData32);
1098 GlobalUnlock16(lpRender->hData16);
Pascal Cuoq724f1901998-10-26 10:58:16 +00001099 }
1100
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00001101 TRACE("\treturning %p (type %i)\n", lpRender->hData32, lpRender->wFormatID);
Noel Borthwick29700671999-09-03 15:17:57 +00001102 return lpRender->hData32;
Alexandre Julliard21979011997-03-05 08:22:35 +00001103}
1104
Noel Borthwick29700671999-09-03 15:17:57 +00001105
Alexandre Julliard21979011997-03-05 08:22:35 +00001106/**************************************************************************
Patrik Stridvall2ece70e2000-12-22 01:38:01 +00001107 * CountClipboardFormats (USER.143)
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00001108 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001109INT16 WINAPI CountClipboardFormats16(void)
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00001110{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001111 return CountClipboardFormats();
Alexandre Julliardf0cbfa01997-02-15 14:29:56 +00001112}
1113
1114
1115/**************************************************************************
Patrik Stridvall2ece70e2000-12-22 01:38:01 +00001116 * CountClipboardFormats (USER32.@)
Alexandre Julliardf0cbfa01997-02-15 14:29:56 +00001117 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001118INT WINAPI CountClipboardFormats(void)
Alexandre Julliardf0cbfa01997-02-15 14:29:56 +00001119{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001120 INT FormatCount = 0;
Vincent Béron9a624912002-05-31 23:06:46 +00001121 LPWINE_CLIPFORMAT lpFormat = ClipFormats;
Alexandre Julliard1e9ac791996-06-06 18:38:27 +00001122
Noel Borthwick29700671999-09-03 15:17:57 +00001123 TRACE("()\n");
Alexandre Julliard1e9ac791996-06-06 18:38:27 +00001124
Vincent Béron9a624912002-05-31 23:06:46 +00001125 while(TRUE)
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00001126 {
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00001127 if (lpFormat == NULL) break;
Alex Korobka44a1b591999-04-01 12:03:52 +00001128
Noel Borthwick29700671999-09-03 15:17:57 +00001129 if( lpFormat->wFormatID != CF_TEXT ) /* Don't count CF_TEXT */
1130 {
1131 /*
1132 * The format is available if either:
1133 * 1. The data is already in the cache.
1134 * 2. The selection is not owned by us(WINE) and the data is
1135 * available to the clipboard driver.
1136 */
1137 if ( lpFormat->wDataPresent ||
Alexandre Julliard42d20f92000-08-10 01:16:19 +00001138 ( !USER_Driver.pIsSelectionOwner()
1139 && USER_Driver.pIsClipboardFormatAvailable( lpFormat->wFormatID ) ) )
Noel Borthwick29700671999-09-03 15:17:57 +00001140 {
Juergen Schmied1c35dae2000-02-07 16:22:57 +00001141 TRACE("\tdata found for format 0x%04x(%s)\n",
Ulrich Czekalla651c5982002-08-27 19:19:49 +00001142 lpFormat->wFormatID, CLIPBOARD_GetFormatName(lpFormat->wFormatID, NULL, 0));
Noel Borthwick29700671999-09-03 15:17:57 +00001143 FormatCount++;
1144 }
1145 }
1146
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00001147 lpFormat = lpFormat->NextFormat;
1148 }
Alexandre Julliard1e9ac791996-06-06 18:38:27 +00001149
Dmitry Timoshkov1df0d362000-12-11 01:09:56 +00001150 /* these are equivalent, adjust the total */
1151 FormatCount += (ClipFormats[CF_UNICODETEXT-1].wDataPresent ||
1152 ClipFormats[CF_TEXT-1].wDataPresent ||
1153 ClipFormats[CF_OEMTEXT-1].wDataPresent) ? 1 : 0;
Alex Korobka44a1b591999-04-01 12:03:52 +00001154
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001155 TRACE("\ttotal %d\n", FormatCount);
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00001156 return FormatCount;
1157}
1158
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00001159/**************************************************************************
Patrik Stridvall2ece70e2000-12-22 01:38:01 +00001160 * EnumClipboardFormats (USER.144)
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00001161 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001162UINT16 WINAPI EnumClipboardFormats16( UINT16 wFormat )
Alexandre Julliardf0cbfa01997-02-15 14:29:56 +00001163{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001164 return EnumClipboardFormats( wFormat );
Alexandre Julliardf0cbfa01997-02-15 14:29:56 +00001165}
1166
1167
1168/**************************************************************************
Patrik Stridvall2ece70e2000-12-22 01:38:01 +00001169 * EnumClipboardFormats (USER32.@)
Alexandre Julliardf0cbfa01997-02-15 14:29:56 +00001170 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001171UINT WINAPI EnumClipboardFormats( UINT wFormat )
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00001172{
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001173 TRACE("(%04X)\n", wFormat);
Alexandre Julliard1e9ac791996-06-06 18:38:27 +00001174
Noel Borthwick29700671999-09-03 15:17:57 +00001175 if (CLIPBOARD_IsLocked())
1176 {
Francois Gougete76218d2001-05-09 17:31:31 +00001177 WARN("Clipboard not opened by calling task!\n");
Noel Borthwick29700671999-09-03 15:17:57 +00001178 return 0;
1179 }
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +00001180
Gerard Patel9289a5d2000-12-22 23:26:18 +00001181 return CLIPBOARD_EnumClipboardFormats(wFormat);
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00001182}
1183
1184
1185/**************************************************************************
Dmitry Timoshkov56a19922001-07-02 01:21:26 +00001186 * RegisterClipboardFormatA (USER32.@)
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00001187 */
Dmitry Timoshkov56a19922001-07-02 01:21:26 +00001188UINT WINAPI RegisterClipboardFormatA( LPCSTR FormatName )
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00001189{
Vincent Béron9a624912002-05-31 23:06:46 +00001190 LPWINE_CLIPFORMAT lpNewFormat;
1191 LPWINE_CLIPFORMAT lpFormat = ClipFormats;
Alexandre Julliard1e9ac791996-06-06 18:38:27 +00001192
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00001193 if (FormatName == NULL) return 0;
Alexandre Julliard1e9ac791996-06-06 18:38:27 +00001194
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001195 TRACE("('%s') !\n", FormatName);
Alexandre Julliard1e9ac791996-06-06 18:38:27 +00001196
1197 /* walk format chain to see if it's already registered */
1198
Vincent Béron9a624912002-05-31 23:06:46 +00001199 while(TRUE)
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00001200 {
Ulrich Czekalla651c5982002-08-27 19:19:49 +00001201 if ( !strcasecmp(lpFormat->Name,FormatName) )
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00001202 {
Alexandre Julliard1e9ac791996-06-06 18:38:27 +00001203 lpFormat->wRefCount++;
1204 return lpFormat->wFormatID;
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00001205 }
Vincent Béron9a624912002-05-31 23:06:46 +00001206
Alexandre Julliard1e9ac791996-06-06 18:38:27 +00001207 if ( lpFormat->NextFormat == NULL ) break;
1208
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00001209 lpFormat = lpFormat->NextFormat;
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00001210 }
Alexandre Julliard1e9ac791996-06-06 18:38:27 +00001211
1212 /* allocate storage for new format entry */
1213
Dimitrie O. Paun9ad96362000-03-19 14:29:50 +00001214 lpNewFormat = (LPWINE_CLIPFORMAT)HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CLIPFORMAT));
1215 if(lpNewFormat == NULL) {
Francois Gougete76218d2001-05-09 17:31:31 +00001216 WARN("No more memory for a new format!\n");
Dimitrie O. Paun9ad96362000-03-19 14:29:50 +00001217 return 0;
1218 }
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00001219 lpFormat->NextFormat = lpNewFormat;
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00001220 lpNewFormat->wRefCount = 1;
Alexandre Julliard1e9ac791996-06-06 18:38:27 +00001221
Alexandre Julliard5f728ca2001-07-24 21:45:22 +00001222 if (!(lpNewFormat->Name = HeapAlloc(GetProcessHeap(), 0, strlen(FormatName)+1 )))
1223 {
Francois Gougete76218d2001-05-09 17:31:31 +00001224 WARN("No more memory for the new format name!\n");
Dimitrie O. Paun9ad96362000-03-19 14:29:50 +00001225 HeapFree(GetProcessHeap(), 0, lpNewFormat);
1226 return 0;
1227 }
Alexandre Julliard5f728ca2001-07-24 21:45:22 +00001228 strcpy( lpNewFormat->Name, FormatName );
Ulrich Czekalla651c5982002-08-27 19:19:49 +00001229 CharLowerA(lpNewFormat->Name);
Alexandre Julliard1e9ac791996-06-06 18:38:27 +00001230
1231 lpNewFormat->wDataPresent = 0;
Pascal Cuoq724f1901998-10-26 10:58:16 +00001232 lpNewFormat->hData16 = 0;
Noel Borthwick83579c81999-07-24 12:18:04 +00001233 lpNewFormat->hDataSrc32 = 0;
Pascal Cuoq724f1901998-10-26 10:58:16 +00001234 lpNewFormat->hData32 = 0;
Noel Borthwick29700671999-09-03 15:17:57 +00001235 lpNewFormat->drvData = 0;
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00001236 lpNewFormat->PrevFormat = lpFormat;
1237 lpNewFormat->NextFormat = NULL;
Alexandre Julliard1e9ac791996-06-06 18:38:27 +00001238
Noel Borthwick29700671999-09-03 15:17:57 +00001239 /* Pass on the registration request to the driver */
Ulrich Czekalla651c5982002-08-27 19:19:49 +00001240 lpNewFormat->wFormatID = USER_Driver.pRegisterClipboardFormat(lpNewFormat->Name);
Vincent Béron9a624912002-05-31 23:06:46 +00001241
Ulrich Czekalla651c5982002-08-27 19:19:49 +00001242 TRACE("Registering format(%d): %s\n", lpNewFormat->wFormatID, FormatName);
1243 return lpNewFormat->wFormatID;
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00001244}
1245
1246
1247/**************************************************************************
Dmitry Timoshkov56a19922001-07-02 01:21:26 +00001248 * RegisterClipboardFormat (USER.145)
Alexandre Julliardb1bac321996-12-15 19:45:59 +00001249 */
Dmitry Timoshkov56a19922001-07-02 01:21:26 +00001250UINT16 WINAPI RegisterClipboardFormat16( LPCSTR FormatName )
Alexandre Julliardb1bac321996-12-15 19:45:59 +00001251{
Dmitry Timoshkov56a19922001-07-02 01:21:26 +00001252 return RegisterClipboardFormatA( FormatName );
Alexandre Julliardb1bac321996-12-15 19:45:59 +00001253}
1254
1255
1256/**************************************************************************
Patrik Stridvall2ece70e2000-12-22 01:38:01 +00001257 * RegisterClipboardFormatW (USER32.@)
Alexandre Julliardb1bac321996-12-15 19:45:59 +00001258 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001259UINT WINAPI RegisterClipboardFormatW( LPCWSTR formatName )
Alexandre Julliardb1bac321996-12-15 19:45:59 +00001260{
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +00001261 LPSTR aFormat = HEAP_strdupWtoA( GetProcessHeap(), 0, formatName );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001262 UINT ret = RegisterClipboardFormatA( aFormat );
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +00001263 HeapFree( GetProcessHeap(), 0, aFormat );
Alexandre Julliardb1bac321996-12-15 19:45:59 +00001264 return ret;
1265}
1266
Noel Borthwick29700671999-09-03 15:17:57 +00001267
Alexandre Julliardb1bac321996-12-15 19:45:59 +00001268/**************************************************************************
Patrik Stridvall2ece70e2000-12-22 01:38:01 +00001269 * GetClipboardFormatName (USER.146)
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00001270 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001271INT16 WINAPI GetClipboardFormatName16( UINT16 wFormat, LPSTR retStr, INT16 maxlen )
Alexandre Julliard21979011997-03-05 08:22:35 +00001272{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001273 return GetClipboardFormatNameA( wFormat, retStr, maxlen );
Alexandre Julliard21979011997-03-05 08:22:35 +00001274}
1275
1276
1277/**************************************************************************
Patrik Stridvall2ece70e2000-12-22 01:38:01 +00001278 * GetClipboardFormatNameA (USER32.@)
Alexandre Julliard21979011997-03-05 08:22:35 +00001279 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001280INT WINAPI GetClipboardFormatNameA( UINT wFormat, LPSTR retStr, INT maxlen )
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00001281{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001282 LPWINE_CLIPFORMAT lpFormat = __lookup_format( ClipFormats, wFormat );
Alexandre Julliard1e9ac791996-06-06 18:38:27 +00001283
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001284 TRACE("(%04X, %p, %d) !\n", wFormat, retStr, maxlen);
Alexandre Julliard1e9ac791996-06-06 18:38:27 +00001285
Ulrich Czekalla651c5982002-08-27 19:19:49 +00001286 if (lpFormat == NULL || lpFormat->Name == NULL)
1287 {
1288 /* Check if another wine process already registered the format */
1289 if (wFormat && !USER_Driver.pGetClipboardFormatName(wFormat, retStr, maxlen))
1290 {
1291 RegisterClipboardFormatA(retStr); /* Make a cache entry */
1292 return strlen(retStr);
1293 }
1294 else
1295 {
1296 TRACE("wFormat=%d not found\n", wFormat);
1297 return 0;
1298 }
1299 }
Alexandre Julliard1e9ac791996-06-06 18:38:27 +00001300
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001301 TRACE("Name='%s' !\n", lpFormat->Name);
Alexandre Julliard1e9ac791996-06-06 18:38:27 +00001302
Alexandre Julliarda3960291999-02-26 11:11:13 +00001303 lstrcpynA( retStr, lpFormat->Name, maxlen );
Alexandre Julliard1e9ac791996-06-06 18:38:27 +00001304 return strlen(retStr);
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00001305}
1306
1307
1308/**************************************************************************
Patrik Stridvall2ece70e2000-12-22 01:38:01 +00001309 * GetClipboardFormatNameW (USER32.@)
Alexandre Julliard21979011997-03-05 08:22:35 +00001310 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001311INT WINAPI GetClipboardFormatNameW( UINT wFormat, LPWSTR retStr, INT maxlen )
Alexandre Julliard21979011997-03-05 08:22:35 +00001312{
Dimitrie O. Paun4d48dd32000-04-30 12:22:18 +00001313 INT ret;
1314 LPSTR p = HeapAlloc( GetProcessHeap(), 0, maxlen );
1315 if(p == NULL) return 0; /* FIXME: is this the correct failure value? */
Vincent Béron9a624912002-05-31 23:06:46 +00001316
Dimitrie O. Paun4d48dd32000-04-30 12:22:18 +00001317 ret = GetClipboardFormatNameA( wFormat, p, maxlen );
Alexandre Julliard24a62ab2000-11-28 22:40:56 +00001318
1319 if (maxlen > 0 && !MultiByteToWideChar( CP_ACP, 0, p, -1, retStr, maxlen ))
1320 retStr[maxlen-1] = 0;
Alexandre Julliard21979011997-03-05 08:22:35 +00001321 HeapFree( GetProcessHeap(), 0, p );
1322 return ret;
1323}
1324
1325
1326/**************************************************************************
Patrik Stridvall2ece70e2000-12-22 01:38:01 +00001327 * SetClipboardViewer (USER32.@)
Alexandre Julliardf0cbfa01997-02-15 14:29:56 +00001328 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001329HWND WINAPI SetClipboardViewer( HWND hWnd )
Alexandre Julliardf0cbfa01997-02-15 14:29:56 +00001330{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001331 HWND hwndPrev = hWndViewer;
Alexandre Julliard1e9ac791996-06-06 18:38:27 +00001332
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00001333 TRACE("(%p): returning %p\n", hWnd, hwndPrev);
Alexandre Julliard1e9ac791996-06-06 18:38:27 +00001334
Alexandre Julliard37a46392001-09-12 17:19:13 +00001335 hWndViewer = WIN_GetFullHandle( hWnd );
Alexandre Julliardecc37121994-11-22 16:31:29 +00001336 return hwndPrev;
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00001337}
1338
1339
1340/**************************************************************************
Patrik Stridvall2ece70e2000-12-22 01:38:01 +00001341 * GetClipboardViewer (USER32.@)
Alexandre Julliardf0cbfa01997-02-15 14:29:56 +00001342 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001343HWND WINAPI GetClipboardViewer(void)
Alexandre Julliardf0cbfa01997-02-15 14:29:56 +00001344{
Noel Borthwick29700671999-09-03 15:17:57 +00001345 TRACE("()\n");
Alexandre Julliardaca05781994-10-17 18:12:41 +00001346 return hWndViewer;
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00001347}
1348
1349
1350/**************************************************************************
Patrik Stridvall2ece70e2000-12-22 01:38:01 +00001351 * ChangeClipboardChain (USER32.@)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001352 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001353BOOL WINAPI ChangeClipboardChain(HWND hWnd, HWND hWndNext)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001354{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001355 BOOL bRet = 0;
Alexandre Julliard234bc241994-12-10 13:02:28 +00001356
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00001357 FIXME("(%p, %p): stub?\n", hWnd, hWndNext);
Alexandre Julliard1e9ac791996-06-06 18:38:27 +00001358
1359 if( hWndViewer )
Alexandre Julliardcb25e252001-08-08 23:28:42 +00001360 bRet = !SendMessageW( hWndViewer, WM_CHANGECBCHAIN, (WPARAM)hWnd, (LPARAM)hWndNext );
Alexandre Julliard1e9ac791996-06-06 18:38:27 +00001361 else
Alexandre Julliard359f497e1999-07-04 16:02:24 +00001362 WARN("hWndViewer is lost\n");
Alexandre Julliard1e9ac791996-06-06 18:38:27 +00001363
Alexandre Julliardf44bbb82001-09-14 00:24:39 +00001364 if( WIN_GetFullHandle(hWnd) == hWndViewer ) hWndViewer = WIN_GetFullHandle( hWndNext );
Alexandre Julliard1e9ac791996-06-06 18:38:27 +00001365
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001366 return bRet;
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00001367}
1368
1369
1370/**************************************************************************
Patrik Stridvall0c610282001-01-25 22:22:21 +00001371 * IsClipboardFormatAvailable (USER.193)
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00001372 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001373BOOL16 WINAPI IsClipboardFormatAvailable16( UINT16 wFormat )
Alexandre Julliardf0cbfa01997-02-15 14:29:56 +00001374{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001375 return IsClipboardFormatAvailable( wFormat );
Alexandre Julliardf0cbfa01997-02-15 14:29:56 +00001376}
1377
1378
1379/**************************************************************************
Patrik Stridvall2ece70e2000-12-22 01:38:01 +00001380 * IsClipboardFormatAvailable (USER32.@)
Alexandre Julliardf0cbfa01997-02-15 14:29:56 +00001381 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001382BOOL WINAPI IsClipboardFormatAvailable( UINT wFormat )
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00001383{
Noel Borthwick29700671999-09-03 15:17:57 +00001384 BOOL bRet;
Alexandre Julliard1e9ac791996-06-06 18:38:27 +00001385
Noel Borthwick29700671999-09-03 15:17:57 +00001386 if (wFormat == 0) /* Reject this case quickly */
1387 bRet = FALSE;
Dmitry Timoshkov1df0d362000-12-11 01:09:56 +00001388 else
Gerard Patel9289a5d2000-12-22 23:26:18 +00001389 {
1390 UINT iret = CLIPBOARD_EnumClipboardFormats(wFormat - 1);
1391 if ((wFormat == CF_TEXT) || (wFormat == CF_OEMTEXT) || (wFormat == CF_UNICODETEXT))
1392 bRet = ((iret == CF_TEXT) || (iret == CF_OEMTEXT) || (iret == CF_UNICODETEXT));
1393 else
1394 bRet = iret == wFormat;
1395 }
Noel Borthwick29700671999-09-03 15:17:57 +00001396 TRACE("(%04X)- ret(%d)\n", wFormat, bRet);
1397 return bRet;
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00001398}
1399
1400
1401/**************************************************************************
Patrik Stridvall2ece70e2000-12-22 01:38:01 +00001402 * GetOpenClipboardWindow (USER32.@)
Noel Borthwick29700671999-09-03 15:17:57 +00001403 * FIXME: This wont work if an external app owns the selection
Alexandre Julliardf0cbfa01997-02-15 14:29:56 +00001404 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001405HWND WINAPI GetOpenClipboardWindow(void)
Alexandre Julliardf0cbfa01997-02-15 14:29:56 +00001406{
Noel Borthwick29700671999-09-03 15:17:57 +00001407 TRACE("()\n");
Alexandre Julliard1e9ac791996-06-06 18:38:27 +00001408 return hWndClipWindow;
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00001409}
1410
1411
1412/**************************************************************************
Patrik Stridvall2ece70e2000-12-22 01:38:01 +00001413 * GetPriorityClipboardFormat (USER32.@)
Alexandre Julliard21979011997-03-05 08:22:35 +00001414 */
Alexandre Julliardd23a82b2001-09-19 20:37:04 +00001415INT WINAPI GetPriorityClipboardFormat( UINT *list, INT nCount )
Alexandre Julliard21979011997-03-05 08:22:35 +00001416{
Alexandre Julliardd23a82b2001-09-19 20:37:04 +00001417 int i;
Noel Borthwick29700671999-09-03 15:17:57 +00001418 TRACE("()\n");
Alexandre Julliard0623a6f1998-01-18 18:01:49 +00001419
Alexandre Julliardd23a82b2001-09-19 20:37:04 +00001420 if(CountClipboardFormats() == 0) return 0;
Alexandre Julliard0623a6f1998-01-18 18:01:49 +00001421
Alexandre Julliardd23a82b2001-09-19 20:37:04 +00001422 for (i = 0; i < nCount; i++)
1423 if (IsClipboardFormatAvailable( list[i] )) return list[i];
Alexandre Julliard0623a6f1998-01-18 18:01:49 +00001424 return -1;
Alexandre Julliardfb9a9191994-03-01 19:48:04 +00001425}
1426
David Elliott44f84b52000-10-29 01:24:54 +00001427
1428/**************************************************************************
Patrik Stridvall2ece70e2000-12-22 01:38:01 +00001429 * GetClipboardSequenceNumber (USER32.@)
David Elliott44f84b52000-10-29 01:24:54 +00001430 * Supported on Win2k/Win98
1431 * MSDN: Windows clipboard code keeps a serial number for the clipboard
1432 * for each window station. The number is incremented whenever the
1433 * contents change or are emptied.
1434 * If you do not have WINSTA_ACCESSCLIPBOARD then the function returns 0
1435 */
1436DWORD WINAPI GetClipboardSequenceNumber(VOID)
1437{
1438 FIXME("Returning 0, see windows/clipboard.c\n");
1439 /* FIXME: Use serial numbers */
1440 return 0;
1441}