Merged display.dll into USER.
[wine] / windows / clipboard.c
1 /*
2  * WIN32 clipboard implementation
3  *
4  * Copyright 1994 Martin Ayotte
5  *           1996 Alex Korobka
6  *           1999 Noel Borthwick
7  *
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)
15  *
16  * TODO: 
17  *
18  */
19
20 #include <stdlib.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <fcntl.h>
24 #include <unistd.h>
25 #include <string.h>
26 #include "windef.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "wine/winuser16.h"
30 #include "wine/winbase16.h"
31 #include "heap.h"
32 #include "message.h"
33 #include "task.h"
34 #include "queue.h"
35 #include "clipboard.h"
36 #include "debugtools.h"
37
38 DEFAULT_DEBUG_CHANNEL(clipboard)
39
40 #define  CF_REGFORMATBASE       0xC000
41
42 /**************************************************************************
43  *        Clipboard context global variables
44  */
45
46 CLIPBOARD_DRIVER *CLIPBOARD_Driver = NULL;
47
48 static HANDLE hClipLock   = 0;
49 static BOOL bCBHasChanged  = FALSE;
50
51 HWND hWndClipWindow = 0;          /* window that last opened clipboard */
52 HWND hWndClipOwner  = 0;          /* current clipboard owner */
53 HANDLE16 hTaskClipOwner = 0;      /* clipboard owner's task  */
54 static HWND hWndViewer     = 0;   /* start of viewers chain */
55
56 static WORD LastRegFormat = CF_REGFORMATBASE;
57
58 /* Clipboard cache initial data.
59  * WARNING: This data ordering is dependendent on the WINE_CLIPFORMAT structure
60  * declared in clipboard.h
61  */
62 WINE_CLIPFORMAT ClipFormats[17]  = {
63     { CF_TEXT, 1, 0, "Text",  (HANDLE16)NULL, (HANDLE)NULL, (HANDLE)NULL, 0, NULL, &ClipFormats[1]},
64     { CF_BITMAP, 1, 0, "Bitmap", (HANDLE16)NULL, (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[0], &ClipFormats[2]},
65     { CF_METAFILEPICT, 1, 0, "MetaFile Picture", (HANDLE16)NULL, (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[1], &ClipFormats[3]},
66     { CF_SYLK, 1, 0, "Sylk", (HANDLE16)NULL, (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[2], &ClipFormats[4]},
67     { CF_DIF, 1, 0, "DIF", (HANDLE16)NULL, (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[3], &ClipFormats[5]},
68     { CF_TIFF, 1, 0, "TIFF", (HANDLE16)NULL, (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[4], &ClipFormats[6]},
69     { CF_OEMTEXT, 1, 0, "OEM Text", (HANDLE16)NULL, (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[5], &ClipFormats[7]},
70     { CF_DIB, 1, 0, "DIB", (HANDLE16)NULL, (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[6], &ClipFormats[8]},
71     { CF_PALETTE, 1, 0, "Palette", (HANDLE16)NULL, (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[7], &ClipFormats[9]},
72     { CF_PENDATA, 1, 0, "PenData", (HANDLE16)NULL, (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[8], &ClipFormats[10]},
73     { CF_RIFF, 1, 0, "RIFF", (HANDLE16)NULL, (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[9], &ClipFormats[11]},
74     { CF_WAVE, 1, 0, "Wave", (HANDLE16)NULL, (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[10], &ClipFormats[12]},
75     { CF_OWNERDISPLAY, 1, 0, "Owner Display", (HANDLE16)NULL, (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[11], &ClipFormats[13]},
76     { CF_DSPTEXT, 1, 0, "DSPText", (HANDLE16)NULL, (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[12], &ClipFormats[14]},
77     { CF_DSPMETAFILEPICT, 1, 0, "DSPMetaFile Picture", (HANDLE16)NULL, (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[13], &ClipFormats[15]},
78     { CF_DSPBITMAP, 1, 0, "DSPBitmap", (HANDLE16)NULL, (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[14], &ClipFormats[16]},
79     { CF_HDROP, 1, 0, "HDROP", (HANDLE16)NULL, (HANDLE)NULL, (HANDLE)NULL, 0, &ClipFormats[15], NULL}
80     };
81
82
83 /**************************************************************************
84  *                Internal Clipboard implementation methods
85  **************************************************************************/
86
87
88 /**************************************************************************
89  *                      CLIPBOARD_LookupFormat
90  */
91 static LPWINE_CLIPFORMAT __lookup_format( LPWINE_CLIPFORMAT lpFormat, WORD wID )
92 {
93     while(TRUE)
94     {
95         if (lpFormat == NULL ||
96             lpFormat->wFormatID == wID) break;
97         lpFormat = lpFormat->NextFormat;
98     }
99     return lpFormat;
100 }
101
102 LPWINE_CLIPFORMAT CLIPBOARD_LookupFormat( WORD wID )
103 {
104   return __lookup_format( ClipFormats, wID );
105 }
106
107 /**************************************************************************
108  *                      CLIPBOARD_IsLocked
109  *  Check if the clipboard cache is available to the caller
110  */
111 BOOL CLIPBOARD_IsLocked()
112 {
113   BOOL bIsLocked = TRUE;
114   HANDLE16 hTaskCur = GetCurrentTask();
115
116   /*
117    * The clipboard is available:
118    * 1. if the caller's task has opened the clipboard,
119    * or
120    * 2. if the caller is the clipboard owners task, AND is responding to a
121    *    WM_RENDERFORMAT message.
122    */
123   if ( hClipLock == hTaskCur )
124       bIsLocked = FALSE;
125       
126   else if ( hTaskCur == hTaskClipOwner )
127   {
128       /* Check if we're currently executing inside a window procedure
129        * called in response to a WM_RENDERFORMAT message. A WM_RENDERFORMAT
130        * handler is not permitted to open the clipboard since it has been opened
131        * by another client. However the handler must have access to the
132        * clipboard in order to update data in response to this message.
133        */
134       MESSAGEQUEUE *queue = QUEUE_Lock( GetFastQueue16() );
135       
136       if ( queue
137            && queue->smWaiting
138            && queue->smWaiting->msg == WM_RENDERFORMAT
139            && queue->smWaiting->hSrcQueue
140          )
141         bIsLocked = FALSE;
142         
143       QUEUE_Unlock( queue );
144   }
145
146   return bIsLocked;
147 }
148
149 /**************************************************************************
150  *                      CLIPBOARD_ReleaseOwner
151  *   Gives up ownership of the clipboard
152  */
153 void CLIPBOARD_ReleaseOwner()
154 {
155    hWndClipOwner = 0;
156    hTaskClipOwner = 0;
157 }
158
159 /**************************************************************************
160  *                      CLIPBOARD_GlobalFreeProc
161  *
162  * This is a callback mechanism to allow HGLOBAL data to be released in
163  * the context of the process which allocated it. We post a WM_TIMER message
164  * to the owner window(in CLIPBOARD_DeleteRecord) and destroy the data(in idEvent)
165  * in this WndProc, which is invoked when the apps message loop calls DispatchMessage.
166  * This technique is discussed in Matt Pietrek's "Under the Hood".
167  * An article describing the same may be found in MSDN by searching for WM_TIMER.
168  * Note that this mechanism will probably stop working when WINE supports
169  * address space separation. When "queue events" are implemented in Wine we
170  * should switch to using that mechanism, since it is more robust and does not
171  * require a procedure address to be passed. See the SetWinEventHook API for
172  * more info on this.
173  */
174 VOID CALLBACK CLIPBOARD_GlobalFreeProc( HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime )
175 {
176     /* idEvent is the HGLOBAL to be deleted */
177     GlobalFree( (HGLOBAL)idEvent );
178 }
179
180 /**************************************************************************
181  *                      CLIPBOARD_DeleteRecord
182  */
183 void CLIPBOARD_DeleteRecord(LPWINE_CLIPFORMAT lpFormat, BOOL bChange)
184 {
185     if( (lpFormat->wFormatID >= CF_GDIOBJFIRST &&
186          lpFormat->wFormatID <= CF_GDIOBJLAST) || lpFormat->wFormatID == CF_BITMAP 
187             || lpFormat->wFormatID == CF_PALETTE)
188     {
189       if (lpFormat->hData32)
190         DeleteObject(lpFormat->hData32);
191       if (lpFormat->hData16)
192         DeleteObject16(lpFormat->hData16);
193     }
194     else if( lpFormat->wFormatID == CF_METAFILEPICT )
195     {
196       if (lpFormat->hData32)
197       {
198         DeleteMetaFile( ((METAFILEPICT *)GlobalLock( lpFormat->hData32 ))->hMF );
199         PostMessageA(hWndClipOwner, WM_TIMER,
200                      (WPARAM)lpFormat->hData32, (LPARAM)CLIPBOARD_GlobalFreeProc);
201         if (lpFormat->hDataSrc32)
202         {
203           /* Release lpFormat->hData32 in the context of the process which created it.
204            * See CLIPBOARD_GlobalFreeProc for more details about this technique.
205            * GlobalFree(lpFormat->hDataSrc32);
206            */
207           PostMessageA(hWndClipOwner, WM_TIMER,
208                        (WPARAM)lpFormat->hDataSrc32, (LPARAM)CLIPBOARD_GlobalFreeProc);
209         }
210           
211         if (lpFormat->hData16)
212           /* HMETAFILE16 and HMETAFILE32 are apparently the same thing, 
213              and a shallow copy is enough to share a METAFILEPICT
214              structure between 16bit and 32bit clipboards.  The MetaFile
215              should of course only be deleted once. */
216           GlobalFree16(lpFormat->hData16);
217       }
218       if (lpFormat->hData16)
219       {
220         DeleteMetaFile16( ((METAFILEPICT16 *)GlobalLock16( lpFormat->hData16 ))->hMF );
221         GlobalFree16(lpFormat->hData16);
222       }
223     }
224     else 
225     {
226       if (lpFormat->hData32)
227       {
228         /* Release lpFormat->hData32 in the context of the process which created it.
229          * See CLIPBOARD_GlobalFreeProc for more details about this technique.
230          * GlobalFree( lpFormat->hData32 );
231          */
232         PostMessageA(hWndClipOwner, WM_TIMER,
233                      (WPARAM)lpFormat->hData32, (LPARAM)CLIPBOARD_GlobalFreeProc);
234       }
235       if (lpFormat->hDataSrc32)
236       {
237         /* Release lpFormat->hData32 in the context of the process which created it.
238          * See CLIPBOARD_GlobalFreeProc for more details about this technique.
239          * GlobalFree(lpFormat->hDataSrc32);
240          */
241         PostMessageA(hWndClipOwner, WM_TIMER,
242                      (WPARAM)lpFormat->hDataSrc32, (LPARAM)CLIPBOARD_GlobalFreeProc);
243       }
244       if (lpFormat->hData16)
245         GlobalFree16(lpFormat->hData16);
246     }
247
248     lpFormat->wDataPresent = 0; 
249     lpFormat->hData16 = 0;
250     lpFormat->hData32 = 0;
251     lpFormat->hDataSrc32 = 0;
252     lpFormat->drvData = 0;
253
254     if( bChange ) bCBHasChanged = TRUE;
255 }
256
257 /**************************************************************************
258  *                      CLIPBOARD_EmptyCache
259  */
260 void CLIPBOARD_EmptyCache( BOOL bChange )
261 {
262     LPWINE_CLIPFORMAT lpFormat = ClipFormats; 
263
264     while(lpFormat)
265     {
266         if ( lpFormat->wDataPresent || lpFormat->hData16 || lpFormat->hData32 )
267              CLIPBOARD_DeleteRecord( lpFormat, bChange );
268
269         lpFormat = lpFormat->NextFormat;
270     }
271 }
272
273 /**************************************************************************
274  *                      CLIPBOARD_IsPresent
275  */
276 BOOL CLIPBOARD_IsPresent(WORD wFormat)
277 {
278     /* special case */
279
280     if( wFormat == CF_TEXT || wFormat == CF_OEMTEXT )
281         return ClipFormats[CF_TEXT-1].wDataPresent ||
282                ClipFormats[CF_OEMTEXT-1].wDataPresent;
283     else
284     {
285         LPWINE_CLIPFORMAT lpFormat = __lookup_format( ClipFormats, wFormat );
286         if( lpFormat ) return (lpFormat->wDataPresent);
287     }
288     return FALSE;
289 }
290
291 /**************************************************************************
292  *                      CLIPBOARD_IsCacheRendered
293  *  Checks if any data needs to be rendered to the clipboard cache
294  *  RETURNS:
295  *    TRUE  - All clipboard data is available in the cache
296  *    FALSE - Some data is marked for delayed render and needs rendering
297  */
298 BOOL CLIPBOARD_IsCacheRendered()
299 {
300     LPWINE_CLIPFORMAT lpFormat = ClipFormats;
301     
302     /* check if all formats were rendered */
303     while(lpFormat)
304     {
305         if( lpFormat->wDataPresent && !lpFormat->hData16 && !lpFormat->hData32 )
306             return FALSE;
307         
308         lpFormat = lpFormat->NextFormat;
309     }
310     
311     return TRUE;
312 }
313
314
315 /**************************************************************************
316  *                      CLIPBOARD_IsMemoryObject
317  *  Tests if the clipboard format specifies a memory object
318  */
319 BOOL CLIPBOARD_IsMemoryObject( WORD wFormat )
320 {
321     switch(wFormat)
322     {
323         case CF_BITMAP:
324         case CF_METAFILEPICT:
325         case CF_DSPTEXT:
326         case CF_ENHMETAFILE:
327         case CF_HDROP:
328         case CF_PALETTE:
329         case CF_PENDATA:
330             return FALSE;
331         default:
332             return TRUE;
333      }
334 }
335
336 /***********************************************************************
337  * CLIPBOARD_GlobalDupMem( HGLOBAL )
338  * Helper method to duplicate an HGLOBAL chunk of memory into shared memory
339  */
340 HGLOBAL CLIPBOARD_GlobalDupMem( HGLOBAL hGlobalSrc )
341 {
342     HGLOBAL hGlobalDest;
343     PVOID pGlobalSrc, pGlobalDest;
344     DWORD cBytes;
345     
346     if ( !hGlobalSrc )
347       return 0;
348
349     cBytes = GlobalSize(hGlobalSrc);
350     if ( 0 == cBytes )
351       return 0;
352
353     /* Turn on the DDESHARE and _MOVEABLE flags explicitly */
354     hGlobalDest = GlobalAlloc( GlobalFlags(hGlobalSrc) | GMEM_DDESHARE | GMEM_MOVEABLE,
355                                cBytes );
356     if ( !hGlobalDest )
357       return 0;
358     
359     pGlobalSrc = GlobalLock(hGlobalSrc);
360     pGlobalDest = GlobalLock(hGlobalDest);
361     if ( !pGlobalSrc || !pGlobalDest )
362       return 0;
363
364     memcpy(pGlobalDest, pGlobalSrc, cBytes);
365         
366     GlobalUnlock(hGlobalSrc);
367     GlobalUnlock(hGlobalDest);
368
369     return hGlobalDest;
370 }
371
372 /**************************************************************************
373  *                      CLIPBOARD_GetFormatName
374  *  Gets the format name associated with an ID
375  */
376 char * CLIPBOARD_GetFormatName(UINT wFormat)
377 {
378     LPWINE_CLIPFORMAT lpFormat = __lookup_format( ClipFormats, wFormat );
379     return (lpFormat) ? lpFormat->Name : NULL;
380 }
381
382
383 /**************************************************************************
384  *                      CLIPBOARD_RenderFormat
385  */
386 static BOOL CLIPBOARD_RenderFormat(LPWINE_CLIPFORMAT lpFormat)
387 {
388   /*
389    * If WINE is not the selection owner, and the format is available
390    * we must ask the the driver to render the data to the clipboard cache.
391    */
392   if ( !CLIPBOARD_Driver->pIsSelectionOwner() 
393        && CLIPBOARD_Driver->pIsFormatAvailable( lpFormat->wFormatID ) )
394   {
395     if ( !CLIPBOARD_Driver->pGetData( lpFormat->wFormatID ) )
396       return FALSE;
397   }
398   /*
399    * If Wine owns the clipboard, and the data is marked for delayed render,
400    * render it now.
401    */
402   else if( lpFormat->wDataPresent && !lpFormat->hData16 && !lpFormat->hData32 )
403   {
404     if( IsWindow(hWndClipOwner) )
405     {
406       /* Send a WM_RENDERFORMAT message to notify the owner to render the
407        * data requested into the clipboard.
408        */
409       TRACE("Sending WM_RENDERFORMAT message\n");
410       SendMessage16(hWndClipOwner,WM_RENDERFORMAT,
411                     (WPARAM16)lpFormat->wFormatID,0L);
412     }
413     else
414     {
415       WARN("\thWndClipOwner (%04x) is lost!\n", 
416            hWndClipOwner);
417       CLIPBOARD_ReleaseOwner();
418       lpFormat->wDataPresent = 0;
419       return FALSE;
420     }
421   }
422
423   return (lpFormat->hData16 || lpFormat->hData32) ? TRUE : FALSE;
424 }
425
426
427 /**************************************************************************
428  *                      CLIPBOARD_RenderText
429  *
430  * Renders text to the clipboard buffer converting between UNIX and DOS formats.
431  *
432  * RETURNS: pointer to the WINE_CLIPFORMAT if successful, NULL otherwise
433  *
434  * FIXME: Should be a pair of driver functions that convert between OEM text and Windows.
435  *
436  */
437 static LPWINE_CLIPFORMAT CLIPBOARD_RenderText( UINT wFormat )
438 {
439     LPWINE_CLIPFORMAT lpSource = ClipFormats; 
440     LPWINE_CLIPFORMAT lpTarget;
441     
442     /* Asked for CF_TEXT and not available - always attempt to convert from CF_OEM_TEXT */
443     if( wFormat == CF_TEXT && !ClipFormats[CF_TEXT-1].wDataPresent )
444     {
445         /* Convert OEMTEXT -> TEXT */
446         lpSource = &ClipFormats[CF_OEMTEXT-1];
447         lpTarget = &ClipFormats[CF_TEXT-1];
448
449         TRACE("\tOEMTEXT -> TEXT\n");
450     }
451     /* Asked for CF_OEM_TEXT, and CF_TEXT available */
452     else if( wFormat == CF_OEMTEXT && !ClipFormats[CF_OEMTEXT-1].wDataPresent
453                                    &&  ClipFormats[CF_TEXT-1].wDataPresent )
454     {
455         /* Convert TEXT -> OEMTEXT */
456         lpSource = &ClipFormats[CF_TEXT-1];
457         lpTarget = &ClipFormats[CF_OEMTEXT-1];
458         
459         TRACE("\tTEXT -> OEMTEXT\n");
460     }
461     /* Text format requested is available - no conversion necessary */
462     else
463     {
464         lpSource = __lookup_format( ClipFormats, wFormat );
465         lpTarget = lpSource;
466     }
467
468     /* First render the source text format */
469     if ( !lpSource || !CLIPBOARD_RenderFormat(lpSource) ) return NULL;
470
471     /* Convert to the desired target text format, if necessary */
472     if( lpTarget != lpSource && !lpTarget->hData16 && !lpTarget->hData32 )
473     {
474         UINT16 size;
475         LPCSTR lpstrS; 
476         LPSTR  lpstrT;
477     
478         if (lpSource->hData32)
479         {
480           size = GlobalSize( lpSource->hData32 );
481           lpstrS = (LPSTR)GlobalLock(lpSource->hData32);
482         }
483         else
484         {
485           size = GlobalSize16( lpSource->hData16 );
486           lpstrS = (LPSTR)GlobalLock16(lpSource->hData16);
487         }
488     
489         if( !lpstrS ) return NULL;
490         TRACE("\tconverting from '%s' to '%s', %i chars\n",
491                                           lpSource->Name, lpTarget->Name, size);
492     
493         lpTarget->hData32 = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE, size);
494         lpstrT = (LPSTR)GlobalLock(lpTarget->hData32);
495     
496         if( lpstrT )
497         {
498             if( lpSource->wFormatID == CF_TEXT )
499                 CharToOemBuffA(lpstrS, lpstrT, size);
500             else
501                 OemToCharBuffA(lpstrS, lpstrT, size);
502             TRACE("\tgot %s\n", lpstrT);
503             GlobalUnlock(lpTarget->hData32);
504         }
505         else
506             lpTarget->hData32 = 0;
507
508         /* Unlock source */
509         if (lpSource->hData32)
510           GlobalUnlock(lpSource->hData32);
511         else
512           GlobalUnlock16(lpSource->hData16);
513     }
514
515     return (lpTarget->hData16 || lpTarget->hData32) ? lpTarget : NULL;
516 }
517
518 /**************************************************************************
519  *                WIN32 Clipboard implementation 
520  **************************************************************************/
521
522 /**************************************************************************
523  *            OpenClipboard16   (USER.137)
524  */
525 BOOL16 WINAPI OpenClipboard16( HWND16 hWnd )
526 {
527     return OpenClipboard( hWnd );
528 }
529
530
531 /**************************************************************************
532  *            OpenClipboard   (USER32.407)
533  *
534  * Note: Netscape uses NULL hWnd to open the clipboard.
535  */
536 BOOL WINAPI OpenClipboard( HWND hWnd )
537 {
538     BOOL bRet;
539
540     TRACE("(%04x)...\n", hWnd);
541
542     if (!hClipLock)
543     {
544         hClipLock = GetCurrentTask();
545
546         /* Save current user of the clipboard */
547         hWndClipWindow = hWnd;
548         bCBHasChanged = FALSE;
549         bRet = TRUE;
550     }
551     else bRet = FALSE;
552
553     TRACE("   returning %i\n", bRet);
554     return bRet;
555 }
556
557
558 /**************************************************************************
559  *            CloseClipboard16   (USER.138)
560  */
561 BOOL16 WINAPI CloseClipboard16(void)
562 {
563     return CloseClipboard();
564 }
565
566
567 /**************************************************************************
568  *            CloseClipboard   (USER32.54)
569  */
570 BOOL WINAPI CloseClipboard(void)
571 {
572     TRACE("()\n");
573
574     if (hClipLock == GetCurrentTask())
575     {
576         hWndClipWindow = 0;
577
578         if (bCBHasChanged && hWndViewer) 
579             SendMessage16(hWndViewer, WM_DRAWCLIPBOARD, 0, 0L);
580         hClipLock = 0;
581     }
582     return TRUE;
583 }
584
585
586 /**************************************************************************
587  *            EmptyClipboard16   (USER.139)
588  */
589 BOOL16 WINAPI EmptyClipboard16(void)
590 {
591     return EmptyClipboard();
592 }
593
594
595 /**************************************************************************
596  *            EmptyClipboard   (USER32.169)
597  *  Empties and acquires ownership of the clipboard
598  */
599 BOOL WINAPI EmptyClipboard(void)
600 {
601     TRACE("()\n");
602
603     if (hClipLock != GetCurrentTask())
604     {
605         WARN("Clipboard not opened by calling task!");
606         return FALSE;
607     }
608     
609     /* destroy private objects */
610
611     if (hWndClipOwner)
612         SendMessage16(hWndClipOwner, WM_DESTROYCLIPBOARD, 0, 0L);
613
614     /* empty the cache */
615     CLIPBOARD_EmptyCache(TRUE);
616
617     /* Assign ownership of the clipboard to the current client */
618     hWndClipOwner = hWndClipWindow;
619
620     /* Save the current task */
621     hTaskClipOwner = GetCurrentTask();
622     
623     /* Tell the driver to acquire the selection */
624     CLIPBOARD_Driver->pAcquire();
625
626     return TRUE;
627 }
628
629
630 /**************************************************************************
631  *            GetClipboardOwner16   (USER.140)
632  *  FIXME: Can't return the owner if the clipbard is owned by an external app
633  */
634 HWND16 WINAPI GetClipboardOwner16(void)
635 {
636     TRACE("()\n");
637     return hWndClipOwner;
638 }
639
640
641 /**************************************************************************
642  *            GetClipboardOwner   (USER32.225)
643  *  FIXME: Can't return the owner if the clipbard is owned by an external app
644  */
645 HWND WINAPI GetClipboardOwner(void)
646 {
647     TRACE("()\n");
648     return hWndClipOwner;
649 }
650
651
652 /**************************************************************************
653  *            SetClipboardData16   (USER.141)
654  */
655 HANDLE16 WINAPI SetClipboardData16( UINT16 wFormat, HANDLE16 hData )
656 {
657     LPWINE_CLIPFORMAT lpFormat = __lookup_format( ClipFormats, wFormat );
658
659     TRACE("(%04X, %04x) !\n", wFormat, hData);
660
661     /* NOTE: If the hData is zero and current owner doesn't match
662      * the window that opened the clipboard then this application
663      * is screwed because WM_RENDERFORMAT will go to the owner.
664      * (to become the owner it must call EmptyClipboard() before
665      *  adding new data).
666      */
667
668     if( CLIPBOARD_IsLocked() || !lpFormat ||
669         (!hData && (!hWndClipOwner || (hWndClipOwner != hWndClipWindow))) )
670     {
671         WARN("Invalid hData or clipboard not opened by calling task!\n");
672         return 0;
673     }
674
675     /* Pass on the request to the driver */
676     CLIPBOARD_Driver->pSetData(wFormat);
677
678     if ( lpFormat->wDataPresent || lpFormat->hData16 || lpFormat->hData32 ) 
679     {
680         CLIPBOARD_DeleteRecord(lpFormat, TRUE);
681
682         /* delete existing CF_TEXT/CF_OEMTEXT aliases */
683
684         if( wFormat == CF_TEXT 
685             && ( ClipFormats[CF_OEMTEXT-1].hData16 
686                  ||  ClipFormats[CF_OEMTEXT-1].hData32 )
687             && !ClipFormats[CF_OEMTEXT-1].wDataPresent )
688             CLIPBOARD_DeleteRecord(&ClipFormats[CF_OEMTEXT-1], TRUE);
689         if( wFormat == CF_OEMTEXT 
690             && ( ClipFormats[CF_OEMTEXT-1].hData16 
691                  ||  ClipFormats[CF_OEMTEXT-1].hData32 )
692             && !ClipFormats[CF_TEXT-1].wDataPresent )
693             CLIPBOARD_DeleteRecord(&ClipFormats[CF_TEXT-1], TRUE);
694     }
695
696     bCBHasChanged = TRUE;
697     lpFormat->wDataPresent = 1;
698     lpFormat->hData16 = hData;          /* 0 is legal, see WM_RENDERFORMAT */
699     lpFormat->hData32 = 0;
700
701     return lpFormat->hData16;
702 }
703
704
705 /**************************************************************************
706  *            SetClipboardData   (USER32.470)
707  */
708 HANDLE WINAPI SetClipboardData( UINT wFormat, HANDLE hData )
709 {
710     LPWINE_CLIPFORMAT lpFormat = __lookup_format( ClipFormats, wFormat );
711
712     TRACE("(%08X, %08x) !\n", wFormat, hData);
713
714     /* NOTE: If the hData is zero and current owner doesn't match
715      * the window that opened the clipboard then this application
716      * is screwed because WM_RENDERFORMAT will go to the owner.
717      * (to become the owner it must call EmptyClipboard() before
718      *  adding new data).
719      */
720
721     if( CLIPBOARD_IsLocked() || !lpFormat ||
722         (!hData && (!hWndClipOwner || (hWndClipOwner != hWndClipWindow))) )
723     {
724         WARN("Invalid hData or clipboard not opened by calling task!\n");
725         return 0;
726     }
727
728     /* Tell the driver to acquire the selection */
729     CLIPBOARD_Driver->pAcquire();
730
731     if ( lpFormat->wDataPresent &&
732          (lpFormat->hData16 || lpFormat->hData32) )
733     {
734         CLIPBOARD_DeleteRecord(lpFormat, TRUE);
735
736         /* delete existing CF_TEXT/CF_OEMTEXT aliases */
737
738         if( wFormat == CF_TEXT 
739             && ( ClipFormats[CF_OEMTEXT-1].hData16 
740                  ||  ClipFormats[CF_OEMTEXT-1].hData32 )
741             && !ClipFormats[CF_OEMTEXT-1].wDataPresent )
742             CLIPBOARD_DeleteRecord(&ClipFormats[CF_OEMTEXT-1], TRUE);
743         if( wFormat == CF_OEMTEXT 
744             && ( ClipFormats[CF_OEMTEXT-1].hData16 
745                  ||  ClipFormats[CF_OEMTEXT-1].hData32 )
746             && !ClipFormats[CF_TEXT-1].wDataPresent )
747             CLIPBOARD_DeleteRecord(&ClipFormats[CF_TEXT-1], TRUE);
748     }
749
750     bCBHasChanged = TRUE;
751     lpFormat->wDataPresent = 1;
752     lpFormat->hDataSrc32 = hData;  /* Save the source handle */
753
754     /*
755      * Make a shared duplicate if the memory is not shared
756      * TODO: What should be done for non-memory objects
757      */
758     if ( CLIPBOARD_IsMemoryObject(wFormat) && hData && !(GlobalFlags(hData) & GMEM_DDESHARE) )
759         lpFormat->hData32 = CLIPBOARD_GlobalDupMem( hData );
760     else
761         lpFormat->hData32 = hData;          /* 0 is legal, see WM_RENDERFORMAT */
762     
763     lpFormat->hData16 = 0;
764
765     return lpFormat->hData32;   /* Should we return lpFormat->hDataSrc32 */
766 }
767
768
769 /**************************************************************************
770  *             GetClipboardData16   (USER.142)
771  */
772 HANDLE16 WINAPI GetClipboardData16( UINT16 wFormat )
773 {
774     LPWINE_CLIPFORMAT lpRender = ClipFormats; 
775
776     TRACE("(%04X)\n", wFormat);
777
778     if (CLIPBOARD_IsLocked())
779     {
780         WARN("Clipboard not opened by calling task!\n");
781         return 0;
782     }
783
784     if( wFormat == CF_TEXT || wFormat == CF_OEMTEXT )
785     {
786         lpRender = CLIPBOARD_RenderText(wFormat);
787         if ( !lpRender ) return 0;
788     }
789     else
790     {
791         lpRender = __lookup_format( ClipFormats, wFormat );
792         if( !lpRender || !CLIPBOARD_RenderFormat(lpRender) ) return 0;
793     }
794    
795     /* Convert between 32 -> 16 bit data, if necessary */
796     if( lpRender->hData32 && !lpRender->hData16
797         && CLIPBOARD_IsMemoryObject(wFormat) )
798     {
799       int size;
800       if( lpRender->wFormatID == CF_METAFILEPICT )
801         size = sizeof( METAFILEPICT16 );
802       else
803           size = GlobalSize(lpRender->hData32);
804       
805       lpRender->hData16 = GlobalAlloc16(GMEM_ZEROINIT, size);
806       if( !lpRender->hData16 )
807         ERR("(%04X) -- not enough memory in 16b heap\n", wFormat);
808       else
809       {
810         if( lpRender->wFormatID == CF_METAFILEPICT )
811         {
812           FIXME("\timplement function CopyMetaFilePict32to16\n");
813           FIXME("\tin the appropriate file.\n");
814   #ifdef SOMEONE_IMPLEMENTED_ME
815           CopyMetaFilePict32to16( GlobalLock16(lpRender->hData16), 
816                                   GlobalLock(lpRender->hData32) );
817   #endif
818         }
819         else
820         {
821           memcpy( GlobalLock16(lpRender->hData16), 
822                   GlobalLock(lpRender->hData32), 
823                   size );
824         }
825         GlobalUnlock16(lpRender->hData16);
826         GlobalUnlock(lpRender->hData32);
827       }
828     }
829
830     TRACE("\treturning %04x (type %i)\n", 
831                               lpRender->hData16, lpRender->wFormatID);
832     return lpRender->hData16;
833 }
834
835
836 /**************************************************************************
837  *             GetClipboardData   (USER32.222)
838  */
839 HANDLE WINAPI GetClipboardData( UINT wFormat )
840 {
841     LPWINE_CLIPFORMAT lpRender = ClipFormats; 
842
843     TRACE("(%08X)\n", wFormat);
844
845     if (CLIPBOARD_IsLocked())
846     {
847         WARN("Clipboard not opened by calling task!");
848         return 0;
849     }
850
851     if( wFormat == CF_TEXT || wFormat == CF_OEMTEXT )
852     {
853         lpRender = CLIPBOARD_RenderText(wFormat);
854         if ( !lpRender ) return 0;
855     }
856     else
857     {
858         lpRender = __lookup_format( ClipFormats, wFormat );
859         if( !lpRender || !CLIPBOARD_RenderFormat(lpRender) ) return 0;
860     }
861    
862     /* Convert between 16 -> 32 bit data, if necessary */
863     if( lpRender->hData16 && !lpRender->hData32
864         && CLIPBOARD_IsMemoryObject(wFormat) )
865     {
866       int size;
867       if( lpRender->wFormatID == CF_METAFILEPICT )
868         size = sizeof( METAFILEPICT );
869       else
870         size = GlobalSize16(lpRender->hData16);
871       lpRender->hData32 = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE,
872                                       size);
873       if( lpRender->wFormatID == CF_METAFILEPICT )
874       {
875         FIXME("\timplement function CopyMetaFilePict16to32\n");
876         FIXME("\tin the appropriate file.\n");
877 #ifdef SOMEONE_IMPLEMENTED_ME
878         CopyMetaFilePict16to32( GlobalLock16(lpRender->hData32), 
879                                 GlobalLock(lpRender->hData16) );
880 #endif
881       }
882       else
883       {
884         memcpy( GlobalLock(lpRender->hData32), 
885                 GlobalLock16(lpRender->hData16), 
886                 size );
887       }
888       GlobalUnlock(lpRender->hData32);
889       GlobalUnlock16(lpRender->hData16);
890     }
891
892     TRACE("\treturning %04x (type %i)\n", 
893                               lpRender->hData32, lpRender->wFormatID);
894     return lpRender->hData32;
895 }
896
897
898 /**************************************************************************
899  *           CountClipboardFormats16   (USER.143)
900  */
901 INT16 WINAPI CountClipboardFormats16(void)
902 {
903     return CountClipboardFormats();
904 }
905
906
907 /**************************************************************************
908  *           CountClipboardFormats   (USER32.63)
909  */
910 INT WINAPI CountClipboardFormats(void)
911 {
912     INT FormatCount = 0;
913     LPWINE_CLIPFORMAT lpFormat = ClipFormats; 
914
915     TRACE("()\n");
916
917     while(TRUE) 
918     {
919         if (lpFormat == NULL) break;
920
921         if( lpFormat->wFormatID != CF_TEXT ) /* Don't count CF_TEXT */
922         {
923           /*
924            * The format is available if either:
925            * 1. The data is already in the cache.
926            * 2. The selection is not owned by us(WINE) and the data is
927            *    available to the clipboard driver.
928            */
929           if ( lpFormat->wDataPresent ||
930                ( !CLIPBOARD_Driver->pIsSelectionOwner()
931                  && CLIPBOARD_Driver->pIsFormatAvailable( lpFormat->wFormatID ) ) )
932           {
933               TRACE("\tdata found for format 0x%04x(%s)\n",
934                     lpFormat->wFormatID, CLIPBOARD_GetFormatName(lpFormat->wFormatID));
935               FormatCount++;
936           }
937         }
938
939         lpFormat = lpFormat->NextFormat;
940     }
941
942     /* these two are equivalent, adjust the total */
943
944     FormatCount += abs(ClipFormats[CF_TEXT-1].wDataPresent -
945                        ClipFormats[CF_OEMTEXT-1].wDataPresent);
946
947     TRACE("\ttotal %d\n", FormatCount);
948     return FormatCount;
949 }
950
951
952 /**************************************************************************
953  *            EnumClipboardFormats16   (USER.144)
954  */
955 UINT16 WINAPI EnumClipboardFormats16( UINT16 wFormat )
956 {
957     return EnumClipboardFormats( wFormat );
958 }
959
960
961 /**************************************************************************
962  *            EnumClipboardFormats   (USER32.179)
963  */
964 UINT WINAPI EnumClipboardFormats( UINT wFormat )
965 {
966     LPWINE_CLIPFORMAT lpFormat = ClipFormats;
967     BOOL bFormatPresent;
968
969     TRACE("(%04X)\n", wFormat);
970
971     if (CLIPBOARD_IsLocked())
972     {
973         WARN("Clipboard not opened by calling task!");
974         return 0;
975     }
976
977     if (wFormat == 0) /* start from the beginning */
978         lpFormat = ClipFormats;
979     else
980     {
981         /* walk up to the specified format record */
982
983         if( !(lpFormat = __lookup_format( lpFormat, wFormat )) ) 
984             return 0;
985         lpFormat = lpFormat->NextFormat; /* right */
986     }
987
988     while(TRUE) 
989     {
990         if (lpFormat == NULL) return 0;
991
992         /* Synthesize CF_TEXT from CF_OEMTEXT and vice versa */
993         bFormatPresent = (lpFormat->wDataPresent ||
994            (lpFormat->wFormatID == CF_OEMTEXT && ClipFormats[CF_TEXT-1].wDataPresent) ||
995            (lpFormat->wFormatID == CF_TEXT && ClipFormats[CF_OEMTEXT-1].wDataPresent) );
996
997         /* Query the driver if not yet in the cache */
998         if (!bFormatPresent && !CLIPBOARD_Driver->pIsSelectionOwner())
999         {
1000             bFormatPresent =
1001                CLIPBOARD_Driver->pIsFormatAvailable( (lpFormat->wFormatID == CF_TEXT) ?
1002                                                       CF_OEMTEXT : lpFormat->wFormatID );
1003         }
1004
1005         if (bFormatPresent)
1006             break;
1007
1008         lpFormat = lpFormat->NextFormat;
1009     }
1010
1011     return lpFormat->wFormatID;
1012 }
1013
1014
1015 /**************************************************************************
1016  *            RegisterClipboardFormat16  (USER.145)
1017  */
1018 UINT16 WINAPI RegisterClipboardFormat16( LPCSTR FormatName )
1019 {
1020     LPWINE_CLIPFORMAT lpNewFormat; 
1021     LPWINE_CLIPFORMAT lpFormat = ClipFormats; 
1022
1023     if (FormatName == NULL) return 0;
1024
1025     TRACE("('%s') !\n", FormatName);
1026
1027     /* walk format chain to see if it's already registered */
1028
1029     while(TRUE) 
1030     {
1031         if ( !strcmp(lpFormat->Name,FormatName) )
1032         {
1033              lpFormat->wRefCount++;
1034              return lpFormat->wFormatID;
1035         }
1036  
1037         if ( lpFormat->NextFormat == NULL ) break;
1038
1039         lpFormat = lpFormat->NextFormat;
1040     }
1041
1042     /* allocate storage for new format entry */
1043
1044     lpNewFormat = (LPWINE_CLIPFORMAT)HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CLIPFORMAT));
1045     if(lpNewFormat == NULL) {
1046         WARN("No more memory for a new format!");
1047         return 0;
1048     }
1049     lpFormat->NextFormat = lpNewFormat;
1050     lpNewFormat->wFormatID = LastRegFormat;
1051     lpNewFormat->wRefCount = 1;
1052
1053     lpNewFormat->Name = (LPSTR)HEAP_strdupA(GetProcessHeap(), 0, FormatName);
1054     if(lpNewFormat->Name == NULL) {
1055         WARN("No more memory for the new format name!");
1056         HeapFree(GetProcessHeap(), 0, lpNewFormat);
1057         return 0;
1058     }
1059
1060     lpNewFormat->wDataPresent = 0;
1061     lpNewFormat->hData16 = 0;
1062     lpNewFormat->hDataSrc32 = 0;
1063     lpNewFormat->hData32 = 0;
1064     lpNewFormat->drvData = 0;
1065     lpNewFormat->PrevFormat = lpFormat;
1066     lpNewFormat->NextFormat = NULL;
1067
1068     /* Pass on the registration request to the driver */
1069     CLIPBOARD_Driver->pRegisterFormat( FormatName );
1070     
1071     return LastRegFormat++;
1072 }
1073
1074
1075 /**************************************************************************
1076  *            RegisterClipboardFormatA   (USER32.431)
1077  */
1078 UINT WINAPI RegisterClipboardFormatA( LPCSTR formatName )
1079 {
1080     return RegisterClipboardFormat16( formatName );
1081 }
1082
1083
1084 /**************************************************************************
1085  *            RegisterClipboardFormatW   (USER32.432)
1086  */
1087 UINT WINAPI RegisterClipboardFormatW( LPCWSTR formatName )
1088 {
1089     LPSTR aFormat = HEAP_strdupWtoA( GetProcessHeap(), 0, formatName );
1090     UINT ret = RegisterClipboardFormatA( aFormat );
1091     HeapFree( GetProcessHeap(), 0, aFormat );
1092     return ret;
1093 }
1094
1095
1096 /**************************************************************************
1097  *            GetClipboardFormatName16   (USER.146)
1098  */
1099 INT16 WINAPI GetClipboardFormatName16( UINT16 wFormat, LPSTR retStr, INT16 maxlen )
1100 {
1101     return GetClipboardFormatNameA( wFormat, retStr, maxlen );
1102 }
1103
1104
1105 /**************************************************************************
1106  *            GetClipboardFormatNameA   (USER32.223)
1107  */
1108 INT WINAPI GetClipboardFormatNameA( UINT wFormat, LPSTR retStr, INT maxlen )
1109 {
1110     LPWINE_CLIPFORMAT lpFormat = __lookup_format( ClipFormats, wFormat );
1111
1112     TRACE("(%04X, %p, %d) !\n", wFormat, retStr, maxlen);
1113
1114     if (lpFormat == NULL || lpFormat->Name == NULL || 
1115         lpFormat->wFormatID < CF_REGFORMATBASE) return 0;
1116
1117     TRACE("Name='%s' !\n", lpFormat->Name);
1118
1119     lstrcpynA( retStr, lpFormat->Name, maxlen );
1120     return strlen(retStr);
1121 }
1122
1123
1124 /**************************************************************************
1125  *            GetClipboardFormatNameW   (USER32.224)
1126  */
1127 INT WINAPI GetClipboardFormatNameW( UINT wFormat, LPWSTR retStr, INT maxlen )
1128 {
1129     INT ret;
1130     LPSTR p = HeapAlloc( GetProcessHeap(), 0, maxlen );
1131     if(p == NULL) return 0; /* FIXME: is this the correct failure value? */
1132     
1133     ret = GetClipboardFormatNameA( wFormat, p, maxlen );
1134     lstrcpynAtoW( retStr, p, maxlen );
1135     HeapFree( GetProcessHeap(), 0, p );
1136     return ret;
1137 }
1138
1139
1140 /**************************************************************************
1141  *            SetClipboardViewer16   (USER.147)
1142  */
1143 HWND16 WINAPI SetClipboardViewer16( HWND16 hWnd )
1144 {
1145     TRACE("(%04x)\n", hWnd);
1146     return SetClipboardViewer( hWnd );
1147 }
1148
1149
1150 /**************************************************************************
1151  *            SetClipboardViewer   (USER32.471)
1152  */
1153 HWND WINAPI SetClipboardViewer( HWND hWnd )
1154 {
1155     HWND hwndPrev = hWndViewer;
1156
1157     TRACE("(%04x): returning %04x\n", hWnd, hwndPrev);
1158
1159     hWndViewer = hWnd;
1160     return hwndPrev;
1161 }
1162
1163
1164 /**************************************************************************
1165  *           GetClipboardViewer16   (USER.148)
1166  */
1167 HWND16 WINAPI GetClipboardViewer16(void)
1168 {
1169     TRACE("()\n");
1170     return hWndViewer;
1171 }
1172
1173
1174 /**************************************************************************
1175  *           GetClipboardViewer   (USER32.226)
1176  */
1177 HWND WINAPI GetClipboardViewer(void)
1178 {
1179     TRACE("()\n");
1180     return hWndViewer;
1181 }
1182
1183
1184 /**************************************************************************
1185  *           ChangeClipboardChain16   (USER.149)
1186  */
1187 BOOL16 WINAPI ChangeClipboardChain16(HWND16 hWnd, HWND16 hWndNext)
1188 {
1189     return ChangeClipboardChain(hWnd, hWndNext);
1190 }
1191
1192
1193 /**************************************************************************
1194  *           ChangeClipboardChain   (USER32.22)
1195  */
1196 BOOL WINAPI ChangeClipboardChain(HWND hWnd, HWND hWndNext)
1197 {
1198     BOOL bRet = 0;
1199
1200     FIXME("(0x%04x, 0x%04x): stub?\n", hWnd, hWndNext);
1201
1202     if( hWndViewer )
1203         bRet = !SendMessage16( hWndViewer, WM_CHANGECBCHAIN,
1204                              (WPARAM16)hWnd, (LPARAM)hWndNext);   
1205     else
1206         WARN("hWndViewer is lost\n");
1207
1208     if( hWnd == hWndViewer ) hWndViewer = hWndNext;
1209
1210     return bRet;
1211 }
1212
1213
1214 /**************************************************************************
1215  *           IsClipboardFormatAvailable16   (USER.193)
1216  */
1217 BOOL16 WINAPI IsClipboardFormatAvailable16( UINT16 wFormat )
1218 {
1219     return IsClipboardFormatAvailable( wFormat );
1220 }
1221
1222
1223 /**************************************************************************
1224  *           IsClipboardFormatAvailable   (USER32.340)
1225  */
1226 BOOL WINAPI IsClipboardFormatAvailable( UINT wFormat )
1227 {
1228     BOOL bRet;
1229
1230     if (wFormat == 0)  /* Reject this case quickly */
1231         bRet = FALSE;
1232
1233     /* If WINE is not the clipboard selection owner ask the clipboard driver */
1234     else if ( !CLIPBOARD_Driver->pIsSelectionOwner() )
1235         bRet = CLIPBOARD_Driver->pIsFormatAvailable( (wFormat == CF_TEXT) ?
1236                                                      CF_OEMTEXT : wFormat );
1237     /* Check if the format is in the local cache */
1238     else 
1239         bRet = CLIPBOARD_IsPresent(wFormat);
1240
1241     TRACE("(%04X)- ret(%d)\n", wFormat, bRet);
1242     return bRet;
1243 }
1244
1245
1246 /**************************************************************************
1247  *             GetOpenClipboardWindow16   (USER.248)
1248  *  FIXME: This wont work if an external app owns the selection
1249  */
1250 HWND16 WINAPI GetOpenClipboardWindow16(void)
1251 {
1252     TRACE("()\n");
1253     return hWndClipWindow;
1254 }
1255
1256
1257 /**************************************************************************
1258  *             GetOpenClipboardWindow   (USER32.277)
1259  *  FIXME: This wont work if an external app owns the selection
1260  */
1261 HWND WINAPI GetOpenClipboardWindow(void)
1262 {
1263     TRACE("()\n");
1264     return hWndClipWindow;
1265 }
1266
1267
1268 /**************************************************************************
1269  *             GetPriorityClipboardFormat16   (USER.402)
1270  */
1271 INT16 WINAPI GetPriorityClipboardFormat16( UINT16 *lpPriorityList, INT16 nCount)
1272 {
1273     FIXME("(%p,%d): stub\n", lpPriorityList, nCount );
1274     return 0;
1275 }
1276
1277
1278 /**************************************************************************
1279  *             GetPriorityClipboardFormat   (USER32.279)
1280  */
1281 INT WINAPI GetPriorityClipboardFormat( UINT *lpPriorityList, INT nCount )
1282 {
1283     int Counter;
1284     TRACE("()\n");
1285
1286     if(CountClipboardFormats() == 0) 
1287     { 
1288         return 0;
1289     }
1290
1291     for(Counter = 0; Counter <= nCount; Counter++)
1292     {
1293         if(IsClipboardFormatAvailable(*(lpPriorityList+sizeof(INT)*Counter)))
1294             return *(lpPriorityList+sizeof(INT)*Counter);
1295     }
1296
1297     return -1;
1298 }
1299