Yet another major reorganization and a few new features.
[wine/wine64.git] / windows / clipboard.c
blob76e113baf011fccb4f26dc87169c57f23ac02bcb
1 /*
2 * WIN32 clipboard implementation
4 * Copyright 1994 Martin Ayotte
5 * 1996 Alex Korobka
6 * 1999 Noel Borthwick
8 * NOTES:
9 * This file contains the implementation for the WIN32 Clipboard API
10 * and Wine's internal clipboard cache.
11 * The actual contents of the clipboard are held in the clipboard cache.
12 * The internal implementation talks to a "clipboard driver" to fill or
13 * expose the cache to the native device. (Currently only the X11 and
14 * TTY clipboard driver are available)
16 * TODO:
20 #include <stdlib.h>
21 #include <sys/types.h>
22 #include <fcntl.h>
23 #include <unistd.h>
24 #include <string.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "winuser.h"
30 #include "wine/winuser16.h"
31 #include "wine/winbase16.h"
32 #include "heap.h"
33 #include "message.h"
34 #include "user.h"
35 #include "clipboard.h"
36 #include "debugtools.h"
38 DEFAULT_DEBUG_CHANNEL(clipboard);
40 #define CF_REGFORMATBASE 0xC000
42 /**************************************************************************
43 * Clipboard context global variables
46 static HANDLE hClipLock = 0;
47 static BOOL bCBHasChanged = FALSE;
49 HWND hWndClipWindow = 0; /* window that last opened clipboard */
50 HWND hWndClipOwner = 0; /* current clipboard owner */
51 HANDLE16 hTaskClipOwner = 0; /* clipboard owner's task */
52 static HWND hWndViewer = 0; /* start of viewers chain */
54 static WORD LastRegFormat = CF_REGFORMATBASE;
56 /* Clipboard cache initial data.
57 * WARNING: This data ordering is dependent on the WINE_CLIPFORMAT structure
58 * declared in clipboard.h
60 WINE_CLIPFORMAT ClipFormats[] = {
61 { CF_TEXT, 1, 0, "Text", 0, 0, 0, 0, NULL, &ClipFormats[1]},
62 { CF_BITMAP, 1, 0, "Bitmap", 0, 0, 0, 0, &ClipFormats[0], &ClipFormats[2]},
63 { CF_METAFILEPICT, 1, 0, "MetaFile Picture", 0, 0, 0, 0, &ClipFormats[1], &ClipFormats[3]},
64 { CF_SYLK, 1, 0, "Sylk", 0, 0, 0, 0, &ClipFormats[2], &ClipFormats[4]},
65 { CF_DIF, 1, 0, "DIF", 0, 0, 0, 0, &ClipFormats[3], &ClipFormats[5]},
66 { CF_TIFF, 1, 0, "TIFF", 0, 0, 0, 0, &ClipFormats[4], &ClipFormats[6]},
67 { CF_OEMTEXT, 1, 0, "OEM Text", 0, 0, 0, 0, &ClipFormats[5], &ClipFormats[7]},
68 { CF_DIB, 1, 0, "DIB", 0, 0, 0, 0, &ClipFormats[6], &ClipFormats[8]},
69 { CF_PALETTE, 1, 0, "Palette", 0, 0, 0, 0, &ClipFormats[7], &ClipFormats[9]},
70 { CF_PENDATA, 1, 0, "PenData", 0, 0, 0, 0, &ClipFormats[8], &ClipFormats[10]},
71 { CF_RIFF, 1, 0, "RIFF", 0, 0, 0, 0, &ClipFormats[9], &ClipFormats[11]},
72 { CF_WAVE, 1, 0, "Wave", 0, 0, 0, 0, &ClipFormats[10], &ClipFormats[12]},
73 { CF_UNICODETEXT, 1, 0, "Unicode Text", 0, 0, 0, 0, &ClipFormats[11], &ClipFormats[13]},
74 { CF_OWNERDISPLAY, 1, 0, "Owner Display", 0, 0, 0, 0, &ClipFormats[12], &ClipFormats[14]},
75 { CF_DSPTEXT, 1, 0, "DSPText", 0, 0, 0, 0, &ClipFormats[13], &ClipFormats[15]},
76 { CF_DSPMETAFILEPICT, 1, 0, "DSPMetaFile Picture", 0, 0, 0, 0, &ClipFormats[14], &ClipFormats[16]},
77 { CF_DSPBITMAP, 1, 0, "DSPBitmap", 0, 0, 0, 0, &ClipFormats[15], &ClipFormats[17]},
78 { CF_HDROP, 1, 0, "HDROP", 0, 0, 0, 0, &ClipFormats[16], NULL}
82 /**************************************************************************
83 * Internal Clipboard implementation methods
84 **************************************************************************/
87 /**************************************************************************
88 * CLIPBOARD_LookupFormat
90 static LPWINE_CLIPFORMAT __lookup_format( LPWINE_CLIPFORMAT lpFormat, WORD wID )
92 while(TRUE)
94 if (lpFormat == NULL ||
95 lpFormat->wFormatID == wID) break;
96 lpFormat = lpFormat->NextFormat;
98 return lpFormat;
101 LPWINE_CLIPFORMAT CLIPBOARD_LookupFormat( WORD wID )
103 return __lookup_format( ClipFormats, wID );
106 /**************************************************************************
107 * CLIPBOARD_IsLocked
108 * Check if the clipboard cache is available to the caller
110 BOOL CLIPBOARD_IsLocked()
112 BOOL bIsLocked = TRUE;
113 HANDLE16 hTaskCur = GetCurrentTask();
116 * The clipboard is available:
117 * 1. if the caller's task has opened the clipboard,
118 * or
119 * 2. if the caller is the clipboard owners task, AND is responding to a
120 * WM_RENDERFORMAT message.
122 if ( hClipLock == hTaskCur )
123 bIsLocked = FALSE;
125 else if ( hTaskCur == hTaskClipOwner )
127 /* Check if we're currently executing inside a window procedure
128 * called in response to a WM_RENDERFORMAT message. A WM_RENDERFORMAT
129 * handler is not permitted to open the clipboard since it has been opened
130 * by another client. However the handler must have access to the
131 * clipboard in order to update data in response to this message.
133 #if 0
134 MESSAGEQUEUE *queue = QUEUE_Lock( GetFastQueue16() );
136 if ( queue
137 && queue->smWaiting
138 && queue->smWaiting->msg == WM_RENDERFORMAT
139 && queue->smWaiting->hSrcQueue
141 bIsLocked = FALSE;
143 QUEUE_Unlock( queue );
144 #else
145 /* FIXME: queue check no longer possible */
146 bIsLocked = FALSE;
147 #endif
150 return bIsLocked;
153 /**************************************************************************
154 * CLIPBOARD_ReleaseOwner
155 * Gives up ownership of the clipboard
157 void CLIPBOARD_ReleaseOwner()
159 hWndClipOwner = 0;
160 hTaskClipOwner = 0;
163 /**************************************************************************
164 * CLIPBOARD_GlobalFreeProc
166 * This is a callback mechanism to allow HGLOBAL data to be released in
167 * the context of the process which allocated it. We post a WM_TIMER message
168 * to the owner window(in CLIPBOARD_DeleteRecord) and destroy the data(in idEvent)
169 * in this WndProc, which is invoked when the apps message loop calls DispatchMessage.
170 * This technique is discussed in Matt Pietrek's "Under the Hood".
171 * An article describing the same may be found in MSDN by searching for WM_TIMER.
172 * Note that this mechanism will probably stop working when WINE supports
173 * address space separation. When "queue events" are implemented in Wine we
174 * should switch to using that mechanism, since it is more robust and does not
175 * require a procedure address to be passed. See the SetWinEventHook API for
176 * more info on this.
178 VOID CALLBACK CLIPBOARD_GlobalFreeProc( HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime )
180 /* idEvent is the HGLOBAL to be deleted */
181 GlobalFree( (HGLOBAL)idEvent );
184 /**************************************************************************
185 * CLIPBOARD_DeleteRecord
187 void CLIPBOARD_DeleteRecord(LPWINE_CLIPFORMAT lpFormat, BOOL bChange)
189 if( (lpFormat->wFormatID >= CF_GDIOBJFIRST &&
190 lpFormat->wFormatID <= CF_GDIOBJLAST) || lpFormat->wFormatID == CF_BITMAP
191 || lpFormat->wFormatID == CF_PALETTE)
193 if (lpFormat->hData32)
194 DeleteObject(lpFormat->hData32);
195 if (lpFormat->hData16)
196 DeleteObject(lpFormat->hData16);
198 else if( lpFormat->wFormatID == CF_METAFILEPICT )
200 if (lpFormat->hData32)
202 DeleteMetaFile( ((METAFILEPICT *)GlobalLock( lpFormat->hData32 ))->hMF );
203 PostMessageA(hWndClipOwner, WM_TIMER,
204 (WPARAM)lpFormat->hData32, (LPARAM)CLIPBOARD_GlobalFreeProc);
205 if (lpFormat->hDataSrc32)
207 /* Release lpFormat->hData32 in the context of the process which created it.
208 * See CLIPBOARD_GlobalFreeProc for more details about this technique.
209 * GlobalFree(lpFormat->hDataSrc32);
211 PostMessageA(hWndClipOwner, WM_TIMER,
212 (WPARAM)lpFormat->hDataSrc32, (LPARAM)CLIPBOARD_GlobalFreeProc);
215 if (lpFormat->hData16)
216 /* HMETAFILE16 and HMETAFILE32 are apparently the same thing,
217 and a shallow copy is enough to share a METAFILEPICT
218 structure between 16bit and 32bit clipboards. The MetaFile
219 should of course only be deleted once. */
220 GlobalFree16(lpFormat->hData16);
222 if (lpFormat->hData16)
224 DeleteMetaFile16( ((METAFILEPICT16 *)GlobalLock16( lpFormat->hData16 ))->hMF );
225 GlobalFree16(lpFormat->hData16);
228 else
230 if (lpFormat->hData32)
232 /* Release lpFormat->hData32 in the context of the process which created it.
233 * See CLIPBOARD_GlobalFreeProc for more details about this technique.
234 * GlobalFree( lpFormat->hData32 );
236 PostMessageA(hWndClipOwner, WM_TIMER,
237 (WPARAM)lpFormat->hData32, (LPARAM)CLIPBOARD_GlobalFreeProc);
239 if (lpFormat->hDataSrc32)
241 /* Release lpFormat->hData32 in the context of the process which created it.
242 * See CLIPBOARD_GlobalFreeProc for more details about this technique.
243 * GlobalFree(lpFormat->hDataSrc32);
245 PostMessageA(hWndClipOwner, WM_TIMER,
246 (WPARAM)lpFormat->hDataSrc32, (LPARAM)CLIPBOARD_GlobalFreeProc);
248 if (lpFormat->hData16)
249 GlobalFree16(lpFormat->hData16);
252 lpFormat->wDataPresent = 0;
253 lpFormat->hData16 = 0;
254 lpFormat->hData32 = 0;
255 lpFormat->hDataSrc32 = 0;
256 lpFormat->drvData = 0;
258 if( bChange ) bCBHasChanged = TRUE;
261 /**************************************************************************
262 * CLIPBOARD_EmptyCache
264 void CLIPBOARD_EmptyCache( BOOL bChange )
266 LPWINE_CLIPFORMAT lpFormat = ClipFormats;
268 while(lpFormat)
270 if ( lpFormat->wDataPresent || lpFormat->hData16 || lpFormat->hData32 )
271 CLIPBOARD_DeleteRecord( lpFormat, bChange );
273 lpFormat = lpFormat->NextFormat;
277 /**************************************************************************
278 * CLIPBOARD_IsPresent
280 BOOL CLIPBOARD_IsPresent(WORD wFormat)
282 /* special case */
284 if( wFormat == CF_TEXT || wFormat == CF_OEMTEXT || wFormat == CF_UNICODETEXT )
285 return ClipFormats[CF_TEXT-1].wDataPresent ||
286 ClipFormats[CF_OEMTEXT-1].wDataPresent ||
287 ClipFormats[CF_UNICODETEXT-1].wDataPresent;
288 else
290 LPWINE_CLIPFORMAT lpFormat = __lookup_format( ClipFormats, wFormat );
291 if( lpFormat ) return (lpFormat->wDataPresent);
293 return FALSE;
296 /**************************************************************************
297 * CLIPBOARD_IsCacheRendered
298 * Checks if any data needs to be rendered to the clipboard cache
299 * RETURNS:
300 * TRUE - All clipboard data is available in the cache
301 * FALSE - Some data is marked for delayed render and needs rendering
303 BOOL CLIPBOARD_IsCacheRendered()
305 LPWINE_CLIPFORMAT lpFormat = ClipFormats;
307 /* check if all formats were rendered */
308 while(lpFormat)
310 if( lpFormat->wDataPresent && !lpFormat->hData16 && !lpFormat->hData32 )
311 return FALSE;
313 lpFormat = lpFormat->NextFormat;
316 return TRUE;
320 /**************************************************************************
321 * CLIPBOARD_IsMemoryObject
322 * Tests if the clipboard format specifies a memory object
324 BOOL CLIPBOARD_IsMemoryObject( WORD wFormat )
326 switch(wFormat)
328 case CF_BITMAP:
329 case CF_METAFILEPICT:
330 case CF_DSPTEXT:
331 case CF_ENHMETAFILE:
332 case CF_HDROP:
333 case CF_PALETTE:
334 case CF_PENDATA:
335 return FALSE;
336 default:
337 return TRUE;
341 /***********************************************************************
342 * CLIPBOARD_GlobalDupMem( HGLOBAL )
343 * Helper method to duplicate an HGLOBAL chunk of memory into shared memory
345 HGLOBAL CLIPBOARD_GlobalDupMem( HGLOBAL hGlobalSrc )
347 HGLOBAL hGlobalDest;
348 PVOID pGlobalSrc, pGlobalDest;
349 DWORD cBytes;
351 if ( !hGlobalSrc )
352 return 0;
354 cBytes = GlobalSize(hGlobalSrc);
355 if ( 0 == cBytes )
356 return 0;
358 /* Turn on the DDESHARE and _MOVEABLE flags explicitly */
359 hGlobalDest = GlobalAlloc( GlobalFlags(hGlobalSrc) | GMEM_DDESHARE | GMEM_MOVEABLE,
360 cBytes );
361 if ( !hGlobalDest )
362 return 0;
364 pGlobalSrc = GlobalLock(hGlobalSrc);
365 pGlobalDest = GlobalLock(hGlobalDest);
366 if ( !pGlobalSrc || !pGlobalDest )
367 return 0;
369 memcpy(pGlobalDest, pGlobalSrc, cBytes);
371 GlobalUnlock(hGlobalSrc);
372 GlobalUnlock(hGlobalDest);
374 return hGlobalDest;
377 /**************************************************************************
378 * CLIPBOARD_GetFormatName
379 * Gets the format name associated with an ID
381 char * CLIPBOARD_GetFormatName(UINT wFormat)
383 LPWINE_CLIPFORMAT lpFormat = __lookup_format( ClipFormats, wFormat );
384 return (lpFormat) ? lpFormat->Name : NULL;
388 /**************************************************************************
389 * CLIPBOARD_RenderFormat
391 static BOOL CLIPBOARD_RenderFormat(LPWINE_CLIPFORMAT lpFormat)
394 * If WINE is not the selection owner, and the format is available
395 * we must ask the driver to render the data to the clipboard cache.
397 TRACE("enter format=%d\n", lpFormat->wFormatID);
398 if ( !USER_Driver.pIsSelectionOwner()
399 && USER_Driver.pIsClipboardFormatAvailable( lpFormat->wFormatID ) )
401 if ( !USER_Driver.pGetClipboardData( lpFormat->wFormatID ) )
402 return FALSE;
405 * If Wine owns the clipboard, and the data is marked for delayed render,
406 * render it now.
408 else if( lpFormat->wDataPresent && !lpFormat->hData16 && !lpFormat->hData32 )
410 if( IsWindow(hWndClipOwner) )
412 /* Send a WM_RENDERFORMAT message to notify the owner to render the
413 * data requested into the clipboard.
415 TRACE("Sending WM_RENDERFORMAT message\n");
416 SendMessage16(hWndClipOwner,WM_RENDERFORMAT,
417 (WPARAM16)lpFormat->wFormatID,0L);
419 else
421 WARN("\thWndClipOwner (%04x) is lost!\n",
422 hWndClipOwner);
423 CLIPBOARD_ReleaseOwner();
424 lpFormat->wDataPresent = 0;
425 return FALSE;
429 return (lpFormat->hData16 || lpFormat->hData32) ? TRUE : FALSE;
432 /**************************************************************************
433 * CLIPBOARD_ConvertText
434 * Returns number of required/converted characters - not bytes!
436 static INT CLIPBOARD_ConvertText(WORD src_fmt, void const *src, INT src_size,
437 WORD dst_fmt, void *dst, INT dst_size)
439 UINT cp;
441 if(src_fmt == CF_UNICODETEXT)
443 switch(dst_fmt)
445 case CF_TEXT:
446 cp = CP_ACP;
447 break;
448 case CF_OEMTEXT:
449 cp = CP_OEMCP;
450 break;
451 default:
452 return 0;
454 return WideCharToMultiByte(cp, 0, src, src_size, dst, dst_size, NULL, NULL);
457 if(dst_fmt == CF_UNICODETEXT)
459 switch(src_fmt)
461 case CF_TEXT:
462 cp = CP_ACP;
463 break;
464 case CF_OEMTEXT:
465 cp = CP_OEMCP;
466 break;
467 default:
468 return 0;
470 return MultiByteToWideChar(cp, 0, src, src_size, dst, dst_size);
473 if(!dst_size) return src_size;
475 if(dst_size > src_size) dst_size = src_size;
477 if(src_fmt == CF_TEXT )
478 CharToOemBuffA(src, dst, dst_size);
479 else
480 OemToCharBuffA(src, dst, dst_size);
482 return dst_size;
485 /**************************************************************************
486 * CLIPBOARD_RenderText
488 * Renders text to the clipboard buffer converting between UNIX and DOS formats.
490 * RETURNS: pointer to the WINE_CLIPFORMAT if successful, NULL otherwise
492 * FIXME: Should be a pair of driver functions that convert between OEM text and Windows.
495 static LPWINE_CLIPFORMAT CLIPBOARD_RenderText( UINT wFormat )
497 LPWINE_CLIPFORMAT lpSource = ClipFormats;
498 LPWINE_CLIPFORMAT lpTarget = NULL;
499 BOOL foundData = FALSE;
501 /* Asked for CF_TEXT */
502 if( wFormat == CF_TEXT)
504 if(ClipFormats[CF_TEXT-1].wDataPresent)
506 lpSource = &ClipFormats[CF_TEXT-1];
507 lpTarget = &ClipFormats[CF_TEXT-1];
508 foundData = TRUE;
509 TRACE("\t TEXT -> TEXT\n");
511 else if(ClipFormats[CF_UNICODETEXT-1].wDataPresent)
513 /* Convert UNICODETEXT -> TEXT */
514 lpSource = &ClipFormats[CF_UNICODETEXT-1];
515 lpTarget = &ClipFormats[CF_TEXT-1];
516 foundData = TRUE;
517 TRACE("\tUNICODETEXT -> TEXT\n");
519 else if(ClipFormats[CF_OEMTEXT-1].wDataPresent)
521 /* Convert OEMTEXT -> TEXT */
522 lpSource = &ClipFormats[CF_OEMTEXT-1];
523 lpTarget = &ClipFormats[CF_TEXT-1];
524 foundData = TRUE;
525 TRACE("\tOEMTEXT -> TEXT\n");
528 /* Asked for CF_OEMTEXT */
529 else if( wFormat == CF_OEMTEXT)
531 if(ClipFormats[CF_OEMTEXT-1].wDataPresent)
533 lpSource = &ClipFormats[CF_OEMTEXT-1];
534 lpTarget = &ClipFormats[CF_OEMTEXT-1];
535 foundData = TRUE;
536 TRACE("\tOEMTEXT -> OEMTEXT\n");
538 else if(ClipFormats[CF_UNICODETEXT-1].wDataPresent)
540 /* Convert UNICODETEXT -> OEMTEXT */
541 lpSource = &ClipFormats[CF_UNICODETEXT-1];
542 lpTarget = &ClipFormats[CF_OEMTEXT-1];
543 foundData = TRUE;
544 TRACE("\tUNICODETEXT -> OEMTEXT\n");
546 else if(ClipFormats[CF_TEXT-1].wDataPresent)
548 /* Convert TEXT -> OEMTEXT */
549 lpSource = &ClipFormats[CF_TEXT-1];
550 lpTarget = &ClipFormats[CF_OEMTEXT-1];
551 foundData = TRUE;
552 TRACE("\tTEXT -> OEMTEXT\n");
555 /* Asked for CF_UNICODETEXT */
556 else if( wFormat == CF_UNICODETEXT )
558 if(ClipFormats[CF_UNICODETEXT-1].wDataPresent)
560 lpSource = &ClipFormats[CF_UNICODETEXT-1];
561 lpTarget = &ClipFormats[CF_UNICODETEXT-1];
562 foundData = TRUE;
563 TRACE("\tUNICODETEXT -> UNICODETEXT\n");
565 else if(ClipFormats[CF_TEXT-1].wDataPresent)
567 /* Convert TEXT -> UNICODETEXT */
568 lpSource = &ClipFormats[CF_TEXT-1];
569 lpTarget = &ClipFormats[CF_UNICODETEXT-1];
570 foundData = TRUE;
571 TRACE("\tTEXT -> UNICODETEXT\n");
573 else if(ClipFormats[CF_OEMTEXT-1].wDataPresent)
575 /* Convert OEMTEXT -> UNICODETEXT */
576 lpSource = &ClipFormats[CF_OEMTEXT-1];
577 lpTarget = &ClipFormats[CF_UNICODETEXT-1];
578 foundData = TRUE;
579 TRACE("\tOEMTEXT -> UNICODETEXT\n");
582 if (!foundData)
584 if ((wFormat == CF_TEXT) || (wFormat == CF_OEMTEXT))
586 lpSource = &ClipFormats[CF_UNICODETEXT-1];
587 lpTarget = __lookup_format( ClipFormats, wFormat );
589 else
591 lpSource = __lookup_format( ClipFormats, wFormat );
592 lpTarget = lpSource;
596 /* First render the source text format */
597 if ( !lpSource || !CLIPBOARD_RenderFormat(lpSource) ) return NULL;
599 /* Convert to the desired target text format, if necessary */
600 if( lpTarget != lpSource && !lpTarget->hData16 && !lpTarget->hData32 )
602 INT src_chars, dst_chars, alloc_size;
603 LPCSTR lpstrS;
604 LPSTR lpstrT;
606 if (lpSource->hData32)
608 lpstrS = (LPSTR)GlobalLock(lpSource->hData32);
610 else
612 lpstrS = (LPSTR)GlobalLock16(lpSource->hData16);
615 if( !lpstrS ) return NULL;
617 /* Text always NULL terminated */
618 if(lpSource->wFormatID == CF_UNICODETEXT)
619 src_chars = strlenW((LPCWSTR)lpstrS)+1;
620 else
621 src_chars = strlen(lpstrS)+1;
623 /* Calculate number of characters in the destination buffer */
624 dst_chars = CLIPBOARD_ConvertText(lpSource->wFormatID, lpstrS, src_chars,
625 lpTarget->wFormatID, NULL, 0);
626 if(!dst_chars) return NULL;
628 TRACE("\tconverting from '%s' to '%s', %i chars\n",
629 lpSource->Name, lpTarget->Name, src_chars);
631 /* Convert characters to bytes */
632 if(lpTarget->wFormatID == CF_UNICODETEXT)
633 alloc_size = dst_chars * sizeof(WCHAR);
634 else
635 alloc_size = dst_chars;
637 lpTarget->hData32 = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE, alloc_size);
638 lpstrT = (LPSTR)GlobalLock(lpTarget->hData32);
640 if( lpstrT )
642 CLIPBOARD_ConvertText(lpSource->wFormatID, lpstrS, src_chars,
643 lpTarget->wFormatID, lpstrT, dst_chars);
644 GlobalUnlock(lpTarget->hData32);
646 else
647 lpTarget->hData32 = 0;
649 /* Unlock source */
650 if (lpSource->hData32)
651 GlobalUnlock(lpSource->hData32);
652 else
653 GlobalUnlock16(lpSource->hData16);
656 return (lpTarget->hData16 || lpTarget->hData32) ? lpTarget : NULL;
659 /**************************************************************************
660 * CLIPBOARD_EnumClipboardFormats (internal)
662 static UINT CLIPBOARD_EnumClipboardFormats( UINT wFormat )
664 LPWINE_CLIPFORMAT lpFormat = ClipFormats;
665 BOOL bFormatPresent;
667 if (wFormat == 0) /* start from the beginning */
668 lpFormat = ClipFormats;
669 else
671 /* walk up to the specified format record */
673 if( !(lpFormat = __lookup_format( lpFormat, wFormat )) )
674 return 0;
675 lpFormat = lpFormat->NextFormat; /* right */
678 while(TRUE)
680 if (lpFormat == NULL) return 0;
682 if(CLIPBOARD_IsPresent(lpFormat->wFormatID))
683 break;
685 /* Query the driver if not yet in the cache */
686 if (!USER_Driver.pIsSelectionOwner())
688 if(lpFormat->wFormatID == CF_UNICODETEXT ||
689 lpFormat->wFormatID == CF_TEXT ||
690 lpFormat->wFormatID == CF_OEMTEXT)
692 if(USER_Driver.pIsClipboardFormatAvailable(CF_UNICODETEXT) ||
693 USER_Driver.pIsClipboardFormatAvailable(CF_TEXT) ||
694 USER_Driver.pIsClipboardFormatAvailable(CF_OEMTEXT))
695 bFormatPresent = TRUE;
696 else
697 bFormatPresent = FALSE;
699 else
700 bFormatPresent = USER_Driver.pIsClipboardFormatAvailable(lpFormat->wFormatID);
702 if(bFormatPresent)
703 break;
706 lpFormat = lpFormat->NextFormat;
709 TRACE("Next available format %d\n", lpFormat->wFormatID);
711 return lpFormat->wFormatID;
715 /**************************************************************************
716 * WIN32 Clipboard implementation
717 **************************************************************************/
719 /**************************************************************************
720 * OpenClipboard (USER.137)
722 BOOL16 WINAPI OpenClipboard16( HWND16 hWnd )
724 return OpenClipboard( hWnd );
728 /**************************************************************************
729 * OpenClipboard (USER32.@)
731 * Note: Netscape uses NULL hWnd to open the clipboard.
733 BOOL WINAPI OpenClipboard( HWND hWnd )
735 BOOL bRet;
737 TRACE("(%04x)...\n", hWnd);
739 if (!hClipLock)
741 hClipLock = GetCurrentTask();
743 /* Save current user of the clipboard */
744 hWndClipWindow = hWnd;
745 bCBHasChanged = FALSE;
746 bRet = TRUE;
748 else bRet = FALSE;
750 TRACE(" returning %i\n", bRet);
751 return bRet;
755 /**************************************************************************
756 * CloseClipboard (USER.138)
758 BOOL16 WINAPI CloseClipboard16(void)
760 return CloseClipboard();
764 /**************************************************************************
765 * CloseClipboard (USER32.@)
767 BOOL WINAPI CloseClipboard(void)
769 TRACE("()\n");
771 if (hClipLock == GetCurrentTask())
773 hWndClipWindow = 0;
775 if (bCBHasChanged && hWndViewer)
776 SendMessage16(hWndViewer, WM_DRAWCLIPBOARD, 0, 0L);
777 hClipLock = 0;
779 return TRUE;
783 /**************************************************************************
784 * EmptyClipboard (USER.139)
786 BOOL16 WINAPI EmptyClipboard16(void)
788 return EmptyClipboard();
792 /**************************************************************************
793 * EmptyClipboard (USER32.@)
794 * Empties and acquires ownership of the clipboard
796 BOOL WINAPI EmptyClipboard(void)
798 TRACE("()\n");
800 if (hClipLock != GetCurrentTask())
802 WARN("Clipboard not opened by calling task!\n");
803 return FALSE;
806 /* destroy private objects */
808 if (hWndClipOwner)
809 SendMessage16(hWndClipOwner, WM_DESTROYCLIPBOARD, 0, 0L);
811 /* empty the cache */
812 CLIPBOARD_EmptyCache(TRUE);
814 /* Assign ownership of the clipboard to the current client */
815 hWndClipOwner = hWndClipWindow;
817 /* Save the current task */
818 hTaskClipOwner = GetCurrentTask();
820 /* Tell the driver to acquire the selection */
821 USER_Driver.pAcquireClipboard();
823 return TRUE;
827 /**************************************************************************
828 * GetClipboardOwner (USER.140)
829 * FIXME: Can't return the owner if the clipbard is owned by an external app
831 HWND16 WINAPI GetClipboardOwner16(void)
833 TRACE("()\n");
834 return hWndClipOwner;
838 /**************************************************************************
839 * GetClipboardOwner (USER32.@)
840 * FIXME: Can't return the owner if the clipbard is owned by an external app
842 HWND WINAPI GetClipboardOwner(void)
844 TRACE("()\n");
845 return hWndClipOwner;
849 /**************************************************************************
850 * SetClipboardData (USER.141)
852 HANDLE16 WINAPI SetClipboardData16( UINT16 wFormat, HANDLE16 hData )
854 LPWINE_CLIPFORMAT lpFormat = __lookup_format( ClipFormats, wFormat );
856 TRACE("(%04X, %04x) !\n", wFormat, hData);
858 /* NOTE: If the hData is zero and current owner doesn't match
859 * the window that opened the clipboard then this application
860 * is screwed because WM_RENDERFORMAT will go to the owner.
861 * (to become the owner it must call EmptyClipboard() before
862 * adding new data).
865 if( CLIPBOARD_IsLocked() || !lpFormat ||
866 (!hData && (!hWndClipOwner || (hWndClipOwner != hWndClipWindow))) )
868 WARN("Invalid hData or clipboard not opened by calling task!\n");
869 return 0;
872 /* Pass on the request to the driver */
873 USER_Driver.pSetClipboardData(wFormat);
875 if ( lpFormat->wDataPresent || lpFormat->hData16 || lpFormat->hData32 )
877 CLIPBOARD_DeleteRecord(lpFormat, TRUE);
879 /* delete existing CF_UNICODETEXT/CF_TEXT/CF_OEMTEXT aliases */
880 if(wFormat == CF_UNICODETEXT)
882 CLIPBOARD_DeleteRecord(&ClipFormats[CF_TEXT-1], TRUE);
883 CLIPBOARD_DeleteRecord(&ClipFormats[CF_OEMTEXT-1], TRUE);
885 else if(wFormat == CF_TEXT)
887 CLIPBOARD_DeleteRecord(&ClipFormats[CF_UNICODETEXT-1], TRUE);
888 CLIPBOARD_DeleteRecord(&ClipFormats[CF_OEMTEXT-1], TRUE);
890 else if(wFormat == CF_OEMTEXT)
892 CLIPBOARD_DeleteRecord(&ClipFormats[CF_UNICODETEXT-1], TRUE);
893 CLIPBOARD_DeleteRecord(&ClipFormats[CF_TEXT-1], TRUE);
897 bCBHasChanged = TRUE;
898 lpFormat->wDataPresent = 1;
899 lpFormat->hData16 = hData; /* 0 is legal, see WM_RENDERFORMAT */
900 lpFormat->hData32 = 0;
902 return lpFormat->hData16;
906 /**************************************************************************
907 * SetClipboardData (USER32.@)
909 HANDLE WINAPI SetClipboardData( UINT wFormat, HANDLE hData )
911 LPWINE_CLIPFORMAT lpFormat = __lookup_format( ClipFormats, wFormat );
913 TRACE("(%08X, %08x) !\n", wFormat, hData);
915 /* NOTE: If the hData is zero and current owner doesn't match
916 * the window that opened the clipboard then this application
917 * is screwed because WM_RENDERFORMAT will go to the owner.
918 * (to become the owner it must call EmptyClipboard() before
919 * adding new data).
922 if( CLIPBOARD_IsLocked() || !lpFormat ||
923 (!hData && (!hWndClipOwner || (hWndClipOwner != hWndClipWindow))) )
925 WARN("Invalid hData or clipboard not opened by calling task!\n");
926 return 0;
929 /* Tell the driver to acquire the selection */
930 USER_Driver.pAcquireClipboard();
932 if ( lpFormat->wDataPresent &&
933 (lpFormat->hData16 || lpFormat->hData32) )
935 CLIPBOARD_DeleteRecord(lpFormat, TRUE);
937 /* delete existing CF_UNICODETEXT/CF_TEXT/CF_OEMTEXT aliases */
938 if(wFormat == CF_UNICODETEXT)
940 CLIPBOARD_DeleteRecord(&ClipFormats[CF_TEXT-1], TRUE);
941 CLIPBOARD_DeleteRecord(&ClipFormats[CF_OEMTEXT-1], TRUE);
943 else if(wFormat == CF_TEXT)
945 CLIPBOARD_DeleteRecord(&ClipFormats[CF_UNICODETEXT-1], TRUE);
946 CLIPBOARD_DeleteRecord(&ClipFormats[CF_OEMTEXT-1], TRUE);
948 else if(wFormat == CF_OEMTEXT)
950 CLIPBOARD_DeleteRecord(&ClipFormats[CF_UNICODETEXT-1], TRUE);
951 CLIPBOARD_DeleteRecord(&ClipFormats[CF_TEXT-1], TRUE);
955 bCBHasChanged = TRUE;
956 lpFormat->wDataPresent = 1;
957 lpFormat->hDataSrc32 = hData; /* Save the source handle */
960 * Make a shared duplicate if the memory is not shared
961 * TODO: What should be done for non-memory objects
963 if ( CLIPBOARD_IsMemoryObject(wFormat) && hData && !(GlobalFlags(hData) & GMEM_DDESHARE) )
964 lpFormat->hData32 = CLIPBOARD_GlobalDupMem( hData );
965 else
966 lpFormat->hData32 = hData; /* 0 is legal, see WM_RENDERFORMAT */
968 lpFormat->hData16 = 0;
970 return lpFormat->hData32; /* Should we return lpFormat->hDataSrc32 */
974 /**************************************************************************
975 * GetClipboardData (USER.142)
977 HANDLE16 WINAPI GetClipboardData16( UINT16 wFormat )
979 LPWINE_CLIPFORMAT lpRender = ClipFormats;
981 TRACE("(%04X)\n", wFormat);
983 if (CLIPBOARD_IsLocked())
985 WARN("Clipboard not opened by calling task!\n");
986 return 0;
989 if( wFormat == CF_UNICODETEXT || wFormat == CF_TEXT || wFormat == CF_OEMTEXT )
991 lpRender = CLIPBOARD_RenderText(wFormat);
992 if ( !lpRender ) return 0;
994 else
996 lpRender = __lookup_format( ClipFormats, wFormat );
997 if( !lpRender || !CLIPBOARD_RenderFormat(lpRender) ) return 0;
1000 /* Convert between 32 -> 16 bit data, if necessary */
1001 if( lpRender->hData32 && !lpRender->hData16
1002 && CLIPBOARD_IsMemoryObject(wFormat) )
1004 int size;
1005 if( lpRender->wFormatID == CF_METAFILEPICT )
1006 size = sizeof( METAFILEPICT16 );
1007 else
1008 size = GlobalSize(lpRender->hData32);
1010 lpRender->hData16 = GlobalAlloc16(GMEM_ZEROINIT, size);
1011 if( !lpRender->hData16 )
1012 ERR("(%04X) -- not enough memory in 16b heap\n", wFormat);
1013 else
1015 if( lpRender->wFormatID == CF_METAFILEPICT )
1017 FIXME("\timplement function CopyMetaFilePict32to16\n");
1018 FIXME("\tin the appropriate file.\n");
1019 #ifdef SOMEONE_IMPLEMENTED_ME
1020 CopyMetaFilePict32to16( GlobalLock16(lpRender->hData16),
1021 GlobalLock(lpRender->hData32) );
1022 #endif
1024 else
1026 memcpy( GlobalLock16(lpRender->hData16),
1027 GlobalLock(lpRender->hData32),
1028 size );
1030 GlobalUnlock16(lpRender->hData16);
1031 GlobalUnlock(lpRender->hData32);
1035 TRACE("\treturning %04x (type %i)\n",
1036 lpRender->hData16, lpRender->wFormatID);
1037 return lpRender->hData16;
1041 /**************************************************************************
1042 * GetClipboardData (USER32.@)
1044 HANDLE WINAPI GetClipboardData( UINT wFormat )
1046 LPWINE_CLIPFORMAT lpRender = ClipFormats;
1048 TRACE("(%08X)\n", wFormat);
1050 if (CLIPBOARD_IsLocked())
1052 WARN("Clipboard not opened by calling task!\n");
1053 return 0;
1056 if( wFormat == CF_UNICODETEXT || wFormat == CF_TEXT || wFormat == CF_OEMTEXT )
1058 lpRender = CLIPBOARD_RenderText(wFormat);
1059 if ( !lpRender ) return 0;
1061 else
1063 lpRender = __lookup_format( ClipFormats, wFormat );
1064 if( !lpRender || !CLIPBOARD_RenderFormat(lpRender) ) return 0;
1067 /* Convert between 16 -> 32 bit data, if necessary */
1068 if( lpRender->hData16 && !lpRender->hData32
1069 && CLIPBOARD_IsMemoryObject(wFormat) )
1071 int size;
1072 if( lpRender->wFormatID == CF_METAFILEPICT )
1073 size = sizeof( METAFILEPICT );
1074 else
1075 size = GlobalSize16(lpRender->hData16);
1076 lpRender->hData32 = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE,
1077 size);
1078 if( lpRender->wFormatID == CF_METAFILEPICT )
1080 FIXME("\timplement function CopyMetaFilePict16to32\n");
1081 FIXME("\tin the appropriate file.\n");
1082 #ifdef SOMEONE_IMPLEMENTED_ME
1083 CopyMetaFilePict16to32( GlobalLock16(lpRender->hData32),
1084 GlobalLock(lpRender->hData16) );
1085 #endif
1087 else
1089 memcpy( GlobalLock(lpRender->hData32),
1090 GlobalLock16(lpRender->hData16),
1091 size );
1093 GlobalUnlock(lpRender->hData32);
1094 GlobalUnlock16(lpRender->hData16);
1097 TRACE("\treturning %04x (type %i)\n",
1098 lpRender->hData32, lpRender->wFormatID);
1099 return lpRender->hData32;
1103 /**************************************************************************
1104 * CountClipboardFormats (USER.143)
1106 INT16 WINAPI CountClipboardFormats16(void)
1108 return CountClipboardFormats();
1112 /**************************************************************************
1113 * CountClipboardFormats (USER32.@)
1115 INT WINAPI CountClipboardFormats(void)
1117 INT FormatCount = 0;
1118 LPWINE_CLIPFORMAT lpFormat = ClipFormats;
1120 TRACE("()\n");
1122 while(TRUE)
1124 if (lpFormat == NULL) break;
1126 if( lpFormat->wFormatID != CF_TEXT ) /* Don't count CF_TEXT */
1129 * The format is available if either:
1130 * 1. The data is already in the cache.
1131 * 2. The selection is not owned by us(WINE) and the data is
1132 * available to the clipboard driver.
1134 if ( lpFormat->wDataPresent ||
1135 ( !USER_Driver.pIsSelectionOwner()
1136 && USER_Driver.pIsClipboardFormatAvailable( lpFormat->wFormatID ) ) )
1138 TRACE("\tdata found for format 0x%04x(%s)\n",
1139 lpFormat->wFormatID, CLIPBOARD_GetFormatName(lpFormat->wFormatID));
1140 FormatCount++;
1144 lpFormat = lpFormat->NextFormat;
1147 /* these are equivalent, adjust the total */
1148 FormatCount += (ClipFormats[CF_UNICODETEXT-1].wDataPresent ||
1149 ClipFormats[CF_TEXT-1].wDataPresent ||
1150 ClipFormats[CF_OEMTEXT-1].wDataPresent) ? 1 : 0;
1152 TRACE("\ttotal %d\n", FormatCount);
1153 return FormatCount;
1156 /**************************************************************************
1157 * EnumClipboardFormats (USER.144)
1159 UINT16 WINAPI EnumClipboardFormats16( UINT16 wFormat )
1161 return EnumClipboardFormats( wFormat );
1165 /**************************************************************************
1166 * EnumClipboardFormats (USER32.@)
1168 UINT WINAPI EnumClipboardFormats( UINT wFormat )
1170 TRACE("(%04X)\n", wFormat);
1172 if (CLIPBOARD_IsLocked())
1174 WARN("Clipboard not opened by calling task!\n");
1175 return 0;
1178 return CLIPBOARD_EnumClipboardFormats(wFormat);
1182 /**************************************************************************
1183 * RegisterClipboardFormatA (USER32.@)
1185 UINT WINAPI RegisterClipboardFormatA( LPCSTR FormatName )
1187 LPWINE_CLIPFORMAT lpNewFormat;
1188 LPWINE_CLIPFORMAT lpFormat = ClipFormats;
1190 if (FormatName == NULL) return 0;
1192 TRACE("('%s') !\n", FormatName);
1194 /* walk format chain to see if it's already registered */
1196 while(TRUE)
1198 if ( !strcmp(lpFormat->Name,FormatName) )
1200 lpFormat->wRefCount++;
1201 return lpFormat->wFormatID;
1204 if ( lpFormat->NextFormat == NULL ) break;
1206 lpFormat = lpFormat->NextFormat;
1209 /* allocate storage for new format entry */
1211 lpNewFormat = (LPWINE_CLIPFORMAT)HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CLIPFORMAT));
1212 if(lpNewFormat == NULL) {
1213 WARN("No more memory for a new format!\n");
1214 return 0;
1216 lpFormat->NextFormat = lpNewFormat;
1217 lpNewFormat->wFormatID = LastRegFormat;
1218 lpNewFormat->wRefCount = 1;
1220 lpNewFormat->Name = (LPSTR)HEAP_strdupA(GetProcessHeap(), 0, FormatName);
1221 if(lpNewFormat->Name == NULL) {
1222 WARN("No more memory for the new format name!\n");
1223 HeapFree(GetProcessHeap(), 0, lpNewFormat);
1224 return 0;
1227 lpNewFormat->wDataPresent = 0;
1228 lpNewFormat->hData16 = 0;
1229 lpNewFormat->hDataSrc32 = 0;
1230 lpNewFormat->hData32 = 0;
1231 lpNewFormat->drvData = 0;
1232 lpNewFormat->PrevFormat = lpFormat;
1233 lpNewFormat->NextFormat = NULL;
1235 /* Pass on the registration request to the driver */
1236 USER_Driver.pRegisterClipboardFormat( FormatName );
1238 return LastRegFormat++;
1242 /**************************************************************************
1243 * RegisterClipboardFormat (USER.145)
1245 UINT16 WINAPI RegisterClipboardFormat16( LPCSTR FormatName )
1247 return RegisterClipboardFormatA( FormatName );
1251 /**************************************************************************
1252 * RegisterClipboardFormatW (USER32.@)
1254 UINT WINAPI RegisterClipboardFormatW( LPCWSTR formatName )
1256 LPSTR aFormat = HEAP_strdupWtoA( GetProcessHeap(), 0, formatName );
1257 UINT ret = RegisterClipboardFormatA( aFormat );
1258 HeapFree( GetProcessHeap(), 0, aFormat );
1259 return ret;
1263 /**************************************************************************
1264 * GetClipboardFormatName (USER.146)
1266 INT16 WINAPI GetClipboardFormatName16( UINT16 wFormat, LPSTR retStr, INT16 maxlen )
1268 return GetClipboardFormatNameA( wFormat, retStr, maxlen );
1272 /**************************************************************************
1273 * GetClipboardFormatNameA (USER32.@)
1275 INT WINAPI GetClipboardFormatNameA( UINT wFormat, LPSTR retStr, INT maxlen )
1277 LPWINE_CLIPFORMAT lpFormat = __lookup_format( ClipFormats, wFormat );
1279 TRACE("(%04X, %p, %d) !\n", wFormat, retStr, maxlen);
1281 if (lpFormat == NULL || lpFormat->Name == NULL ||
1282 lpFormat->wFormatID < CF_REGFORMATBASE) return 0;
1284 TRACE("Name='%s' !\n", lpFormat->Name);
1286 lstrcpynA( retStr, lpFormat->Name, maxlen );
1287 return strlen(retStr);
1291 /**************************************************************************
1292 * GetClipboardFormatNameW (USER32.@)
1294 INT WINAPI GetClipboardFormatNameW( UINT wFormat, LPWSTR retStr, INT maxlen )
1296 INT ret;
1297 LPSTR p = HeapAlloc( GetProcessHeap(), 0, maxlen );
1298 if(p == NULL) return 0; /* FIXME: is this the correct failure value? */
1300 ret = GetClipboardFormatNameA( wFormat, p, maxlen );
1302 if (maxlen > 0 && !MultiByteToWideChar( CP_ACP, 0, p, -1, retStr, maxlen ))
1303 retStr[maxlen-1] = 0;
1304 HeapFree( GetProcessHeap(), 0, p );
1305 return ret;
1309 /**************************************************************************
1310 * SetClipboardViewer (USER.147)
1312 HWND16 WINAPI SetClipboardViewer16( HWND16 hWnd )
1314 TRACE("(%04x)\n", hWnd);
1315 return SetClipboardViewer( hWnd );
1319 /**************************************************************************
1320 * SetClipboardViewer (USER32.@)
1322 HWND WINAPI SetClipboardViewer( HWND hWnd )
1324 HWND hwndPrev = hWndViewer;
1326 TRACE("(%04x): returning %04x\n", hWnd, hwndPrev);
1328 hWndViewer = hWnd;
1329 return hwndPrev;
1333 /**************************************************************************
1334 * GetClipboardViewer (USER.148)
1336 HWND16 WINAPI GetClipboardViewer16(void)
1338 TRACE("()\n");
1339 return hWndViewer;
1343 /**************************************************************************
1344 * GetClipboardViewer (USER32.@)
1346 HWND WINAPI GetClipboardViewer(void)
1348 TRACE("()\n");
1349 return hWndViewer;
1353 /**************************************************************************
1354 * ChangeClipboardChain (USER.149)
1356 BOOL16 WINAPI ChangeClipboardChain16(HWND16 hWnd, HWND16 hWndNext)
1358 return ChangeClipboardChain(hWnd, hWndNext);
1362 /**************************************************************************
1363 * ChangeClipboardChain (USER32.@)
1365 BOOL WINAPI ChangeClipboardChain(HWND hWnd, HWND hWndNext)
1367 BOOL bRet = 0;
1369 FIXME("(0x%04x, 0x%04x): stub?\n", hWnd, hWndNext);
1371 if( hWndViewer )
1372 bRet = !SendMessage16( hWndViewer, WM_CHANGECBCHAIN,
1373 (WPARAM16)hWnd, (LPARAM)hWndNext);
1374 else
1375 WARN("hWndViewer is lost\n");
1377 if( hWnd == hWndViewer ) hWndViewer = hWndNext;
1379 return bRet;
1383 /**************************************************************************
1384 * IsClipboardFormatAvailable (USER.193)
1386 BOOL16 WINAPI IsClipboardFormatAvailable16( UINT16 wFormat )
1388 return IsClipboardFormatAvailable( wFormat );
1392 /**************************************************************************
1393 * IsClipboardFormatAvailable (USER32.@)
1395 BOOL WINAPI IsClipboardFormatAvailable( UINT wFormat )
1397 BOOL bRet;
1399 if (wFormat == 0) /* Reject this case quickly */
1400 bRet = FALSE;
1401 else
1403 UINT iret = CLIPBOARD_EnumClipboardFormats(wFormat - 1);
1404 if ((wFormat == CF_TEXT) || (wFormat == CF_OEMTEXT) || (wFormat == CF_UNICODETEXT))
1405 bRet = ((iret == CF_TEXT) || (iret == CF_OEMTEXT) || (iret == CF_UNICODETEXT));
1406 else
1407 bRet = iret == wFormat;
1409 TRACE("(%04X)- ret(%d)\n", wFormat, bRet);
1410 return bRet;
1414 /**************************************************************************
1415 * GetOpenClipboardWindow (USER.248)
1416 * FIXME: This wont work if an external app owns the selection
1418 HWND16 WINAPI GetOpenClipboardWindow16(void)
1420 TRACE("()\n");
1421 return hWndClipWindow;
1425 /**************************************************************************
1426 * GetOpenClipboardWindow (USER32.@)
1427 * FIXME: This wont work if an external app owns the selection
1429 HWND WINAPI GetOpenClipboardWindow(void)
1431 TRACE("()\n");
1432 return hWndClipWindow;
1436 /**************************************************************************
1437 * GetPriorityClipboardFormat (USER.402)
1439 INT16 WINAPI GetPriorityClipboardFormat16( UINT16 *lpPriorityList, INT16 nCount)
1441 FIXME("(%p,%d): stub\n", lpPriorityList, nCount );
1442 return 0;
1446 /**************************************************************************
1447 * GetPriorityClipboardFormat (USER32.@)
1449 INT WINAPI GetPriorityClipboardFormat( UINT *lpPriorityList, INT nCount )
1451 int Counter;
1452 TRACE("()\n");
1454 if(CountClipboardFormats() == 0)
1456 return 0;
1459 for(Counter = 0; Counter <= nCount; Counter++)
1461 if(IsClipboardFormatAvailable(*(lpPriorityList+sizeof(INT)*Counter)))
1462 return *(lpPriorityList+sizeof(INT)*Counter);
1465 return -1;
1469 /**************************************************************************
1470 * GetClipboardSequenceNumber (USER32.@)
1471 * Supported on Win2k/Win98
1472 * MSDN: Windows clipboard code keeps a serial number for the clipboard
1473 * for each window station. The number is incremented whenever the
1474 * contents change or are emptied.
1475 * If you do not have WINSTA_ACCESSCLIPBOARD then the function returns 0
1477 DWORD WINAPI GetClipboardSequenceNumber(VOID)
1479 FIXME("Returning 0, see windows/clipboard.c\n");
1480 /* FIXME: Use serial numbers */
1481 return 0;