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