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