Make sure that HWND comparisons are always done with full 32-bit
[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
17 #include <stdlib.h>
18 #include <sys/types.h>
19 #include <fcntl.h>
20 #include <unistd.h>
21 #include <string.h>
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wingdi.h"
26 #include "winuser.h"
27 #include "wine/winuser16.h"
28 #include "wine/winbase16.h"
29 #include "heap.h"
30 #include "user.h"
31 #include "win.h"
32 #include "clipboard.h"
33 #include "debugtools.h"
34
35 DEFAULT_DEBUG_CHANNEL(clipboard);
36
37 #define  CF_REGFORMATBASE       0xC000
38
39 /**************************************************************************
40  *        Clipboard context global variables
41  */
42
43 static HANDLE hClipLock   = 0;
44 static BOOL bCBHasChanged  = FALSE;
45
46 static HWND hWndClipWindow;        /* window that last opened clipboard */
47 static HWND hWndClipOwner;         /* current clipboard owner */
48 static HANDLE16 hTaskClipOwner;    /* clipboard owner's task  */
49 static HWND hWndViewer;            /* start of viewers chain */
50
51 static WORD LastRegFormat = CF_REGFORMATBASE;
52
53 /* Clipboard cache initial data.
54  * WARNING: This data ordering is dependent on the WINE_CLIPFORMAT structure
55  * declared in clipboard.h
56  */
57 WINE_CLIPFORMAT ClipFormats[]  = {
58     { CF_TEXT, 1, 0, "Text",  0, 0, 0, 0, NULL, &ClipFormats[1]},
59     { CF_BITMAP, 1, 0, "Bitmap", 0, 0, 0, 0, &ClipFormats[0], &ClipFormats[2]},
60     { CF_METAFILEPICT, 1, 0, "MetaFile Picture", 0, 0, 0, 0, &ClipFormats[1], &ClipFormats[3]},
61     { CF_SYLK, 1, 0, "Sylk", 0, 0, 0, 0, &ClipFormats[2], &ClipFormats[4]},
62     { CF_DIF, 1, 0, "DIF", 0, 0, 0, 0, &ClipFormats[3], &ClipFormats[5]},
63     { CF_TIFF, 1, 0, "TIFF", 0, 0, 0, 0, &ClipFormats[4], &ClipFormats[6]},
64     { CF_OEMTEXT, 1, 0, "OEM Text", 0, 0, 0, 0, &ClipFormats[5], &ClipFormats[7]},
65     { CF_DIB, 1, 0, "DIB", 0, 0, 0, 0, &ClipFormats[6], &ClipFormats[8]},
66     { CF_PALETTE, 1, 0, "Palette", 0, 0, 0, 0, &ClipFormats[7], &ClipFormats[9]},
67     { CF_PENDATA, 1, 0, "PenData", 0, 0, 0, 0, &ClipFormats[8], &ClipFormats[10]},
68     { CF_RIFF, 1, 0, "RIFF", 0, 0, 0, 0, &ClipFormats[9], &ClipFormats[11]},
69     { CF_WAVE, 1, 0, "Wave", 0, 0, 0, 0, &ClipFormats[10], &ClipFormats[12]},
70     { CF_UNICODETEXT, 1, 0, "Unicode Text", 0, 0, 0, 0, &ClipFormats[11], &ClipFormats[13]},
71     { CF_OWNERDISPLAY, 1, 0, "Owner Display", 0, 0, 0, 0, &ClipFormats[12], &ClipFormats[14]},
72     { CF_DSPTEXT, 1, 0, "DSPText", 0, 0, 0, 0, &ClipFormats[13], &ClipFormats[15]},
73     { CF_DSPMETAFILEPICT, 1, 0, "DSPMetaFile Picture", 0, 0, 0, 0, &ClipFormats[14], &ClipFormats[16]},
74     { CF_DSPBITMAP, 1, 0, "DSPBitmap", 0, 0, 0, 0, &ClipFormats[15], &ClipFormats[17]},
75     { CF_HDROP, 1, 0, "HDROP", 0, 0, 0, 0, &ClipFormats[16], NULL}
76 };
77
78
79 /**************************************************************************
80  *                Internal Clipboard implementation methods
81  **************************************************************************/
82
83
84 /**************************************************************************
85  *                      CLIPBOARD_LookupFormat
86  */
87 static LPWINE_CLIPFORMAT __lookup_format( LPWINE_CLIPFORMAT lpFormat, WORD wID )
88 {
89     while(TRUE)
90     {
91         if (lpFormat == NULL ||
92             lpFormat->wFormatID == wID) break;
93         lpFormat = lpFormat->NextFormat;
94     }
95     return lpFormat;
96 }
97
98 LPWINE_CLIPFORMAT CLIPBOARD_LookupFormat( WORD wID )
99 {
100   return __lookup_format( ClipFormats, wID );
101 }
102
103 /**************************************************************************
104  *                      CLIPBOARD_IsLocked
105  *  Check if the clipboard cache is available to the caller
106  */
107 BOOL CLIPBOARD_IsLocked()
108 {
109   BOOL bIsLocked = TRUE;
110   HANDLE16 hTaskCur = GetCurrentTask();
111
112   /*
113    * The clipboard is available:
114    * 1. if the caller's task has opened the clipboard,
115    * or
116    * 2. if the caller is the clipboard owners task, AND is responding to a
117    *    WM_RENDERFORMAT message.
118    */
119   if ( hClipLock == hTaskCur )
120       bIsLocked = FALSE;
121       
122   else if ( hTaskCur == hTaskClipOwner )
123   {
124       /* Check if we're currently executing inside a window procedure
125        * called in response to a WM_RENDERFORMAT message. A WM_RENDERFORMAT
126        * handler is not permitted to open the clipboard since it has been opened
127        * by another client. However the handler must have access to the
128        * clipboard in order to update data in response to this message.
129        */
130 #if 0
131       MESSAGEQUEUE *queue = QUEUE_Current();
132       
133       if ( queue
134            && queue->smWaiting
135            && queue->smWaiting->msg == WM_RENDERFORMAT
136            && queue->smWaiting->hSrcQueue
137          )
138         bIsLocked = FALSE;
139 #else
140       /* FIXME: queue check no longer possible */
141       bIsLocked = FALSE;
142 #endif
143   }
144
145   return bIsLocked;
146 }
147
148 /**************************************************************************
149  *                      CLIPBOARD_ReleaseOwner
150  *   Gives up ownership of the clipboard
151  */
152 void CLIPBOARD_ReleaseOwner()
153 {
154    hWndClipOwner = 0;
155    hTaskClipOwner = 0;
156 }
157
158 /**************************************************************************
159  *                      CLIPBOARD_GlobalFreeProc
160  *
161  * This is a callback mechanism to allow HGLOBAL data to be released in
162  * the context of the process which allocated it. We post a WM_TIMER message
163  * to the owner window(in CLIPBOARD_DeleteRecord) and destroy the data(in idEvent)
164  * in this WndProc, which is invoked when the apps message loop calls DispatchMessage.
165  * This technique is discussed in Matt Pietrek's "Under the Hood".
166  * An article describing the same may be found in MSDN by searching for WM_TIMER.
167  * Note that this mechanism will probably stop working when WINE supports
168  * address space separation. When "queue events" are implemented in Wine we
169  * should switch to using that mechanism, since it is more robust and does not
170  * require a procedure address to be passed. See the SetWinEventHook API for
171  * more info on this.
172  */
173 VOID CALLBACK CLIPBOARD_GlobalFreeProc( HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime )
174 {
175     /* idEvent is the HGLOBAL to be deleted */
176     GlobalFree( (HGLOBAL)idEvent );
177 }
178
179 /**************************************************************************
180  *                      CLIPBOARD_DeleteRecord
181  */
182 void CLIPBOARD_DeleteRecord(LPWINE_CLIPFORMAT lpFormat, BOOL bChange)
183 {
184     if( (lpFormat->wFormatID >= CF_GDIOBJFIRST &&
185          lpFormat->wFormatID <= CF_GDIOBJLAST) || lpFormat->wFormatID == CF_BITMAP 
186             || lpFormat->wFormatID == CF_PALETTE)
187     {
188       if (lpFormat->hData32)
189         DeleteObject(lpFormat->hData32);
190       if (lpFormat->hData16)
191         DeleteObject(lpFormat->hData16);
192     }
193     else if( lpFormat->wFormatID == CF_METAFILEPICT )
194     {
195       if (lpFormat->hData32)
196       {
197         DeleteMetaFile( ((METAFILEPICT *)GlobalLock( lpFormat->hData32 ))->hMF );
198         PostMessageA(hWndClipOwner, WM_TIMER,
199                      (WPARAM)lpFormat->hData32, (LPARAM)CLIPBOARD_GlobalFreeProc);
200         if (lpFormat->hDataSrc32)
201         {
202           /* Release lpFormat->hData32 in the context of the process which created it.
203            * See CLIPBOARD_GlobalFreeProc for more details about this technique.
204            * GlobalFree(lpFormat->hDataSrc32);
205            */
206           PostMessageA(hWndClipOwner, WM_TIMER,
207                        (WPARAM)lpFormat->hDataSrc32, (LPARAM)CLIPBOARD_GlobalFreeProc);
208         }
209           
210         if (lpFormat->hData16)
211           /* HMETAFILE16 and HMETAFILE32 are apparently the same thing, 
212              and a shallow copy is enough to share a METAFILEPICT
213              structure between 16bit and 32bit clipboards.  The MetaFile
214              should of course only be deleted once. */
215           GlobalFree16(lpFormat->hData16);
216       }
217       if (lpFormat->hData16)
218       {
219         DeleteMetaFile16( ((METAFILEPICT16 *)GlobalLock16( lpFormat->hData16 ))->hMF );
220         GlobalFree16(lpFormat->hData16);
221       }
222     }
223     else 
224     {
225       if (lpFormat->hData32)
226       {
227         /* Release lpFormat->hData32 in the context of the process which created it.
228          * See CLIPBOARD_GlobalFreeProc for more details about this technique.
229          * GlobalFree( lpFormat->hData32 );
230          */
231         PostMessageA(hWndClipOwner, WM_TIMER,
232                      (WPARAM)lpFormat->hData32, (LPARAM)CLIPBOARD_GlobalFreeProc);
233       }
234       if (lpFormat->hDataSrc32)
235       {
236         /* Release lpFormat->hData32 in the context of the process which created it.
237          * See CLIPBOARD_GlobalFreeProc for more details about this technique.
238          * GlobalFree(lpFormat->hDataSrc32);
239          */
240         PostMessageA(hWndClipOwner, WM_TIMER,
241                      (WPARAM)lpFormat->hDataSrc32, (LPARAM)CLIPBOARD_GlobalFreeProc);
242       }
243       if (lpFormat->hData16)
244         GlobalFree16(lpFormat->hData16);
245     }
246
247     lpFormat->wDataPresent = 0; 
248     lpFormat->hData16 = 0;
249     lpFormat->hData32 = 0;
250     lpFormat->hDataSrc32 = 0;
251     lpFormat->drvData = 0;
252
253     if( bChange ) bCBHasChanged = TRUE;
254 }
255
256 /**************************************************************************
257  *                      CLIPBOARD_EmptyCache
258  */
259 void CLIPBOARD_EmptyCache( BOOL bChange )
260 {
261     LPWINE_CLIPFORMAT lpFormat = ClipFormats; 
262
263     while(lpFormat)
264     {
265         if ( lpFormat->wDataPresent || lpFormat->hData16 || lpFormat->hData32 )
266              CLIPBOARD_DeleteRecord( lpFormat, bChange );
267
268         lpFormat = lpFormat->NextFormat;
269     }
270 }
271
272 /**************************************************************************
273  *                      CLIPBOARD_IsPresent
274  */
275 BOOL CLIPBOARD_IsPresent(WORD wFormat)
276 {
277     /* special case */
278
279     if( wFormat == CF_TEXT || wFormat == CF_OEMTEXT || wFormat == CF_UNICODETEXT )
280         return ClipFormats[CF_TEXT-1].wDataPresent ||
281                ClipFormats[CF_OEMTEXT-1].wDataPresent ||
282                ClipFormats[CF_UNICODETEXT-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 driver to render the data to the clipboard cache.
391    */
392   TRACE("enter format=%d\n", lpFormat->wFormatID);
393   if ( !USER_Driver.pIsSelectionOwner() 
394        && USER_Driver.pIsClipboardFormatAvailable( lpFormat->wFormatID ) )
395   {
396     if ( !USER_Driver.pGetClipboardData( lpFormat->wFormatID ) )
397       return FALSE;
398   }
399   /*
400    * If Wine owns the clipboard, and the data is marked for delayed render,
401    * render it now.
402    */
403   else if( lpFormat->wDataPresent && !lpFormat->hData16 && !lpFormat->hData32 )
404   {
405     if( IsWindow(hWndClipOwner) )
406     {
407       /* Send a WM_RENDERFORMAT message to notify the owner to render the
408        * data requested into the clipboard.
409        */
410       TRACE("Sending WM_RENDERFORMAT message\n");
411       SendMessageW( hWndClipOwner, WM_RENDERFORMAT, (WPARAM)lpFormat->wFormatID, 0 );
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  *                      CLIPBOARD_ConvertText
428  * Returns number of required/converted characters - not bytes!
429  */
430 static INT CLIPBOARD_ConvertText(WORD src_fmt, void const *src, INT src_size,
431                                  WORD dst_fmt, void *dst, INT dst_size)
432 {
433     UINT cp;
434
435     if(src_fmt == CF_UNICODETEXT)
436     {
437         switch(dst_fmt)
438         {
439         case CF_TEXT:
440             cp = CP_ACP;
441             break;
442         case CF_OEMTEXT:
443             cp = CP_OEMCP;
444             break;
445         default:
446             return 0;
447         }
448         return WideCharToMultiByte(cp, 0, src, src_size, dst, dst_size, NULL, NULL);
449     }
450
451     if(dst_fmt == CF_UNICODETEXT)
452     {
453         switch(src_fmt)
454         {
455         case CF_TEXT:
456             cp = CP_ACP;
457             break;
458         case CF_OEMTEXT:
459             cp = CP_OEMCP;
460             break;
461         default:
462             return 0;
463         }
464         return MultiByteToWideChar(cp, 0, src, src_size, dst, dst_size);
465     }
466
467     if(!dst_size) return src_size;
468
469     if(dst_size > src_size) dst_size = src_size;
470
471     if(src_fmt == CF_TEXT )
472         CharToOemBuffA(src, dst, dst_size);
473     else
474         OemToCharBuffA(src, dst, dst_size);
475
476     return dst_size;
477 }
478
479 /**************************************************************************
480  *                      CLIPBOARD_RenderText
481  *
482  * Renders text to the clipboard buffer converting between UNIX and DOS formats.
483  *
484  * RETURNS: pointer to the WINE_CLIPFORMAT if successful, NULL otherwise
485  *
486  * FIXME: Should be a pair of driver functions that convert between OEM text and Windows.
487  *
488  */
489 static LPWINE_CLIPFORMAT CLIPBOARD_RenderText( UINT wFormat )
490 {
491     LPWINE_CLIPFORMAT lpSource = ClipFormats; 
492     LPWINE_CLIPFORMAT lpTarget = NULL;
493     BOOL foundData = FALSE;
494  
495     /* Asked for CF_TEXT */
496     if( wFormat == CF_TEXT)
497     {
498         if(ClipFormats[CF_TEXT-1].wDataPresent)
499         {
500             lpSource = &ClipFormats[CF_TEXT-1];
501             lpTarget = &ClipFormats[CF_TEXT-1];
502             foundData = TRUE;
503             TRACE("\t TEXT -> TEXT\n");
504         }
505         else if(ClipFormats[CF_UNICODETEXT-1].wDataPresent)
506         {
507             /* Convert UNICODETEXT -> TEXT */
508             lpSource = &ClipFormats[CF_UNICODETEXT-1];
509             lpTarget = &ClipFormats[CF_TEXT-1];
510             foundData = TRUE;
511             TRACE("\tUNICODETEXT -> TEXT\n");
512         }
513         else if(ClipFormats[CF_OEMTEXT-1].wDataPresent)
514         {
515             /* Convert OEMTEXT -> TEXT */
516             lpSource = &ClipFormats[CF_OEMTEXT-1];
517             lpTarget = &ClipFormats[CF_TEXT-1];
518             foundData = TRUE;
519             TRACE("\tOEMTEXT -> TEXT\n");
520         }
521     }
522     /* Asked for CF_OEMTEXT  */
523     else if( wFormat == CF_OEMTEXT)
524     {
525         if(ClipFormats[CF_OEMTEXT-1].wDataPresent)
526         {
527             lpSource = &ClipFormats[CF_OEMTEXT-1];
528             lpTarget = &ClipFormats[CF_OEMTEXT-1];
529             foundData = TRUE;
530             TRACE("\tOEMTEXT -> OEMTEXT\n");
531         }
532         else if(ClipFormats[CF_UNICODETEXT-1].wDataPresent)
533         {
534             /* Convert UNICODETEXT -> OEMTEXT */
535             lpSource = &ClipFormats[CF_UNICODETEXT-1];
536             lpTarget = &ClipFormats[CF_OEMTEXT-1];
537             foundData = TRUE;
538             TRACE("\tUNICODETEXT -> OEMTEXT\n");
539         }
540         else if(ClipFormats[CF_TEXT-1].wDataPresent)
541         {
542             /* Convert TEXT -> OEMTEXT */
543             lpSource = &ClipFormats[CF_TEXT-1];
544             lpTarget = &ClipFormats[CF_OEMTEXT-1];
545             foundData = TRUE;
546             TRACE("\tTEXT -> OEMTEXT\n");
547         }
548     }
549     /* Asked for CF_UNICODETEXT */
550     else if( wFormat == CF_UNICODETEXT )
551     {
552         if(ClipFormats[CF_UNICODETEXT-1].wDataPresent)
553         {
554             lpSource = &ClipFormats[CF_UNICODETEXT-1];
555             lpTarget = &ClipFormats[CF_UNICODETEXT-1];
556             foundData = TRUE;
557             TRACE("\tUNICODETEXT -> UNICODETEXT\n");
558         }
559         else if(ClipFormats[CF_TEXT-1].wDataPresent)
560         {
561             /* Convert TEXT -> UNICODETEXT */
562             lpSource = &ClipFormats[CF_TEXT-1];
563             lpTarget = &ClipFormats[CF_UNICODETEXT-1];
564             foundData = TRUE;
565             TRACE("\tTEXT -> UNICODETEXT\n");
566         }
567         else if(ClipFormats[CF_OEMTEXT-1].wDataPresent)
568         {
569             /* Convert OEMTEXT -> UNICODETEXT */
570             lpSource = &ClipFormats[CF_OEMTEXT-1];
571             lpTarget = &ClipFormats[CF_UNICODETEXT-1];
572             foundData = TRUE;
573             TRACE("\tOEMTEXT -> UNICODETEXT\n");
574         }
575     }
576     if (!foundData)
577     {   
578         if ((wFormat == CF_TEXT) || (wFormat == CF_OEMTEXT))
579         {
580             lpSource = &ClipFormats[CF_UNICODETEXT-1];
581             lpTarget = __lookup_format( ClipFormats, wFormat );
582         }
583         else
584         {
585             lpSource = __lookup_format( ClipFormats, wFormat );
586             lpTarget = lpSource;
587         }
588     }
589
590     /* First render the source text format */
591     if ( !lpSource || !CLIPBOARD_RenderFormat(lpSource) ) return NULL;
592
593     /* Convert to the desired target text format, if necessary */
594     if( lpTarget != lpSource && !lpTarget->hData16 && !lpTarget->hData32 )
595     {
596         INT src_chars, dst_chars, alloc_size;
597         LPCSTR lpstrS; 
598         LPSTR  lpstrT;
599     
600         if (lpSource->hData32)
601         {
602           lpstrS = (LPSTR)GlobalLock(lpSource->hData32);
603         }
604         else
605         {
606           lpstrS = (LPSTR)GlobalLock16(lpSource->hData16);
607         }
608     
609         if( !lpstrS ) return NULL;
610
611         /* Text always NULL terminated */
612         if(lpSource->wFormatID == CF_UNICODETEXT)
613             src_chars = strlenW((LPCWSTR)lpstrS)+1;
614         else
615             src_chars = strlen(lpstrS)+1;
616
617         /* Calculate number of characters in the destination buffer */
618         dst_chars = CLIPBOARD_ConvertText(lpSource->wFormatID, lpstrS, src_chars,
619                                      lpTarget->wFormatID, NULL, 0);
620         if(!dst_chars) return NULL;
621
622         TRACE("\tconverting from '%s' to '%s', %i chars\n",
623                 lpSource->Name, lpTarget->Name, src_chars);
624
625         /* Convert characters to bytes */
626         if(lpTarget->wFormatID == CF_UNICODETEXT)
627             alloc_size = dst_chars * sizeof(WCHAR);
628         else
629             alloc_size = dst_chars;
630
631         lpTarget->hData32 = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE, alloc_size);
632         lpstrT = (LPSTR)GlobalLock(lpTarget->hData32);
633
634         if( lpstrT )
635         {
636             CLIPBOARD_ConvertText(lpSource->wFormatID, lpstrS, src_chars,
637                                   lpTarget->wFormatID, lpstrT, dst_chars);
638             GlobalUnlock(lpTarget->hData32);
639         }
640         else
641             lpTarget->hData32 = 0;
642
643         /* Unlock source */
644         if (lpSource->hData32)
645           GlobalUnlock(lpSource->hData32);
646         else
647           GlobalUnlock16(lpSource->hData16);
648     }
649
650     return (lpTarget->hData16 || lpTarget->hData32) ? lpTarget : NULL;
651 }
652
653 /**************************************************************************
654  *            CLIPBOARD_EnumClipboardFormats   (internal)
655  */
656 static UINT CLIPBOARD_EnumClipboardFormats( UINT wFormat )
657 {
658     LPWINE_CLIPFORMAT lpFormat = ClipFormats;
659     BOOL bFormatPresent;
660
661     if (wFormat == 0) /* start from the beginning */
662         lpFormat = ClipFormats;
663     else
664     {
665         /* walk up to the specified format record */
666
667         if( !(lpFormat = __lookup_format( lpFormat, wFormat )) ) 
668             return 0;
669         lpFormat = lpFormat->NextFormat; /* right */
670     }
671
672     while(TRUE) 
673     {
674         if (lpFormat == NULL) return 0;
675
676         if(CLIPBOARD_IsPresent(lpFormat->wFormatID))
677             break;
678
679         /* Query the driver if not yet in the cache */
680         if (!USER_Driver.pIsSelectionOwner())
681         {
682             if(lpFormat->wFormatID == CF_UNICODETEXT ||
683                lpFormat->wFormatID == CF_TEXT ||
684                lpFormat->wFormatID == CF_OEMTEXT)
685             {
686                 if(USER_Driver.pIsClipboardFormatAvailable(CF_UNICODETEXT) ||
687                    USER_Driver.pIsClipboardFormatAvailable(CF_TEXT) ||
688                    USER_Driver.pIsClipboardFormatAvailable(CF_OEMTEXT))
689                     bFormatPresent = TRUE;
690                 else
691                     bFormatPresent = FALSE;
692             }
693             else
694                 bFormatPresent = USER_Driver.pIsClipboardFormatAvailable(lpFormat->wFormatID);
695
696             if(bFormatPresent)
697                 break;
698         }
699
700         lpFormat = lpFormat->NextFormat;
701     }
702
703     TRACE("Next available format %d\n", lpFormat->wFormatID);
704
705     return lpFormat->wFormatID;
706 }
707
708
709 /**************************************************************************
710  *                WIN32 Clipboard implementation 
711  **************************************************************************/
712
713 /**************************************************************************
714  *              OpenClipboard (USER.137)
715  */
716 BOOL16 WINAPI OpenClipboard16( HWND16 hWnd )
717 {
718     return OpenClipboard( hWnd );
719 }
720
721
722 /**************************************************************************
723  *              OpenClipboard (USER32.@)
724  *
725  * Note: Netscape uses NULL hWnd to open the clipboard.
726  */
727 BOOL WINAPI OpenClipboard( HWND hWnd )
728 {
729     BOOL bRet;
730
731     TRACE("(%04x)...\n", hWnd);
732
733     if (!hClipLock)
734     {
735         hClipLock = GetCurrentTask();
736
737         /* Save current user of the clipboard */
738         hWndClipWindow = WIN_GetFullHandle( hWnd );
739         bCBHasChanged = FALSE;
740         bRet = TRUE;
741     }
742     else bRet = FALSE;
743
744     TRACE("   returning %i\n", bRet);
745     return bRet;
746 }
747
748
749 /**************************************************************************
750  *              CloseClipboard (USER.138)
751  */
752 BOOL16 WINAPI CloseClipboard16(void)
753 {
754     return CloseClipboard();
755 }
756
757
758 /**************************************************************************
759  *              CloseClipboard (USER32.@)
760  */
761 BOOL WINAPI CloseClipboard(void)
762 {
763     TRACE("()\n");
764
765     if (hClipLock == GetCurrentTask())
766     {
767         hWndClipWindow = 0;
768
769         if (bCBHasChanged && hWndViewer) SendMessageW( hWndViewer, WM_DRAWCLIPBOARD, 0, 0 );
770         hClipLock = 0;
771     }
772     return TRUE;
773 }
774
775
776 /**************************************************************************
777  *              EmptyClipboard (USER.139)
778  */
779 BOOL16 WINAPI EmptyClipboard16(void)
780 {
781     return EmptyClipboard();
782 }
783
784
785 /**************************************************************************
786  *              EmptyClipboard (USER32.@)
787  *  Empties and acquires ownership of the clipboard
788  */
789 BOOL WINAPI EmptyClipboard(void)
790 {
791     TRACE("()\n");
792
793     if (hClipLock != GetCurrentTask())
794     {
795         WARN("Clipboard not opened by calling task!\n");
796         return FALSE;
797     }
798     
799     /* destroy private objects */
800
801     if (hWndClipOwner) SendMessageW( hWndClipOwner, WM_DESTROYCLIPBOARD, 0, 0 );
802
803     /* empty the cache */
804     CLIPBOARD_EmptyCache(TRUE);
805
806     /* Assign ownership of the clipboard to the current client */
807     hWndClipOwner = hWndClipWindow;
808
809     /* Save the current task */
810     hTaskClipOwner = GetCurrentTask();
811     
812     /* Tell the driver to acquire the selection */
813     USER_Driver.pAcquireClipboard();
814
815     return TRUE;
816 }
817
818
819 /**************************************************************************
820  *              GetClipboardOwner (USER.140)
821  *  FIXME: Can't return the owner if the clipbard is owned by an external app
822  */
823 HWND16 WINAPI GetClipboardOwner16(void)
824 {
825     TRACE("()\n");
826     return hWndClipOwner;
827 }
828
829
830 /**************************************************************************
831  *              GetClipboardOwner (USER32.@)
832  *  FIXME: Can't return the owner if the clipbard is owned by an external app
833  */
834 HWND WINAPI GetClipboardOwner(void)
835 {
836     TRACE("()\n");
837     return hWndClipOwner;
838 }
839
840
841 /**************************************************************************
842  *              SetClipboardData (USER.141)
843  */
844 HANDLE16 WINAPI SetClipboardData16( UINT16 wFormat, HANDLE16 hData )
845 {
846     LPWINE_CLIPFORMAT lpFormat = __lookup_format( ClipFormats, wFormat );
847
848     TRACE("(%04X, %04x) !\n", wFormat, hData);
849
850     /* NOTE: If the hData is zero and current owner doesn't match
851      * the window that opened the clipboard then this application
852      * is screwed because WM_RENDERFORMAT will go to the owner.
853      * (to become the owner it must call EmptyClipboard() before
854      *  adding new data).
855      */
856
857     if( CLIPBOARD_IsLocked() || !lpFormat ||
858         (!hData && (!hWndClipOwner || (hWndClipOwner != hWndClipWindow))) )
859     {
860         WARN("Invalid hData or clipboard not opened by calling task!\n");
861         return 0;
862     }
863
864     /* Pass on the request to the driver */
865     USER_Driver.pSetClipboardData(wFormat);
866
867     if ( lpFormat->wDataPresent || lpFormat->hData16 || lpFormat->hData32 ) 
868     {
869         CLIPBOARD_DeleteRecord(lpFormat, TRUE);
870
871         /* delete existing CF_UNICODETEXT/CF_TEXT/CF_OEMTEXT aliases */
872         if(wFormat == CF_UNICODETEXT)
873         {
874             CLIPBOARD_DeleteRecord(&ClipFormats[CF_TEXT-1], TRUE);
875             CLIPBOARD_DeleteRecord(&ClipFormats[CF_OEMTEXT-1], TRUE);
876         }
877         else if(wFormat == CF_TEXT)
878         {
879             CLIPBOARD_DeleteRecord(&ClipFormats[CF_UNICODETEXT-1], TRUE);
880             CLIPBOARD_DeleteRecord(&ClipFormats[CF_OEMTEXT-1], TRUE);
881         }
882         else if(wFormat == CF_OEMTEXT)
883         {
884             CLIPBOARD_DeleteRecord(&ClipFormats[CF_UNICODETEXT-1], TRUE);
885             CLIPBOARD_DeleteRecord(&ClipFormats[CF_TEXT-1], TRUE);
886         }
887     }
888
889     bCBHasChanged = TRUE;
890     lpFormat->wDataPresent = 1;
891     lpFormat->hData16 = hData;          /* 0 is legal, see WM_RENDERFORMAT */
892     lpFormat->hData32 = 0;
893
894     return lpFormat->hData16;
895 }
896
897
898 /**************************************************************************
899  *              SetClipboardData (USER32.@)
900  */
901 HANDLE WINAPI SetClipboardData( UINT wFormat, HANDLE hData )
902 {
903     LPWINE_CLIPFORMAT lpFormat = __lookup_format( ClipFormats, wFormat );
904
905     TRACE("(%08X, %08x) !\n", wFormat, hData);
906
907     /* NOTE: If the hData is zero and current owner doesn't match
908      * the window that opened the clipboard then this application
909      * is screwed because WM_RENDERFORMAT will go to the owner.
910      * (to become the owner it must call EmptyClipboard() before
911      *  adding new data).
912      */
913
914     if( CLIPBOARD_IsLocked() || !lpFormat ||
915         (!hData && (!hWndClipOwner || (hWndClipOwner != hWndClipWindow))) )
916     {
917         WARN("Invalid hData or clipboard not opened by calling task!\n");
918         return 0;
919     }
920
921     /* Tell the driver to acquire the selection */
922     USER_Driver.pAcquireClipboard();
923
924     if ( lpFormat->wDataPresent &&
925          (lpFormat->hData16 || lpFormat->hData32) )
926     {
927         CLIPBOARD_DeleteRecord(lpFormat, TRUE);
928
929         /* delete existing CF_UNICODETEXT/CF_TEXT/CF_OEMTEXT aliases */
930         if(wFormat == CF_UNICODETEXT)
931         {
932             CLIPBOARD_DeleteRecord(&ClipFormats[CF_TEXT-1], TRUE);
933             CLIPBOARD_DeleteRecord(&ClipFormats[CF_OEMTEXT-1], TRUE);
934         }
935         else if(wFormat == CF_TEXT)
936         {
937             CLIPBOARD_DeleteRecord(&ClipFormats[CF_UNICODETEXT-1], TRUE);
938             CLIPBOARD_DeleteRecord(&ClipFormats[CF_OEMTEXT-1], TRUE);
939         }
940         else if(wFormat == CF_OEMTEXT)
941         {
942             CLIPBOARD_DeleteRecord(&ClipFormats[CF_UNICODETEXT-1], TRUE);
943             CLIPBOARD_DeleteRecord(&ClipFormats[CF_TEXT-1], TRUE);
944         }
945     }
946
947     bCBHasChanged = TRUE;
948     lpFormat->wDataPresent = 1;
949     lpFormat->hDataSrc32 = hData;  /* Save the source handle */
950
951     /*
952      * Make a shared duplicate if the memory is not shared
953      * TODO: What should be done for non-memory objects
954      */
955     if ( CLIPBOARD_IsMemoryObject(wFormat) && hData && !(GlobalFlags(hData) & GMEM_DDESHARE) )
956         lpFormat->hData32 = CLIPBOARD_GlobalDupMem( hData );
957     else
958         lpFormat->hData32 = hData;          /* 0 is legal, see WM_RENDERFORMAT */
959     
960     lpFormat->hData16 = 0;
961
962     return lpFormat->hData32;   /* Should we return lpFormat->hDataSrc32 */
963 }
964
965
966 /**************************************************************************
967  *              GetClipboardData (USER.142)
968  */
969 HANDLE16 WINAPI GetClipboardData16( UINT16 wFormat )
970 {
971     LPWINE_CLIPFORMAT lpRender = ClipFormats; 
972
973     TRACE("(%04X)\n", wFormat);
974
975     if (CLIPBOARD_IsLocked())
976     {
977         WARN("Clipboard not opened by calling task!\n");
978         return 0;
979     }
980
981     if( wFormat == CF_UNICODETEXT || wFormat == CF_TEXT || wFormat == CF_OEMTEXT )
982     {
983         lpRender = CLIPBOARD_RenderText(wFormat);
984         if ( !lpRender ) return 0;
985     }
986     else
987     {
988         lpRender = __lookup_format( ClipFormats, wFormat );
989         if( !lpRender || !CLIPBOARD_RenderFormat(lpRender) ) return 0;
990     }
991    
992     /* Convert between 32 -> 16 bit data, if necessary */
993     if( lpRender->hData32 && !lpRender->hData16
994         && CLIPBOARD_IsMemoryObject(wFormat) )
995     {
996       int size;
997       if( lpRender->wFormatID == CF_METAFILEPICT )
998         size = sizeof( METAFILEPICT16 );
999       else
1000           size = GlobalSize(lpRender->hData32);
1001       
1002       lpRender->hData16 = GlobalAlloc16(GMEM_ZEROINIT, size);
1003       if( !lpRender->hData16 )
1004         ERR("(%04X) -- not enough memory in 16b heap\n", wFormat);
1005       else
1006       {
1007         if( lpRender->wFormatID == CF_METAFILEPICT )
1008         {
1009           FIXME("\timplement function CopyMetaFilePict32to16\n");
1010           FIXME("\tin the appropriate file.\n");
1011   #ifdef SOMEONE_IMPLEMENTED_ME
1012           CopyMetaFilePict32to16( GlobalLock16(lpRender->hData16), 
1013                                   GlobalLock(lpRender->hData32) );
1014   #endif
1015         }
1016         else
1017         {
1018           memcpy( GlobalLock16(lpRender->hData16), 
1019                   GlobalLock(lpRender->hData32), 
1020                   size );
1021         }
1022         GlobalUnlock16(lpRender->hData16);
1023         GlobalUnlock(lpRender->hData32);
1024       }
1025     }
1026
1027     TRACE("\treturning %04x (type %i)\n", 
1028                               lpRender->hData16, lpRender->wFormatID);
1029     return lpRender->hData16;
1030 }
1031
1032
1033 /**************************************************************************
1034  *              GetClipboardData (USER32.@)
1035  */
1036 HANDLE WINAPI GetClipboardData( UINT wFormat )
1037 {
1038     LPWINE_CLIPFORMAT lpRender = ClipFormats; 
1039
1040     TRACE("(%08X)\n", wFormat);
1041
1042     if (CLIPBOARD_IsLocked())
1043     {
1044         WARN("Clipboard not opened by calling task!\n");
1045         return 0;
1046     }
1047
1048     if( wFormat == CF_UNICODETEXT || wFormat == CF_TEXT || wFormat == CF_OEMTEXT )
1049     {
1050         lpRender = CLIPBOARD_RenderText(wFormat);
1051         if ( !lpRender ) return 0;
1052     }
1053     else
1054     {
1055         lpRender = __lookup_format( ClipFormats, wFormat );
1056         if( !lpRender || !CLIPBOARD_RenderFormat(lpRender) ) return 0;
1057     }
1058    
1059     /* Convert between 16 -> 32 bit data, if necessary */
1060     if( lpRender->hData16 && !lpRender->hData32
1061         && CLIPBOARD_IsMemoryObject(wFormat) )
1062     {
1063       int size;
1064       if( lpRender->wFormatID == CF_METAFILEPICT )
1065         size = sizeof( METAFILEPICT );
1066       else
1067         size = GlobalSize16(lpRender->hData16);
1068       lpRender->hData32 = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE,
1069                                       size);
1070       if( lpRender->wFormatID == CF_METAFILEPICT )
1071       {
1072         FIXME("\timplement function CopyMetaFilePict16to32\n");
1073         FIXME("\tin the appropriate file.\n");
1074 #ifdef SOMEONE_IMPLEMENTED_ME
1075         CopyMetaFilePict16to32( GlobalLock16(lpRender->hData32), 
1076                                 GlobalLock(lpRender->hData16) );
1077 #endif
1078       }
1079       else
1080       {
1081         memcpy( GlobalLock(lpRender->hData32), 
1082                 GlobalLock16(lpRender->hData16), 
1083                 size );
1084       }
1085       GlobalUnlock(lpRender->hData32);
1086       GlobalUnlock16(lpRender->hData16);
1087     }
1088
1089     TRACE("\treturning %04x (type %i)\n", 
1090                               lpRender->hData32, lpRender->wFormatID);
1091     return lpRender->hData32;
1092 }
1093
1094
1095 /**************************************************************************
1096  *              CountClipboardFormats (USER.143)
1097  */
1098 INT16 WINAPI CountClipboardFormats16(void)
1099 {
1100     return CountClipboardFormats();
1101 }
1102
1103
1104 /**************************************************************************
1105  *              CountClipboardFormats (USER32.@)
1106  */
1107 INT WINAPI CountClipboardFormats(void)
1108 {
1109     INT FormatCount = 0;
1110     LPWINE_CLIPFORMAT lpFormat = ClipFormats; 
1111
1112     TRACE("()\n");
1113
1114     while(TRUE) 
1115     {
1116         if (lpFormat == NULL) break;
1117
1118         if( lpFormat->wFormatID != CF_TEXT ) /* Don't count CF_TEXT */
1119         {
1120           /*
1121            * The format is available if either:
1122            * 1. The data is already in the cache.
1123            * 2. The selection is not owned by us(WINE) and the data is
1124            *    available to the clipboard driver.
1125            */
1126           if ( lpFormat->wDataPresent ||
1127                ( !USER_Driver.pIsSelectionOwner()
1128                  && USER_Driver.pIsClipboardFormatAvailable( lpFormat->wFormatID ) ) )
1129           {
1130               TRACE("\tdata found for format 0x%04x(%s)\n",
1131                     lpFormat->wFormatID, CLIPBOARD_GetFormatName(lpFormat->wFormatID));
1132               FormatCount++;
1133           }
1134         }
1135
1136         lpFormat = lpFormat->NextFormat;
1137     }
1138
1139     /* these are equivalent, adjust the total */
1140     FormatCount += (ClipFormats[CF_UNICODETEXT-1].wDataPresent ||
1141                     ClipFormats[CF_TEXT-1].wDataPresent ||
1142                     ClipFormats[CF_OEMTEXT-1].wDataPresent) ? 1 : 0;
1143
1144     TRACE("\ttotal %d\n", FormatCount);
1145     return FormatCount;
1146 }
1147
1148 /**************************************************************************
1149  *              EnumClipboardFormats (USER.144)
1150  */
1151 UINT16 WINAPI EnumClipboardFormats16( UINT16 wFormat )
1152 {
1153     return EnumClipboardFormats( wFormat );
1154 }
1155
1156
1157 /**************************************************************************
1158  *              EnumClipboardFormats (USER32.@)
1159  */
1160 UINT WINAPI EnumClipboardFormats( UINT wFormat )
1161 {
1162     TRACE("(%04X)\n", wFormat);
1163
1164     if (CLIPBOARD_IsLocked())
1165     {
1166         WARN("Clipboard not opened by calling task!\n");
1167         return 0;
1168     }
1169
1170     return CLIPBOARD_EnumClipboardFormats(wFormat);
1171 }
1172
1173
1174 /**************************************************************************
1175  *              RegisterClipboardFormatA (USER32.@)
1176  */
1177 UINT WINAPI RegisterClipboardFormatA( LPCSTR FormatName )
1178 {
1179     LPWINE_CLIPFORMAT lpNewFormat; 
1180     LPWINE_CLIPFORMAT lpFormat = ClipFormats; 
1181
1182     if (FormatName == NULL) return 0;
1183
1184     TRACE("('%s') !\n", FormatName);
1185
1186     /* walk format chain to see if it's already registered */
1187
1188     while(TRUE) 
1189     {
1190         if ( !strcmp(lpFormat->Name,FormatName) )
1191         {
1192              lpFormat->wRefCount++;
1193              return lpFormat->wFormatID;
1194         }
1195  
1196         if ( lpFormat->NextFormat == NULL ) break;
1197
1198         lpFormat = lpFormat->NextFormat;
1199     }
1200
1201     /* allocate storage for new format entry */
1202
1203     lpNewFormat = (LPWINE_CLIPFORMAT)HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_CLIPFORMAT));
1204     if(lpNewFormat == NULL) {
1205         WARN("No more memory for a new format!\n");
1206         return 0;
1207     }
1208     lpFormat->NextFormat = lpNewFormat;
1209     lpNewFormat->wFormatID = LastRegFormat;
1210     lpNewFormat->wRefCount = 1;
1211
1212     if (!(lpNewFormat->Name = HeapAlloc(GetProcessHeap(), 0, strlen(FormatName)+1 )))
1213     {
1214         WARN("No more memory for the new format name!\n");
1215         HeapFree(GetProcessHeap(), 0, lpNewFormat);
1216         return 0;
1217     }
1218     strcpy( lpNewFormat->Name, FormatName );
1219
1220     lpNewFormat->wDataPresent = 0;
1221     lpNewFormat->hData16 = 0;
1222     lpNewFormat->hDataSrc32 = 0;
1223     lpNewFormat->hData32 = 0;
1224     lpNewFormat->drvData = 0;
1225     lpNewFormat->PrevFormat = lpFormat;
1226     lpNewFormat->NextFormat = NULL;
1227
1228     /* Pass on the registration request to the driver */
1229     USER_Driver.pRegisterClipboardFormat( FormatName );
1230     
1231     return LastRegFormat++;
1232 }
1233
1234
1235 /**************************************************************************
1236  *              RegisterClipboardFormat (USER.145)
1237  */
1238 UINT16 WINAPI RegisterClipboardFormat16( LPCSTR FormatName )
1239 {
1240     return RegisterClipboardFormatA( FormatName );
1241 }
1242
1243
1244 /**************************************************************************
1245  *              RegisterClipboardFormatW (USER32.@)
1246  */
1247 UINT WINAPI RegisterClipboardFormatW( LPCWSTR formatName )
1248 {
1249     LPSTR aFormat = HEAP_strdupWtoA( GetProcessHeap(), 0, formatName );
1250     UINT ret = RegisterClipboardFormatA( aFormat );
1251     HeapFree( GetProcessHeap(), 0, aFormat );
1252     return ret;
1253 }
1254
1255
1256 /**************************************************************************
1257  *              GetClipboardFormatName (USER.146)
1258  */
1259 INT16 WINAPI GetClipboardFormatName16( UINT16 wFormat, LPSTR retStr, INT16 maxlen )
1260 {
1261     return GetClipboardFormatNameA( wFormat, retStr, maxlen );
1262 }
1263
1264
1265 /**************************************************************************
1266  *              GetClipboardFormatNameA (USER32.@)
1267  */
1268 INT WINAPI GetClipboardFormatNameA( UINT wFormat, LPSTR retStr, INT maxlen )
1269 {
1270     LPWINE_CLIPFORMAT lpFormat = __lookup_format( ClipFormats, wFormat );
1271
1272     TRACE("(%04X, %p, %d) !\n", wFormat, retStr, maxlen);
1273
1274     if (lpFormat == NULL || lpFormat->Name == NULL || 
1275         lpFormat->wFormatID < CF_REGFORMATBASE) return 0;
1276
1277     TRACE("Name='%s' !\n", lpFormat->Name);
1278
1279     lstrcpynA( retStr, lpFormat->Name, maxlen );
1280     return strlen(retStr);
1281 }
1282
1283
1284 /**************************************************************************
1285  *              GetClipboardFormatNameW (USER32.@)
1286  */
1287 INT WINAPI GetClipboardFormatNameW( UINT wFormat, LPWSTR retStr, INT maxlen )
1288 {
1289     INT ret;
1290     LPSTR p = HeapAlloc( GetProcessHeap(), 0, maxlen );
1291     if(p == NULL) return 0; /* FIXME: is this the correct failure value? */
1292     
1293     ret = GetClipboardFormatNameA( wFormat, p, maxlen );
1294
1295     if (maxlen > 0 && !MultiByteToWideChar( CP_ACP, 0, p, -1, retStr, maxlen ))
1296         retStr[maxlen-1] = 0;
1297     HeapFree( GetProcessHeap(), 0, p );
1298     return ret;
1299 }
1300
1301
1302 /**************************************************************************
1303  *              SetClipboardViewer (USER.147)
1304  */
1305 HWND16 WINAPI SetClipboardViewer16( HWND16 hWnd )
1306 {
1307     TRACE("(%04x)\n", hWnd);
1308     return SetClipboardViewer( hWnd );
1309 }
1310
1311
1312 /**************************************************************************
1313  *              SetClipboardViewer (USER32.@)
1314  */
1315 HWND WINAPI SetClipboardViewer( HWND hWnd )
1316 {
1317     HWND hwndPrev = hWndViewer;
1318
1319     TRACE("(%04x): returning %04x\n", hWnd, hwndPrev);
1320
1321     hWndViewer = WIN_GetFullHandle( hWnd );
1322     return hwndPrev;
1323 }
1324
1325
1326 /**************************************************************************
1327  *              GetClipboardViewer (USER.148)
1328  */
1329 HWND16 WINAPI GetClipboardViewer16(void)
1330 {
1331     TRACE("()\n");
1332     return hWndViewer;
1333 }
1334
1335
1336 /**************************************************************************
1337  *              GetClipboardViewer (USER32.@)
1338  */
1339 HWND WINAPI GetClipboardViewer(void)
1340 {
1341     TRACE("()\n");
1342     return hWndViewer;
1343 }
1344
1345
1346 /**************************************************************************
1347  *              ChangeClipboardChain (USER.149)
1348  */
1349 BOOL16 WINAPI ChangeClipboardChain16(HWND16 hWnd, HWND16 hWndNext)
1350 {
1351     return ChangeClipboardChain(hWnd, hWndNext);
1352 }
1353
1354
1355 /**************************************************************************
1356  *              ChangeClipboardChain (USER32.@)
1357  */
1358 BOOL WINAPI ChangeClipboardChain(HWND hWnd, HWND hWndNext)
1359 {
1360     BOOL bRet = 0;
1361
1362     FIXME("(0x%04x, 0x%04x): stub?\n", hWnd, hWndNext);
1363
1364     if( hWndViewer )
1365         bRet = !SendMessageW( hWndViewer, WM_CHANGECBCHAIN, (WPARAM)hWnd, (LPARAM)hWndNext );
1366     else
1367         WARN("hWndViewer is lost\n");
1368
1369     if( WIN_GetFullHandle(hWnd) == hWndViewer ) hWndViewer = WIN_GetFullHandle( hWndNext );
1370
1371     return bRet;
1372 }
1373
1374
1375 /**************************************************************************
1376  *              IsClipboardFormatAvailable (USER.193)
1377  */
1378 BOOL16 WINAPI IsClipboardFormatAvailable16( UINT16 wFormat )
1379 {
1380     return IsClipboardFormatAvailable( wFormat );
1381 }
1382
1383
1384 /**************************************************************************
1385  *              IsClipboardFormatAvailable (USER32.@)
1386  */
1387 BOOL WINAPI IsClipboardFormatAvailable( UINT wFormat )
1388 {
1389     BOOL bRet;
1390
1391     if (wFormat == 0)  /* Reject this case quickly */
1392         bRet = FALSE;
1393     else
1394     {
1395         UINT iret = CLIPBOARD_EnumClipboardFormats(wFormat - 1);
1396         if ((wFormat == CF_TEXT) || (wFormat == CF_OEMTEXT) || (wFormat == CF_UNICODETEXT))
1397             bRet = ((iret == CF_TEXT) || (iret == CF_OEMTEXT) || (iret == CF_UNICODETEXT));
1398         else
1399             bRet = iret == wFormat;
1400     }
1401     TRACE("(%04X)- ret(%d)\n", wFormat, bRet);
1402     return bRet;
1403 }
1404
1405
1406 /**************************************************************************
1407  *              GetOpenClipboardWindow (USER.248)
1408  *  FIXME: This wont work if an external app owns the selection
1409  */
1410 HWND16 WINAPI GetOpenClipboardWindow16(void)
1411 {
1412     TRACE("()\n");
1413     return hWndClipWindow;
1414 }
1415
1416
1417 /**************************************************************************
1418  *              GetOpenClipboardWindow (USER32.@)
1419  *  FIXME: This wont work if an external app owns the selection
1420  */
1421 HWND WINAPI GetOpenClipboardWindow(void)
1422 {
1423     TRACE("()\n");
1424     return hWndClipWindow;
1425 }
1426
1427
1428 /**************************************************************************
1429  *              GetPriorityClipboardFormat (USER.402)
1430  */
1431 INT16 WINAPI GetPriorityClipboardFormat16( UINT16 *lpPriorityList, INT16 nCount)
1432 {
1433     FIXME("(%p,%d): stub\n", lpPriorityList, nCount );
1434     return 0;
1435 }
1436
1437
1438 /**************************************************************************
1439  *              GetPriorityClipboardFormat (USER32.@)
1440  */
1441 INT WINAPI GetPriorityClipboardFormat( UINT *lpPriorityList, INT nCount )
1442 {
1443     int Counter;
1444     TRACE("()\n");
1445
1446     if(CountClipboardFormats() == 0) 
1447     { 
1448         return 0;
1449     }
1450
1451     for(Counter = 0; Counter <= nCount; Counter++)
1452     {
1453         if(IsClipboardFormatAvailable(*(lpPriorityList+sizeof(INT)*Counter)))
1454             return *(lpPriorityList+sizeof(INT)*Counter);
1455     }
1456
1457     return -1;
1458 }
1459
1460
1461 /**************************************************************************
1462  *              GetClipboardSequenceNumber (USER32.@)
1463  * Supported on Win2k/Win98
1464  * MSDN: Windows clipboard code keeps a serial number for the clipboard
1465  * for each window station.  The number is incremented whenever the
1466  * contents change or are emptied.
1467  * If you do not have WINSTA_ACCESSCLIPBOARD then the function returns 0
1468  */
1469 DWORD WINAPI GetClipboardSequenceNumber(VOID)
1470 {
1471         FIXME("Returning 0, see windows/clipboard.c\n");
1472         /* FIXME: Use serial numbers */
1473         return 0;
1474 }