Removed -noimport on functions that are forwards to ntdll.
[wine/multimedia.git] / windows / clipboard.c
blob8931dd78bb4fd02b03d72284aae7f9bcd76dbb6e
1 /*
2 * WIN32 clipboard implementation
4 * Copyright 1994 Martin Ayotte
5 * 1996 Alex Korobka
6 * 1999 Noel Borthwick
8 * 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.
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.
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
22 * 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)
31 #include "config.h"
32 #include "wine/port.h"
34 #include <stdlib.h>
35 #include <sys/types.h>
36 #include <fcntl.h>
37 #ifdef HAVE_UNISTD_H
38 # include <unistd.h>
39 #endif
40 #include <string.h>
42 #include "windef.h"
43 #include "winbase.h"
44 #include "wingdi.h"
45 #include "winuser.h"
46 #include "wine/winuser16.h"
47 #include "wine/winbase16.h"
48 #include "heap.h"
49 #include "user.h"
50 #include "win.h"
51 #include "clipboard.h"
53 #include "wine/debug.h"
54 #include "wine/unicode.h"
56 WINE_DEFAULT_DEBUG_CHANNEL(clipboard);
58 #define CF_REGFORMATBASE 0xC000
60 /**************************************************************************
61 * Clipboard context global variables
64 static HANDLE hClipLock = 0;
65 static BOOL bCBHasChanged = FALSE;
67 static HWND hWndClipWindow; /* window that last opened clipboard */
68 static HWND hWndClipOwner; /* current clipboard owner */
69 static HANDLE16 hTaskClipOwner; /* clipboard owner's task */
70 static HWND hWndViewer; /* start of viewers chain */
72 /* Clipboard cache initial data.
73 * WARNING: This data ordering is dependent on the WINE_CLIPFORMAT structure
74 * declared in clipboard.h
76 WINE_CLIPFORMAT ClipFormats[] = {
77 { CF_TEXT, 1, 0, "Text", 0, 0, 0, 0, NULL, &ClipFormats[1]},
78 { CF_BITMAP, 1, 0, "Bitmap", 0, 0, 0, 0, &ClipFormats[0], &ClipFormats[2]},
79 { CF_METAFILEPICT, 1, 0, "MetaFile Picture", 0, 0, 0, 0, &ClipFormats[1], &ClipFormats[3]},
80 { CF_SYLK, 1, 0, "Sylk", 0, 0, 0, 0, &ClipFormats[2], &ClipFormats[4]},
81 { CF_DIF, 1, 0, "DIF", 0, 0, 0, 0, &ClipFormats[3], &ClipFormats[5]},
82 { CF_TIFF, 1, 0, "TIFF", 0, 0, 0, 0, &ClipFormats[4], &ClipFormats[6]},
83 { CF_OEMTEXT, 1, 0, "OEM Text", 0, 0, 0, 0, &ClipFormats[5], &ClipFormats[7]},
84 { CF_DIB, 1, 0, "DIB", 0, 0, 0, 0, &ClipFormats[6], &ClipFormats[8]},
85 { CF_PALETTE, 1, 0, "Palette", 0, 0, 0, 0, &ClipFormats[7], &ClipFormats[9]},
86 { CF_PENDATA, 1, 0, "PenData", 0, 0, 0, 0, &ClipFormats[8], &ClipFormats[10]},
87 { CF_RIFF, 1, 0, "RIFF", 0, 0, 0, 0, &ClipFormats[9], &ClipFormats[11]},
88 { CF_WAVE, 1, 0, "Wave", 0, 0, 0, 0, &ClipFormats[10], &ClipFormats[12]},
89 { CF_UNICODETEXT, 1, 0, "Unicode Text", 0, 0, 0, 0, &ClipFormats[11], &ClipFormats[13]},
90 { CF_OWNERDISPLAY, 1, 0, "Owner Display", 0, 0, 0, 0, &ClipFormats[12], &ClipFormats[14]},
91 { CF_DSPTEXT, 1, 0, "DSPText", 0, 0, 0, 0, &ClipFormats[13], &ClipFormats[15]},
92 { CF_DSPMETAFILEPICT, 1, 0, "DSPMetaFile Picture", 0, 0, 0, 0, &ClipFormats[14], &ClipFormats[16]},
93 { CF_DSPBITMAP, 1, 0, "DSPBitmap", 0, 0, 0, 0, &ClipFormats[15], &ClipFormats[17]},
94 { CF_HDROP, 1, 0, "HDROP", 0, 0, 0, 0, &ClipFormats[16], &ClipFormats[18]},
95 { CF_ENHMETAFILE, 1, 0, "Enhmetafile", 0, 0, 0, 0, &ClipFormats[17], NULL}
99 /**************************************************************************
100 * Internal Clipboard implementation methods
101 **************************************************************************/
104 /**************************************************************************
105 * CLIPBOARD_LookupFormat
107 static LPWINE_CLIPFORMAT __lookup_format( LPWINE_CLIPFORMAT lpFormat, WORD wID )
109 while(TRUE)
111 if (lpFormat == NULL ||
112 lpFormat->wFormatID == wID) break;
113 lpFormat = lpFormat->NextFormat;
115 return lpFormat;
118 LPWINE_CLIPFORMAT CLIPBOARD_LookupFormat( WORD wID )
120 return __lookup_format( ClipFormats, wID );
123 /**************************************************************************
124 * CLIPBOARD_IsLocked
125 * Check if the clipboard cache is available to the caller
127 BOOL CLIPBOARD_IsLocked()
129 BOOL bIsLocked = TRUE;
130 HANDLE16 hTaskCur = GetCurrentTask();
133 * The clipboard is available:
134 * 1. if the caller's task has opened the clipboard,
135 * or
136 * 2. if the caller is the clipboard owners task, AND is responding to a
137 * WM_RENDERFORMAT message.
139 if ( hClipLock == hTaskCur )
140 bIsLocked = FALSE;
142 else if ( hTaskCur == hTaskClipOwner )
144 /* Check if we're currently executing inside a window procedure
145 * called in response to a WM_RENDERFORMAT message. A WM_RENDERFORMAT
146 * handler is not permitted to open the clipboard since it has been opened
147 * by another client. However the handler must have access to the
148 * clipboard in order to update data in response to this message.
150 #if 0
151 MESSAGEQUEUE *queue = QUEUE_Current();
153 if ( queue
154 && queue->smWaiting
155 && queue->smWaiting->msg == WM_RENDERFORMAT
156 && queue->smWaiting->hSrcQueue
158 bIsLocked = FALSE;
159 #else
160 /* FIXME: queue check no longer possible */
161 bIsLocked = FALSE;
162 #endif
165 return bIsLocked;
168 /**************************************************************************
169 * CLIPBOARD_ReleaseOwner
170 * Gives up ownership of the clipboard
172 void CLIPBOARD_ReleaseOwner()
174 hWndClipOwner = 0;
175 hTaskClipOwner = 0;
178 /**************************************************************************
179 * CLIPBOARD_GlobalFreeProc
181 * This is a callback mechanism to allow HGLOBAL data to be released in
182 * the context of the process which allocated it. We post a WM_TIMER message
183 * to the owner window(in CLIPBOARD_DeleteRecord) and destroy the data(in idEvent)
184 * in this WndProc, which is invoked when the apps message loop calls DispatchMessage.
185 * This technique is discussed in Matt Pietrek's "Under the Hood".
186 * An article describing the same may be found in MSDN by searching for WM_TIMER.
187 * Note that this mechanism will probably stop working when WINE supports
188 * address space separation. When "queue events" are implemented in Wine we
189 * should switch to using that mechanism, since it is more robust and does not
190 * require a procedure address to be passed. See the SetWinEventHook API for
191 * more info on this.
193 VOID CALLBACK CLIPBOARD_GlobalFreeProc( HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime )
195 /* idEvent is the HGLOBAL to be deleted */
196 GlobalFree( (HGLOBAL)idEvent );
199 /**************************************************************************
200 * CLIPBOARD_DeleteRecord
202 void CLIPBOARD_DeleteRecord(LPWINE_CLIPFORMAT lpFormat, BOOL bChange)
204 if( (lpFormat->wFormatID >= CF_GDIOBJFIRST &&
205 lpFormat->wFormatID <= CF_GDIOBJLAST) || lpFormat->wFormatID == CF_BITMAP
206 || lpFormat->wFormatID == CF_PALETTE)
208 if (lpFormat->hData32)
209 DeleteObject(lpFormat->hData32);
210 if (lpFormat->hData16)
211 DeleteObject(lpFormat->hData16);
213 else if( lpFormat->wFormatID == CF_METAFILEPICT )
215 if (lpFormat->hData32)
217 DeleteMetaFile( ((METAFILEPICT *)GlobalLock( lpFormat->hData32 ))->hMF );
218 PostMessageA(hWndClipOwner, WM_TIMER,
219 (WPARAM)lpFormat->hData32, (LPARAM)CLIPBOARD_GlobalFreeProc);
220 if (lpFormat->hDataSrc32)
222 /* Release lpFormat->hData32 in the context of the process which created it.
223 * See CLIPBOARD_GlobalFreeProc for more details about this technique.
224 * GlobalFree(lpFormat->hDataSrc32);
226 PostMessageA(hWndClipOwner, WM_TIMER,
227 (WPARAM)lpFormat->hDataSrc32, (LPARAM)CLIPBOARD_GlobalFreeProc);
230 if (lpFormat->hData16)
231 /* HMETAFILE16 and HMETAFILE32 are apparently the same thing,
232 and a shallow copy is enough to share a METAFILEPICT
233 structure between 16bit and 32bit clipboards. The MetaFile
234 should of course only be deleted once. */
235 GlobalFree16(lpFormat->hData16);
237 if (lpFormat->hData16)
239 DeleteMetaFile16( ((METAFILEPICT16 *)GlobalLock16( lpFormat->hData16 ))->hMF );
240 GlobalFree16(lpFormat->hData16);
243 else
245 if (lpFormat->hData32)
247 /* Release lpFormat->hData32 in the context of the process which created it.
248 * See CLIPBOARD_GlobalFreeProc for more details about this technique.
249 * GlobalFree( lpFormat->hData32 );
251 PostMessageA(hWndClipOwner, WM_TIMER,
252 (WPARAM)lpFormat->hData32, (LPARAM)CLIPBOARD_GlobalFreeProc);
254 if (lpFormat->hDataSrc32)
256 /* Release lpFormat->hData32 in the context of the process which created it.
257 * See CLIPBOARD_GlobalFreeProc for more details about this technique.
258 * GlobalFree(lpFormat->hDataSrc32);
260 PostMessageA(hWndClipOwner, WM_TIMER,
261 (WPARAM)lpFormat->hDataSrc32, (LPARAM)CLIPBOARD_GlobalFreeProc);
263 if (lpFormat->hData16)
264 GlobalFree16(lpFormat->hData16);
267 lpFormat->wDataPresent = 0;
268 lpFormat->hData16 = 0;
269 lpFormat->hData32 = 0;
270 lpFormat->hDataSrc32 = 0;
271 lpFormat->drvData = 0;
273 if( bChange ) bCBHasChanged = TRUE;
276 /**************************************************************************
277 * CLIPBOARD_EmptyCache
279 void CLIPBOARD_EmptyCache( BOOL bChange )
281 LPWINE_CLIPFORMAT lpFormat = ClipFormats;
283 while(lpFormat)
285 if ( lpFormat->wDataPresent || lpFormat->hData16 || lpFormat->hData32 )
286 CLIPBOARD_DeleteRecord( lpFormat, bChange );
288 lpFormat = lpFormat->NextFormat;
292 /**************************************************************************
293 * CLIPBOARD_IsPresent
295 BOOL CLIPBOARD_IsPresent(WORD wFormat)
297 /* special case */
299 if( wFormat == CF_TEXT || wFormat == CF_OEMTEXT || wFormat == CF_UNICODETEXT )
300 return ClipFormats[CF_TEXT-1].wDataPresent ||
301 ClipFormats[CF_OEMTEXT-1].wDataPresent ||
302 ClipFormats[CF_UNICODETEXT-1].wDataPresent;
303 else
305 LPWINE_CLIPFORMAT lpFormat = __lookup_format( ClipFormats, wFormat );
306 if( lpFormat ) return (lpFormat->wDataPresent);
308 return FALSE;
311 /**************************************************************************
312 * CLIPBOARD_IsCacheRendered
313 * Checks if any data needs to be rendered to the clipboard cache
314 * RETURNS:
315 * TRUE - All clipboard data is available in the cache
316 * FALSE - Some data is marked for delayed render and needs rendering
318 BOOL CLIPBOARD_IsCacheRendered()
320 LPWINE_CLIPFORMAT lpFormat = ClipFormats;
322 /* check if all formats were rendered */
323 while(lpFormat)
325 if( lpFormat->wDataPresent && !lpFormat->hData16 && !lpFormat->hData32 )
326 return FALSE;
328 lpFormat = lpFormat->NextFormat;
331 return TRUE;
335 /**************************************************************************
336 * CLIPBOARD_IsMemoryObject
337 * Tests if the clipboard format specifies a memory object
339 BOOL CLIPBOARD_IsMemoryObject( WORD wFormat )
341 switch(wFormat)
343 case CF_BITMAP:
344 case CF_METAFILEPICT:
345 case CF_DSPTEXT:
346 case CF_ENHMETAFILE:
347 case CF_HDROP:
348 case CF_PALETTE:
349 case CF_PENDATA:
350 return FALSE;
351 default:
352 return TRUE;
356 /***********************************************************************
357 * CLIPBOARD_GlobalDupMem( HGLOBAL )
358 * Helper method to duplicate an HGLOBAL chunk of memory into shared memory
360 HGLOBAL CLIPBOARD_GlobalDupMem( HGLOBAL hGlobalSrc )
362 HGLOBAL hGlobalDest;
363 PVOID pGlobalSrc, pGlobalDest;
364 DWORD cBytes;
366 if ( !hGlobalSrc )
367 return 0;
369 cBytes = GlobalSize(hGlobalSrc);
370 if ( 0 == cBytes )
371 return 0;
373 /* Turn on the DDESHARE and _MOVEABLE flags explicitly */
374 hGlobalDest = GlobalAlloc( GlobalFlags(hGlobalSrc) | GMEM_DDESHARE | GMEM_MOVEABLE,
375 cBytes );
376 if ( !hGlobalDest )
377 return 0;
379 pGlobalSrc = GlobalLock(hGlobalSrc);
380 pGlobalDest = GlobalLock(hGlobalDest);
381 if ( !pGlobalSrc || !pGlobalDest )
382 return 0;
384 memcpy(pGlobalDest, pGlobalSrc, cBytes);
386 GlobalUnlock(hGlobalSrc);
387 GlobalUnlock(hGlobalDest);
389 return hGlobalDest;
392 /**************************************************************************
393 * CLIPBOARD_GetFormatName
394 * Gets the format name associated with an ID
396 char * CLIPBOARD_GetFormatName(UINT wFormat, LPSTR buf, INT size)
398 LPWINE_CLIPFORMAT lpFormat = __lookup_format( ClipFormats, wFormat );
400 if (lpFormat)
402 if (buf)
404 strncpy(buf, lpFormat->Name, size);
405 CharLowerA(buf);
408 return lpFormat->Name;
410 else
411 return NULL;
415 /**************************************************************************
416 * CLIPBOARD_RenderFormat
418 static BOOL CLIPBOARD_RenderFormat(LPWINE_CLIPFORMAT lpFormat)
421 * If WINE is not the selection owner, and the format is available
422 * we must ask the driver to render the data to the clipboard cache.
424 TRACE("enter format=%d\n", lpFormat->wFormatID);
425 if ( !USER_Driver.pIsSelectionOwner()
426 && USER_Driver.pIsClipboardFormatAvailable( lpFormat->wFormatID ) )
428 if ( !USER_Driver.pGetClipboardData( lpFormat->wFormatID ) )
429 return FALSE;
432 * If Wine owns the clipboard, and the data is marked for delayed render,
433 * render it now.
435 else if( lpFormat->wDataPresent && !lpFormat->hData16 && !lpFormat->hData32 )
437 if( IsWindow(hWndClipOwner) )
439 /* Send a WM_RENDERFORMAT message to notify the owner to render the
440 * data requested into the clipboard.
442 TRACE("Sending WM_RENDERFORMAT message\n");
443 SendMessageW( hWndClipOwner, WM_RENDERFORMAT, (WPARAM)lpFormat->wFormatID, 0 );
445 else
447 WARN("\thWndClipOwner (%04x) is lost!\n",
448 hWndClipOwner);
449 CLIPBOARD_ReleaseOwner();
450 lpFormat->wDataPresent = 0;
451 return FALSE;
455 return (lpFormat->hData16 || lpFormat->hData32) ? TRUE : FALSE;
458 /**************************************************************************
459 * CLIPBOARD_ConvertText
460 * Returns number of required/converted characters - not bytes!
462 static INT CLIPBOARD_ConvertText(WORD src_fmt, void const *src, INT src_size,
463 WORD dst_fmt, void *dst, INT dst_size)
465 UINT cp;
467 if(src_fmt == CF_UNICODETEXT)
469 switch(dst_fmt)
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;
480 return WideCharToMultiByte(cp, 0, src, src_size, dst, dst_size, NULL, NULL);
483 if(dst_fmt == CF_UNICODETEXT)
485 switch(src_fmt)
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;
496 return MultiByteToWideChar(cp, 0, src, src_size, dst, dst_size);
499 if(!dst_size) return src_size;
501 if(dst_size > src_size) dst_size = src_size;
503 if(src_fmt == CF_TEXT )
504 CharToOemBuffA(src, dst, dst_size);
505 else
506 OemToCharBuffA(src, dst, dst_size);
508 return dst_size;
511 /**************************************************************************
512 * CLIPBOARD_RenderText
514 * Renders text to the clipboard buffer converting between UNIX and DOS formats.
516 * RETURNS: pointer to the WINE_CLIPFORMAT if successful, NULL otherwise
518 * FIXME: Should be a pair of driver functions that convert between OEM text and Windows.
521 static LPWINE_CLIPFORMAT CLIPBOARD_RenderText( UINT wFormat )
523 LPWINE_CLIPFORMAT lpSource = ClipFormats;
524 LPWINE_CLIPFORMAT lpTarget = NULL;
525 BOOL foundData = FALSE;
527 /* Asked for CF_TEXT */
528 if( wFormat == CF_TEXT)
530 if(ClipFormats[CF_TEXT-1].wDataPresent)
532 lpSource = &ClipFormats[CF_TEXT-1];
533 lpTarget = &ClipFormats[CF_TEXT-1];
534 foundData = TRUE;
535 TRACE("\t TEXT -> TEXT\n");
537 else if(ClipFormats[CF_UNICODETEXT-1].wDataPresent)
539 /* Convert UNICODETEXT -> TEXT */
540 lpSource = &ClipFormats[CF_UNICODETEXT-1];
541 lpTarget = &ClipFormats[CF_TEXT-1];
542 foundData = TRUE;
543 TRACE("\tUNICODETEXT -> TEXT\n");
545 else if(ClipFormats[CF_OEMTEXT-1].wDataPresent)
547 /* Convert OEMTEXT -> TEXT */
548 lpSource = &ClipFormats[CF_OEMTEXT-1];
549 lpTarget = &ClipFormats[CF_TEXT-1];
550 foundData = TRUE;
551 TRACE("\tOEMTEXT -> TEXT\n");
554 /* Asked for CF_OEMTEXT */
555 else if( wFormat == CF_OEMTEXT)
557 if(ClipFormats[CF_OEMTEXT-1].wDataPresent)
559 lpSource = &ClipFormats[CF_OEMTEXT-1];
560 lpTarget = &ClipFormats[CF_OEMTEXT-1];
561 foundData = TRUE;
562 TRACE("\tOEMTEXT -> OEMTEXT\n");
564 else if(ClipFormats[CF_UNICODETEXT-1].wDataPresent)
566 /* Convert UNICODETEXT -> OEMTEXT */
567 lpSource = &ClipFormats[CF_UNICODETEXT-1];
568 lpTarget = &ClipFormats[CF_OEMTEXT-1];
569 foundData = TRUE;
570 TRACE("\tUNICODETEXT -> OEMTEXT\n");
572 else if(ClipFormats[CF_TEXT-1].wDataPresent)
574 /* Convert TEXT -> OEMTEXT */
575 lpSource = &ClipFormats[CF_TEXT-1];
576 lpTarget = &ClipFormats[CF_OEMTEXT-1];
577 foundData = TRUE;
578 TRACE("\tTEXT -> OEMTEXT\n");
581 /* Asked for CF_UNICODETEXT */
582 else if( wFormat == CF_UNICODETEXT )
584 if(ClipFormats[CF_UNICODETEXT-1].wDataPresent)
586 lpSource = &ClipFormats[CF_UNICODETEXT-1];
587 lpTarget = &ClipFormats[CF_UNICODETEXT-1];
588 foundData = TRUE;
589 TRACE("\tUNICODETEXT -> UNICODETEXT\n");
591 else if(ClipFormats[CF_TEXT-1].wDataPresent)
593 /* Convert TEXT -> UNICODETEXT */
594 lpSource = &ClipFormats[CF_TEXT-1];
595 lpTarget = &ClipFormats[CF_UNICODETEXT-1];
596 foundData = TRUE;
597 TRACE("\tTEXT -> UNICODETEXT\n");
599 else if(ClipFormats[CF_OEMTEXT-1].wDataPresent)
601 /* Convert OEMTEXT -> UNICODETEXT */
602 lpSource = &ClipFormats[CF_OEMTEXT-1];
603 lpTarget = &ClipFormats[CF_UNICODETEXT-1];
604 foundData = TRUE;
605 TRACE("\tOEMTEXT -> UNICODETEXT\n");
608 if (!foundData)
610 if ((wFormat == CF_TEXT) || (wFormat == CF_OEMTEXT))
612 lpSource = &ClipFormats[CF_UNICODETEXT-1];
613 lpTarget = __lookup_format( ClipFormats, wFormat );
615 else
617 lpSource = __lookup_format( ClipFormats, wFormat );
618 lpTarget = lpSource;
622 /* First render the source text format */
623 if ( !lpSource || !CLIPBOARD_RenderFormat(lpSource) ) return NULL;
625 /* Convert to the desired target text format, if necessary */
626 if( lpTarget != lpSource && !lpTarget->hData16 && !lpTarget->hData32 )
628 INT src_chars, dst_chars, alloc_size;
629 LPCSTR lpstrS;
630 LPSTR lpstrT;
632 if (lpSource->hData32)
634 lpstrS = (LPSTR)GlobalLock(lpSource->hData32);
636 else
638 lpstrS = (LPSTR)GlobalLock16(lpSource->hData16);
641 if( !lpstrS ) return NULL;
643 /* Text always NULL terminated */
644 if(lpSource->wFormatID == CF_UNICODETEXT)
645 src_chars = strlenW((LPCWSTR)lpstrS)+1;
646 else
647 src_chars = strlen(lpstrS)+1;
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;
654 TRACE("\tconverting from '%s' to '%s', %i chars\n",
655 lpSource->Name, lpTarget->Name, src_chars);
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;
663 lpTarget->hData32 = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE, alloc_size);
664 lpstrT = (LPSTR)GlobalLock(lpTarget->hData32);
666 if( lpstrT )
668 CLIPBOARD_ConvertText(lpSource->wFormatID, lpstrS, src_chars,
669 lpTarget->wFormatID, lpstrT, dst_chars);
670 GlobalUnlock(lpTarget->hData32);
672 else
673 lpTarget->hData32 = 0;
675 /* Unlock source */
676 if (lpSource->hData32)
677 GlobalUnlock(lpSource->hData32);
678 else
679 GlobalUnlock16(lpSource->hData16);
682 return (lpTarget->hData16 || lpTarget->hData32) ? lpTarget : NULL;
685 /**************************************************************************
686 * CLIPBOARD_EnumClipboardFormats (internal)
688 static UINT CLIPBOARD_EnumClipboardFormats( UINT wFormat )
690 LPWINE_CLIPFORMAT lpFormat = ClipFormats;
691 BOOL bFormatPresent;
693 if (wFormat == 0) /* start from the beginning */
694 lpFormat = ClipFormats;
695 else
697 /* walk up to the specified format record */
699 if( !(lpFormat = __lookup_format( lpFormat, wFormat )) )
700 return 0;
701 lpFormat = lpFormat->NextFormat; /* right */
704 while(TRUE)
706 if (lpFormat == NULL) return 0;
708 if(CLIPBOARD_IsPresent(lpFormat->wFormatID))
709 break;
711 /* Query the driver if not yet in the cache */
712 if (!USER_Driver.pIsSelectionOwner())
714 if(lpFormat->wFormatID == CF_UNICODETEXT ||
715 lpFormat->wFormatID == CF_TEXT ||
716 lpFormat->wFormatID == CF_OEMTEXT)
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;
725 else
726 bFormatPresent = USER_Driver.pIsClipboardFormatAvailable(lpFormat->wFormatID);
728 if(bFormatPresent)
729 break;
732 lpFormat = lpFormat->NextFormat;
735 TRACE("Next available format %d\n", lpFormat->wFormatID);
737 return lpFormat->wFormatID;
741 /**************************************************************************
742 * WIN32 Clipboard implementation
743 **************************************************************************/
745 /**************************************************************************
746 * OpenClipboard (USER32.@)
748 * Note: Netscape uses NULL hWnd to open the clipboard.
750 BOOL WINAPI OpenClipboard( HWND hWnd )
752 BOOL bRet;
754 TRACE("(%04x)...\n", hWnd);
756 if (!hClipLock)
758 hClipLock = GetCurrentTask();
760 /* Save current user of the clipboard */
761 hWndClipWindow = WIN_GetFullHandle( hWnd );
762 bCBHasChanged = FALSE;
763 bRet = TRUE;
765 else bRet = FALSE;
767 TRACE(" returning %i\n", bRet);
768 return bRet;
772 /**************************************************************************
773 * CloseClipboard (USER.138)
775 BOOL16 WINAPI CloseClipboard16(void)
777 return CloseClipboard();
781 /**************************************************************************
782 * CloseClipboard (USER32.@)
784 BOOL WINAPI CloseClipboard(void)
786 TRACE("()\n");
788 if (hClipLock == GetCurrentTask())
790 hWndClipWindow = 0;
792 if (bCBHasChanged && hWndViewer) SendMessageW( hWndViewer, WM_DRAWCLIPBOARD, 0, 0 );
793 hClipLock = 0;
795 return TRUE;
799 /**************************************************************************
800 * EmptyClipboard (USER.139)
802 BOOL16 WINAPI EmptyClipboard16(void)
804 return EmptyClipboard();
808 /**************************************************************************
809 * EmptyClipboard (USER32.@)
810 * Empties and acquires ownership of the clipboard
812 BOOL WINAPI EmptyClipboard(void)
814 TRACE("()\n");
816 if (hClipLock != GetCurrentTask())
818 WARN("Clipboard not opened by calling task!\n");
819 return FALSE;
822 /* destroy private objects */
824 if (hWndClipOwner) SendMessageW( hWndClipOwner, WM_DESTROYCLIPBOARD, 0, 0 );
826 /* empty the cache */
827 CLIPBOARD_EmptyCache(TRUE);
829 /* Assign ownership of the clipboard to the current client */
830 hWndClipOwner = hWndClipWindow;
832 /* Save the current task */
833 hTaskClipOwner = GetCurrentTask();
835 /* Tell the driver to acquire the selection */
836 USER_Driver.pAcquireClipboard();
838 return TRUE;
842 /**************************************************************************
843 * GetClipboardOwner (USER32.@)
844 * FIXME: Can't return the owner if the clipbard is owned by an external app
846 HWND WINAPI GetClipboardOwner(void)
848 TRACE("()\n");
849 return hWndClipOwner;
853 /**************************************************************************
854 * SetClipboardData (USER.141)
856 HANDLE16 WINAPI SetClipboardData16( UINT16 wFormat, HANDLE16 hData )
858 LPWINE_CLIPFORMAT lpFormat = __lookup_format( ClipFormats, wFormat );
860 TRACE("(%04X, %04x) !\n", wFormat, hData);
862 /* NOTE: If the hData is zero and current owner doesn't match
863 * the window that opened the clipboard then this application
864 * is screwed because WM_RENDERFORMAT will go to the owner.
865 * (to become the owner it must call EmptyClipboard() before
866 * adding new data).
869 if( CLIPBOARD_IsLocked() || !lpFormat ||
870 (!hData && (!hWndClipOwner || (hWndClipOwner != hWndClipWindow))) )
872 WARN("Invalid hData or clipboard not opened by calling task!\n");
873 return 0;
876 /* Pass on the request to the driver */
877 USER_Driver.pSetClipboardData(wFormat);
879 if ( lpFormat->wDataPresent || lpFormat->hData16 || lpFormat->hData32 )
881 CLIPBOARD_DeleteRecord(lpFormat, TRUE);
883 /* delete existing CF_UNICODETEXT/CF_TEXT/CF_OEMTEXT aliases */
884 if(wFormat == CF_UNICODETEXT)
886 CLIPBOARD_DeleteRecord(&ClipFormats[CF_TEXT-1], TRUE);
887 CLIPBOARD_DeleteRecord(&ClipFormats[CF_OEMTEXT-1], TRUE);
889 else if(wFormat == CF_TEXT)
891 CLIPBOARD_DeleteRecord(&ClipFormats[CF_UNICODETEXT-1], TRUE);
892 CLIPBOARD_DeleteRecord(&ClipFormats[CF_OEMTEXT-1], TRUE);
894 else if(wFormat == CF_OEMTEXT)
896 CLIPBOARD_DeleteRecord(&ClipFormats[CF_UNICODETEXT-1], TRUE);
897 CLIPBOARD_DeleteRecord(&ClipFormats[CF_TEXT-1], TRUE);
901 bCBHasChanged = TRUE;
902 lpFormat->wDataPresent = 1;
903 lpFormat->hData16 = hData; /* 0 is legal, see WM_RENDERFORMAT */
904 lpFormat->hData32 = 0;
906 return lpFormat->hData16;
910 /**************************************************************************
911 * SetClipboardData (USER32.@)
913 HANDLE WINAPI SetClipboardData( UINT wFormat, HANDLE hData )
915 LPWINE_CLIPFORMAT lpFormat = __lookup_format( ClipFormats, wFormat );
917 TRACE("(%08X, %08x) !\n", wFormat, hData);
919 /* NOTE: If the hData is zero and current owner doesn't match
920 * the window that opened the clipboard then this application
921 * is screwed because WM_RENDERFORMAT will go to the owner.
922 * (to become the owner it must call EmptyClipboard() before
923 * adding new data).
926 if( CLIPBOARD_IsLocked() || !lpFormat ||
927 (!hData && (!hWndClipOwner || (hWndClipOwner != hWndClipWindow))) )
929 WARN("Invalid hData or clipboard not opened by calling task!\n");
930 return 0;
933 /* Tell the driver to acquire the selection */
934 USER_Driver.pAcquireClipboard();
936 if ( lpFormat->wDataPresent &&
937 (lpFormat->hData16 || lpFormat->hData32) )
939 CLIPBOARD_DeleteRecord(lpFormat, TRUE);
941 /* delete existing CF_UNICODETEXT/CF_TEXT/CF_OEMTEXT aliases */
942 if(wFormat == CF_UNICODETEXT)
944 CLIPBOARD_DeleteRecord(&ClipFormats[CF_TEXT-1], TRUE);
945 CLIPBOARD_DeleteRecord(&ClipFormats[CF_OEMTEXT-1], TRUE);
947 else if(wFormat == CF_TEXT)
949 CLIPBOARD_DeleteRecord(&ClipFormats[CF_UNICODETEXT-1], TRUE);
950 CLIPBOARD_DeleteRecord(&ClipFormats[CF_OEMTEXT-1], TRUE);
952 else if(wFormat == CF_OEMTEXT)
954 CLIPBOARD_DeleteRecord(&ClipFormats[CF_UNICODETEXT-1], TRUE);
955 CLIPBOARD_DeleteRecord(&ClipFormats[CF_TEXT-1], TRUE);
959 bCBHasChanged = TRUE;
960 lpFormat->wDataPresent = 1;
961 lpFormat->hDataSrc32 = hData; /* Save the source handle */
964 * Make a shared duplicate if the memory is not shared
965 * TODO: What should be done for non-memory objects
967 if ( CLIPBOARD_IsMemoryObject(wFormat) && hData && !(GlobalFlags(hData) & GMEM_DDESHARE) )
968 lpFormat->hData32 = CLIPBOARD_GlobalDupMem( hData );
969 else
970 lpFormat->hData32 = hData; /* 0 is legal, see WM_RENDERFORMAT */
972 lpFormat->hData16 = 0;
974 return lpFormat->hData32; /* Should we return lpFormat->hDataSrc32 */
978 /**************************************************************************
979 * GetClipboardData (USER.142)
981 HANDLE16 WINAPI GetClipboardData16( UINT16 wFormat )
983 LPWINE_CLIPFORMAT lpRender = ClipFormats;
985 TRACE("(%04X)\n", wFormat);
987 if (CLIPBOARD_IsLocked())
989 WARN("Clipboard not opened by calling task!\n");
990 return 0;
993 if( wFormat == CF_UNICODETEXT || wFormat == CF_TEXT || wFormat == CF_OEMTEXT )
995 lpRender = CLIPBOARD_RenderText(wFormat);
996 if ( !lpRender ) return 0;
998 else
1000 lpRender = __lookup_format( ClipFormats, wFormat );
1001 if( !lpRender || !CLIPBOARD_RenderFormat(lpRender) ) return 0;
1004 /* Convert between 32 -> 16 bit data, if necessary */
1005 if( lpRender->hData32 && !lpRender->hData16
1006 && CLIPBOARD_IsMemoryObject(wFormat) )
1008 int size;
1009 if( lpRender->wFormatID == CF_METAFILEPICT )
1010 size = sizeof( METAFILEPICT16 );
1011 else
1012 size = GlobalSize(lpRender->hData32);
1014 lpRender->hData16 = GlobalAlloc16(GMEM_ZEROINIT, size);
1015 if( !lpRender->hData16 )
1016 ERR("(%04X) -- not enough memory in 16b heap\n", wFormat);
1017 else
1019 if( lpRender->wFormatID == CF_METAFILEPICT )
1021 FIXME("\timplement function CopyMetaFilePict32to16\n");
1022 FIXME("\tin the appropriate file.\n");
1023 #ifdef SOMEONE_IMPLEMENTED_ME
1024 CopyMetaFilePict32to16( GlobalLock16(lpRender->hData16),
1025 GlobalLock(lpRender->hData32) );
1026 #endif
1028 else
1030 memcpy( GlobalLock16(lpRender->hData16),
1031 GlobalLock(lpRender->hData32),
1032 size );
1034 GlobalUnlock16(lpRender->hData16);
1035 GlobalUnlock(lpRender->hData32);
1039 TRACE("\treturning %04x (type %i)\n",
1040 lpRender->hData16, lpRender->wFormatID);
1041 return lpRender->hData16;
1045 /**************************************************************************
1046 * GetClipboardData (USER32.@)
1048 HANDLE WINAPI GetClipboardData( UINT wFormat )
1050 LPWINE_CLIPFORMAT lpRender = ClipFormats;
1052 TRACE("(%08X)\n", wFormat);
1054 if (CLIPBOARD_IsLocked())
1056 WARN("Clipboard not opened by calling task!\n");
1057 return 0;
1060 if( wFormat == CF_UNICODETEXT || wFormat == CF_TEXT || wFormat == CF_OEMTEXT )
1062 lpRender = CLIPBOARD_RenderText(wFormat);
1063 if ( !lpRender ) return 0;
1065 else
1067 lpRender = __lookup_format( ClipFormats, wFormat );
1068 if( !lpRender || !CLIPBOARD_RenderFormat(lpRender) ) return 0;
1071 /* Convert between 16 -> 32 bit data, if necessary */
1072 if( lpRender->hData16 && !lpRender->hData32
1073 && CLIPBOARD_IsMemoryObject(wFormat) )
1075 int size;
1076 if( lpRender->wFormatID == CF_METAFILEPICT )
1077 size = sizeof( METAFILEPICT );
1078 else
1079 size = GlobalSize16(lpRender->hData16);
1080 lpRender->hData32 = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE,
1081 size);
1082 if( lpRender->wFormatID == CF_METAFILEPICT )
1084 FIXME("\timplement function CopyMetaFilePict16to32\n");
1085 FIXME("\tin the appropriate file.\n");
1086 #ifdef SOMEONE_IMPLEMENTED_ME
1087 CopyMetaFilePict16to32( GlobalLock16(lpRender->hData32),
1088 GlobalLock(lpRender->hData16) );
1089 #endif
1091 else
1093 memcpy( GlobalLock(lpRender->hData32),
1094 GlobalLock16(lpRender->hData16),
1095 size );
1097 GlobalUnlock(lpRender->hData32);
1098 GlobalUnlock16(lpRender->hData16);
1101 TRACE("\treturning %04x (type %i)\n",
1102 lpRender->hData32, lpRender->wFormatID);
1103 return lpRender->hData32;
1107 /**************************************************************************
1108 * CountClipboardFormats (USER.143)
1110 INT16 WINAPI CountClipboardFormats16(void)
1112 return CountClipboardFormats();
1116 /**************************************************************************
1117 * CountClipboardFormats (USER32.@)
1119 INT WINAPI CountClipboardFormats(void)
1121 INT FormatCount = 0;
1122 LPWINE_CLIPFORMAT lpFormat = ClipFormats;
1124 TRACE("()\n");
1126 while(TRUE)
1128 if (lpFormat == NULL) break;
1130 if( lpFormat->wFormatID != CF_TEXT ) /* Don't count CF_TEXT */
1133 * The format is available if either:
1134 * 1. The data is already in the cache.
1135 * 2. The selection is not owned by us(WINE) and the data is
1136 * available to the clipboard driver.
1138 if ( lpFormat->wDataPresent ||
1139 ( !USER_Driver.pIsSelectionOwner()
1140 && USER_Driver.pIsClipboardFormatAvailable( lpFormat->wFormatID ) ) )
1142 TRACE("\tdata found for format 0x%04x(%s)\n",
1143 lpFormat->wFormatID, CLIPBOARD_GetFormatName(lpFormat->wFormatID, NULL, 0));
1144 FormatCount++;
1148 lpFormat = lpFormat->NextFormat;
1151 /* these are equivalent, adjust the total */
1152 FormatCount += (ClipFormats[CF_UNICODETEXT-1].wDataPresent ||
1153 ClipFormats[CF_TEXT-1].wDataPresent ||
1154 ClipFormats[CF_OEMTEXT-1].wDataPresent) ? 1 : 0;
1156 TRACE("\ttotal %d\n", FormatCount);
1157 return FormatCount;
1160 /**************************************************************************
1161 * EnumClipboardFormats (USER.144)
1163 UINT16 WINAPI EnumClipboardFormats16( UINT16 wFormat )
1165 return EnumClipboardFormats( wFormat );
1169 /**************************************************************************
1170 * EnumClipboardFormats (USER32.@)
1172 UINT WINAPI EnumClipboardFormats( UINT wFormat )
1174 TRACE("(%04X)\n", wFormat);
1176 if (CLIPBOARD_IsLocked())
1178 WARN("Clipboard not opened by calling task!\n");
1179 return 0;
1182 return CLIPBOARD_EnumClipboardFormats(wFormat);
1186 /**************************************************************************
1187 * RegisterClipboardFormatA (USER32.@)
1189 UINT WINAPI RegisterClipboardFormatA( LPCSTR FormatName )
1191 LPWINE_CLIPFORMAT lpNewFormat;
1192 LPWINE_CLIPFORMAT lpFormat = ClipFormats;
1194 if (FormatName == NULL) return 0;
1196 TRACE("('%s') !\n", FormatName);
1198 /* walk format chain to see if it's already registered */
1200 while(TRUE)
1202 if ( !strcasecmp(lpFormat->Name,FormatName) )
1204 lpFormat->wRefCount++;
1205 return lpFormat->wFormatID;
1208 if ( lpFormat->NextFormat == NULL ) break;
1210 lpFormat = lpFormat->NextFormat;
1213 /* allocate storage for new format entry */
1215 lpNewFormat = (LPWINE_CLIPFORMAT)HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CLIPFORMAT));
1216 if(lpNewFormat == NULL) {
1217 WARN("No more memory for a new format!\n");
1218 return 0;
1220 lpFormat->NextFormat = lpNewFormat;
1221 lpNewFormat->wRefCount = 1;
1223 if (!(lpNewFormat->Name = HeapAlloc(GetProcessHeap(), 0, strlen(FormatName)+1 )))
1225 WARN("No more memory for the new format name!\n");
1226 HeapFree(GetProcessHeap(), 0, lpNewFormat);
1227 return 0;
1229 strcpy( lpNewFormat->Name, FormatName );
1230 CharLowerA(lpNewFormat->Name);
1232 lpNewFormat->wDataPresent = 0;
1233 lpNewFormat->hData16 = 0;
1234 lpNewFormat->hDataSrc32 = 0;
1235 lpNewFormat->hData32 = 0;
1236 lpNewFormat->drvData = 0;
1237 lpNewFormat->PrevFormat = lpFormat;
1238 lpNewFormat->NextFormat = NULL;
1240 /* Pass on the registration request to the driver */
1241 lpNewFormat->wFormatID = USER_Driver.pRegisterClipboardFormat(lpNewFormat->Name);
1243 TRACE("Registering format(%d): %s\n", lpNewFormat->wFormatID, FormatName);
1244 return lpNewFormat->wFormatID;
1248 /**************************************************************************
1249 * RegisterClipboardFormat (USER.145)
1251 UINT16 WINAPI RegisterClipboardFormat16( LPCSTR FormatName )
1253 return RegisterClipboardFormatA( FormatName );
1257 /**************************************************************************
1258 * RegisterClipboardFormatW (USER32.@)
1260 UINT WINAPI RegisterClipboardFormatW( LPCWSTR formatName )
1262 LPSTR aFormat = HEAP_strdupWtoA( GetProcessHeap(), 0, formatName );
1263 UINT ret = RegisterClipboardFormatA( aFormat );
1264 HeapFree( GetProcessHeap(), 0, aFormat );
1265 return ret;
1269 /**************************************************************************
1270 * GetClipboardFormatName (USER.146)
1272 INT16 WINAPI GetClipboardFormatName16( UINT16 wFormat, LPSTR retStr, INT16 maxlen )
1274 return GetClipboardFormatNameA( wFormat, retStr, maxlen );
1278 /**************************************************************************
1279 * GetClipboardFormatNameA (USER32.@)
1281 INT WINAPI GetClipboardFormatNameA( UINT wFormat, LPSTR retStr, INT maxlen )
1283 LPWINE_CLIPFORMAT lpFormat = __lookup_format( ClipFormats, wFormat );
1285 TRACE("(%04X, %p, %d) !\n", wFormat, retStr, maxlen);
1287 if (lpFormat == NULL || lpFormat->Name == NULL)
1289 /* Check if another wine process already registered the format */
1290 if (wFormat && !USER_Driver.pGetClipboardFormatName(wFormat, retStr, maxlen))
1292 RegisterClipboardFormatA(retStr); /* Make a cache entry */
1293 return strlen(retStr);
1295 else
1297 TRACE("wFormat=%d not found\n", wFormat);
1298 return 0;
1302 TRACE("Name='%s' !\n", lpFormat->Name);
1304 lstrcpynA( retStr, lpFormat->Name, maxlen );
1305 return strlen(retStr);
1309 /**************************************************************************
1310 * GetClipboardFormatNameW (USER32.@)
1312 INT WINAPI GetClipboardFormatNameW( UINT wFormat, LPWSTR retStr, INT maxlen )
1314 INT ret;
1315 LPSTR p = HeapAlloc( GetProcessHeap(), 0, maxlen );
1316 if(p == NULL) return 0; /* FIXME: is this the correct failure value? */
1318 ret = GetClipboardFormatNameA( wFormat, p, maxlen );
1320 if (maxlen > 0 && !MultiByteToWideChar( CP_ACP, 0, p, -1, retStr, maxlen ))
1321 retStr[maxlen-1] = 0;
1322 HeapFree( GetProcessHeap(), 0, p );
1323 return ret;
1327 /**************************************************************************
1328 * SetClipboardViewer (USER32.@)
1330 HWND WINAPI SetClipboardViewer( HWND hWnd )
1332 HWND hwndPrev = hWndViewer;
1334 TRACE("(%04x): returning %04x\n", hWnd, hwndPrev);
1336 hWndViewer = WIN_GetFullHandle( hWnd );
1337 return hwndPrev;
1341 /**************************************************************************
1342 * GetClipboardViewer (USER32.@)
1344 HWND WINAPI GetClipboardViewer(void)
1346 TRACE("()\n");
1347 return hWndViewer;
1351 /**************************************************************************
1352 * ChangeClipboardChain (USER32.@)
1354 BOOL WINAPI ChangeClipboardChain(HWND hWnd, HWND hWndNext)
1356 BOOL bRet = 0;
1358 FIXME("(0x%04x, 0x%04x): stub?\n", hWnd, hWndNext);
1360 if( hWndViewer )
1361 bRet = !SendMessageW( hWndViewer, WM_CHANGECBCHAIN, (WPARAM)hWnd, (LPARAM)hWndNext );
1362 else
1363 WARN("hWndViewer is lost\n");
1365 if( WIN_GetFullHandle(hWnd) == hWndViewer ) hWndViewer = WIN_GetFullHandle( hWndNext );
1367 return bRet;
1371 /**************************************************************************
1372 * IsClipboardFormatAvailable (USER.193)
1374 BOOL16 WINAPI IsClipboardFormatAvailable16( UINT16 wFormat )
1376 return IsClipboardFormatAvailable( wFormat );
1380 /**************************************************************************
1381 * IsClipboardFormatAvailable (USER32.@)
1383 BOOL WINAPI IsClipboardFormatAvailable( UINT wFormat )
1385 BOOL bRet;
1387 if (wFormat == 0) /* Reject this case quickly */
1388 bRet = FALSE;
1389 else
1391 UINT iret = CLIPBOARD_EnumClipboardFormats(wFormat - 1);
1392 if ((wFormat == CF_TEXT) || (wFormat == CF_OEMTEXT) || (wFormat == CF_UNICODETEXT))
1393 bRet = ((iret == CF_TEXT) || (iret == CF_OEMTEXT) || (iret == CF_UNICODETEXT));
1394 else
1395 bRet = iret == wFormat;
1397 TRACE("(%04X)- ret(%d)\n", wFormat, bRet);
1398 return bRet;
1402 /**************************************************************************
1403 * GetOpenClipboardWindow (USER32.@)
1404 * FIXME: This wont work if an external app owns the selection
1406 HWND WINAPI GetOpenClipboardWindow(void)
1408 TRACE("()\n");
1409 return hWndClipWindow;
1413 /**************************************************************************
1414 * GetPriorityClipboardFormat (USER32.@)
1416 INT WINAPI GetPriorityClipboardFormat( UINT *list, INT nCount )
1418 int i;
1419 TRACE("()\n");
1421 if(CountClipboardFormats() == 0) return 0;
1423 for (i = 0; i < nCount; i++)
1424 if (IsClipboardFormatAvailable( list[i] )) return list[i];
1425 return -1;
1429 /**************************************************************************
1430 * GetClipboardSequenceNumber (USER32.@)
1431 * Supported on Win2k/Win98
1432 * MSDN: Windows clipboard code keeps a serial number for the clipboard
1433 * for each window station. The number is incremented whenever the
1434 * contents change or are emptied.
1435 * If you do not have WINSTA_ACCESSCLIPBOARD then the function returns 0
1437 DWORD WINAPI GetClipboardSequenceNumber(VOID)
1439 FIXME("Returning 0, see windows/clipboard.c\n");
1440 /* FIXME: Use serial numbers */
1441 return 0;