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