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