1 /*
2  * Unit test suite for clipboard functions.
3  *
4  * Copyright 2002 Dmitry Timoshkov
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #include <stdio.h>
22 #include "wine/test.h"
23 #include "winbase.h"
24 #include "winerror.h"
25 #include "wingdi.h"
26 #include "winuser.h"
27 #include "winnls.h"
28 
29 #ifdef __REACTOS__
30 #define WM_CLIPBOARDUPDATE 0x031D
31 #endif
32 
33 static BOOL (WINAPI *pAddClipboardFormatListener)(HWND hwnd);
34 static BOOL (WINAPI *pRemoveClipboardFormatListener)(HWND hwnd);
35 static BOOL (WINAPI *pGetUpdatedClipboardFormats)( UINT *formats, UINT count, UINT *out_count );
36 
37 static int thread_from_line;
38 static char *argv0;
39 
40 static DWORD WINAPI open_clipboard_thread(LPVOID arg)
41 {
42     HWND hWnd = arg;
43     ok(OpenClipboard(hWnd), "%u: OpenClipboard failed\n", thread_from_line);
44     return 0;
45 }
46 
47 static DWORD WINAPI empty_clipboard_thread(LPVOID arg)
48 {
49     SetLastError( 0xdeadbeef );
50     ok(!EmptyClipboard(), "%u: EmptyClipboard succeeded\n", thread_from_line );
51     ok( GetLastError() == ERROR_CLIPBOARD_NOT_OPEN, "%u: wrong error %u\n",
52         thread_from_line, GetLastError());
53     return 0;
54 }
55 
56 static DWORD WINAPI open_and_empty_clipboard_thread(LPVOID arg)
57 {
58     HWND hWnd = arg;
59     ok(OpenClipboard(hWnd), "%u: OpenClipboard failed\n", thread_from_line);
60     ok(EmptyClipboard(), "%u: EmptyClipboard failed\n", thread_from_line );
61     return 0;
62 }
63 
64 static DWORD WINAPI open_and_empty_clipboard_win_thread(LPVOID arg)
65 {
66     HWND hwnd = CreateWindowA( "static", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL );
67     ok(OpenClipboard(hwnd), "%u: OpenClipboard failed\n", thread_from_line);
68     ok(EmptyClipboard(), "%u: EmptyClipboard failed\n", thread_from_line );
69     return 0;
70 }
71 
72 static DWORD WINAPI set_clipboard_data_thread(LPVOID arg)
73 {
74     HWND hwnd = arg;
75     HANDLE ret;
76 
77     SetLastError( 0xdeadbeef );
78     if (GetClipboardOwner() == hwnd)
79     {
80         SetClipboardData( CF_WAVE, 0 );
81         ok( IsClipboardFormatAvailable( CF_WAVE ), "%u: SetClipboardData failed\n", thread_from_line );
82         ret = SetClipboardData( CF_WAVE, GlobalAlloc( GMEM_DDESHARE | GMEM_ZEROINIT, 100 ));
83         ok( ret != 0, "%u: SetClipboardData failed err %u\n", thread_from_line, GetLastError() );
84         SetLastError( 0xdeadbeef );
85         ret = GetClipboardData( CF_WAVE );
86         ok( !ret, "%u: GetClipboardData succeeded\n", thread_from_line );
87         ok( GetLastError() == ERROR_CLIPBOARD_NOT_OPEN, "%u: wrong error %u\n",
88             thread_from_line, GetLastError());
89     }
90     else
91     {
92         SetClipboardData( CF_WAVE, 0 );
93         ok( GetLastError() == ERROR_CLIPBOARD_NOT_OPEN, "%u: wrong error %u\n",
94             thread_from_line, GetLastError());
95         ok( !IsClipboardFormatAvailable( CF_WAVE ), "%u: SetClipboardData succeeded\n", thread_from_line );
96         ret = SetClipboardData( CF_WAVE, GlobalAlloc( GMEM_DDESHARE | GMEM_ZEROINIT, 100 ));
97         ok( !ret, "%u: SetClipboardData succeeded\n", thread_from_line );
98         ok( GetLastError() == ERROR_CLIPBOARD_NOT_OPEN, "%u: wrong error %u\n",
99             thread_from_line, GetLastError());
100     }
101     return 0;
102 }
103 
104 static void set_clipboard_data_process( int arg )
105 {
106     HANDLE ret;
107 
108     SetLastError( 0xdeadbeef );
109     if (arg)
110     {
111         ok( IsClipboardFormatAvailable( CF_WAVE ), "process %u: CF_WAVE not available\n", arg );
112         ret = SetClipboardData( CF_WAVE, GlobalAlloc( GMEM_DDESHARE | GMEM_ZEROINIT, 100 ));
113         ok( ret != 0, "process %u: SetClipboardData failed err %u\n", arg, GetLastError() );
114     }
115     else
116     {
117         SetClipboardData( CF_WAVE, 0 );
118         ok( GetLastError() == ERROR_CLIPBOARD_NOT_OPEN, "process %u: wrong error %u\n",
119             arg, GetLastError());
120         ok( !IsClipboardFormatAvailable( CF_WAVE ), "process %u: SetClipboardData succeeded\n", arg );
121         ret = SetClipboardData( CF_WAVE, GlobalAlloc( GMEM_DDESHARE | GMEM_ZEROINIT, 100 ));
122         ok( !ret, "process %u: SetClipboardData succeeded\n", arg );
123         ok( GetLastError() == ERROR_CLIPBOARD_NOT_OPEN, "process %u: wrong error %u\n",
124             arg, GetLastError());
125     }
126 }
127 
128 static void grab_clipboard_process( int arg )
129 {
130     BOOL ret;
131 
132     SetLastError( 0xdeadbeef );
133     ret = OpenClipboard( 0 );
134     ok( ret, "OpenClipboard failed\n" );
135     ret = EmptyClipboard();
136     ok( ret, "EmptyClipboard failed\n" );
137     if (arg)
138     {
139         HANDLE ret = SetClipboardData( CF_WAVE, GlobalAlloc( GMEM_DDESHARE | GMEM_ZEROINIT, 100 ));
140         ok( ret != 0, "process %u: SetClipboardData failed err %u\n", arg, GetLastError() );
141     }
142 }
143 
144 static void run_thread( LPTHREAD_START_ROUTINE func, void *arg, int line )
145 {
146     DWORD ret;
147     HANDLE thread;
148 
149     thread_from_line = line;
150     thread = CreateThread(NULL, 0, func, arg, 0, NULL);
151     ok(thread != NULL, "%u: CreateThread failed with error %d\n", line, GetLastError());
152     for (;;)
153     {
154         ret = MsgWaitForMultipleObjectsEx( 1, &thread, 1000, QS_ALLINPUT, 0 );
155         if (ret == WAIT_OBJECT_0 + 1)
156         {
157             MSG msg;
158             while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg );
159         }
160         else break;
161     }
162     ok(ret == WAIT_OBJECT_0, "%u: expected WAIT_OBJECT_0, got %u\n", line, ret);
163     CloseHandle(thread);
164 }
165 
166 static void run_process( const char *args )
167 {
168     char cmd[MAX_PATH];
169     PROCESS_INFORMATION info;
170     STARTUPINFOA startup;
171 
172     sprintf( cmd, "%s clipboard %s", argv0, args );
173     memset( &startup, 0, sizeof(startup) );
174     startup.cb = sizeof(startup);
175     ok( CreateProcessA( NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info ),
176         "CreateProcess %s failed\n", cmd );
177 
178     winetest_wait_child_process( info.hProcess );
179     CloseHandle( info.hProcess );
180     CloseHandle( info.hThread );
181 }
182 
183 static WNDPROC old_proc;
184 static LRESULT CALLBACK winproc_wrapper( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
185 {
186     static int wm_renderallformats;
187     static int wm_drawclipboard;
188     static int seqno;
189     DWORD msg_flags = InSendMessageEx( NULL );
190 
191     if (!seqno) seqno = GetClipboardSequenceNumber();
192 
193     trace( "%p msg %04x\n", hwnd, msg );
194     if (!wm_renderallformats)
195     {
196         ok( GetClipboardOwner() == hwnd, "%04x: wrong owner %p/%p\n", msg, GetClipboardOwner(), hwnd );
197         ok( seqno == GetClipboardSequenceNumber(), "%04x: seqno changed\n", msg );
198     }
199     else
200     {
201         ok( !GetClipboardOwner(), "%04x: wrong owner %p\n", msg, GetClipboardOwner() );
202         ok( seqno + 1 == GetClipboardSequenceNumber(), "%04x: seqno unchanged\n", msg );
203     }
204     ok( GetClipboardViewer() == hwnd, "%04x: wrong viewer %p/%p\n", msg, GetClipboardViewer(), hwnd );
205     ok( GetOpenClipboardWindow() == hwnd, "%04x: wrong open win %p/%p\n",
206         msg, GetOpenClipboardWindow(), hwnd );
207 
208     switch (msg)
209     {
210     case WM_DESTROY:
211         ok( wm_renderallformats, "didn't receive WM_RENDERALLFORMATS before WM_DESTROY\n" );
212         ok( wm_drawclipboard, "didn't receive WM_DRAWCLIPBOARD before WM_DESTROY\n" );
213         break;
214     case WM_DRAWCLIPBOARD:
215         ok( msg_flags == ISMEX_NOSEND, "WM_DRAWCLIPBOARD wrong flags %x\n", msg_flags );
216         wm_drawclipboard++;
217         break;
218     case WM_RENDERALLFORMATS:
219         ok( msg_flags == ISMEX_NOSEND, "WM_RENDERALLFORMATS wrong flags %x\n", msg_flags );
220         wm_renderallformats++;
221         break;
222     }
223     return old_proc( hwnd, msg, wp, lp );
224 }
225 
226 static void test_ClipboardOwner(void)
227 {
228     HWND hWnd1, hWnd2;
229     BOOL ret;
230 
231     SetLastError(0xdeadbeef);
232     ok(!GetClipboardOwner() && GetLastError() == 0xdeadbeef,
233        "could not perform clipboard test: clipboard already owned\n");
234 
235     hWnd1 = CreateWindowExA(0, "static", NULL, WS_POPUP,
236                                  0, 0, 10, 10, 0, 0, 0, NULL);
237     ok(hWnd1 != 0, "CreateWindowExA error %d\n", GetLastError());
238     trace("hWnd1 = %p\n", hWnd1);
239 
240     hWnd2 = CreateWindowExA(0, "static", NULL, WS_POPUP,
241                                  0, 0, 10, 10, 0, 0, 0, NULL);
242     ok(hWnd2 != 0, "CreateWindowExA error %d\n", GetLastError());
243     trace("hWnd2 = %p\n", hWnd2);
244 
245     SetLastError(0xdeadbeef);
246     ok(!CloseClipboard(), "CloseClipboard should fail if clipboard wasn't open\n");
247     ok(GetLastError() == ERROR_CLIPBOARD_NOT_OPEN || broken(GetLastError() == 0xdeadbeef), /* wow64 */
248        "wrong error %u\n", GetLastError());
249 
250     ok(OpenClipboard(0), "OpenClipboard failed\n");
251     ok(!GetClipboardOwner(), "clipboard should still be not owned\n");
252     ok(!OpenClipboard(hWnd1), "OpenClipboard should fail since clipboard already opened\n");
253     ok(OpenClipboard(0), "OpenClipboard again failed\n");
254     ret = CloseClipboard();
255     ok( ret, "CloseClipboard error %d\n", GetLastError());
256 
257     ok(OpenClipboard(hWnd1), "OpenClipboard failed\n");
258     run_thread( open_clipboard_thread, hWnd1, __LINE__ );
259     run_thread( empty_clipboard_thread, 0, __LINE__ );
260     run_thread( set_clipboard_data_thread, hWnd1, __LINE__ );
261     ok( !IsClipboardFormatAvailable( CF_WAVE ), "CF_WAVE available\n" );
262     ok( !GetClipboardData( CF_WAVE ), "CF_WAVE data available\n" );
263     run_process( "set_clipboard_data 0" );
264     ok(!CloseClipboard(), "CloseClipboard should fail if clipboard wasn't open\n");
265     ok(OpenClipboard(hWnd1), "OpenClipboard failed\n");
266 
267     SetLastError(0xdeadbeef);
268     ret = OpenClipboard(hWnd2);
269     ok(!ret && (GetLastError() == 0xdeadbeef || GetLastError() == ERROR_ACCESS_DENIED),
270        "OpenClipboard should fail without setting last error value, or with ERROR_ACCESS_DENIED, got error %d\n", GetLastError());
271 
272     SetLastError(0xdeadbeef);
273     ok(!GetClipboardOwner() && GetLastError() == 0xdeadbeef, "clipboard should still be not owned\n");
274     ret = EmptyClipboard();
275     ok( ret, "EmptyClipboard error %d\n", GetLastError());
276     ok(GetClipboardOwner() == hWnd1, "clipboard should be owned by %p, not by %p\n", hWnd1, GetClipboardOwner());
277     run_thread( empty_clipboard_thread, 0, __LINE__ );
278     run_thread( set_clipboard_data_thread, hWnd1, __LINE__ );
279     ok( IsClipboardFormatAvailable( CF_WAVE ), "CF_WAVE not available\n" );
280     ok( GetClipboardData( CF_WAVE ) != 0, "CF_WAVE data not available\n" );
281     run_process( "set_clipboard_data 1" );
282 
283     SetLastError(0xdeadbeef);
284     ret = OpenClipboard(hWnd2);
285     ok(!ret && (GetLastError() == 0xdeadbeef || GetLastError() == ERROR_ACCESS_DENIED),
286        "OpenClipboard should fail without setting last error value, or with ERROR_ACCESS_DENIED, got error %d\n", GetLastError());
287 
288     ret = CloseClipboard();
289     ok( ret, "CloseClipboard error %d\n", GetLastError());
290     ok(GetClipboardOwner() == hWnd1, "clipboard should still be owned\n");
291 
292     /* any window will do, even from a different process */
293     ret = OpenClipboard( GetDesktopWindow() );
294     ok( ret, "OpenClipboard error %d\n", GetLastError());
295     ret = EmptyClipboard();
296     ok( ret, "EmptyClipboard error %d\n", GetLastError());
297     ok( GetClipboardOwner() == GetDesktopWindow(), "wrong owner %p/%p\n",
298         GetClipboardOwner(), GetDesktopWindow() );
299     run_thread( set_clipboard_data_thread, GetDesktopWindow(), __LINE__ );
300     ok( IsClipboardFormatAvailable( CF_WAVE ), "CF_WAVE not available\n" );
301     ok( GetClipboardData( CF_WAVE ) != 0, "CF_WAVE data not available\n" );
302     run_process( "set_clipboard_data 2" );
303     ret = CloseClipboard();
304     ok( ret, "CloseClipboard error %d\n", GetLastError());
305 
306     ret = OpenClipboard( hWnd1 );
307     ok( ret, "OpenClipboard error %d\n", GetLastError());
308     ret = EmptyClipboard();
309     ok( ret, "EmptyClipboard error %d\n", GetLastError());
310     SetClipboardData( CF_WAVE, 0 );
311     SetClipboardViewer( hWnd1 );
312     ok( GetClipboardOwner() == hWnd1, "wrong owner %p/%p\n", GetClipboardOwner(), hWnd1 );
313     ok( GetClipboardViewer() == hWnd1, "wrong viewer %p/%p\n", GetClipboardViewer(), hWnd1 );
314     ok( GetOpenClipboardWindow() == hWnd1, "wrong open win %p/%p\n", GetOpenClipboardWindow(), hWnd1 );
315     ok( IsClipboardFormatAvailable( CF_WAVE ), "CF_WAVE not available\n" );
316 
317     old_proc = (WNDPROC)SetWindowLongPtrA( hWnd1, GWLP_WNDPROC, (LONG_PTR)winproc_wrapper );
318     ret = DestroyWindow(hWnd1);
319     ok( ret, "DestroyWindow error %d\n", GetLastError());
320     ret = DestroyWindow(hWnd2);
321     ok( ret, "DestroyWindow error %d\n", GetLastError());
322     SetLastError(0xdeadbeef);
323     ok(!GetClipboardOwner() && GetLastError() == 0xdeadbeef, "clipboard should not be owned\n");
324     ok(!GetClipboardViewer() && GetLastError() == 0xdeadbeef, "viewer still exists\n");
325     ok(!GetOpenClipboardWindow() && GetLastError() == 0xdeadbeef, "clipboard should not be open\n");
326     ok( !IsClipboardFormatAvailable( CF_WAVE ), "CF_WAVE available\n" );
327 
328     SetLastError( 0xdeadbeef );
329     ret = CloseClipboard();
330     ok( !ret, "CloseClipboard succeeded\n" );
331     ok( GetLastError() == ERROR_CLIPBOARD_NOT_OPEN, "wrong error %u\n", GetLastError() );
332 
333     ret = OpenClipboard( 0 );
334     ok( ret, "OpenClipboard error %d\n", GetLastError());
335     run_thread( set_clipboard_data_thread, 0, __LINE__ );
336     ok( IsClipboardFormatAvailable( CF_WAVE ), "CF_WAVE not available\n" );
337     ok( GetClipboardData( CF_WAVE ) != 0, "CF_WAVE data not available\n" );
338     run_process( "set_clipboard_data 3" );
339     ret = CloseClipboard();
340     ok( ret, "CloseClipboard error %d\n", GetLastError());
341 
342     run_thread( open_and_empty_clipboard_thread, 0, __LINE__ );
343     ok( !GetOpenClipboardWindow(), "wrong open window %p\n", GetOpenClipboardWindow() );
344     ok( !GetClipboardOwner(), "wrong owner window %p\n", GetClipboardOwner() );
345 
346     ret = OpenClipboard( 0 );
347     ok( ret, "OpenClipboard error %d\n", GetLastError());
348     run_thread( set_clipboard_data_thread, 0, __LINE__ );
349     ok( IsClipboardFormatAvailable( CF_WAVE ), "CF_WAVE not available\n" );
350     ok( GetClipboardData( CF_WAVE ) != 0, "CF_WAVE data not available\n" );
351     run_process( "set_clipboard_data 4" );
352     ret = EmptyClipboard();
353     ok( ret, "EmptyClipboard error %d\n", GetLastError());
354     ret = CloseClipboard();
355     ok( ret, "CloseClipboard error %d\n", GetLastError());
356 
357     SetLastError( 0xdeadbeef );
358     ok( !SetClipboardData( CF_WAVE, GlobalAlloc( GMEM_DDESHARE | GMEM_ZEROINIT, 100 )),
359         "SetClipboardData succeeded\n" );
360     ok( GetLastError() == ERROR_CLIPBOARD_NOT_OPEN, "wrong error %u\n", GetLastError() );
361     ok( !IsClipboardFormatAvailable( CF_WAVE ), "SetClipboardData succeeded\n" );
362 
363     run_thread( open_and_empty_clipboard_thread, GetDesktopWindow(), __LINE__ );
364     ok( !GetOpenClipboardWindow(), "wrong open window %p\n", GetOpenClipboardWindow() );
365     ok( GetClipboardOwner() == GetDesktopWindow(), "wrong owner window %p / %p\n",
366         GetClipboardOwner(), GetDesktopWindow() );
367 
368     run_thread( open_and_empty_clipboard_win_thread, 0, __LINE__ );
369     ok( !GetOpenClipboardWindow(), "wrong open window %p\n", GetOpenClipboardWindow() );
370     ok( !GetClipboardOwner(), "wrong owner window %p\n", GetClipboardOwner() );
371 }
372 
373 static void test_RegisterClipboardFormatA(void)
374 {
375     ATOM atom_id;
376     UINT format_id, format_id2;
377     char buf[256];
378     int len;
379     BOOL ret;
380     HANDLE handle;
381 
382     format_id = RegisterClipboardFormatA("my_cool_clipboard_format");
383     ok(format_id > 0xc000 && format_id < 0xffff, "invalid clipboard format id %04x\n", format_id);
384 
385     format_id2 = RegisterClipboardFormatA("MY_COOL_CLIPBOARD_FORMAT");
386     ok(format_id2 == format_id, "invalid clipboard format id %04x\n", format_id2);
387 
388     len = GetClipboardFormatNameA(format_id, buf, 256);
389     ok(len == lstrlenA("my_cool_clipboard_format"), "wrong format name length %d\n", len);
390     ok(!lstrcmpA(buf, "my_cool_clipboard_format"), "wrong format name \"%s\"\n", buf);
391 
392     len = GetClipboardFormatNameA(format_id, NULL, 0);
393     ok(len == 0, "wrong format name length %d\n", len);
394 
395     lstrcpyA(buf, "foo");
396     SetLastError(0xdeadbeef);
397     len = GetAtomNameA((ATOM)format_id, buf, 256);
398     ok(len == 0, "GetAtomNameA should fail\n");
399     ok(GetLastError() == ERROR_INVALID_HANDLE, "err %d\n", GetLastError());
400 
401 todo_wine
402 {
403     lstrcpyA(buf, "foo");
404     SetLastError(0xdeadbeef);
405     len = GlobalGetAtomNameA((ATOM)format_id, buf, 256);
406     ok(len == 0, "GlobalGetAtomNameA should fail\n");
407     ok(GetLastError() == ERROR_INVALID_HANDLE, "err %d\n", GetLastError());
408 }
409 
410     SetLastError(0xdeadbeef);
411     atom_id = FindAtomA("my_cool_clipboard_format");
412     ok(atom_id == 0, "FindAtomA should fail\n");
413     ok(GetLastError() == ERROR_FILE_NOT_FOUND, "err %d\n", GetLastError());
414 
415     if (0)
416     {
417     /* this relies on the clipboard and global atom table being different */
418     SetLastError(0xdeadbeef);
419     atom_id = GlobalFindAtomA("my_cool_clipboard_format");
420     ok(atom_id == 0, "GlobalFindAtomA should fail\n");
421     ok(GetLastError() == ERROR_FILE_NOT_FOUND, "err %d\n", GetLastError());
422     }
423 
424     for (format_id = 0; format_id < 0x10fff; format_id++)
425     {
426         SetLastError(0xdeadbeef);
427         len = GetClipboardFormatNameA(format_id, buf, 256);
428 
429         if (format_id < 0xc000 || format_id > 0xffff)
430             ok(!len, "GetClipboardFormatNameA should fail, but it returned %d (%s)\n", len, buf);
431         else if (len && winetest_debug > 1)
432             trace("%04x: %s\n", format_id, len ? buf : "");
433     }
434 
435     ret = OpenClipboard(0);
436     ok( ret, "OpenClipboard error %d\n", GetLastError());
437 
438     /* try some invalid/unregistered formats */
439     SetLastError( 0xdeadbeef );
440     handle = SetClipboardData( 0, GlobalAlloc( GMEM_DDESHARE | GMEM_MOVEABLE, 1 ));
441     ok( !handle, "SetClipboardData succeeded\n" );
442     ok( GetLastError() == ERROR_CLIPBOARD_NOT_OPEN, "wrong error %u\n", GetLastError());
443     handle = SetClipboardData( 0x1234, GlobalAlloc( GMEM_DDESHARE | GMEM_MOVEABLE, 1 ));
444     ok( handle != 0, "SetClipboardData failed err %d\n", GetLastError());
445     handle = SetClipboardData( 0x123456, GlobalAlloc( GMEM_DDESHARE | GMEM_MOVEABLE, 1 ));
446     ok( handle != 0, "SetClipboardData failed err %d\n", GetLastError());
447     handle = SetClipboardData( 0xffff8765, GlobalAlloc( GMEM_DDESHARE | GMEM_MOVEABLE, 1 ));
448     ok( handle != 0, "SetClipboardData failed err %d\n", GetLastError());
449 
450     ok( IsClipboardFormatAvailable( 0x1234 ), "format missing\n" );
451     ok( IsClipboardFormatAvailable( 0x123456 ), "format missing\n" );
452     ok( IsClipboardFormatAvailable( 0xffff8765 ), "format missing\n" );
453     ok( !IsClipboardFormatAvailable( 0 ), "format available\n" );
454     ok( !IsClipboardFormatAvailable( 0x3456 ), "format available\n" );
455     ok( !IsClipboardFormatAvailable( 0x8765 ), "format available\n" );
456 
457     trace("# of formats available: %d\n", CountClipboardFormats());
458 
459     format_id = 0;
460     while ((format_id = EnumClipboardFormats(format_id)))
461     {
462         ok(IsClipboardFormatAvailable(format_id), "format %04x was listed as available\n", format_id);
463         len = GetClipboardFormatNameA(format_id, buf, 256);
464         trace("%04x: %s\n", format_id, len ? buf : "");
465     }
466 
467     ret = EmptyClipboard();
468     ok( ret, "EmptyClipboard error %d\n", GetLastError());
469     ret =CloseClipboard();
470     ok( ret, "CloseClipboard error %d\n", GetLastError());
471 
472     if (CountClipboardFormats())
473     {
474         SetLastError(0xdeadbeef);
475         ok(!EnumClipboardFormats(0), "EnumClipboardFormats should fail if clipboard wasn't open\n");
476         ok(GetLastError() == ERROR_CLIPBOARD_NOT_OPEN,
477            "Last error should be set to ERROR_CLIPBOARD_NOT_OPEN, not %d\n", GetLastError());
478     }
479 
480     SetLastError(0xdeadbeef);
481     ok(!EmptyClipboard(), "EmptyClipboard should fail if clipboard wasn't open\n");
482     ok(GetLastError() == ERROR_CLIPBOARD_NOT_OPEN || broken(GetLastError() == 0xdeadbeef), /* wow64 */
483        "Wrong error %u\n", GetLastError());
484 
485     format_id = RegisterClipboardFormatA("#1234");
486     ok(format_id == 1234, "invalid clipboard format id %04x\n", format_id);
487 }
488 
489 static HGLOBAL create_textA(void)
490 {
491     HGLOBAL h = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, 10);
492     char *p = GlobalLock(h);
493     memcpy(p, "test\0\0\0\0\0", 10);
494     GlobalUnlock(h);
495     return h;
496 }
497 
498 static HGLOBAL create_textW(void)
499 {
500     static const WCHAR testW[] = {'t','e','s','t',0,0,0,0,0,0};
501     HGLOBAL h = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, sizeof(testW));
502     WCHAR *p = GlobalLock(h);
503     memcpy(p, testW, sizeof(testW));
504     GlobalUnlock(h);
505     return h;
506 }
507 
508 static HANDLE create_metafile(void)
509 {
510     const RECT rect = {0, 0, 100, 100};
511     METAFILEPICT *pict;
512     HANDLE ret;
513     HMETAFILE mf;
514     HDC hdc = CreateMetaFileA( NULL );
515     ExtTextOutA( hdc, 0, 0, ETO_OPAQUE, &rect, "Test String", strlen("Test String"), NULL );
516     mf = CloseMetaFile( hdc );
517     ret = GlobalAlloc( GMEM_DDESHARE | GMEM_MOVEABLE, sizeof(*pict) );
518     pict = GlobalLock( ret );
519     pict->mm = MM_TEXT;
520     pict->xExt = pict->yExt = 100;
521     pict->hMF = mf;
522     GlobalUnlock( ret );
523     return ret;
524 }
525 
526 static HENHMETAFILE create_emf(void)
527 {
528     const RECT rect = {0, 0, 100, 100};
529     HDC hdc = CreateEnhMetaFileA(NULL, NULL, &rect, "HENHMETAFILE Ole Clipboard Test\0Test\0\0");
530     ExtTextOutA(hdc, 0, 0, ETO_OPAQUE, &rect, "Test String", strlen("Test String"), NULL);
531     return CloseEnhMetaFile(hdc);
532 }
533 
534 static HBITMAP create_bitmap(void)
535 {
536     HDC hdc = GetDC( 0 );
537     UINT bpp = GetDeviceCaps( hdc, BITSPIXEL );
538     ReleaseDC( 0, hdc );
539     return CreateBitmap( 10, 10, 1, bpp, NULL );
540 }
541 
542 static HBITMAP create_dib( BOOL v5 )
543 {
544     HANDLE ret;
545     BITMAPINFOHEADER *hdr;
546 
547     ret = GlobalAlloc( GMEM_DDESHARE | GMEM_MOVEABLE | GMEM_ZEROINIT,
548                        sizeof(BITMAPV5HEADER) + 256 * sizeof(RGBQUAD) + 16 * 16 * 4 );
549     hdr = GlobalLock( ret );
550     hdr->biSize = v5 ? sizeof(BITMAPV5HEADER) : sizeof(*hdr);
551     hdr->biWidth = 16;
552     hdr->biHeight = 16;
553     hdr->biPlanes = 1;
554     hdr->biBitCount = 32;
555     hdr->biCompression = BI_RGB;
556     if (v5)
557     {
558         BITMAPV5HEADER *hdr5 = (BITMAPV5HEADER *)hdr;
559         hdr5->bV5RedMask = 0x0000ff;
560         hdr5->bV5GreenMask = 0x00ff00;
561         hdr5->bV5BlueMask = 0xff0000;
562         hdr5->bV5AlphaMask = 0xff000000;
563     }
564     GlobalUnlock( ret );
565     return ret;
566 }
567 
568 static LRESULT CALLBACK renderer_winproc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
569 {
570     static UINT rendered;
571     UINT ret;
572 
573     switch (msg)
574     {
575     case WM_RENDERFORMAT:
576         if (wp < 32) rendered |= (1 << wp);
577         break;
578     case WM_USER:
579         ret = rendered;
580         rendered = 0;
581         return ret;
582     }
583     return DefWindowProcA( hwnd, msg, wp, lp );
584 }
585 
586 static void test_synthesized(void)
587 {
588     static const struct test
589     {
590         UINT format;
591         UINT expected[8];
592     } tests[] =
593     {
594 /* 0 */ { CF_TEXT, { CF_TEXT, CF_LOCALE, CF_OEMTEXT, CF_UNICODETEXT }},
595         { CF_OEMTEXT, { CF_OEMTEXT, CF_LOCALE, CF_TEXT, CF_UNICODETEXT }},
596         { CF_UNICODETEXT, { CF_UNICODETEXT, CF_LOCALE, CF_TEXT, CF_OEMTEXT }},
597         { CF_ENHMETAFILE, { CF_ENHMETAFILE, CF_METAFILEPICT }},
598         { CF_METAFILEPICT, { CF_METAFILEPICT, CF_ENHMETAFILE }},
599 /* 5 */ { CF_BITMAP, { CF_BITMAP, CF_DIB, CF_DIBV5 }},
600         { CF_DIB, { CF_DIB, CF_BITMAP, CF_DIBV5 }},
601         { CF_DIBV5, { CF_DIBV5, CF_BITMAP, CF_DIB }},
602     };
603 
604     HGLOBAL h, htext;
605     HENHMETAFILE emf;
606     BOOL r;
607     UINT cf, i, j, count, rendered, seq, old_seq;
608     HANDLE data;
609     HWND hwnd;
610 
611     hwnd = CreateWindowA( "static", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL );
612     SetWindowLongPtrA( hwnd, GWLP_WNDPROC, (LONG_PTR)renderer_winproc );
613 
614     htext = create_textA();
615     emf = create_emf();
616 
617     r = OpenClipboard(NULL);
618     ok(r, "gle %d\n", GetLastError());
619     r = EmptyClipboard();
620     ok(r, "gle %d\n", GetLastError());
621     h = SetClipboardData(CF_TEXT, htext);
622     ok(h == htext, "got %p\n", h);
623     h = SetClipboardData(CF_ENHMETAFILE, emf);
624     ok(h == emf, "got %p\n", h);
625     r = CloseClipboard();
626     ok(r, "gle %d\n", GetLastError());
627 
628     count = CountClipboardFormats();
629     ok( count == 6, "count %u\n", count );
630     r = IsClipboardFormatAvailable( CF_TEXT );
631     ok( r, "CF_TEXT not available err %d\n", GetLastError());
632     r = IsClipboardFormatAvailable( CF_LOCALE );
633     ok( r, "CF_LOCALE not available err %d\n", GetLastError());
634     r = IsClipboardFormatAvailable( CF_OEMTEXT );
635     ok( r, "CF_OEMTEXT not available err %d\n", GetLastError());
636     r = IsClipboardFormatAvailable( CF_UNICODETEXT );
637     ok( r, "CF_UNICODETEXT not available err %d\n", GetLastError());
638     r = IsClipboardFormatAvailable( CF_ENHMETAFILE );
639     ok( r, "CF_ENHMETAFILE not available err %d\n", GetLastError());
640     r = IsClipboardFormatAvailable( CF_METAFILEPICT );
641     ok( r, "CF_METAFILEPICT not available err %d\n", GetLastError());
642 
643     r = OpenClipboard(NULL);
644     ok(r, "gle %d\n", GetLastError());
645     cf = EnumClipboardFormats(0);
646     ok(cf == CF_TEXT, "cf %08x\n", cf);
647     data = GetClipboardData(cf);
648     ok(data != NULL, "couldn't get data, cf %08x\n", cf);
649 
650     cf = EnumClipboardFormats(cf);
651     ok(cf == CF_ENHMETAFILE, "cf %08x\n", cf);
652     data = GetClipboardData(cf);
653     ok(data != NULL, "couldn't get data, cf %08x\n", cf);
654 
655     cf = EnumClipboardFormats(cf);
656     ok(cf == CF_LOCALE, "cf %08x\n", cf);
657     data = GetClipboardData(cf);
658     ok(data != NULL, "couldn't get data, cf %08x\n", cf);
659 
660     cf = EnumClipboardFormats(cf);
661     ok(cf == CF_OEMTEXT, "cf %08x\n", cf);
662     data = GetClipboardData(cf);
663     ok(data != NULL, "couldn't get data, cf %08x\n", cf);
664 
665     cf = EnumClipboardFormats(cf);
666     ok(cf == CF_UNICODETEXT, "cf %08x\n", cf);
667 
668     cf = EnumClipboardFormats(cf);
669     ok(cf == CF_METAFILEPICT, "cf %08x\n", cf);
670     data = GetClipboardData(cf);
671     ok(data != NULL, "couldn't get data, cf %08x\n", cf);
672 
673     cf = EnumClipboardFormats(cf);
674     ok(cf == 0, "cf %08x\n", cf);
675 
676     r = EmptyClipboard();
677     ok(r, "gle %d\n", GetLastError());
678 
679     SetClipboardData( CF_UNICODETEXT, create_textW() );
680     SetClipboardData( CF_TEXT, create_textA() );
681     SetClipboardData( CF_OEMTEXT, create_textA() );
682     r = CloseClipboard();
683     ok(r, "gle %d\n", GetLastError());
684 
685     r = OpenClipboard( NULL );
686     ok(r, "gle %d\n", GetLastError());
687     SetLastError( 0xdeadbeef );
688     cf = EnumClipboardFormats(0);
689     ok( cf == CF_UNICODETEXT, "cf %08x\n", cf );
690     ok( GetLastError() == ERROR_SUCCESS, "wrong error %u\n", GetLastError() );
691     SetLastError( 0xdeadbeef );
692     cf = EnumClipboardFormats(cf);
693     ok( cf == CF_TEXT, "cf %08x\n", cf );
694     ok( GetLastError() == ERROR_SUCCESS, "wrong error %u\n", GetLastError() );
695     SetLastError( 0xdeadbeef );
696     cf = EnumClipboardFormats(cf);
697     ok( cf == CF_OEMTEXT, "cf %08x\n", cf );
698     ok( GetLastError() == ERROR_SUCCESS, "wrong error %u\n", GetLastError() );
699     SetLastError( 0xdeadbeef );
700     cf = EnumClipboardFormats(cf);
701     ok( cf == CF_LOCALE, "cf %08x\n", cf );
702     ok( GetLastError() == ERROR_SUCCESS, "wrong error %u\n", GetLastError() );
703     SetLastError( 0xdeadbeef );
704     cf = EnumClipboardFormats( cf );
705     ok( cf == 0, "cf %08x\n", cf );
706     ok( GetLastError() == ERROR_SUCCESS, "wrong error %u\n", GetLastError() );
707     SetLastError( 0xdeadbeef );
708     cf = EnumClipboardFormats( 0xdead );
709     ok( cf == 0, "cf %08x\n", cf );
710     ok( GetLastError() == ERROR_SUCCESS, "wrong error %u\n", GetLastError() );
711 
712     r = EmptyClipboard();
713     ok(r, "gle %d\n", GetLastError());
714 
715     r = CloseClipboard();
716     ok(r, "gle %d\n", GetLastError());
717 
718     for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++)
719     {
720         r = OpenClipboard(NULL);
721         ok(r, "%u: gle %d\n", i, GetLastError());
722         r = EmptyClipboard();
723         ok(r, "%u: gle %d\n", i, GetLastError());
724 
725         switch (tests[i].format)
726         {
727         case CF_TEXT:
728         case CF_OEMTEXT:
729             SetClipboardData( tests[i].format, create_textA() );
730             break;
731         case CF_UNICODETEXT:
732             SetClipboardData( CF_UNICODETEXT, create_textW() );
733             break;
734         case CF_ENHMETAFILE:
735             SetClipboardData( CF_ENHMETAFILE, create_emf() );
736             break;
737         case CF_METAFILEPICT:
738             SetClipboardData( CF_METAFILEPICT, create_metafile() );
739             break;
740         case CF_BITMAP:
741             SetClipboardData( CF_BITMAP, create_bitmap() );
742             break;
743         case CF_DIB:
744         case CF_DIBV5:
745             SetClipboardData( tests[i].format, create_dib( tests[i].format == CF_DIBV5 ));
746             break;
747         }
748 
749         count = CountClipboardFormats();
750         ok( count == 1, "%u: count %u\n", i, count );
751 
752         r = CloseClipboard();
753         ok(r, "%u: gle %d\n", i, GetLastError());
754 
755         count = CountClipboardFormats();
756         for (j = 0; tests[i].expected[j]; j++)
757         {
758             r = IsClipboardFormatAvailable( tests[i].expected[j] );
759             ok( r, "%u: %04x not available\n", i, tests[i].expected[j] );
760         }
761         ok( count == j, "%u: count %u instead of %u\n", i, count, j );
762 
763         r = OpenClipboard( hwnd );
764         ok(r, "%u: gle %d\n", i, GetLastError());
765         cf = 0;
766         for (j = 0; tests[i].expected[j]; j++)
767         {
768             cf = EnumClipboardFormats( cf );
769             ok(cf == tests[i].expected[j], "%u.%u: got %04x instead of %04x\n",
770                i, j, cf, tests[i].expected[j] );
771             if (cf != tests[i].expected[j]) break;
772             old_seq = GetClipboardSequenceNumber();
773             data = GetClipboardData( cf );
774             ok(data != NULL ||
775                broken( tests[i].format == CF_DIBV5 && cf == CF_DIB ), /* >= Vista */
776                "%u: couldn't get data, cf %04x err %d\n", i, cf, GetLastError());
777             seq = GetClipboardSequenceNumber();
778             ok(seq == old_seq, "sequence changed (test %d %d)\n", i, cf);
779             switch (cf)
780             {
781             case CF_LOCALE:
782             {
783                 UINT *ptr = GlobalLock( data );
784                 ok( GlobalSize( data ) == sizeof(*ptr), "%u: size %lu\n", i, GlobalSize( data ));
785                 ok( *ptr == GetUserDefaultLCID() ||
786                     broken( *ptr == MAKELANGID( LANG_ENGLISH, SUBLANG_DEFAULT )),
787                     "%u: CF_LOCALE %08x/%08x\n", i, *ptr, GetUserDefaultLCID() );
788                 GlobalUnlock( data );
789                 break;
790             }
791             case CF_TEXT:
792             case CF_OEMTEXT:
793                 ok( GlobalSize( data ) == 10, "wrong len %ld\n", GlobalSize( data ));
794                 break;
795             case CF_UNICODETEXT:
796                 ok( GlobalSize( data ) == 10 * sizeof(WCHAR), "wrong len %ld\n", GlobalSize( data ));
797                 break;
798             }
799         }
800         if (!tests[i].expected[j])
801         {
802             cf = EnumClipboardFormats( cf );
803             ok(cf == 0, "%u: cf %04x\n", i, cf);
804         }
805 
806         /* now with delayed rendering */
807 
808         r = EmptyClipboard();
809         ok(r, "%u: gle %d\n", i, GetLastError());
810 
811         rendered = SendMessageA( hwnd, WM_USER, 0, 0 );
812         ok( !rendered, "%u: formats %08x have been rendered\n", i, rendered );
813 
814         SetClipboardData( tests[i].format, 0 );
815         rendered = SendMessageA( hwnd, WM_USER, 0, 0 );
816         ok( !rendered, "%u: formats %08x have been rendered\n", i, rendered );
817 
818         count = CountClipboardFormats();
819         ok( count == 1, "%u: count %u\n", i, count );
820 
821         r = CloseClipboard();
822         ok(r, "%u: gle %d\n", i, GetLastError());
823         rendered = SendMessageA( hwnd, WM_USER, 0, 0 );
824         ok( !rendered, "%u: formats %08x have been rendered\n", i, rendered );
825 
826         count = CountClipboardFormats();
827         for (j = 0; tests[i].expected[j]; j++)
828         {
829             r = IsClipboardFormatAvailable( tests[i].expected[j] );
830             ok( r, "%u: %04x not available\n", i, tests[i].expected[j] );
831         }
832         ok( count == j, "%u: count %u instead of %u\n", i, count, j );
833         rendered = SendMessageA( hwnd, WM_USER, 0, 0 );
834         ok( !rendered, "%u: formats %08x have been rendered\n", i, rendered );
835 
836         r = OpenClipboard(NULL);
837         ok(r, "%u: gle %d\n", i, GetLastError());
838         cf = 0;
839         for (j = 0; tests[i].expected[j]; j++)
840         {
841             cf = EnumClipboardFormats( cf );
842             ok(cf == tests[i].expected[j], "%u.%u: got %04x instead of %04x\n",
843                i, j, cf, tests[i].expected[j] );
844             if (cf != tests[i].expected[j]) break;
845             rendered = SendMessageA( hwnd, WM_USER, 0, 0 );
846             ok( !rendered, "%u.%u: formats %08x have been rendered\n", i, j, rendered );
847             data = GetClipboardData( cf );
848             rendered = SendMessageA( hwnd, WM_USER, 0, 0 );
849             if (cf == CF_LOCALE)
850             {
851                 ok(data != NULL, "%u: CF_LOCALE no data\n", i);
852                 ok( !rendered, "%u.%u: formats %08x have been rendered\n", i, j, rendered );
853             }
854             else
855             {
856                 ok(!data, "%u: format %04x got data %p\n", i, cf, data);
857                 ok( rendered == (1 << tests[i].format),
858                     "%u.%u: formats %08x have been rendered\n", i, j, rendered );
859                 /* try to render a second time */
860                 data = GetClipboardData( cf );
861                 rendered = SendMessageA( hwnd, WM_USER, 0, 0 );
862                 ok( rendered == (1 << tests[i].format),
863                     "%u.%u: formats %08x have been rendered\n", i, j, rendered );
864             }
865         }
866         if (!tests[i].expected[j])
867         {
868             cf = EnumClipboardFormats( cf );
869             ok(cf == 0, "%u: cf %04x\n", i, cf);
870         }
871         r = CloseClipboard();
872         ok(r, "%u: gle %d\n", i, GetLastError());
873         rendered = SendMessageA( hwnd, WM_USER, 0, 0 );
874         ok( !rendered, "%u: formats %08x have been rendered\n", i, rendered );
875     }
876 
877     r = OpenClipboard(NULL);
878     ok(r, "gle %d\n", GetLastError());
879     r = EmptyClipboard();
880     ok(r, "gle %d\n", GetLastError());
881     r = CloseClipboard();
882     ok(r, "gle %d\n", GetLastError());
883     DestroyWindow( hwnd );
884 }
885 
886 static DWORD WINAPI clipboard_render_data_thread(void *param)
887 {
888     HANDLE handle = SetClipboardData( CF_UNICODETEXT, create_textW() );
889     ok( handle != 0, "SetClipboardData failed: %d\n", GetLastError() );
890     return 0;
891 }
892 
893 static CRITICAL_SECTION clipboard_cs;
894 static HWND next_wnd;
895 static UINT wm_drawclipboard;
896 static UINT wm_clipboardupdate;
897 static UINT wm_destroyclipboard;
898 static UINT wm_renderformat;
899 static UINT nb_formats;
900 static BOOL cross_thread;
901 static BOOL do_render_format;
902 static HANDLE update_event;
903 
904 static LRESULT CALLBACK clipboard_wnd_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
905 {
906     LRESULT ret;
907     DWORD msg_flags = InSendMessageEx( NULL );
908 
909     switch(msg) {
910     case WM_DRAWCLIPBOARD:
911         ok( msg_flags == (cross_thread ? ISMEX_NOTIFY : ISMEX_NOSEND),
912             "WM_DRAWCLIPBOARD wrong flags %x\n", msg_flags );
913         EnterCriticalSection(&clipboard_cs);
914         wm_drawclipboard++;
915         LeaveCriticalSection(&clipboard_cs);
916         break;
917     case WM_CHANGECBCHAIN:
918         ok( msg_flags == (cross_thread ? ISMEX_SEND : ISMEX_NOSEND),
919             "WM_CHANGECBCHAIN wrong flags %x\n", msg_flags );
920         if (next_wnd == (HWND)wp)
921             next_wnd = (HWND)lp;
922         else if (next_wnd)
923             SendMessageA(next_wnd, msg, wp, lp);
924         break;
925     case WM_DESTROYCLIPBOARD:
926         ok( msg_flags == (cross_thread ? ISMEX_SEND : ISMEX_NOSEND),
927             "WM_DESTROYCLIPBOARD wrong flags %x\n", msg_flags );
928         wm_destroyclipboard++;
929         ok( GetClipboardOwner() == hwnd, "WM_DESTROYCLIPBOARD owner %p\n", GetClipboardOwner() );
930         nb_formats = CountClipboardFormats();
931         break;
932     case WM_RENDERFORMAT:
933         ok( !wm_renderformat, "multiple WM_RENDERFORMAT %04x / %04lx\n", wm_renderformat, wp );
934         wm_renderformat = wp;
935 
936         if (do_render_format)
937         {
938             UINT seq, old_seq;
939             HANDLE handle;
940 
941             old_seq = GetClipboardSequenceNumber();
942             handle = SetClipboardData( CF_TEXT, create_textA() );
943             ok( handle != 0, "SetClipboardData failed: %d\n", GetLastError() );
944             seq = GetClipboardSequenceNumber();
945             ok( seq == old_seq, "sequence changed\n" );
946             old_seq = seq;
947 
948             handle = CreateThread( NULL, 0, clipboard_render_data_thread, NULL, 0, NULL );
949             ok( handle != NULL, "CreateThread failed: %d\n", GetLastError() );
950             ok( WaitForSingleObject(handle, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n" );
951             CloseHandle( handle );
952             seq = GetClipboardSequenceNumber();
953             ok( seq == old_seq, "sequence changed\n" );
954         }
955 
956         break;
957     case WM_CLIPBOARDUPDATE:
958         ok( msg_flags == ISMEX_NOSEND, "WM_CLIPBOARDUPDATE wrong flags %x\n", msg_flags );
959         EnterCriticalSection(&clipboard_cs);
960         wm_clipboardupdate++;
961         SetEvent(update_event);
962         LeaveCriticalSection(&clipboard_cs);
963         break;
964     case WM_USER:
965         ChangeClipboardChain(hwnd, next_wnd);
966         PostQuitMessage(0);
967         break;
968     case WM_USER+1:
969         ret = wm_drawclipboard;
970         wm_drawclipboard = 0;
971         return ret;
972     case WM_USER+2:
973         ret = wm_clipboardupdate;
974         wm_clipboardupdate = 0;
975         return ret;
976     case WM_USER+3:
977         ret = wm_destroyclipboard;
978         wm_destroyclipboard = 0;
979         return ret;
980     case WM_USER+4:
981         ret = wm_renderformat;
982         wm_renderformat = 0;
983         return ret;
984     case WM_USER+5:
985         return nb_formats;
986     }
987 
988     return DefWindowProcA(hwnd, msg, wp, lp);
989 }
990 
991 static void get_clipboard_data_process(void)
992 {
993     HANDLE data;
994     BOOL r;
995 
996     r = OpenClipboard(0);
997     ok(r, "OpenClipboard failed: %d\n", GetLastError());
998     data = GetClipboardData( CF_UNICODETEXT );
999     ok( data != NULL, "GetClipboardData failed: %d\n", GetLastError());
1000     r = CloseClipboard();
1001     ok(r, "CloseClipboard failed: %d\n", GetLastError());
1002 }
1003 
1004 static UINT old_seq;
1005 
1006 static void check_messages_(int line, HWND win, UINT seq_diff, UINT draw, UINT update, UINT destroy, UINT render)
1007 {
1008     MSG msg;
1009     UINT count, fmt, seq;
1010 
1011     seq = GetClipboardSequenceNumber();
1012     ok_(__FILE__, line)(seq - old_seq == seq_diff, "sequence diff %d\n", seq - old_seq);
1013     old_seq = seq;
1014 
1015     if (!cross_thread)
1016     {
1017         while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg );
1018     }
1019 
1020     if (update && !broken(!pAddClipboardFormatListener))
1021         ok(WaitForSingleObject(update_event, 1000) == WAIT_OBJECT_0, "wait failed\n");
1022 
1023     count = SendMessageA( win, WM_USER + 1, 0, 0 );
1024     ok_(__FILE__, line)(count == draw, "WM_DRAWCLIPBOARD %sreceived\n", draw ? "not " : "");
1025     count = SendMessageA( win, WM_USER + 2, 0, 0 );
1026     ok_(__FILE__, line)(count == update || broken(!pAddClipboardFormatListener),
1027                         "WM_CLIPBOARDUPDATE %sreceived\n", update ? "not " : "");
1028     count = SendMessageA( win, WM_USER + 3, 0, 0 );
1029     ok_(__FILE__, line)(count == destroy, "WM_DESTROYCLIPBOARD %sreceived\n", destroy ? "not " : "");
1030     fmt = SendMessageA( win, WM_USER + 4, 0, 0 );
1031     ok_(__FILE__, line)(fmt == render, "WM_RENDERFORMAT received %04x, expected %04x\n", fmt, render);
1032 }
1033 #define check_messages(a,b,c,d,e,f) check_messages_(__LINE__,a,b,c,d,e,f)
1034 
1035 static DWORD WINAPI clipboard_thread(void *param)
1036 {
1037     HWND ret, win = param;
1038     BOOL r;
1039     MSG msg;
1040     HANDLE handle;
1041     UINT count, fmt, formats;
1042 
1043     cross_thread = (GetWindowThreadProcessId( win, NULL ) != GetCurrentThreadId());
1044     trace( "%s-threaded test\n", cross_thread ? "multi" : "single" );
1045 
1046     old_seq = GetClipboardSequenceNumber();
1047 
1048     EnterCriticalSection(&clipboard_cs);
1049     SetLastError(0xdeadbeef);
1050     next_wnd = SetClipboardViewer(win);
1051     ok(GetLastError() == 0xdeadbeef, "GetLastError = %d\n", GetLastError());
1052     LeaveCriticalSection(&clipboard_cs);
1053 
1054     SetLastError( 0xdeadbeef );
1055     ret = SetClipboardViewer( (HWND)0xdead );
1056     ok( !ret, "SetClipboardViewer succeeded\n" );
1057     ok( GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %u\n", GetLastError() );
1058     SetLastError( 0xdeadbeef );
1059     r = ChangeClipboardChain( win, (HWND)0xdead );
1060     ok( !r, "ChangeClipboardChain succeeded\n" );
1061     ok( GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %u\n", GetLastError() );
1062     SetLastError( 0xdeadbeef );
1063     r = ChangeClipboardChain( (HWND)0xdead, next_wnd );
1064     ok( !r, "ChangeClipboardChain succeeded\n" );
1065     ok( GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %u\n", GetLastError() );
1066 
1067     if (pAddClipboardFormatListener)
1068     {
1069         r = pAddClipboardFormatListener(win);
1070         ok( r, "AddClipboardFormatListener failed err %d\n", GetLastError());
1071         SetLastError( 0xdeadbeef );
1072         r = pAddClipboardFormatListener( win );
1073         ok( !r, "AddClipboardFormatListener succeeded\n" );
1074         ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
1075         SetLastError( 0xdeadbeef );
1076         r = pAddClipboardFormatListener( (HWND)0xdead );
1077         ok( !r, "AddClipboardFormatListener succeeded\n" );
1078         ok( GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %u\n", GetLastError() );
1079         r = pAddClipboardFormatListener( GetDesktopWindow() );
1080         ok( r, "AddClipboardFormatListener failed err %d\n", GetLastError());
1081         r = pRemoveClipboardFormatListener( GetDesktopWindow() );
1082         ok( r, "RemoveClipboardFormatListener failed err %d\n", GetLastError());
1083     }
1084 
1085     check_messages(win, 0, 1, 0, 0, 0);
1086 
1087     SetLastError( 0xdeadbeef );
1088     r = OpenClipboard( (HWND)0xdead );
1089     ok( !r, "OpenClipboard succeeded\n" );
1090     ok( GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %u\n", GetLastError() );
1091 
1092     r = OpenClipboard(win);
1093     ok(r, "OpenClipboard failed: %d\n", GetLastError());
1094 
1095     check_messages(win, 0, 0, 0, 0, 0);
1096 
1097     r = EmptyClipboard();
1098     ok(r, "EmptyClipboard failed: %d\n", GetLastError());
1099 
1100     check_messages(win, 1, 0, 0, 0, 0);
1101 
1102     r = EmptyClipboard();
1103     ok(r, "EmptyClipboard failed: %d\n", GetLastError());
1104     /* sequence changes again, even though it was already empty */
1105     check_messages(win, 1, 0, 0, 1, 0);
1106     count = SendMessageA( win, WM_USER+5, 0, 0 );
1107     ok( !count, "wrong format count %u on WM_DESTROYCLIPBOARD\n", count );
1108 
1109     handle = SetClipboardData( CF_TEXT, create_textA() );
1110     ok(handle != 0, "SetClipboardData failed: %d\n", GetLastError());
1111 
1112     check_messages(win, 1, 0, 0, 0, 0);
1113 
1114     SetClipboardData( CF_UNICODETEXT, 0 );
1115 
1116     check_messages(win, 1, 0, 0, 0, 0);
1117 
1118     SetClipboardData( CF_UNICODETEXT, 0 );  /* same data again */
1119 
1120     check_messages(win, 1, 0, 0, 0, 0);
1121 
1122     ok( IsClipboardFormatAvailable( CF_TEXT ), "CF_TEXT available\n" );
1123     ok( IsClipboardFormatAvailable( CF_UNICODETEXT ), "CF_UNICODETEXT available\n" );
1124     ok( !IsClipboardFormatAvailable( CF_OEMTEXT ), "CF_OEMTEXT available\n" );
1125 
1126     EnterCriticalSection(&clipboard_cs);
1127     r = CloseClipboard();
1128     ok(r, "CloseClipboard failed: %d\n", GetLastError());
1129     LeaveCriticalSection(&clipboard_cs);
1130 
1131     check_messages(win, 2, 1, 1, 0, 0);
1132 
1133     r = OpenClipboard(win);
1134     ok(r, "OpenClipboard failed: %d\n", GetLastError());
1135 
1136     check_messages(win, 0, 0, 0, 0, 0);
1137 
1138     ok( IsClipboardFormatAvailable( CF_TEXT ), "CF_TEXT available\n" );
1139     ok( IsClipboardFormatAvailable( CF_UNICODETEXT ), "CF_UNICODETEXT available\n" );
1140     ok( IsClipboardFormatAvailable( CF_OEMTEXT ), "CF_OEMTEXT available\n" );
1141 
1142     ok( GetClipboardOwner() == win, "wrong owner %p\n", GetClipboardOwner());
1143     handle = GetClipboardData( CF_UNICODETEXT );
1144     ok( !handle, "got data for CF_UNICODETEXT\n" );
1145     fmt = SendMessageA( win, WM_USER+4, 0, 0 );
1146     ok( fmt == CF_UNICODETEXT, "WM_RENDERFORMAT received %04x\n", fmt );
1147 
1148     do_render_format = TRUE;
1149     handle = GetClipboardData( CF_OEMTEXT );
1150     ok( handle != NULL, "didn't get data for CF_OEMTEXT\n" );
1151     fmt = SendMessageA( win, WM_USER+4, 0, 0 );
1152     ok( fmt == CF_UNICODETEXT, "WM_RENDERFORMAT received %04x\n", fmt );
1153     do_render_format = FALSE;
1154 
1155     SetClipboardData( CF_WAVE, 0 );
1156     check_messages(win, 1, 0, 0, 0, 0);
1157 
1158     r = CloseClipboard();
1159     ok(r, "CloseClipboard failed: %d\n", GetLastError());
1160     /* no synthesized format, so CloseClipboard doesn't change the sequence */
1161     check_messages(win, 0, 1, 1, 0, 0);
1162 
1163     r = OpenClipboard(win);
1164     ok(r, "OpenClipboard failed: %d\n", GetLastError());
1165     r = CloseClipboard();
1166     ok(r, "CloseClipboard failed: %d\n", GetLastError());
1167     /* nothing changed */
1168     check_messages(win, 0, 0, 0, 0, 0);
1169 
1170     formats = CountClipboardFormats();
1171     r = OpenClipboard(0);
1172     ok(r, "OpenClipboard failed: %d\n", GetLastError());
1173     r = EmptyClipboard();
1174     ok(r, "EmptyClipboard failed: %d\n", GetLastError());
1175     r = CloseClipboard();
1176     ok(r, "CloseClipboard failed: %d\n", GetLastError());
1177 
1178     check_messages(win, 1, 1, 1, 1, 0);
1179     count = SendMessageA( win, WM_USER+5, 0, 0 );
1180     ok( count == formats, "wrong format count %u on WM_DESTROYCLIPBOARD\n", count );
1181 
1182     r = OpenClipboard(win);
1183     ok(r, "OpenClipboard failed: %d\n", GetLastError());
1184     SetClipboardData( CF_WAVE, GlobalAlloc( GMEM_FIXED, 1 ));
1185     check_messages(win, 1, 0, 0, 0, 0);
1186 
1187     EnterCriticalSection(&clipboard_cs);
1188     r = CloseClipboard();
1189     ok(r, "CloseClipboard failed: %d\n", GetLastError());
1190     LeaveCriticalSection(&clipboard_cs);
1191 
1192     check_messages(win, 0, 1, 1, 0, 0);
1193 
1194     run_process( "grab_clipboard 0" );
1195 
1196     if (!cross_thread)
1197     {
1198         /* in this case we get a cross-thread WM_DRAWCLIPBOARD */
1199         cross_thread = TRUE;
1200         while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg );
1201         cross_thread = FALSE;
1202     }
1203     check_messages(win, 1, 1, 1, 0, 0);
1204 
1205     r = OpenClipboard(0);
1206     ok(r, "OpenClipboard failed: %d\n", GetLastError());
1207     SetClipboardData( CF_WAVE, GlobalAlloc( GMEM_FIXED, 1 ));
1208     check_messages(win, 1, 0, 0, 0, 0);
1209 
1210     EnterCriticalSection(&clipboard_cs);
1211     r = CloseClipboard();
1212     ok(r, "CloseClipboard failed: %d\n", GetLastError());
1213     LeaveCriticalSection(&clipboard_cs);
1214 
1215     check_messages(win, 0, 1, 1, 0, 0);
1216 
1217     run_process( "grab_clipboard 1" );
1218 
1219     if (!cross_thread)
1220     {
1221         /* in this case we get a cross-thread WM_DRAWCLIPBOARD */
1222         cross_thread = TRUE;
1223         while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg );
1224         cross_thread = FALSE;
1225     }
1226     check_messages(win, 2, 1, 1, 0, 0);
1227 
1228     r = OpenClipboard(0);
1229     ok(r, "OpenClipboard failed: %d\n", GetLastError());
1230     SetClipboardData( CF_WAVE, GlobalAlloc( GMEM_FIXED, 1 ));
1231     check_messages(win, 1, 0, 0, 0, 0);
1232 
1233     EnterCriticalSection(&clipboard_cs);
1234     r = CloseClipboard();
1235     ok(r, "CloseClipboard failed: %d\n", GetLastError());
1236     LeaveCriticalSection(&clipboard_cs);
1237 
1238     check_messages(win, 0, 1, 1, 0, 0);
1239 
1240     if (cross_thread)
1241     {
1242         r = OpenClipboard( win );
1243         ok(r, "OpenClipboard failed: %d\n", GetLastError());
1244         r = EmptyClipboard();
1245         ok(r, "EmptyClipboard failed: %d\n", GetLastError());
1246         SetClipboardData( CF_TEXT, 0 );
1247         r = CloseClipboard();
1248         ok(r, "CloseClipboard failed: %d\n", GetLastError());
1249 
1250         do_render_format = TRUE;
1251         old_seq = GetClipboardSequenceNumber();
1252         run_process( "get_clipboard_data" );
1253         do_render_format = FALSE;
1254 
1255         check_messages(win, 0, 1, 1, 0, CF_TEXT);
1256     }
1257 
1258     r = PostMessageA(win, WM_USER, 0, 0);
1259     ok(r, "PostMessage failed: %d\n", GetLastError());
1260 
1261     if (pRemoveClipboardFormatListener)
1262     {
1263         r = pRemoveClipboardFormatListener(win);
1264         ok( r, "RemoveClipboardFormatListener failed err %d\n", GetLastError());
1265         SetLastError( 0xdeadbeef );
1266         r = pRemoveClipboardFormatListener(win);
1267         ok( !r, "RemoveClipboardFormatListener succeeded\n" );
1268         ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
1269         SetLastError( 0xdeadbeef );
1270         r = pRemoveClipboardFormatListener( (HWND)0xdead );
1271         ok( !r, "RemoveClipboardFormatListener succeeded\n" );
1272         ok( GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "wrong error %u\n", GetLastError() );
1273     }
1274     return 0;
1275 }
1276 
1277 static void test_messages(void)
1278 {
1279     WNDCLASSA cls;
1280     HWND win;
1281     MSG msg;
1282     HANDLE thread;
1283     DWORD tid;
1284 
1285     InitializeCriticalSection(&clipboard_cs);
1286     update_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1287 
1288     memset(&cls, 0, sizeof(cls));
1289     cls.lpfnWndProc = clipboard_wnd_proc;
1290     cls.hInstance = GetModuleHandleA(NULL);
1291     cls.lpszClassName = "clipboard_test";
1292     RegisterClassA(&cls);
1293 
1294     win = CreateWindowA("clipboard_test", NULL, 0, 0, 0, 0, 0, NULL, 0, NULL, 0);
1295     ok(win != NULL, "CreateWindow failed: %d\n", GetLastError());
1296 
1297     thread = CreateThread(NULL, 0, clipboard_thread, (void*)win, 0, &tid);
1298     ok(thread != NULL, "CreateThread failed: %d\n", GetLastError());
1299 
1300     while(GetMessageA(&msg, NULL, 0, 0))
1301     {
1302         ok( msg.message != WM_DRAWCLIPBOARD, "WM_DRAWCLIPBOARD was posted\n" );
1303         TranslateMessage(&msg);
1304         DispatchMessageA(&msg);
1305     }
1306 
1307     ok(WaitForSingleObject(thread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
1308     CloseHandle(thread);
1309 
1310     DestroyWindow( win );
1311 
1312     /* same tests again but inside a single thread */
1313 
1314     win = CreateWindowA( "clipboard_test", NULL, 0, 0, 0, 0, 0, NULL, 0, NULL, 0 );
1315     ok( win != NULL, "CreateWindow failed: %d\n", GetLastError() );
1316 
1317     clipboard_thread( win );
1318     DestroyWindow( win );
1319 
1320     UnregisterClassA("clipboard_test", GetModuleHandleA(NULL));
1321     DeleteCriticalSection(&clipboard_cs);
1322 }
1323 
1324 static BOOL is_moveable( HANDLE handle )
1325 {
1326     void *ptr = GlobalLock( handle );
1327     if (ptr) GlobalUnlock( handle );
1328     return ptr && ptr != handle;
1329 }
1330 
1331 static BOOL is_fixed( HANDLE handle )
1332 {
1333     void *ptr = GlobalLock( handle );
1334     if (ptr) GlobalUnlock( handle );
1335     return ptr && ptr == handle;
1336 }
1337 
1338 static BOOL is_freed( HANDLE handle )
1339 {
1340     return !GlobalSize( handle );
1341 }
1342 
1343 static UINT format_id;
1344 static HBITMAP bitmap, bitmap2;
1345 static HPALETTE palette;
1346 static const LOGPALETTE logpalette = { 0x300, 1, {{ 0x12, 0x34, 0x56, 0x78 }}};
1347 
1348 static void test_handles( HWND hwnd )
1349 {
1350     HGLOBAL h, htext, htext2, htext3, htext4, htext5;
1351     HGLOBAL hfixed, hfixed2, hmoveable, empty_fixed, empty_moveable;
1352     void *ptr;
1353     UINT format_id2 = RegisterClipboardFormatA( "another format" );
1354     BOOL r;
1355     HANDLE data;
1356     HBITMAP bitmap_temp;
1357     DWORD process;
1358     BOOL is_owner = (GetWindowThreadProcessId( hwnd, &process ) && process == GetCurrentProcessId());
1359 
1360     trace( "hwnd %p\n", hwnd );
1361     htext = create_textA();
1362     htext2 = create_textA();
1363     htext3 = create_textA();
1364     htext4 = create_textA();
1365     htext5 = create_textA();
1366     bitmap = CreateBitmap( 10, 10, 1, 1, NULL );
1367     bitmap2 = CreateBitmap( 10, 10, 1, 1, NULL );
1368     palette = CreatePalette( &logpalette );
1369 
1370     hfixed = GlobalAlloc( GMEM_FIXED, 17 );
1371     hfixed2 = GlobalAlloc( GMEM_FIXED, 17 );
1372     ok( is_fixed( hfixed ), "expected fixed mem %p\n", hfixed );
1373     ok( GlobalSize( hfixed ) == 17, "wrong size %lu\n", GlobalSize( hfixed ));
1374 
1375     hmoveable = GlobalAlloc( GMEM_MOVEABLE, 23 );
1376     ok( is_moveable( hmoveable ), "expected moveable mem %p\n", hmoveable );
1377     ok( GlobalSize( hmoveable ) == 23, "wrong size %lu\n", GlobalSize( hmoveable ));
1378 
1379     empty_fixed = GlobalAlloc( GMEM_FIXED, 0 );
1380     ok( is_fixed( empty_fixed ), "expected fixed mem %p\n", empty_fixed );
1381 
1382     empty_moveable = GlobalAlloc( GMEM_MOVEABLE, 0 );
1383     /* discarded handles can't be GlobalLock'ed */
1384     ok( is_freed( empty_moveable ), "expected free mem %p\n", empty_moveable );
1385 
1386     r = OpenClipboard( hwnd );
1387     ok( r, "gle %d\n", GetLastError() );
1388     r = EmptyClipboard();
1389     ok( r, "gle %d\n", GetLastError() );
1390 
1391     h = SetClipboardData( CF_TEXT, htext );
1392     ok( h == htext, "got %p\n", h );
1393     ok( is_moveable( h ), "expected moveable mem %p\n", h );
1394     h = SetClipboardData( format_id, htext2 );
1395     ok( h == htext2, "got %p\n", h );
1396     ok( is_moveable( h ), "expected moveable mem %p\n", h );
1397     bitmap_temp = CreateBitmap( 10, 10, 1, 1, NULL );
1398     h = SetClipboardData( CF_BITMAP, bitmap_temp );
1399     ok( h == bitmap_temp, "got %p\n", h );
1400     ok( GetObjectType( h ) == OBJ_BITMAP, "expected bitmap %p\n", h );
1401     h = SetClipboardData( CF_BITMAP, bitmap );
1402     ok( h == bitmap, "got %p\n", h );
1403     ok( GetObjectType( h ) == OBJ_BITMAP, "expected bitmap %p\n", h );
1404     ok( !GetObjectType( bitmap_temp ), "expected free object %p\n", bitmap_temp );
1405     h = SetClipboardData( CF_DSPBITMAP, bitmap2 );
1406     ok( h == bitmap2, "got %p\n", h );
1407     ok( GetObjectType( h ) == OBJ_BITMAP, "expected bitmap %p\n", h );
1408     h = SetClipboardData( CF_PALETTE, palette );
1409     ok( h == palette, "got %p\n", h );
1410     ok( GetObjectType( h ) == OBJ_PAL, "expected palette %p\n", h );
1411     h = SetClipboardData( CF_GDIOBJFIRST + 3, htext3 );
1412     ok( h == htext3, "got %p\n", h );
1413     ok( is_moveable( h ), "expected moveable mem %p\n", h );
1414     h = SetClipboardData( CF_PRIVATEFIRST + 7, htext5 );
1415     ok( h == htext5, "got %p\n", h );
1416     ok( is_moveable( h ), "expected moveable mem %p\n", h );
1417     h = SetClipboardData( format_id2, empty_moveable );
1418     ok( !h, "got %p\n", h );
1419     GlobalFree( empty_moveable );
1420 
1421     if (0)  /* crashes on vista64 */
1422     {
1423         ptr = HeapAlloc( GetProcessHeap(), 0, 0 );
1424         h = SetClipboardData( format_id2, ptr );
1425         ok( !h, "got %p\n", h );
1426         HeapFree( GetProcessHeap(), 0, ptr );
1427     }
1428 
1429     h = SetClipboardData( format_id2, empty_fixed );
1430     ok( h == empty_fixed, "got %p\n", h );
1431     ok( is_fixed( h ), "expected fixed mem %p\n", h );
1432     h = SetClipboardData( 0xdeadbeef, hfixed2 );
1433     ok( h == hfixed2, "got %p\n", h );
1434     ok( is_fixed( h ), "expected fixed mem %p\n", h );
1435     h = SetClipboardData( 0xdeadbabe, hmoveable );
1436     ok( h == hmoveable, "got %p\n", h );
1437     ok( is_moveable( h ), "expected moveable mem %p\n", h );
1438 
1439     ptr = HeapAlloc( GetProcessHeap(), 0, 37 );
1440     h = SetClipboardData( 0xdeadfade, ptr );
1441     ok( h == ptr || !h, "got %p\n", h );
1442     if (!h)  /* heap blocks are rejected on >= win8 */
1443     {
1444         HeapFree( GetProcessHeap(), 0, ptr );
1445         ptr = NULL;
1446     }
1447 
1448     data = GetClipboardData( CF_TEXT );
1449     ok( data == htext, "wrong data %p\n", data );
1450     ok( is_moveable( data ), "expected moveable mem %p\n", data );
1451 
1452     data = GetClipboardData( format_id );
1453     ok( data == htext2, "wrong data %p, cf %08x\n", data, format_id );
1454     ok( is_moveable( data ), "expected moveable mem %p\n", data );
1455 
1456     data = GetClipboardData( CF_GDIOBJFIRST + 3 );
1457     ok( data == htext3, "wrong data %p\n", data );
1458     ok( is_moveable( data ), "expected moveable mem %p\n", data );
1459 
1460     data = GetClipboardData( CF_PRIVATEFIRST + 7 );
1461     ok( data == htext5, "wrong data %p\n", data );
1462     ok( is_moveable( data ), "expected moveable mem %p\n", data );
1463 
1464     data = GetClipboardData( format_id2 );
1465     ok( data == empty_fixed, "wrong data %p\n", data );
1466     ok( is_fixed( data ), "expected fixed mem %p\n", data );
1467 
1468     data = GetClipboardData( 0xdeadbeef );
1469     ok( data == hfixed2, "wrong data %p\n", data );
1470     ok( is_fixed( data ), "expected fixed mem %p\n", data );
1471 
1472     data = GetClipboardData( 0xdeadbabe );
1473     ok( data == hmoveable, "wrong data %p\n", data );
1474     ok( is_moveable( data ), "expected moveable mem %p\n", data );
1475 
1476     data = GetClipboardData( 0xdeadfade );
1477     ok( data == ptr, "wrong data %p\n", data );
1478 
1479     h = SetClipboardData( CF_PRIVATEFIRST + 7, htext4 );
1480     ok( h == htext4, "got %p\n", h );
1481     ok( is_moveable( h ), "expected moveable mem %p\n", h );
1482     ok( is_freed( htext5 ), "expected freed mem %p\n", htext5 );
1483 
1484     h = SetClipboardData( 0xdeadbeef, hfixed );
1485     ok( h == hfixed, "got %p\n", h );
1486     ok( is_fixed( h ), "expected fixed mem %p\n", h );
1487     if (0) /* this test is unreliable / crashes */
1488         ok( is_freed( hfixed2 ), "expected freed mem %p\n", hfixed2 );
1489 
1490     r = CloseClipboard();
1491     ok( r, "gle %d\n", GetLastError() );
1492 
1493     /* data handles are still valid */
1494     ok( is_moveable( htext ), "expected moveable mem %p\n", htext );
1495     ok( is_moveable( htext2 ), "expected moveable mem %p\n", htext2 );
1496     ok( is_moveable( htext3 ), "expected moveable mem %p\n", htext3 );
1497     ok( is_moveable( htext4 ), "expected moveable mem %p\n", htext4 );
1498     ok( GetObjectType( bitmap ) == OBJ_BITMAP, "expected bitmap %p\n", bitmap );
1499     ok( GetObjectType( bitmap2 ) == OBJ_BITMAP, "expected bitmap %p\n", bitmap2 );
1500     ok( GetObjectType( palette ) == OBJ_PAL, "expected palette %p\n", palette );
1501     ok( is_fixed( hfixed ), "expected fixed mem %p\n", hfixed );
1502     ok( is_moveable( hmoveable ), "expected moveable mem %p\n", hmoveable );
1503     ok( is_fixed( empty_fixed ), "expected fixed mem %p\n", empty_fixed );
1504 
1505     r = OpenClipboard( hwnd );
1506     ok( r, "gle %d\n", GetLastError() );
1507 
1508     /* and now they are freed, unless we are the owner */
1509     if (!is_owner)
1510     {
1511         ok( is_freed( htext ), "expected freed mem %p\n", htext );
1512         ok( is_freed( htext2 ), "expected freed mem %p\n", htext2 );
1513         ok( is_freed( htext3 ), "expected freed mem %p\n", htext3 );
1514         ok( is_freed( htext4 ), "expected freed mem %p\n", htext4 );
1515         ok( is_freed( hmoveable ), "expected freed mem %p\n", hmoveable );
1516 
1517         data = GetClipboardData( CF_TEXT );
1518         ok( is_fixed( data ), "expected fixed mem %p\n", data );
1519 
1520         data = GetClipboardData( format_id );
1521         ok( is_fixed( data ), "expected fixed mem %p\n", data );
1522 
1523         data = GetClipboardData( CF_GDIOBJFIRST + 3 );
1524         ok( is_fixed( data ), "expected fixed mem %p\n", data );
1525 
1526         data = GetClipboardData( CF_PRIVATEFIRST + 7 );
1527         ok( is_fixed( data ), "expected fixed mem %p\n", data );
1528 
1529         data = GetClipboardData( format_id2 );
1530         ok( is_fixed( data ), "expected fixed mem %p\n", data );
1531         ok( GlobalSize( data ) == 1, "wrong size %lu\n", GlobalSize( data ));
1532 
1533         data = GetClipboardData( 0xdeadbeef );
1534         ok( is_fixed( data ), "expected fixed mem %p\n", data );
1535         ok( GlobalSize( data ) == 17, "wrong size %lu\n", GlobalSize( data ));
1536 
1537         data = GetClipboardData( 0xdeadbabe );
1538         ok( is_fixed( data ), "expected fixed mem %p\n", data );
1539         ok( GlobalSize( data ) == 23, "wrong size %lu\n", GlobalSize( data ));
1540 
1541         data = GetClipboardData( 0xdeadfade );
1542         ok( is_fixed( data ) || !ptr, "expected fixed mem %p\n", data );
1543         if (ptr) ok( GlobalSize( data ) == 37, "wrong size %lu\n", GlobalSize( data ));
1544     }
1545     else
1546     {
1547         ok( is_moveable( htext ), "expected moveable mem %p\n", htext );
1548         ok( is_moveable( htext2 ), "expected moveable mem %p\n", htext2 );
1549         ok( is_moveable( htext3 ), "expected moveable mem %p\n", htext3 );
1550         ok( is_moveable( htext4 ), "expected moveable mem %p\n", htext4 );
1551         ok( is_moveable( hmoveable ), "expected moveable mem %p\n", hmoveable );
1552 
1553         data = GetClipboardData( CF_TEXT );
1554         ok( data == htext, "wrong data %p\n", data );
1555 
1556         data = GetClipboardData( format_id );
1557         ok( data == htext2, "wrong data %p, cf %08x\n", data, format_id );
1558 
1559         data = GetClipboardData( CF_GDIOBJFIRST + 3 );
1560         ok( data == htext3, "wrong data %p\n", data );
1561 
1562         data = GetClipboardData( CF_PRIVATEFIRST + 7 );
1563         ok( data == htext4, "wrong data %p\n", data );
1564 
1565         data = GetClipboardData( format_id2 );
1566         ok( data == empty_fixed, "wrong data %p\n", data );
1567 
1568         data = GetClipboardData( 0xdeadbeef );
1569         ok( data == hfixed, "wrong data %p\n", data );
1570 
1571         data = GetClipboardData( 0xdeadbabe );
1572         ok( data == hmoveable, "wrong data %p\n", data );
1573 
1574         data = GetClipboardData( 0xdeadfade );
1575         ok( data == ptr, "wrong data %p\n", data );
1576     }
1577 
1578     data = GetClipboardData( CF_OEMTEXT );
1579     ok( is_fixed( data ), "expected fixed mem %p\n", data );
1580     data = GetClipboardData( CF_UNICODETEXT );
1581     ok( is_fixed( data ), "expected fixed mem %p\n", data );
1582     data = GetClipboardData( CF_LOCALE );
1583     ok( is_fixed( data ), "expected fixed mem %p\n", data );
1584     data = GetClipboardData( CF_BITMAP );
1585     ok( data == bitmap, "expected bitmap %p\n", data );
1586     data = GetClipboardData( CF_DSPBITMAP );
1587     ok( data == bitmap2, "expected bitmap %p\n", data );
1588     data = GetClipboardData( CF_PALETTE );
1589     ok( data == palette, "expected palette %p\n", data );
1590     data = GetClipboardData( CF_DIB );
1591     ok( is_fixed( data ), "expected fixed mem %p\n", data );
1592     data = GetClipboardData( CF_DIBV5 );
1593     ok( is_fixed( data ), "expected fixed mem %p\n", data );
1594 
1595     ok( GetObjectType( bitmap ) == OBJ_BITMAP, "expected bitmap %p\n", bitmap );
1596     ok( GetObjectType( bitmap2 ) == OBJ_BITMAP, "expected bitmap %p\n", bitmap2 );
1597     ok( GetObjectType( palette ) == OBJ_PAL, "expected palette %p\n", palette );
1598     ok( is_fixed( hfixed ), "expected fixed mem %p\n", hfixed );
1599     ok( is_fixed( empty_fixed ), "expected fixed mem %p\n", empty_fixed );
1600 
1601     r = EmptyClipboard();
1602     ok( r, "gle %d\n", GetLastError() );
1603 
1604     /* w2003, w2008 don't seem to free the data here */
1605     ok( is_freed( htext ) || broken( !is_freed( htext )), "expected freed mem %p\n", htext );
1606     ok( is_freed( htext2 ) || broken( !is_freed( htext2 )), "expected freed mem %p\n", htext2 );
1607     ok( is_freed( htext3 ) || broken( !is_freed( htext3 )), "expected freed mem %p\n", htext3 );
1608     ok( is_freed( htext4 ) || broken( !is_freed( htext4 )), "expected freed mem %p\n", htext4 );
1609     ok( is_freed( hmoveable ) || broken( !is_freed( hmoveable )), "expected freed mem %p\n", hmoveable );
1610     ok( is_fixed( empty_fixed ), "expected fixed mem %p\n", empty_fixed );
1611     ok( is_fixed( hfixed ), "expected fixed mem %p\n", hfixed );
1612     ok( !GetObjectType( bitmap ), "expected freed handle %p\n", bitmap );
1613     ok( !GetObjectType( bitmap2 ), "expected freed handle %p\n", bitmap2 );
1614     ok( !GetObjectType( palette ), "expected freed handle %p\n", palette );
1615 
1616     r = CloseClipboard();
1617     ok( r, "gle %d\n", GetLastError() );
1618 }
1619 
1620 static DWORD WINAPI test_handles_thread( void *arg )
1621 {
1622     trace( "running from different thread\n" );
1623     test_handles( (HWND)arg );
1624     return 0;
1625 }
1626 
1627 static DWORD WINAPI test_handles_thread2( void *arg )
1628 {
1629     BOOL r;
1630     HANDLE h;
1631     char *ptr;
1632 
1633     r = OpenClipboard( 0 );
1634     ok( r, "gle %d\n", GetLastError() );
1635     h = GetClipboardData( CF_TEXT );
1636     ok( is_moveable( h ), "expected moveable mem %p\n", h );
1637     ptr = GlobalLock( h );
1638     if (ptr) ok( !strcmp( "test", ptr ), "wrong data '%.5s'\n", ptr );
1639     GlobalUnlock( h );
1640     h = GetClipboardData( format_id );
1641     ok( is_moveable( h ), "expected moveable mem %p\n", h );
1642     ptr = GlobalLock( h );
1643     if (ptr) ok( !strcmp( "test", ptr ), "wrong data '%.5s'\n", ptr );
1644     GlobalUnlock( h );
1645     h = GetClipboardData( CF_GDIOBJFIRST + 3 );
1646     ok( is_moveable( h ), "expected moveable mem %p\n", h );
1647     ptr = GlobalLock( h );
1648     if (ptr) ok( !strcmp( "test", ptr ), "wrong data '%.5s'\n", ptr );
1649     GlobalUnlock( h );
1650     trace( "gdiobj %p\n", h );
1651     h = GetClipboardData( CF_PRIVATEFIRST + 7 );
1652     ok( is_moveable( h ), "expected moveable mem %p\n", h );
1653     ptr = GlobalLock( h );
1654     if (ptr) ok( !strcmp( "test", ptr ), "wrong data '%.5s'\n", ptr );
1655     GlobalUnlock( h );
1656     trace( "private %p\n", h );
1657     h = GetClipboardData( CF_BITMAP );
1658     ok( GetObjectType( h ) == OBJ_BITMAP, "expected bitmap %p\n", h );
1659     ok( h == bitmap, "different bitmap %p / %p\n", h, bitmap );
1660     trace( "bitmap %p\n", h );
1661     h = GetClipboardData( CF_DSPBITMAP );
1662     ok( GetObjectType( h ) == OBJ_BITMAP, "expected bitmap %p\n", h );
1663     ok( h == bitmap2, "different bitmap %p / %p\n", h, bitmap2 );
1664     trace( "bitmap2 %p\n", h );
1665     h = GetClipboardData( CF_PALETTE );
1666     ok( GetObjectType( h ) == OBJ_PAL, "expected palette %p\n", h );
1667     ok( h == palette, "different palette %p / %p\n", h, palette );
1668     trace( "palette %p\n", h );
1669     h = GetClipboardData( CF_DIB );
1670     ok( is_fixed( h ), "expected fixed mem %p\n", h );
1671     h = GetClipboardData( CF_DIBV5 );
1672     ok( is_fixed( h ), "expected fixed mem %p\n", h );
1673     r = CloseClipboard();
1674     ok( r, "gle %d\n", GetLastError() );
1675     return 0;
1676 }
1677 
1678 static void test_handles_process( const char *str )
1679 {
1680     BOOL r;
1681     HANDLE h;
1682     char *ptr;
1683     BITMAP bm;
1684     PALETTEENTRY entry;
1685     BYTE buffer[1024];
1686 
1687     format_id = RegisterClipboardFormatA( "my_cool_clipboard_format" );
1688     r = OpenClipboard( 0 );
1689     ok( r, "gle %d\n", GetLastError() );
1690     h = GetClipboardData( CF_TEXT );
1691     ok( is_fixed( h ), "expected fixed mem %p\n", h );
1692     ptr = GlobalLock( h );
1693     ok( !strcmp( str, ptr ), "wrong data '%.5s'\n", ptr );
1694     GlobalUnlock( h );
1695     h = GetClipboardData( format_id );
1696     ok( is_fixed( h ), "expected fixed mem %p\n", h );
1697     ptr = GlobalLock( h );
1698     if (ptr) ok( !strcmp( str, ptr ), "wrong data '%.5s'\n", ptr );
1699     GlobalUnlock( h );
1700     h = GetClipboardData( CF_GDIOBJFIRST + 3 );
1701     ok( is_fixed( h ), "expected fixed mem %p\n", h );
1702     ptr = GlobalLock( h );
1703     ok( !strcmp( str, ptr ), "wrong data '%.5s'\n", ptr );
1704     GlobalUnlock( h );
1705     trace( "gdiobj %p\n", h );
1706     h = GetClipboardData( CF_PRIVATEFIRST + 7 );
1707     ok( is_fixed( h ), "expected fixed mem %p\n", h );
1708     ptr = GlobalLock( h );
1709     ok( !strcmp( str, ptr ), "wrong data '%.5s'\n", ptr );
1710     GlobalUnlock( h );
1711     trace( "private %p\n", h );
1712     h = GetClipboardData( CF_BITMAP );
1713     ok( GetObjectType( h ) == OBJ_BITMAP, "expected bitmap %p\n", h );
1714     ok( GetObjectW( h, sizeof(bm), &bm ) == sizeof(bm), "GetObject %p failed\n", h );
1715     ok( bm.bmWidth == 13 && bm.bmHeight == 17, "wrong bitmap %ux%u\n", bm.bmWidth, bm.bmHeight );
1716     trace( "bitmap %p\n", h );
1717     h = GetClipboardData( CF_DSPBITMAP );
1718     ok( !GetObjectType( h ), "expected invalid object %p\n", h );
1719     trace( "bitmap2 %p\n", h );
1720     h = GetClipboardData( CF_PALETTE );
1721     ok( GetObjectType( h ) == OBJ_PAL, "expected palette %p\n", h );
1722     ok( GetPaletteEntries( h, 0, 1, &entry ) == 1, "GetPaletteEntries %p failed\n", h );
1723     ok( entry.peRed == 0x12 && entry.peGreen == 0x34 && entry.peBlue == 0x56,
1724         "wrong color %02x,%02x,%02x\n", entry.peRed, entry.peGreen, entry.peBlue );
1725     trace( "palette %p\n", h );
1726     h = GetClipboardData( CF_METAFILEPICT );
1727     ok( is_fixed( h ), "expected fixed mem %p\n", h );
1728 #ifdef __REACTOS__
1729     if (h != NULL)
1730 #endif
1731     ok( GetObjectType( ((METAFILEPICT *)h)->hMF ) == OBJ_METAFILE,
1732         "wrong object %p\n", ((METAFILEPICT *)h)->hMF );
1733     trace( "metafile %p\n", h );
1734     h = GetClipboardData( CF_DSPMETAFILEPICT );
1735     ok( is_fixed( h ), "expected fixed mem %p\n", h );
1736 #ifdef __REACTOS__
1737     if (h != NULL)
1738 #endif
1739     ok( GetObjectType( ((METAFILEPICT *)h)->hMF ) == OBJ_METAFILE,
1740         "wrong object %p\n", ((METAFILEPICT *)h)->hMF );
1741     trace( "metafile2 %p\n", h );
1742     h = GetClipboardData( CF_ENHMETAFILE );
1743     ok( GetObjectType( h ) == OBJ_ENHMETAFILE, "expected enhmetafile %p\n", h );
1744     ok( GetEnhMetaFileBits( h, sizeof(buffer), buffer ) > sizeof(ENHMETAHEADER),
1745         "GetEnhMetaFileBits failed on %p\n", h );
1746     ok( ((ENHMETAHEADER *)buffer)->nRecords == 3,
1747         "wrong records %u\n", ((ENHMETAHEADER *)buffer)->nRecords );
1748     trace( "enhmetafile %p\n", h );
1749     h = GetClipboardData( CF_DSPENHMETAFILE );
1750     ok( GetObjectType( h ) == OBJ_ENHMETAFILE, "expected enhmetafile %p\n", h );
1751     ok( GetEnhMetaFileBits( h, sizeof(buffer), buffer ) > sizeof(ENHMETAHEADER),
1752         "GetEnhMetaFileBits failed on %p\n", h );
1753     ok( ((ENHMETAHEADER *)buffer)->nRecords == 3,
1754         "wrong records %u\n", ((ENHMETAHEADER *)buffer)->nRecords );
1755     trace( "enhmetafile2 %p\n", h );
1756     h = GetClipboardData( CF_DIB );
1757     ok( is_fixed( h ), "expected fixed mem %p\n", h );
1758     h = GetClipboardData( CF_DIBV5 );
1759     ok( is_fixed( h ), "expected fixed mem %p\n", h );
1760     r = CloseClipboard();
1761     ok( r, "gle %d\n", GetLastError() );
1762 }
1763 
1764 static void test_handles_process_open( const char *str )
1765 {
1766     HANDLE h, text = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, strlen(str) + 1 );
1767     char *ptr = GlobalLock( text );
1768 
1769     strcpy( ptr, str );
1770     GlobalUnlock( text );
1771 
1772     /* clipboard already open by parent process */
1773     h = SetClipboardData( CF_TEXT,  text );
1774     ok( h == text, "wrong mem %p / %p\n", h, text );
1775     ok( is_moveable( h ), "expected moveable mem %p\n", h );
1776 }
1777 
1778 static void test_handles_process_dib( const char *str )
1779 {
1780     BOOL r;
1781     HANDLE h;
1782 
1783     r = OpenClipboard( 0 );
1784     ok( r, "gle %d\n", GetLastError() );
1785     h = GetClipboardData( CF_BITMAP );
1786     ok( !GetObjectType( h ), "expected invalid object %p\n", h );
1787     trace( "dibsection %p\n", h );
1788     r = CloseClipboard();
1789     ok( r, "gle %d\n", GetLastError() );
1790 }
1791 
1792 static void test_data_handles(void)
1793 {
1794     BOOL r;
1795     char *ptr;
1796     HANDLE h, text;
1797     HWND hwnd = CreateWindowA( "static", NULL, WS_POPUP, 0, 0, 10, 10, 0, 0, 0, NULL );
1798     BITMAPINFO bmi;
1799     void *bits;
1800 
1801     ok( hwnd != 0, "window creation failed\n" );
1802     format_id = RegisterClipboardFormatA( "my_cool_clipboard_format" );
1803     test_handles( 0 );
1804     test_handles( GetDesktopWindow() );
1805     test_handles( hwnd );
1806     run_thread( test_handles_thread, hwnd, __LINE__ );
1807 
1808     bitmap = CreateBitmap( 13, 17, 1, 1, NULL );
1809     bitmap2 = CreateBitmap( 10, 10, 1, 1, NULL );
1810     palette = CreatePalette( &logpalette );
1811 
1812     r = OpenClipboard( hwnd );
1813     ok( r, "gle %d\n", GetLastError() );
1814     r = EmptyClipboard();
1815     ok( r, "gle %d\n", GetLastError() );
1816     h = SetClipboardData( CF_TEXT, create_textA() );
1817     ok( is_moveable( h ), "expected moveable mem %p\n", h );
1818     h = SetClipboardData( format_id, create_textA() );
1819     ok( is_moveable( h ), "expected moveable mem %p\n", h );
1820     h = SetClipboardData( CF_BITMAP, bitmap );
1821     ok( GetObjectType( h ) == OBJ_BITMAP, "expected bitmap %p\n", h );
1822     h = SetClipboardData( CF_DSPBITMAP, bitmap2 );
1823     ok( GetObjectType( h ) == OBJ_BITMAP, "expected bitmap %p\n", h );
1824     h = SetClipboardData( CF_PALETTE, palette );
1825     ok( GetObjectType( h ) == OBJ_PAL, "expected palette %p\n", h );
1826     h = SetClipboardData( CF_METAFILEPICT, create_metafile() );
1827     ok( is_moveable( h ), "expected moveable mem %p\n", h );
1828     trace( "metafile %p\n", h );
1829     h = SetClipboardData( CF_DSPMETAFILEPICT, create_metafile() );
1830     ok( is_moveable( h ), "expected moveable mem %p\n", h );
1831     trace( "metafile2 %p\n", h );
1832     h = SetClipboardData( CF_ENHMETAFILE, create_emf() );
1833     ok( GetObjectType( h ) == OBJ_ENHMETAFILE, "expected enhmetafile %p\n", h );
1834     trace( "enhmetafile %p\n", h );
1835     h = SetClipboardData( CF_DSPENHMETAFILE, create_emf() );
1836     ok( GetObjectType( h ) == OBJ_ENHMETAFILE, "expected enhmetafile %p\n", h );
1837     trace( "enhmetafile2 %p\n", h );
1838     h = SetClipboardData( CF_GDIOBJFIRST + 3, create_textA() );
1839     ok( is_moveable( h ), "expected moveable mem %p\n", h );
1840     h = SetClipboardData( CF_PRIVATEFIRST + 7, create_textA() );
1841     ok( is_moveable( h ), "expected moveable mem %p\n", h );
1842     r = CloseClipboard();
1843     ok( r, "gle %d\n", GetLastError() );
1844 
1845     run_thread( test_handles_thread2, 0, __LINE__ );
1846     run_process( "handles test" );
1847 
1848     r = OpenClipboard( hwnd );
1849     ok( r, "gle %d\n", GetLastError() );
1850     h = GetClipboardData( CF_TEXT );
1851     ok( is_moveable( h ), "expected moveable mem %p\n", h );
1852     h = GetClipboardData( format_id );
1853     ok( is_moveable( h ), "expected moveable mem %p\n", h );
1854     h = GetClipboardData( CF_GDIOBJFIRST + 3 );
1855     ok( is_moveable( h ), "expected moveable mem %p\n", h );
1856     h = GetClipboardData( CF_PRIVATEFIRST + 7 );
1857     ok( is_moveable( h ), "expected moveable mem %p\n", h );
1858 
1859     r = EmptyClipboard();
1860     ok( r, "gle %d\n", GetLastError() );
1861     text = create_textA();
1862     h = SetClipboardData( CF_TEXT, text );
1863     ok( is_moveable( h ), "expected moveable mem %p\n", h );
1864 
1865     run_process( "handles_open foobar" );
1866 
1867     ok( is_moveable( text ), "expected moveable mem %p\n", text );
1868     h = GetClipboardData( CF_TEXT );
1869     ok( is_fixed( h ), "expected fixed mem %p\n", h );
1870     ok( is_moveable( text ), "expected moveable mem %p\n", text );
1871     ptr = GlobalLock( h );
1872     ok( !strcmp( ptr, "foobar" ), "wrong data '%.8s'\n", ptr );
1873     GlobalUnlock( h );
1874 
1875     r = EmptyClipboard();
1876     ok( r, "gle %d\n", GetLastError() );
1877     ok( is_fixed( h ), "expected free mem %p\n", h );
1878     ok( is_freed( text ) || broken( is_moveable(text) ), /* w2003, w2008 */
1879         "expected free mem %p\n", text );
1880     r = CloseClipboard();
1881     ok( r, "gle %d\n", GetLastError() );
1882 
1883     /* test CF_BITMAP with a DIB section */
1884     memset( &bmi, 0, sizeof(bmi) );
1885     bmi.bmiHeader.biSize = sizeof( bmi.bmiHeader );
1886     bmi.bmiHeader.biWidth = 29;
1887     bmi.bmiHeader.biHeight = 13;
1888     bmi.bmiHeader.biPlanes = 1;
1889     bmi.bmiHeader.biBitCount = 32;
1890     bitmap = CreateDIBSection( 0, &bmi, DIB_RGB_COLORS, &bits, 0, 0 );
1891 
1892     r = OpenClipboard( hwnd );
1893     ok( r, "gle %d\n", GetLastError() );
1894     r = EmptyClipboard();
1895     ok( r, "gle %d\n", GetLastError() );
1896     h = SetClipboardData( CF_BITMAP, bitmap );
1897     ok( GetObjectType( h ) == OBJ_BITMAP, "expected bitmap %p\n", h );
1898     trace( "dibsection %p\n", h );
1899     r = CloseClipboard();
1900     ok( r, "gle %d\n", GetLastError() );
1901 
1902     run_process( "handles_dib dummy" );
1903 
1904     r = OpenClipboard( hwnd );
1905     ok( r, "gle %d\n", GetLastError() );
1906     ok( GetObjectType( bitmap ) == OBJ_BITMAP, "expected bitmap %p\n", bitmap );
1907     r = EmptyClipboard();
1908     ok( r, "gle %d\n", GetLastError() );
1909     ok( !GetObjectType( bitmap ), "expected deleted %p\n", bitmap );
1910     r = CloseClipboard();
1911     ok( r, "gle %d\n", GetLastError() );
1912 
1913     DestroyWindow( hwnd );
1914 }
1915 
1916 static void test_GetUpdatedClipboardFormats(void)
1917 {
1918     BOOL r;
1919     UINT count, formats[256];
1920 
1921     if (!pGetUpdatedClipboardFormats)
1922     {
1923         win_skip( "GetUpdatedClipboardFormats not supported\n" );
1924         return;
1925     }
1926 
1927     count = 0xdeadbeef;
1928     r = pGetUpdatedClipboardFormats( NULL, 0, &count );
1929     ok( r, "gle %d\n", GetLastError() );
1930     ok( !count, "wrong count %u\n", count );
1931 
1932     count = 0xdeadbeef;
1933     r = pGetUpdatedClipboardFormats( NULL, 256, &count );
1934     ok( r, "gle %d\n", GetLastError() );
1935     ok( !count, "wrong count %u\n", count );
1936 
1937     SetLastError( 0xdeadbeef );
1938     r = pGetUpdatedClipboardFormats( formats, 256, NULL );
1939     ok( !r, "succeeded\n" );
1940     ok( GetLastError() == ERROR_NOACCESS, "wrong error %u\n", GetLastError() );
1941 
1942     count = 0xdeadbeef;
1943     r = pGetUpdatedClipboardFormats( formats, 256, &count );
1944     ok( r, "gle %d\n", GetLastError() );
1945     ok( !count, "wrong count %u\n", count );
1946 
1947     r = OpenClipboard( 0 );
1948     ok( r, "gle %d\n", GetLastError() );
1949     r = EmptyClipboard();
1950     ok( r, "gle %d\n", GetLastError() );
1951 
1952     count = 0xdeadbeef;
1953     r = pGetUpdatedClipboardFormats( formats, 256, &count );
1954     ok( r, "gle %d\n", GetLastError() );
1955     ok( !count, "wrong count %u\n", count );
1956 
1957     SetClipboardData( CF_UNICODETEXT, 0 );
1958 
1959     count = 0xdeadbeef;
1960     memset( formats, 0xcc, sizeof(formats) );
1961     r = pGetUpdatedClipboardFormats( formats, 256, &count );
1962     ok( r, "gle %d\n", GetLastError() );
1963     ok( count == 1, "wrong count %u\n", count );
1964     ok( formats[0] == CF_UNICODETEXT, "wrong format %u\n", formats[0] );
1965     ok( formats[1] == 0xcccccccc, "wrong format %u\n", formats[1] );
1966 
1967     SetClipboardData( CF_TEXT, 0 );
1968     count = 0xdeadbeef;
1969     memset( formats, 0xcc, sizeof(formats) );
1970     r = pGetUpdatedClipboardFormats( formats, 256, &count );
1971     ok( r, "gle %d\n", GetLastError() );
1972     ok( count == 2, "wrong count %u\n", count );
1973     ok( formats[0] == CF_UNICODETEXT, "wrong format %u\n", formats[0] );
1974     ok( formats[1] == CF_TEXT, "wrong format %u\n", formats[1] );
1975     ok( formats[2] == 0xcccccccc, "wrong format %u\n", formats[2] );
1976 
1977     SetLastError( 0xdeadbeef );
1978     count = 0xdeadbeef;
1979     r = pGetUpdatedClipboardFormats( formats, 0, &count );
1980     ok( !r, "succeeded\n" );
1981     ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "wrong error %u\n", GetLastError() );
1982     ok( count == 2, "wrong count %u\n", count );
1983 
1984     SetLastError( 0xdeadbeef );
1985     count = 0xdeadbeef;
1986     r = pGetUpdatedClipboardFormats( formats, 1, &count );
1987     ok( !r, "succeeded\n" );
1988     ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "wrong error %u\n", GetLastError() );
1989     ok( count == 2, "wrong count %u\n", count );
1990 
1991     r = CloseClipboard();
1992     ok( r, "gle %d\n", GetLastError() );
1993 
1994     count = 0xdeadbeef;
1995     memset( formats, 0xcc, sizeof(formats) );
1996     r = pGetUpdatedClipboardFormats( formats, 256, &count );
1997     ok( r, "gle %d\n", GetLastError() );
1998     ok( count == 4, "wrong count %u\n", count );
1999     ok( formats[0] == CF_UNICODETEXT, "wrong format %u\n", formats[0] );
2000     ok( formats[1] == CF_TEXT, "wrong format %u\n", formats[1] );
2001     ok( formats[2] == CF_LOCALE, "wrong format %u\n", formats[2] );
2002     ok( formats[3] == CF_OEMTEXT, "wrong format %u\n", formats[3] );
2003     ok( formats[4] == 0xcccccccc, "wrong format %u\n", formats[4] );
2004 
2005     count = 0xdeadbeef;
2006     memset( formats, 0xcc, sizeof(formats) );
2007     r = pGetUpdatedClipboardFormats( formats, 2, &count );
2008     ok( !r, "gle %d\n", GetLastError() );
2009     ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "wrong error %u\n", GetLastError() );
2010     ok( count == 4, "wrong count %u\n", count );
2011     ok( formats[0] == 0xcccccccc, "wrong format %u\n", formats[0] );
2012 
2013     count = 0xdeadbeef;
2014     r = pGetUpdatedClipboardFormats( NULL, 256, &count );
2015     ok( !r, "gle %d\n", GetLastError() );
2016     ok( GetLastError() == ERROR_NOACCESS, "wrong error %u\n", GetLastError() );
2017     ok( count == 4, "wrong count %u\n", count );
2018 
2019     count = 0xdeadbeef;
2020     r = pGetUpdatedClipboardFormats( NULL, 256, &count );
2021     ok( !r, "gle %d\n", GetLastError() );
2022     ok( GetLastError() == ERROR_NOACCESS, "wrong error %u\n", GetLastError() );
2023     ok( count == 4, "wrong count %u\n", count );
2024 }
2025 
2026 static const struct
2027 {
2028     char strA[12];
2029     WCHAR strW[12];
2030     UINT  len;
2031 } test_data[] =
2032 {
2033     { "foo", {0}, 3 },      /* 0 */
2034     { "foo", {0}, 4 },
2035     { "foo\0bar", {0}, 7 },
2036     { "foo\0bar", {0}, 8 },
2037     { "", {'f','o','o'}, 3 * sizeof(WCHAR) },
2038     { "", {'f','o','o',0}, 4 * sizeof(WCHAR) },     /* 5 */
2039     { "", {'f','o','o',0,'b','a','r'}, 7 * sizeof(WCHAR) },
2040     { "", {'f','o','o',0,'b','a','r',0}, 8 * sizeof(WCHAR) },
2041     { "", {'f','o','o'}, 1 },
2042     { "", {'f','o','o'}, 2 },
2043     { "", {'f','o','o'}, 5 },     /* 10 */
2044     { "", {'f','o','o',0}, 7 },
2045     { "", {'f','o','o',0}, 9 },
2046 };
2047 
2048 static void test_string_data(void)
2049 {
2050     UINT i;
2051     BOOL r;
2052     HANDLE data;
2053     char cmd[16];
2054     char bufferA[12];
2055     WCHAR bufferW[12];
2056 
2057     for (i = 0; i < sizeof(test_data) / sizeof(test_data[0]); i++)
2058     {
2059         /* 1-byte Unicode strings crash on Win64 */
2060 #ifdef _WIN64
2061         if (!test_data[i].strA[0] && test_data[i].len < sizeof(WCHAR)) continue;
2062 #endif
2063         r = OpenClipboard( 0 );
2064         ok( r, "gle %d\n", GetLastError() );
2065         r = EmptyClipboard();
2066         ok( r, "gle %d\n", GetLastError() );
2067         data = GlobalAlloc( GMEM_FIXED, test_data[i].len );
2068         if (test_data[i].strA[0])
2069         {
2070             memcpy( data, test_data[i].strA, test_data[i].len );
2071             SetClipboardData( CF_TEXT, data );
2072             memcpy( bufferA, test_data[i].strA, test_data[i].len );
2073             bufferA[test_data[i].len - 1] = 0;
2074             ok( !memcmp( data, bufferA, test_data[i].len ),
2075                 "%u: wrong data %.*s\n", i, test_data[i].len, (char *)data );
2076         }
2077         else
2078         {
2079             memcpy( data, test_data[i].strW, test_data[i].len );
2080             SetClipboardData( CF_UNICODETEXT, data );
2081             memcpy( bufferW, test_data[i].strW, test_data[i].len );
2082             bufferW[(test_data[i].len + 1) / sizeof(WCHAR) - 1] = 0;
2083             ok( !memcmp( data, bufferW, test_data[i].len ),
2084                 "%u: wrong data %s\n", i, wine_dbgstr_wn( data, (test_data[i].len + 1) / sizeof(WCHAR) ));
2085         }
2086         r = CloseClipboard();
2087         ok( r, "gle %d\n", GetLastError() );
2088         sprintf( cmd, "string_data %u", i );
2089         run_process( cmd );
2090     }
2091 }
2092 
2093 static void test_string_data_process( int i )
2094 {
2095     BOOL r;
2096     HANDLE data;
2097     UINT len, len2;
2098     char bufferA[12];
2099     WCHAR bufferW[12];
2100 
2101     r = OpenClipboard( 0 );
2102     ok( r, "gle %d\n", GetLastError() );
2103     if (test_data[i].strA[0])
2104     {
2105         data = GetClipboardData( CF_TEXT );
2106         ok( data != 0, "%u: could not get data\n", i );
2107         len = GlobalSize( data );
2108         ok( len == test_data[i].len, "%u: wrong size %u / %u\n", i, len, test_data[i].len );
2109         memcpy( bufferA, test_data[i].strA, test_data[i].len );
2110         bufferA[test_data[i].len - 1] = 0;
2111         ok( !memcmp( data, bufferA, len ), "%u: wrong data %.*s\n", i, len, (char *)data );
2112         data = GetClipboardData( CF_UNICODETEXT );
2113         ok( data != 0, "%u: could not get data\n", i );
2114         len = GlobalSize( data );
2115         len2 = MultiByteToWideChar( CP_ACP, 0, bufferA, test_data[i].len, bufferW, 12 );
2116         ok( len == len2 * sizeof(WCHAR), "%u: wrong size %u / %u\n", i, len, len2 );
2117         ok( !memcmp( data, bufferW, len ), "%u: wrong data %s\n", i, wine_dbgstr_wn( data, len2 ));
2118     }
2119     else
2120     {
2121         data = GetClipboardData( CF_UNICODETEXT );
2122         ok( data != 0, "%u: could not get data\n", i );
2123         len = GlobalSize( data );
2124         ok( len == test_data[i].len, "%u: wrong size %u / %u\n", i, len, test_data[i].len );
2125         memcpy( bufferW, test_data[i].strW, test_data[i].len );
2126         bufferW[(test_data[i].len + 1) / sizeof(WCHAR) - 1] = 0;
2127         ok( !memcmp( data, bufferW, len ),
2128             "%u: wrong data %s\n", i, wine_dbgstr_wn( data, (len + 1) / sizeof(WCHAR) ));
2129         data = GetClipboardData( CF_TEXT );
2130         if (test_data[i].len >= sizeof(WCHAR))
2131         {
2132             ok( data != 0, "%u: could not get data\n", i );
2133             len = GlobalSize( data );
2134             len2 = WideCharToMultiByte( CP_ACP, 0, bufferW, test_data[i].len / sizeof(WCHAR),
2135                                         bufferA, 12, NULL, NULL );
2136             bufferA[len2 - 1] = 0;
2137             ok( len == len2, "%u: wrong size %u / %u\n", i, len, len2 );
2138             ok( !memcmp( data, bufferA, len ), "%u: wrong data %.*s\n", i, len, (char *)data );
2139         }
2140         else
2141         {
2142             ok( !data, "%u: got data for empty string\n", i );
2143             ok( IsClipboardFormatAvailable( CF_TEXT ), "%u: text not available\n", i );
2144         }
2145     }
2146     r = CloseClipboard();
2147     ok( r, "gle %d\n", GetLastError() );
2148 }
2149 
2150 START_TEST(clipboard)
2151 {
2152     char **argv;
2153     int argc = winetest_get_mainargs( &argv );
2154     HMODULE mod = GetModuleHandleA( "user32" );
2155 
2156     argv0 = argv[0];
2157     pAddClipboardFormatListener = (void *)GetProcAddress( mod, "AddClipboardFormatListener" );
2158     pRemoveClipboardFormatListener = (void *)GetProcAddress( mod, "RemoveClipboardFormatListener" );
2159     pGetUpdatedClipboardFormats = (void *)GetProcAddress( mod, "GetUpdatedClipboardFormats" );
2160 
2161     if (argc == 4 && !strcmp( argv[2], "set_clipboard_data" ))
2162     {
2163         set_clipboard_data_process( atoi( argv[3] ));
2164         return;
2165     }
2166     if (argc == 4 && !strcmp( argv[2], "grab_clipboard" ))
2167     {
2168         grab_clipboard_process( atoi( argv[3] ));
2169         return;
2170     }
2171     if (argc == 4 && !strcmp( argv[2], "handles" ))
2172     {
2173         test_handles_process( argv[3] );
2174         return;
2175     }
2176     if (argc == 4 && !strcmp( argv[2], "handles_open" ))
2177     {
2178         test_handles_process_open( argv[3] );
2179         return;
2180     }
2181     if (argc == 4 && !strcmp( argv[2], "handles_dib" ))
2182     {
2183         test_handles_process_dib( argv[3] );
2184         return;
2185     }
2186     if (argc == 4 && !strcmp( argv[2], "string_data" ))
2187     {
2188         test_string_data_process( atoi( argv[3] ));
2189         return;
2190     }
2191     if (argc == 3 && !strcmp( argv[2], "get_clipboard_data" ))
2192     {
2193         get_clipboard_data_process( );
2194         return;
2195     }
2196 
2197     test_RegisterClipboardFormatA();
2198     test_ClipboardOwner();
2199     test_synthesized();
2200     test_messages();
2201     test_data_handles();
2202     test_GetUpdatedClipboardFormats();
2203     test_string_data();
2204 }
2205