oleaut32: Add a test for loading/saving an empty picture.
[wine] / dlls / ddraw / tests / ddraw2.c
1 /*
2  * Copyright 2011-2012 Henri Verbeet for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18 #define COBJMACROS
19
20 #include "wine/test.h"
21 #include "d3d.h"
22
23 struct create_window_thread_param
24 {
25     HWND window;
26     HANDLE window_created;
27     HANDLE destroy_window;
28     HANDLE thread;
29 };
30
31 static BOOL compare_color(D3DCOLOR c1, D3DCOLOR c2, BYTE max_diff)
32 {
33     if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff) return FALSE;
34     c1 >>= 8; c2 >>= 8;
35     if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff) return FALSE;
36     c1 >>= 8; c2 >>= 8;
37     if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff) return FALSE;
38     c1 >>= 8; c2 >>= 8;
39     if (abs((c1 & 0xff) - (c2 & 0xff)) > max_diff) return FALSE;
40     return TRUE;
41 }
42
43 static DWORD WINAPI create_window_thread_proc(void *param)
44 {
45     struct create_window_thread_param *p = param;
46     DWORD res;
47     BOOL ret;
48
49     p->window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
50             0, 0, 640, 480, 0, 0, 0, 0);
51     ret = SetEvent(p->window_created);
52     ok(ret, "SetEvent failed, last error %#x.\n", GetLastError());
53
54     for (;;)
55     {
56         MSG msg;
57
58         while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
59             DispatchMessage(&msg);
60         res = WaitForSingleObject(p->destroy_window, 100);
61         if (res == WAIT_OBJECT_0)
62             break;
63         if (res != WAIT_TIMEOUT)
64         {
65             ok(0, "Wait failed (%#x), last error %#x.\n", res, GetLastError());
66             break;
67         }
68     }
69
70     DestroyWindow(p->window);
71
72     return 0;
73 }
74
75 static void create_window_thread(struct create_window_thread_param *p)
76 {
77     DWORD res, tid;
78
79     p->window_created = CreateEvent(NULL, FALSE, FALSE, NULL);
80     ok(!!p->window_created, "CreateEvent failed, last error %#x.\n", GetLastError());
81     p->destroy_window = CreateEvent(NULL, FALSE, FALSE, NULL);
82     ok(!!p->destroy_window, "CreateEvent failed, last error %#x.\n", GetLastError());
83     p->thread = CreateThread(NULL, 0, create_window_thread_proc, p, 0, &tid);
84     ok(!!p->thread, "Failed to create thread, last error %#x.\n", GetLastError());
85     res = WaitForSingleObject(p->window_created, INFINITE);
86     ok(res == WAIT_OBJECT_0, "Wait failed (%#x), last error %#x.\n", res, GetLastError());
87 }
88
89 static void destroy_window_thread(struct create_window_thread_param *p)
90 {
91     SetEvent(p->destroy_window);
92     WaitForSingleObject(p->thread, INFINITE);
93     CloseHandle(p->destroy_window);
94     CloseHandle(p->window_created);
95     CloseHandle(p->thread);
96 }
97
98 static IDirectDrawSurface *get_depth_stencil(IDirect3DDevice2 *device)
99 {
100     IDirectDrawSurface *rt, *ret;
101     DDSCAPS caps = {DDSCAPS_ZBUFFER};
102     HRESULT hr;
103
104     hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
105     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
106     hr = IDirectDrawSurface_GetAttachedSurface(rt, &caps, &ret);
107     ok(SUCCEEDED(hr) || hr == DDERR_NOTFOUND, "Failed to get the z buffer, hr %#x.\n", hr);
108     IDirectDrawSurface_Release(rt);
109     return ret;
110 }
111
112 static D3DCOLOR get_surface_color(IDirectDrawSurface *surface, UINT x, UINT y)
113 {
114     RECT rect = {x, y, x + 1, y + 1};
115     DDSURFACEDESC surface_desc;
116     D3DCOLOR color;
117     HRESULT hr;
118
119     memset(&surface_desc, 0, sizeof(surface_desc));
120     surface_desc.dwSize = sizeof(surface_desc);
121
122     hr = IDirectDrawSurface_Lock(surface, &rect, &surface_desc, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
123     ok(SUCCEEDED(hr), "Failed to lock surface, hr %#x.\n", hr);
124     if (FAILED(hr))
125         return 0xdeadbeef;
126
127     color = *((DWORD *)surface_desc.lpSurface) & 0x00ffffff;
128
129     hr = IDirectDrawSurface_Unlock(surface, NULL);
130     ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#x.\n", hr);
131
132     return color;
133 }
134
135 static HRESULT CALLBACK enum_z_fmt(GUID *guid, char *description, char *name,
136         D3DDEVICEDESC *hal_desc, D3DDEVICEDESC *hel_desc, void *ctx)
137 {
138     DWORD *z_depth = ctx;
139
140     if (!IsEqualGUID(&IID_IDirect3DHALDevice, guid))
141         return D3DENUMRET_OK;
142
143     if (hal_desc->dwDeviceZBufferBitDepth & DDBD_32)
144         *z_depth = 32;
145     else if (hal_desc->dwDeviceZBufferBitDepth & DDBD_24)
146         *z_depth = 24;
147     else if (hal_desc->dwDeviceZBufferBitDepth & DDBD_16)
148         *z_depth = 16;
149
150     return DDENUMRET_OK;
151 }
152
153 static IDirectDraw2 *create_ddraw(void)
154 {
155     IDirectDraw2 *ddraw2;
156     IDirectDraw *ddraw1;
157     HRESULT hr;
158
159     if (FAILED(DirectDrawCreate(NULL, &ddraw1, NULL)))
160         return NULL;
161
162     hr = IDirectDraw_QueryInterface(ddraw1, &IID_IDirectDraw2, (void **)&ddraw2);
163     IDirectDraw_Release(ddraw1);
164     if (FAILED(hr))
165         return NULL;
166
167     return ddraw2;
168 }
169
170 static IDirect3DDevice2 *create_device(IDirectDraw2 *ddraw, HWND window, DWORD coop_level)
171 {
172     IDirectDrawSurface *surface, *ds;
173     IDirect3DDevice2 *device = NULL;
174     DDSURFACEDESC surface_desc;
175     DWORD z_depth = 0;
176     IDirect3D2 *d3d;
177     HRESULT hr;
178
179     hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, coop_level);
180     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
181
182     memset(&surface_desc, 0, sizeof(surface_desc));
183     surface_desc.dwSize = sizeof(surface_desc);
184     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
185     surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
186     surface_desc.dwWidth = 640;
187     surface_desc.dwHeight = 480;
188
189     hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
190     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
191
192     if (coop_level & DDSCL_NORMAL)
193     {
194         IDirectDrawClipper *clipper;
195
196         hr = IDirectDraw2_CreateClipper(ddraw, 0, &clipper, NULL);
197         ok(SUCCEEDED(hr), "Failed to create clipper, hr %#x.\n", hr);
198         hr = IDirectDrawClipper_SetHWnd(clipper, 0, window);
199         ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
200         hr = IDirectDrawSurface_SetClipper(surface, clipper);
201         ok(SUCCEEDED(hr), "Failed to set surface clipper, hr %#x.\n", hr);
202         IDirectDrawClipper_Release(clipper);
203     }
204
205     hr = IDirectDraw2_QueryInterface(ddraw, &IID_IDirect3D2, (void **)&d3d);
206     if (FAILED(hr))
207     {
208         IDirectDrawSurface_Release(surface);
209         return NULL;
210     }
211
212     hr = IDirect3D2_EnumDevices(d3d, enum_z_fmt, &z_depth);
213     ok(SUCCEEDED(hr), "Failed to enumerate z-formats, hr %#x.\n", hr);
214     if (FAILED(hr) || !z_depth)
215     {
216         IDirect3D2_Release(d3d);
217         IDirectDrawSurface_Release(surface);
218         return NULL;
219     }
220
221     memset(&surface_desc, 0, sizeof(surface_desc));
222     surface_desc.dwSize = sizeof(surface_desc);
223     surface_desc.dwFlags = DDSD_CAPS | DDSD_ZBUFFERBITDEPTH | DDSD_WIDTH | DDSD_HEIGHT;
224     surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
225     U2(surface_desc).dwZBufferBitDepth = z_depth;
226     surface_desc.dwWidth = 640;
227     surface_desc.dwHeight = 480;
228     hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &ds, NULL);
229     ok(SUCCEEDED(hr), "Failed to create depth buffer, hr %#x.\n", hr);
230     if (FAILED(hr))
231     {
232         IDirect3D2_Release(d3d);
233         IDirectDrawSurface_Release(surface);
234         return NULL;
235     }
236
237     hr = IDirectDrawSurface_AddAttachedSurface(surface, ds);
238     ok(SUCCEEDED(hr), "Failed to attach depth buffer, hr %#x.\n", hr);
239     IDirectDrawSurface_Release(ds);
240     if (FAILED(hr))
241     {
242         IDirect3D2_Release(d3d);
243         IDirectDrawSurface_Release(surface);
244         return NULL;
245     }
246
247     hr = IDirect3D2_CreateDevice(d3d, &IID_IDirect3DHALDevice, surface, &device);
248     IDirect3D2_Release(d3d);
249     IDirectDrawSurface_Release(surface);
250     if (FAILED(hr))
251         return NULL;
252
253     return device;
254 }
255
256 static IDirect3DViewport2 *create_viewport(IDirect3DDevice2 *device, UINT x, UINT y, UINT w, UINT h)
257 {
258     IDirect3DViewport2 *viewport;
259     D3DVIEWPORT2 vp;
260     IDirect3D2 *d3d;
261     HRESULT hr;
262
263     hr = IDirect3DDevice2_GetDirect3D(device, &d3d);
264     ok(SUCCEEDED(hr), "Failed to get d3d interface, hr %#x.\n", hr);
265     hr = IDirect3D2_CreateViewport(d3d, &viewport, NULL);
266     ok(SUCCEEDED(hr), "Failed to create viewport, hr %#x.\n", hr);
267     hr = IDirect3DDevice2_AddViewport(device, viewport);
268     ok(SUCCEEDED(hr), "Failed to add viewport, hr %#x.\n", hr);
269     memset(&vp, 0, sizeof(vp));
270     vp.dwSize = sizeof(vp);
271     vp.dwX = x;
272     vp.dwY = y;
273     vp.dwWidth = w;
274     vp.dwHeight = h;
275     vp.dvClipX = -1.0f;
276     vp.dvClipY =  1.0f;
277     vp.dvClipWidth = 2.0f;
278     vp.dvClipHeight = 2.0f;
279     vp.dvMinZ = 0.0f;
280     vp.dvMaxZ = 1.0f;
281     hr = IDirect3DViewport2_SetViewport2(viewport, &vp);
282     ok(SUCCEEDED(hr), "Failed to set viewport data, hr %#x.\n", hr);
283     IDirect3D2_Release(d3d);
284
285     return viewport;
286 }
287
288 static void viewport_set_background(IDirect3DDevice2 *device, IDirect3DViewport2 *viewport,
289         IDirect3DMaterial2 *material)
290 {
291     D3DMATERIALHANDLE material_handle;
292     HRESULT hr;
293
294     hr = IDirect3DMaterial2_GetHandle(material, device, &material_handle);
295     ok(SUCCEEDED(hr), "Failed to get material handle, hr %#x.\n", hr);
296     hr = IDirect3DViewport2_SetBackground(viewport, material_handle);
297     ok(SUCCEEDED(hr), "Failed to set viewport background, hr %#x.\n", hr);
298 }
299
300 static void destroy_viewport(IDirect3DDevice2 *device, IDirect3DViewport2 *viewport)
301 {
302     HRESULT hr;
303
304     hr = IDirect3DDevice2_DeleteViewport(device, viewport);
305     ok(SUCCEEDED(hr), "Failed to delete viewport, hr %#x.\n", hr);
306     IDirect3DViewport2_Release(viewport);
307 }
308
309 static IDirect3DMaterial2 *create_diffuse_material(IDirect3DDevice2 *device, float r, float g, float b, float a)
310 {
311     IDirect3DMaterial2 *material;
312     D3DMATERIAL mat;
313     IDirect3D2 *d3d;
314     HRESULT hr;
315
316     hr = IDirect3DDevice2_GetDirect3D(device, &d3d);
317     ok(SUCCEEDED(hr), "Failed to get d3d interface, hr %#x.\n", hr);
318     hr = IDirect3D2_CreateMaterial(d3d, &material, NULL);
319     ok(SUCCEEDED(hr), "Failed to create material, hr %#x.\n", hr);
320     memset(&mat, 0, sizeof(mat));
321     mat.dwSize = sizeof(mat);
322     U1(U(mat).diffuse).r = r;
323     U2(U(mat).diffuse).g = g;
324     U3(U(mat).diffuse).b = b;
325     U4(U(mat).diffuse).a = a;
326     hr = IDirect3DMaterial2_SetMaterial(material, &mat);
327     ok(SUCCEEDED(hr), "Failed to set material data, hr %#x.\n", hr);
328     IDirect3D2_Release(d3d);
329
330     return material;
331 }
332
333 static void destroy_material(IDirect3DMaterial2 *material)
334 {
335     IDirect3DMaterial2_Release(material);
336 }
337
338 static const UINT *expect_messages;
339
340 static LRESULT CALLBACK test_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
341 {
342     if (expect_messages && message == *expect_messages)
343         ++expect_messages;
344
345     return DefWindowProcA(hwnd, message, wparam, lparam);
346 }
347
348 /* Set the wndproc back to what ddraw expects it to be, and release the ddraw
349  * interface. This prevents subsequent SetCooperativeLevel() calls on a
350  * different window from failing with DDERR_HWNDALREADYSET. */
351 static void fix_wndproc(HWND window, LONG_PTR proc)
352 {
353     IDirectDraw2 *ddraw;
354     HRESULT hr;
355
356     if (!(ddraw = create_ddraw()))
357         return;
358
359     SetWindowLongPtrA(window, GWLP_WNDPROC, proc);
360     hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
361     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
362     hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
363     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
364
365     IDirectDraw2_Release(ddraw);
366 }
367
368 static HRESULT CALLBACK restore_callback(IDirectDrawSurface *surface, DDSURFACEDESC *desc, void *context)
369 {
370     HRESULT hr = IDirectDrawSurface_Restore(surface);
371     ok(SUCCEEDED(hr), "Failed to restore surface, hr %#x.\n", hr);
372     IDirectDrawSurface_Release(surface);
373
374     return DDENUMRET_OK;
375 }
376
377 static HRESULT restore_surfaces(IDirectDraw2 *ddraw)
378 {
379     return IDirectDraw2_EnumSurfaces(ddraw, DDENUMSURFACES_ALL | DDENUMSURFACES_DOESEXIST,
380             NULL, NULL, restore_callback);
381 }
382
383 static void test_coop_level_create_device_window(void)
384 {
385     HWND focus_window, device_window;
386     IDirectDraw2 *ddraw;
387     HRESULT hr;
388
389     focus_window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
390             0, 0, 640, 480, 0, 0, 0, 0);
391     if (!(ddraw = create_ddraw()))
392     {
393         skip("Failed to create a ddraw object, skipping test.\n");
394         DestroyWindow(focus_window);
395         return;
396     }
397
398     hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
399     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
400     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
401     ok(!device_window, "Unexpected device window found.\n");
402     hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW);
403     ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
404     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
405     ok(!device_window, "Unexpected device window found.\n");
406     hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_NORMAL);
407     ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
408     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
409     ok(!device_window, "Unexpected device window found.\n");
410     hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_NORMAL | DDSCL_FULLSCREEN);
411     ok(hr == DDERR_INVALIDPARAMS, "Got unexpected hr %#x.\n", hr);
412     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
413     ok(!device_window, "Unexpected device window found.\n");
414     hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
415     ok(hr == DDERR_NOFOCUSWINDOW || broken(hr == DDERR_INVALIDPARAMS), "Got unexpected hr %#x.\n", hr);
416     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
417     ok(!device_window, "Unexpected device window found.\n");
418
419     /* Windows versions before 98 / NT5 don't support DDSCL_CREATEDEVICEWINDOW. */
420     if (broken(hr == DDERR_INVALIDPARAMS))
421     {
422         win_skip("DDSCL_CREATEDEVICEWINDOW not supported, skipping test.\n");
423         IDirectDraw2_Release(ddraw);
424         DestroyWindow(focus_window);
425         return;
426     }
427
428     hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
429     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
430     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
431     ok(!device_window, "Unexpected device window found.\n");
432     hr = IDirectDraw2_SetCooperativeLevel(ddraw, focus_window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
433     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
434     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
435     ok(!device_window, "Unexpected device window found.\n");
436
437     hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
438     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
439     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
440     ok(!device_window, "Unexpected device window found.\n");
441     hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_SETFOCUSWINDOW
442             | DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
443     ok(hr == DDERR_NOHWND, "Got unexpected hr %#x.\n", hr);
444     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
445     ok(!!device_window, "Device window not found.\n");
446
447     hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
448     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
449     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
450     ok(!device_window, "Unexpected device window found.\n");
451     hr = IDirectDraw2_SetCooperativeLevel(ddraw, focus_window, DDSCL_SETFOCUSWINDOW
452             | DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
453     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
454     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
455     ok(!!device_window, "Device window not found.\n");
456
457     hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
458     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
459     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
460     ok(!device_window, "Unexpected device window found.\n");
461     hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
462     ok(hr == DDERR_NOFOCUSWINDOW, "Got unexpected hr %#x.\n", hr);
463     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
464     ok(!device_window, "Unexpected device window found.\n");
465     hr = IDirectDraw2_SetCooperativeLevel(ddraw, focus_window, DDSCL_SETFOCUSWINDOW);
466     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
467     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
468     ok(!device_window, "Unexpected device window found.\n");
469     hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
470     ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
471     device_window = FindWindowA("DirectDrawDeviceWnd", "DirectDrawDeviceWnd");
472     ok(!!device_window, "Device window not found.\n");
473
474     IDirectDraw2_Release(ddraw);
475     DestroyWindow(focus_window);
476 }
477
478 static void test_clipper_blt(void)
479 {
480     IDirectDrawSurface *src_surface, *dst_surface;
481     RECT client_rect, src_rect;
482     IDirectDrawClipper *clipper;
483     DDSURFACEDESC surface_desc;
484     unsigned int i, j, x, y;
485     IDirectDraw2 *ddraw;
486     RGNDATA *rgn_data;
487     D3DCOLOR color;
488     HRGN r1, r2;
489     HWND window;
490     DDBLTFX fx;
491     HRESULT hr;
492     DWORD *ptr;
493     DWORD ret;
494
495     static const DWORD src_data[] =
496     {
497         0xff0000ff, 0xff0000ff, 0xff00ff00, 0xffff0000, 0xffffffff, 0xffffffff,
498         0xff0000ff, 0xff0000ff, 0xff00ff00, 0xffff0000, 0xffffffff, 0xffffffff,
499         0xff0000ff, 0xff0000ff, 0xff00ff00, 0xffff0000, 0xffffffff, 0xffffffff,
500     };
501     static const D3DCOLOR expected1[] =
502     {
503         0x000000ff, 0x0000ff00, 0x00000000, 0x00000000,
504         0x000000ff, 0x0000ff00, 0x00000000, 0x00000000,
505         0x00000000, 0x00000000, 0x00ff0000, 0x00ffffff,
506         0x00000000, 0x00000000, 0x00ff0000, 0x00ffffff,
507     };
508     static const D3DCOLOR expected2[] =
509     {
510         0x000000ff, 0x000000ff, 0x00000000, 0x00000000,
511         0x000000ff, 0x000000ff, 0x00000000, 0x00000000,
512         0x00000000, 0x00000000, 0x000000ff, 0x000000ff,
513         0x00000000, 0x00000000, 0x000000ff, 0x000000ff,
514     };
515
516     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
517             10, 10, 640, 480, 0, 0, 0, 0);
518     ShowWindow(window, SW_SHOW);
519     if (!(ddraw = create_ddraw()))
520     {
521         skip("Failed to create a ddraw object, skipping test.\n");
522         DestroyWindow(window);
523         return;
524     }
525
526     ret = GetClientRect(window, &client_rect);
527     ok(ret, "Failed to get client rect.\n");
528     ret = MapWindowPoints(window, NULL, (POINT *)&client_rect, 2);
529     ok(ret, "Failed to map client rect.\n");
530
531     hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
532     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
533
534     hr = IDirectDraw2_CreateClipper(ddraw, 0, &clipper, NULL);
535     ok(SUCCEEDED(hr), "Failed to create clipper, hr %#x.\n", hr);
536     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
537     ok(hr == DDERR_NOCLIPLIST, "Got unexpected hr %#x.\n", hr);
538     hr = IDirectDrawClipper_SetHWnd(clipper, 0, window);
539     ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
540     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
541     ok(SUCCEEDED(hr), "Failed to get clip list size, hr %#x.\n", hr);
542     rgn_data = HeapAlloc(GetProcessHeap(), 0, ret);
543     hr = IDirectDrawClipper_GetClipList(clipper, NULL, rgn_data, &ret);
544     ok(SUCCEEDED(hr), "Failed to get clip list, hr %#x.\n", hr);
545     ok(rgn_data->rdh.dwSize == sizeof(rgn_data->rdh), "Got unexpected structure size %#x.\n", rgn_data->rdh.dwSize);
546     ok(rgn_data->rdh.iType == RDH_RECTANGLES, "Got unexpected type %#x.\n", rgn_data->rdh.iType);
547     ok(rgn_data->rdh.nCount >= 1, "Got unexpected count %u.\n", rgn_data->rdh.nCount);
548     ok(EqualRect(&rgn_data->rdh.rcBound, &client_rect),
549             "Got unexpected bounding rect {%d, %d, %d, %d}, expected {%d, %d, %d, %d}.\n",
550             rgn_data->rdh.rcBound.left, rgn_data->rdh.rcBound.top,
551             rgn_data->rdh.rcBound.right, rgn_data->rdh.rcBound.bottom,
552             client_rect.left, client_rect.top, client_rect.right, client_rect.bottom);
553     HeapFree(GetProcessHeap(), 0, rgn_data);
554
555     r1 = CreateRectRgn(0, 0, 320, 240);
556     ok(!!r1, "Failed to create region.\n");
557     r2 = CreateRectRgn(320, 240, 640, 480);
558     ok(!!r2, "Failed to create region.\n");
559     CombineRgn(r1, r1, r2, RGN_OR);
560     ret = GetRegionData(r1, 0, NULL);
561     rgn_data = HeapAlloc(GetProcessHeap(), 0, ret);
562     ret = GetRegionData(r1, ret, rgn_data);
563     ok(!!ret, "Failed to get region data.\n");
564
565     DeleteObject(r2);
566     DeleteObject(r1);
567
568     hr = IDirectDrawClipper_SetClipList(clipper, rgn_data, 0);
569     ok(hr == DDERR_CLIPPERISUSINGHWND, "Got unexpected hr %#x.\n", hr);
570     hr = IDirectDrawClipper_SetHWnd(clipper, 0, NULL);
571     ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
572     hr = IDirectDrawClipper_SetClipList(clipper, rgn_data, 0);
573     ok(SUCCEEDED(hr), "Failed to set clip list, hr %#x.\n", hr);
574
575     HeapFree(GetProcessHeap(), 0, rgn_data);
576
577     memset(&surface_desc, 0, sizeof(surface_desc));
578     surface_desc.dwSize = sizeof(surface_desc);
579     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
580     surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
581     surface_desc.dwWidth = 640;
582     surface_desc.dwHeight = 480;
583     surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
584     surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
585     U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
586     U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
587     U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
588     U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
589
590     hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &src_surface, NULL);
591     ok(SUCCEEDED(hr), "Failed to create source surface, hr %#x.\n", hr);
592     hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &dst_surface, NULL);
593     ok(SUCCEEDED(hr), "Failed to create destination surface, hr %#x.\n", hr);
594
595     memset(&fx, 0, sizeof(fx));
596     fx.dwSize = sizeof(fx);
597     hr = IDirectDrawSurface_Blt(src_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
598     ok(SUCCEEDED(hr), "Failed to clear source surface, hr %#x.\n", hr);
599     hr = IDirectDrawSurface_Blt(dst_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
600     ok(SUCCEEDED(hr), "Failed to clear destination surface, hr %#x.\n", hr);
601
602     hr = IDirectDrawSurface_Lock(src_surface, NULL, &surface_desc, DDLOCK_WAIT, NULL);
603     ok(SUCCEEDED(hr), "Failed to lock source surface, hr %#x.\n", hr);
604     ok(U1(surface_desc).lPitch == 2560, "Got unexpected surface pitch %u.\n", U1(surface_desc).lPitch);
605     ptr = surface_desc.lpSurface;
606     memcpy(&ptr[   0], &src_data[ 0], 6 * sizeof(DWORD));
607     memcpy(&ptr[ 640], &src_data[ 6], 6 * sizeof(DWORD));
608     memcpy(&ptr[1280], &src_data[12], 6 * sizeof(DWORD));
609     hr = IDirectDrawSurface_Unlock(src_surface, NULL);
610     ok(SUCCEEDED(hr), "Failed to unlock source surface, hr %#x.\n", hr);
611
612     hr = IDirectDrawSurface_SetClipper(dst_surface, clipper);
613     ok(SUCCEEDED(hr), "Failed to set clipper, hr %#x.\n", hr);
614
615     SetRect(&src_rect, 1, 1, 5, 2);
616     hr = IDirectDrawSurface_Blt(dst_surface, NULL, src_surface, &src_rect, DDBLT_WAIT, NULL);
617     ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
618     for (i = 0; i < 4; ++i)
619     {
620         for (j = 0; j < 4; ++j)
621         {
622             x = 80 * ((2 * j) + 1);
623             y = 60 * ((2 * i) + 1);
624             color = get_surface_color(dst_surface, x, y);
625             ok(compare_color(color, expected1[i * 4 + j], 1),
626                     "Expected color 0x%08x at %u,%u, got 0x%08x.\n", expected1[i * 4 + j], x, y, color);
627         }
628     }
629
630     U5(fx).dwFillColor = 0xff0000ff;
631     hr = IDirectDrawSurface_Blt(dst_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
632     ok(SUCCEEDED(hr), "Failed to clear destination surface, hr %#x.\n", hr);
633     for (i = 0; i < 4; ++i)
634     {
635         for (j = 0; j < 4; ++j)
636         {
637             x = 80 * ((2 * j) + 1);
638             y = 60 * ((2 * i) + 1);
639             color = get_surface_color(dst_surface, x, y);
640             ok(compare_color(color, expected2[i * 4 + j], 1),
641                     "Expected color 0x%08x at %u,%u, got 0x%08x.\n", expected2[i * 4 + j], x, y, color);
642         }
643     }
644
645     hr = IDirectDrawSurface_BltFast(dst_surface, 0, 0, src_surface, NULL, DDBLTFAST_WAIT);
646     ok(hr == DDERR_BLTFASTCANTCLIP || broken(hr == E_NOTIMPL /* NT4 */), "Got unexpected hr %#x.\n", hr);
647
648     hr = IDirectDrawClipper_SetHWnd(clipper, 0, window);
649     ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
650     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
651     ok(SUCCEEDED(hr), "Failed to get clip list size, hr %#x.\n", hr);
652     DestroyWindow(window);
653     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
654     ok(hr == E_FAIL, "Got unexpected hr %#x.\n", hr);
655     hr = IDirectDrawClipper_SetHWnd(clipper, 0, NULL);
656     ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
657     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
658     ok(SUCCEEDED(hr), "Failed to get clip list size, hr %#x.\n", hr);
659     hr = IDirectDrawClipper_SetClipList(clipper, NULL, 0);
660     ok(SUCCEEDED(hr), "Failed to set clip list, hr %#x.\n", hr);
661     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
662     ok(hr == DDERR_NOCLIPLIST, "Got unexpected hr %#x.\n", hr);
663     hr = IDirectDrawSurface_Blt(dst_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
664     ok(hr == DDERR_NOCLIPLIST, "Got unexpected hr %#x.\n", hr);
665
666     IDirectDrawSurface_Release(dst_surface);
667     IDirectDrawSurface_Release(src_surface);
668     IDirectDrawClipper_Release(clipper);
669     IDirectDraw2_Release(ddraw);
670 }
671
672 static void test_coop_level_d3d_state(void)
673 {
674     D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
675     IDirectDrawSurface *rt, *surface;
676     IDirect3DMaterial2 *background;
677     IDirect3DViewport2 *viewport;
678     IDirect3DDevice2 *device;
679     D3DMATERIAL material;
680     IDirectDraw2 *ddraw;
681     D3DCOLOR color;
682     DWORD value;
683     HWND window;
684     HRESULT hr;
685
686     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
687             0, 0, 640, 480, 0, 0, 0, 0);
688     if (!(ddraw = create_ddraw()))
689     {
690         skip("Failed to create ddraw object, skipping test.\n");
691         DestroyWindow(window);
692         return;
693     }
694     if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
695     {
696         skip("Failed to create D3D device, skipping test.\n");
697         IDirectDraw2_Release(ddraw);
698         DestroyWindow(window);
699         return;
700     }
701
702     background = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
703     viewport = create_viewport(device, 0, 0, 640, 480);
704     viewport_set_background(device, viewport, background);
705
706     hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
707     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
708     hr = IDirect3DDevice2_GetRenderState(device, D3DRENDERSTATE_ZENABLE, &value);
709     ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr);
710     ok(!!value, "Got unexpected z-enable state %#x.\n", value);
711     hr = IDirect3DDevice2_GetRenderState(device, D3DRENDERSTATE_ALPHABLENDENABLE, &value);
712     ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr);
713     ok(!value, "Got unexpected alpha blend enable state %#x.\n", value);
714     hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);
715     ok(SUCCEEDED(hr), "Failed to set render state, hr %#x.\n", hr);
716     hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
717     ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
718     color = get_surface_color(rt, 320, 240);
719     ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
720
721     hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
722     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
723     hr = IDirectDrawSurface_IsLost(rt);
724     ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#x.\n", hr);
725     hr = restore_surfaces(ddraw);
726     ok(SUCCEEDED(hr), "Failed to restore surfaces, hr %#x.\n", hr);
727
728     memset(&material, 0, sizeof(material));
729     material.dwSize = sizeof(material);
730     U1(U(material).diffuse).r = 0.0f;
731     U2(U(material).diffuse).g = 1.0f;
732     U3(U(material).diffuse).b = 0.0f;
733     U4(U(material).diffuse).a = 1.0f;
734     hr = IDirect3DMaterial2_SetMaterial(background, &material);
735     ok(SUCCEEDED(hr), "Failed to set material data, hr %#x.\n", hr);
736
737     hr = IDirect3DDevice2_GetRenderTarget(device, &surface);
738     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
739     ok(surface == rt, "Got unexpected surface %p.\n", surface);
740     hr = IDirect3DDevice2_GetRenderState(device, D3DRENDERSTATE_ZENABLE, &value);
741     ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr);
742     ok(!!value, "Got unexpected z-enable state %#x.\n", value);
743     hr = IDirect3DDevice2_GetRenderState(device, D3DRENDERSTATE_ALPHABLENDENABLE, &value);
744     ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr);
745     ok(!!value, "Got unexpected alpha blend enable state %#x.\n", value);
746     hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
747     ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
748     color = get_surface_color(rt, 320, 240);
749     ok(compare_color(color, 0x0000ff00, 1), "Got unexpected color 0x%08x.\n", color);
750
751     destroy_viewport(device, viewport);
752     destroy_material(background);
753     IDirectDrawSurface_Release(surface);
754     IDirectDrawSurface_Release(rt);
755     IDirect3DDevice2_Release(device);
756     IDirectDraw2_Release(ddraw);
757     DestroyWindow(window);
758 }
759
760 static void test_surface_interface_mismatch(void)
761 {
762     IDirectDraw2 *ddraw = NULL;
763     IDirect3D2 *d3d = NULL;
764     IDirectDrawSurface *surface = NULL, *ds;
765     IDirectDrawSurface3 *surface3 = NULL;
766     IDirect3DDevice2 *device = NULL;
767     IDirect3DViewport2 *viewport = NULL;
768     IDirect3DMaterial2 *background = NULL;
769     DDSURFACEDESC surface_desc;
770     DWORD z_depth = 0;
771     ULONG refcount;
772     HRESULT hr;
773     D3DCOLOR color;
774     HWND window;
775     D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
776
777     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
778             0, 0, 640, 480, 0, 0, 0, 0);
779
780     if (!(ddraw = create_ddraw()))
781     {
782         skip("Failed to create a ddraw object, skipping test.\n");
783         goto cleanup;
784     }
785
786     hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
787     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
788
789     memset(&surface_desc, 0, sizeof(surface_desc));
790     surface_desc.dwSize = sizeof(surface_desc);
791     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
792     surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
793     surface_desc.dwWidth = 640;
794     surface_desc.dwHeight = 480;
795
796     hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
797     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
798
799     hr = IDirectDrawSurface2_QueryInterface(surface, &IID_IDirectDrawSurface3, (void **)&surface3);
800     if (FAILED(hr))
801     {
802         skip("Failed to get the IDirectDrawSurface3 interface, skipping test.\n");
803         goto cleanup;
804     }
805
806     hr = IDirectDraw2_QueryInterface(ddraw, &IID_IDirect3D2, (void **)&d3d);
807     if (FAILED(hr))
808     {
809         skip("Failed to get the IDirect3D2 interface, skipping test.\n");
810         goto cleanup;
811     }
812
813     hr = IDirect3D2_EnumDevices(d3d, enum_z_fmt, &z_depth);
814     if (FAILED(hr) || !z_depth)
815     {
816         skip("No depth buffer formats available, skipping test.\n");
817         goto cleanup;
818     }
819
820     memset(&surface_desc, 0, sizeof(surface_desc));
821     surface_desc.dwSize = sizeof(surface_desc);
822     surface_desc.dwFlags = DDSD_CAPS | DDSD_ZBUFFERBITDEPTH | DDSD_WIDTH | DDSD_HEIGHT;
823     surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
824     U2(surface_desc).dwZBufferBitDepth = z_depth;
825     surface_desc.dwWidth = 640;
826     surface_desc.dwHeight = 480;
827     hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &ds, NULL);
828     ok(SUCCEEDED(hr), "Failed to create depth buffer, hr %#x.\n", hr);
829     if (FAILED(hr))
830         goto cleanup;
831
832     /* Using a different surface interface version still works */
833     hr = IDirectDrawSurface3_AddAttachedSurface(surface3, (IDirectDrawSurface3 *)ds);
834     ok(SUCCEEDED(hr), "Failed to attach depth buffer, hr %#x.\n", hr);
835     refcount = IDirectDrawSurface_Release(ds);
836     ok(refcount == 1, "Got unexpected refcount %u.\n", refcount);
837     if (FAILED(hr))
838         goto cleanup;
839
840     /* Here too */
841     hr = IDirect3D2_CreateDevice(d3d, &IID_IDirect3DHALDevice, (IDirectDrawSurface *)surface3, &device);
842     ok(SUCCEEDED(hr), "Failed to create d3d device.\n");
843     if (FAILED(hr))
844         goto cleanup;
845
846     background = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
847     viewport = create_viewport(device, 0, 0, 640, 480);
848     viewport_set_background(device, viewport, background);
849
850     hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
851     ok(SUCCEEDED(hr), "Failed to clear render target, hr %#x.\n", hr);
852     color = get_surface_color(surface, 320, 240);
853     ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
854
855 cleanup:
856     if (viewport)
857         destroy_viewport(device, viewport);
858     if (background)
859         destroy_material(background);
860     if (surface3) IDirectDrawSurface3_Release(surface3);
861     if (surface) IDirectDrawSurface_Release(surface);
862     if (device) IDirect3DDevice2_Release(device);
863     if (d3d) IDirect3D2_Release(d3d);
864     if (ddraw) IDirectDraw2_Release(ddraw);
865     DestroyWindow(window);
866 }
867
868 static void test_coop_level_threaded(void)
869 {
870     struct create_window_thread_param p;
871     IDirectDraw2 *ddraw;
872     HRESULT hr;
873
874     if (!(ddraw = create_ddraw()))
875     {
876         skip("Failed to create a ddraw object, skipping test.\n");
877         return;
878     }
879     create_window_thread(&p);
880
881     hr = IDirectDraw2_SetCooperativeLevel(ddraw, p.window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
882     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
883
884     IDirectDraw2_Release(ddraw);
885     destroy_window_thread(&p);
886 }
887
888 static void test_depth_blit(void)
889 {
890     static D3DLVERTEX quad1[] =
891     {
892         {{-1.0}, { 1.0}, {0.50f}, 0, {0xff00ff00}},
893         {{ 1.0}, { 1.0}, {0.50f}, 0, {0xff00ff00}},
894         {{-1.0}, {-1.0}, {0.50f}, 0, {0xff00ff00}},
895         {{ 1.0}, {-1.0}, {0.50f}, 0, {0xff00ff00}},
896     };
897     static const D3DCOLOR expected_colors[4][4] =
898     {
899         {0x00ff0000, 0x00ff0000, 0x0000ff00, 0x0000ff00},
900         {0x00ff0000, 0x00ff0000, 0x0000ff00, 0x0000ff00},
901         {0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00},
902         {0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00},
903     };
904     static const BOOL todo[4][4] =
905     {
906         {FALSE, FALSE, TRUE, TRUE},
907         {FALSE, FALSE, TRUE, TRUE},
908         {TRUE,  TRUE,  TRUE, TRUE},
909         {TRUE,  TRUE,  TRUE, TRUE},
910     };
911     DDSURFACEDESC ddsd_new, ddsd_existing;
912
913     IDirect3DDevice2 *device;
914     IDirectDrawSurface *ds1, *ds2, *ds3, *rt;
915     IDirect3DViewport2 *viewport;
916     RECT src_rect, dst_rect;
917     unsigned int i, j;
918     D3DCOLOR color;
919     HRESULT hr;
920     IDirectDraw2 *ddraw;
921     DDBLTFX fx;
922     HWND window;
923     D3DRECT d3drect;
924     IDirect3DMaterial2 *background;
925
926     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
927             0, 0, 640, 480, 0, 0, 0, 0);
928     if (!(ddraw = create_ddraw()))
929     {
930         skip("Failed to create ddraw object, skipping test.\n");
931         DestroyWindow(window);
932         return;
933     }
934     if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
935     {
936         skip("Failed to create D3D device, skipping test.\n");
937         IDirectDraw2_Release(ddraw);
938         DestroyWindow(window);
939         return;
940     }
941
942     ds1 = get_depth_stencil(device);
943
944     memset(&ddsd_new, 0, sizeof(ddsd_new));
945     ddsd_new.dwSize = sizeof(ddsd_new);
946     memset(&ddsd_existing, 0, sizeof(ddsd_existing));
947     ddsd_existing.dwSize = sizeof(ddsd_existing);
948     hr = IDirectDrawSurface_GetSurfaceDesc(ds1, &ddsd_existing);
949     ddsd_new.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
950     ddsd_new.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
951     ddsd_new.dwWidth = ddsd_existing.dwWidth;
952     ddsd_new.dwHeight = ddsd_existing.dwHeight;
953     ddsd_new.ddpfPixelFormat = ddsd_existing.ddpfPixelFormat;
954     hr = IDirectDraw2_CreateSurface(ddraw, &ddsd_new, &ds2, NULL);
955     ok(SUCCEEDED(hr), "Failed to create a surface, hr %#x.\n", hr);
956     hr = IDirectDraw2_CreateSurface(ddraw, &ddsd_new, &ds3, NULL);
957     ok(SUCCEEDED(hr), "Failed to create a surface, hr %#x.\n", hr);
958
959     background = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
960     viewport = create_viewport(device, 0, 0, ddsd_existing.dwWidth, ddsd_existing.dwHeight);
961     viewport_set_background(device, viewport, background);
962     hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
963     ok(SUCCEEDED(hr), "Failed to activate the viewport, hr %#x.\n", hr);
964
965     hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ZENABLE, D3DZB_TRUE);
966     ok(SUCCEEDED(hr), "Failed to enable z testing, hr %#x.\n", hr);
967     hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ZFUNC, D3DCMP_LESSEQUAL);
968     ok(SUCCEEDED(hr), "Failed to set the z function, hr %#x.\n", hr);
969
970     U1(d3drect).x1 = U2(d3drect).y1 = 0;
971     U3(d3drect).x2 = ddsd_existing.dwWidth; U4(d3drect).y2 = ddsd_existing.dwHeight;
972     hr = IDirect3DViewport2_Clear(viewport, 1, &d3drect, D3DCLEAR_ZBUFFER);
973     ok(SUCCEEDED(hr), "Failed to clear the z buffer, hr %#x.\n", hr);
974
975     /* Partial blit. */
976     SetRect(&src_rect, 0, 0, 320, 240);
977     SetRect(&dst_rect, 0, 0, 320, 240);
978     hr = IDirectDrawSurface_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
979     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
980     /* Different locations. */
981     SetRect(&src_rect, 0, 0, 320, 240);
982     SetRect(&dst_rect, 320, 240, 640, 480);
983     hr = IDirectDrawSurface_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
984     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
985     /* Streched. */
986     SetRect(&src_rect, 0, 0, 320, 240);
987     SetRect(&dst_rect, 0, 0, 640, 480);
988     hr = IDirectDrawSurface_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
989     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
990     /* Flipped. */
991     SetRect(&src_rect, 0, 480, 640, 0);
992     SetRect(&dst_rect, 0, 0, 640, 480);
993     hr = IDirectDrawSurface_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
994     ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#x.\n", hr);
995     SetRect(&src_rect, 0, 0, 640, 480);
996     SetRect(&dst_rect, 0, 480, 640, 0);
997     hr = IDirectDrawSurface_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
998     ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#x.\n", hr);
999     /* Full, explicit. */
1000     SetRect(&src_rect, 0, 0, 640, 480);
1001     SetRect(&dst_rect, 0, 0, 640, 480);
1002     hr = IDirectDrawSurface_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
1003     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1004     /* Depth -> color blit: Succeeds on Win7 + Radeon HD 5700, fails on WinXP + Radeon X1600 */
1005
1006     /* Depth blit inside a BeginScene / EndScene pair */
1007     hr = IDirect3DDevice2_BeginScene(device);
1008     ok(SUCCEEDED(hr), "Failed to start a scene, hr %#x.\n", hr);
1009     /* From the current depth stencil */
1010     hr = IDirectDrawSurface_Blt(ds2, NULL, ds1, NULL, DDBLT_WAIT, NULL);
1011     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1012     /* To the current depth stencil */
1013     hr = IDirectDrawSurface_Blt(ds1, NULL, ds2, NULL, DDBLT_WAIT, NULL);
1014     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1015     /* Between unbound surfaces */
1016     hr = IDirectDrawSurface_Blt(ds3, NULL, ds2, NULL, DDBLT_WAIT, NULL);
1017     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1018     hr = IDirect3DDevice2_EndScene(device);
1019     ok(SUCCEEDED(hr), "Failed to end a scene, hr %#x.\n", hr);
1020
1021     /* Avoid changing the depth stencil, it doesn't work properly on Windows.
1022      * Instead use DDBLT_DEPTHFILL to clear the depth stencil. Unfortunately
1023      * drivers disagree on the meaning of dwFillDepth. Only 0 seems to produce
1024      * a reliable result(z = 0.0) */
1025     memset(&fx, 0, sizeof(fx));
1026     fx.dwSize = sizeof(fx);
1027     U5(fx).dwFillDepth = 0;
1028     hr = IDirectDrawSurface_Blt(ds2, NULL, NULL, NULL, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
1029     ok(SUCCEEDED(hr), "Failed to clear the source z buffer, hr %#x.\n", hr);
1030
1031     /* This clears the Z buffer with 1.0 */
1032     hr = IDirect3DViewport2_Clear(viewport, 1, &d3drect, D3DCLEAR_ZBUFFER | D3DCLEAR_TARGET);
1033     ok(SUCCEEDED(hr), "Failed to clear the color and z buffers, hr %#x.\n", hr);
1034
1035     SetRect(&dst_rect, 0, 0, 320, 240);
1036     hr = IDirectDrawSurface_Blt(ds1, &dst_rect, ds2, NULL, DDBLT_WAIT, NULL);
1037     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1038     IDirectDrawSurface_Release(ds3);
1039     IDirectDrawSurface_Release(ds2);
1040     IDirectDrawSurface_Release(ds1);
1041
1042     hr = IDirect3DDevice2_BeginScene(device);
1043     ok(SUCCEEDED(hr), "Failed to start a scene, hr %#x.\n", hr);
1044     hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_LVERTEX, quad1, 4, 0);
1045     ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
1046     hr = IDirect3DDevice2_EndScene(device);
1047     ok(SUCCEEDED(hr), "Failed to end a scene, hr %#x.\n", hr);
1048
1049     hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
1050     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
1051     for (i = 0; i < 4; ++i)
1052     {
1053         for (j = 0; j < 4; ++j)
1054         {
1055             unsigned int x = 80 * ((2 * j) + 1);
1056             unsigned int y = 60 * ((2 * i) + 1);
1057             color = get_surface_color(rt, x, y);
1058             if (todo[i][j])
1059                 todo_wine ok(compare_color(color, expected_colors[i][j], 1),
1060                         "Expected color 0x%08x at %u,%u, got 0x%08x.\n", expected_colors[i][j], x, y, color);
1061             else
1062                 ok(compare_color(color, expected_colors[i][j], 1),
1063                         "Expected color 0x%08x at %u,%u, got 0x%08x.\n", expected_colors[i][j], x, y, color);
1064         }
1065     }
1066     IDirectDrawSurface_Release(rt);
1067
1068     destroy_viewport(device, viewport);
1069     destroy_material(background);
1070     IDirect3DDevice2_Release(device);
1071     IDirectDraw2_Release(ddraw);
1072     DestroyWindow(window);
1073 }
1074
1075 static void test_texture_load_ckey(void)
1076 {
1077     IDirectDraw2 *ddraw = NULL;
1078     IDirectDrawSurface *src = NULL;
1079     IDirectDrawSurface *dst = NULL;
1080     IDirect3DTexture *src_tex = NULL;
1081     IDirect3DTexture *dst_tex = NULL;
1082     DDSURFACEDESC ddsd;
1083     HRESULT hr;
1084     DDCOLORKEY ckey;
1085
1086     if (!(ddraw = create_ddraw()))
1087     {
1088         skip("Failed to create ddraw object, skipping test.\n");
1089         return;
1090     }
1091     hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
1092     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
1093
1094     memset(&ddsd, 0, sizeof(ddsd));
1095     ddsd.dwSize = sizeof(ddsd);
1096     ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
1097     ddsd.dwHeight = 128;
1098     ddsd.dwWidth = 128;
1099     ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_SYSTEMMEMORY;
1100     hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &src, NULL);
1101     ok(SUCCEEDED(hr), "Failed to create source texture, hr %#x.\n", hr);
1102     ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1103     hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &dst, NULL);
1104     ok(SUCCEEDED(hr), "Failed to create destination texture, hr %#x.\n", hr);
1105
1106     hr = IDirectDrawSurface_QueryInterface(src, &IID_IDirect3DTexture, (void **)&src_tex);
1107     ok(SUCCEEDED(hr) || hr == E_NOINTERFACE, "Failed to get Direct3DTexture interface, hr %#x.\n", hr);
1108     if (FAILED(hr))
1109     {
1110         /* 64 bit ddraw does not support d3d */
1111         skip("Could not get Direct3DTexture interface, skipping texture::Load color keying tests.\n");
1112         goto done;
1113     }
1114     hr = IDirectDrawSurface_QueryInterface(dst, &IID_IDirect3DTexture, (void **)&dst_tex);
1115     ok(SUCCEEDED(hr), "Failed to get Direct3DTexture interface, hr %#x.\n", hr);
1116
1117     /* No surface has a color key */
1118     hr = IDirect3DTexture_Load(dst_tex, src_tex);
1119     ok(SUCCEEDED(hr) || broken(hr == DDERR_INVALIDCAPS), "Got unexpected hr %#x.\n", hr);
1120     if (FAILED(hr))
1121     {
1122         /* Testbot Windows NT VMs */
1123         skip("IDirect3DTexture::Load does not work, skipping color keying tests.\n");
1124         goto done;
1125     }
1126
1127     ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0xdeadbeef;
1128     hr = IDirectDrawSurface_GetColorKey(dst, DDCKEY_SRCBLT, &ckey);
1129     ok(hr == DDERR_NOCOLORKEY, "Got unexpected hr %#x.\n", hr);
1130     ok(ckey.dwColorSpaceLowValue == 0xdeadbeef, "dwColorSpaceLowValue is %#x.\n", ckey.dwColorSpaceLowValue);
1131     ok(ckey.dwColorSpaceHighValue == 0xdeadbeef, "dwColorSpaceHighValue is %#x.\n", ckey.dwColorSpaceHighValue);
1132
1133     /* Source surface has a color key */
1134     ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0x0000ff00;
1135     hr = IDirectDrawSurface_SetColorKey(src, DDCKEY_SRCBLT, &ckey);
1136     ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
1137     hr = IDirect3DTexture_Load(dst_tex, src_tex);
1138     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1139     hr = IDirectDrawSurface_GetColorKey(dst, DDCKEY_SRCBLT, &ckey);
1140     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1141     ok(ckey.dwColorSpaceLowValue == 0x0000ff00, "dwColorSpaceLowValue is %#x.\n", ckey.dwColorSpaceLowValue);
1142     ok(ckey.dwColorSpaceHighValue == 0x0000ff00, "dwColorSpaceHighValue is %#x.\n", ckey.dwColorSpaceHighValue);
1143
1144     /* Both surfaces have a color key: Dest ckey is overwritten */
1145     ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0x000000ff;
1146     hr = IDirectDrawSurface_SetColorKey(dst, DDCKEY_SRCBLT, &ckey);
1147     ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
1148     hr = IDirect3DTexture_Load(dst_tex, src_tex);
1149     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1150     hr = IDirectDrawSurface_GetColorKey(dst, DDCKEY_SRCBLT, &ckey);
1151     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1152     ok(ckey.dwColorSpaceLowValue == 0x0000ff00, "dwColorSpaceLowValue is %#x.\n", ckey.dwColorSpaceLowValue);
1153     ok(ckey.dwColorSpaceHighValue == 0x0000ff00, "dwColorSpaceHighValue is %#x.\n", ckey.dwColorSpaceHighValue);
1154
1155     /* Only the destination has a color key: It is not deleted */
1156     hr = IDirectDrawSurface_SetColorKey(src, DDCKEY_SRCBLT, NULL);
1157     ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
1158     hr = IDirectDrawSurface_GetColorKey(src, DDCKEY_SRCBLT, &ckey);
1159     ok(hr == DDERR_NOCOLORKEY, "Got unexpected hr %#x.\n", hr);
1160     hr = IDirect3DTexture_Load(dst_tex, src_tex);
1161     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1162     hr = IDirectDrawSurface_GetColorKey(dst, DDCKEY_SRCBLT, &ckey);
1163     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1164     ok(ckey.dwColorSpaceLowValue == 0x0000ff00, "dwColorSpaceLowValue is %#x.\n", ckey.dwColorSpaceLowValue);
1165     ok(ckey.dwColorSpaceHighValue == 0x0000ff00, "dwColorSpaceHighValue is %#x.\n", ckey.dwColorSpaceHighValue);
1166
1167 done:
1168     if (dst_tex) IDirect3DTexture_Release(dst_tex);
1169     if (src_tex) IDirect3DTexture_Release(src_tex);
1170     if (dst) IDirectDrawSurface_Release(dst);
1171     if (src) IDirectDrawSurface_Release(src);
1172     if (ddraw) IDirectDraw2_Release(ddraw);
1173 }
1174
1175 static ULONG get_refcount(IUnknown *test_iface)
1176 {
1177     IUnknown_AddRef(test_iface);
1178     return IUnknown_Release(test_iface);
1179 }
1180
1181 static void test_viewport_interfaces(void)
1182 {
1183     IDirectDraw2 *ddraw;
1184     IDirect3D2 *d3d;
1185     HRESULT hr;
1186     ULONG ref, old_d3d_ref;
1187     IDirect3DViewport *viewport;
1188     IDirect3DViewport2 *viewport2;
1189     IDirect3DViewport3 *viewport3;
1190     IDirectDrawGammaControl *gamma;
1191     IUnknown *unknown;
1192
1193     if (!(ddraw = create_ddraw()))
1194     {
1195         skip("Failed to create ddraw object, skipping test.\n");
1196         return;
1197     }
1198
1199     hr = IDirectDraw2_QueryInterface(ddraw, &IID_IDirect3D2, (void **)&d3d);
1200     ok(SUCCEEDED(hr) || hr == E_NOINTERFACE, "Failed to get d3d interface, hr %#x.\n", hr);
1201     if (FAILED(hr))
1202     {
1203         skip("Direct3D not available, skipping tests\n");
1204         IDirectDraw2_Release(ddraw);
1205         return;
1206     }
1207     old_d3d_ref = get_refcount((IUnknown *)d3d);
1208
1209     hr = IDirect3D2_CreateViewport(d3d, &viewport2, NULL);
1210     ok(SUCCEEDED(hr), "Failed to create viewport, hr %#x.\n", hr);
1211     ref = get_refcount((IUnknown *)viewport2);
1212     ok(ref == 1, "Initial IDirect3DViewport2 refcount is %u\n", ref);
1213     ref = get_refcount((IUnknown *)d3d);
1214     ok(ref == old_d3d_ref, "IDirect3D2 refcount is %u\n", ref);
1215
1216     gamma = (IDirectDrawGammaControl *)0xdeadbeef;
1217     hr = IDirect3DViewport2_QueryInterface(viewport2, &IID_IDirectDrawGammaControl, (void **)&gamma);
1218     ok(hr == E_NOINTERFACE, "Got unexpected hr %#x.\n", hr);
1219     ok(gamma == NULL, "Interface not set to NULL by failed QI call: %p\n", gamma);
1220     if (SUCCEEDED(hr)) IDirectDrawGammaControl_Release(gamma);
1221     /* NULL iid: Segfaults */
1222
1223     hr = IDirect3DViewport2_QueryInterface(viewport2, &IID_IDirect3DViewport, (void **)&viewport);
1224     ok(SUCCEEDED(hr), "Failed to QI IDirect3DViewport, hr %#x.\n", hr);
1225     if (viewport)
1226     {
1227         ref = get_refcount((IUnknown *)viewport);
1228         ok(ref == 2, "IDirect3DViewport refcount is %u\n", ref);
1229         ref = get_refcount((IUnknown *)viewport2);
1230         ok(ref == 2, "IDirect3DViewport2 refcount is %u\n", ref);
1231         IDirect3DViewport_Release(viewport);
1232         viewport = NULL;
1233     }
1234
1235     hr = IDirect3DViewport2_QueryInterface(viewport2, &IID_IDirect3DViewport3, (void **)&viewport3);
1236     ok(SUCCEEDED(hr) || hr == E_NOINTERFACE, "Failed to QI IDirect3DViewport3, hr %#x.\n", hr);
1237     if (viewport3)
1238     {
1239         ref = get_refcount((IUnknown *)viewport2);
1240         ok(ref == 2, "IDirect3DViewport2 refcount is %u\n", ref);
1241         ref = get_refcount((IUnknown *)viewport3);
1242         ok(ref == 2, "IDirect3DViewport3 refcount is %u\n", ref);
1243         IDirect3DViewport3_Release(viewport3);
1244     }
1245
1246     hr = IDirect3DViewport2_QueryInterface(viewport2, &IID_IUnknown, (void **)&unknown);
1247     ok(SUCCEEDED(hr), "Failed to QI IUnknown, hr %#x.\n", hr);
1248     if (unknown)
1249     {
1250         ref = get_refcount((IUnknown *)viewport2);
1251         ok(ref == 2, "IDirect3DViewport2 refcount is %u\n", ref);
1252         ref = get_refcount(unknown);
1253         ok(ref == 2, "IUnknown refcount is %u\n", ref);
1254         IUnknown_Release(unknown);
1255     }
1256
1257     IDirect3DViewport2_Release(viewport2);
1258     IDirect3D2_Release(d3d);
1259     IDirectDraw2_Release(ddraw);
1260 }
1261
1262 static void test_zenable(void)
1263 {
1264     static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
1265     static D3DTLVERTEX tquad[] =
1266     {
1267         {{  0.0f}, {480.0f}, {-0.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}},
1268         {{  0.0f}, {  0.0f}, {-0.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}},
1269         {{640.0f}, {480.0f}, { 1.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}},
1270         {{640.0f}, {  0.0f}, { 1.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}},
1271     };
1272     IDirect3DMaterial2 *background;
1273     IDirect3DViewport2 *viewport;
1274     IDirect3DDevice2 *device;
1275     IDirectDrawSurface *rt;
1276     IDirectDraw2 *ddraw;
1277     D3DCOLOR color;
1278     HWND window;
1279     HRESULT hr;
1280     UINT x, y;
1281     UINT i, j;
1282
1283     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1284             0, 0, 640, 480, 0, 0, 0, 0);
1285     if (!(ddraw = create_ddraw()))
1286     {
1287         skip("Failed to create ddraw object, skipping test.\n");
1288         DestroyWindow(window);
1289         return;
1290     }
1291     if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
1292     {
1293         skip("Failed to create D3D device, skipping test.\n");
1294         IDirectDraw2_Release(ddraw);
1295         DestroyWindow(window);
1296         return;
1297     }
1298
1299     background = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
1300     viewport = create_viewport(device, 0, 0, 640, 480);
1301     viewport_set_background(device, viewport, background);
1302     hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
1303     ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#x.\n", hr);
1304
1305     hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ZENABLE, D3DZB_FALSE);
1306     ok(SUCCEEDED(hr), "Failed to disable z-buffering, hr %#x.\n", hr);
1307
1308     hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
1309     ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
1310     hr = IDirect3DDevice2_BeginScene(device);
1311     ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
1312     hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_TLVERTEX, tquad, 4, 0);
1313     ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
1314     hr = IDirect3DDevice2_EndScene(device);
1315     ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1316
1317     hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
1318     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
1319     for (i = 0; i < 4; ++i)
1320     {
1321         for (j = 0; j < 4; ++j)
1322         {
1323             x = 80 * ((2 * j) + 1);
1324             y = 60 * ((2 * i) + 1);
1325             color = get_surface_color(rt, x, y);
1326             ok(compare_color(color, 0x0000ff00, 1),
1327                     "Expected color 0x0000ff00 at %u, %u, got 0x%08x.\n", x, y, color);
1328         }
1329     }
1330     IDirectDrawSurface_Release(rt);
1331
1332     destroy_viewport(device, viewport);
1333     destroy_material(background);
1334     IDirect3DDevice2_Release(device);
1335     IDirectDraw2_Release(ddraw);
1336     DestroyWindow(window);
1337 }
1338
1339 static void test_ck_rgba(void)
1340 {
1341     static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
1342     static D3DTLVERTEX tquad[] =
1343     {
1344         {{  0.0f}, {480.0f}, {0.25f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {0.0f}},
1345         {{  0.0f}, {  0.0f}, {0.25f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {1.0f}},
1346         {{640.0f}, {480.0f}, {0.25f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {0.0f}},
1347         {{640.0f}, {  0.0f}, {0.25f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {1.0f}},
1348         {{  0.0f}, {480.0f}, {0.75f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {0.0f}},
1349         {{  0.0f}, {  0.0f}, {0.75f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {1.0f}},
1350         {{640.0f}, {480.0f}, {0.75f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {0.0f}},
1351         {{640.0f}, {  0.0f}, {0.75f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {1.0f}},
1352     };
1353     static const struct
1354     {
1355         D3DCOLOR fill_color;
1356         BOOL color_key;
1357         BOOL blend;
1358         D3DCOLOR result1;
1359         D3DCOLOR result2;
1360     }
1361     tests[] =
1362     {
1363         {0xff00ff00, TRUE,  TRUE,  0x00ff0000, 0x000000ff},
1364         {0xff00ff00, TRUE,  FALSE, 0x00ff0000, 0x000000ff},
1365         {0xff00ff00, FALSE, TRUE,  0x0000ff00, 0x0000ff00},
1366         {0xff00ff00, FALSE, FALSE, 0x0000ff00, 0x0000ff00},
1367         {0x7f00ff00, TRUE,  TRUE,  0x00807f00, 0x00807f00},
1368         {0x7f00ff00, TRUE,  FALSE, 0x0000ff00, 0x0000ff00},
1369         {0x7f00ff00, FALSE, TRUE,  0x00807f00, 0x00807f00},
1370         {0x7f00ff00, FALSE, FALSE, 0x0000ff00, 0x0000ff00},
1371     };
1372
1373     D3DTEXTUREHANDLE texture_handle;
1374     IDirect3DMaterial2 *background;
1375     IDirectDrawSurface *surface;
1376     IDirect3DViewport2 *viewport;
1377     IDirect3DTexture2 *texture;
1378     DDSURFACEDESC surface_desc;
1379     IDirect3DDevice2 *device;
1380     IDirectDrawSurface *rt;
1381     IDirectDraw2 *ddraw;
1382     D3DCOLOR color;
1383     HWND window;
1384     DDBLTFX fx;
1385     HRESULT hr;
1386     UINT i;
1387
1388     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1389             0, 0, 640, 480, 0, 0, 0, 0);
1390     if (!(ddraw = create_ddraw()))
1391     {
1392         skip("Failed to create ddraw object, skipping test.\n");
1393         DestroyWindow(window);
1394         return;
1395     }
1396     if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
1397     {
1398         skip("Failed to create D3D device, skipping test.\n");
1399         IDirectDraw2_Release(ddraw);
1400         DestroyWindow(window);
1401         return;
1402     }
1403
1404     background = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
1405     viewport = create_viewport(device, 0, 0, 640, 480);
1406     viewport_set_background(device, viewport, background);
1407     hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
1408     ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#x.\n", hr);
1409
1410     memset(&surface_desc, 0, sizeof(surface_desc));
1411     surface_desc.dwSize = sizeof(surface_desc);
1412     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CKSRCBLT;
1413     surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1414     surface_desc.dwWidth = 256;
1415     surface_desc.dwHeight = 256;
1416     surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
1417     surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
1418     U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
1419     U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
1420     U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
1421     U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
1422     U5(surface_desc.ddpfPixelFormat).dwRGBAlphaBitMask = 0xff000000;
1423     surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0xff00ff00;
1424     surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0xff00ff00;
1425     hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
1426     ok(SUCCEEDED(hr), "Failed to create destination surface, hr %#x.\n", hr);
1427     hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirect3DTexture2, (void **)&texture);
1428     ok(SUCCEEDED(hr), "Failed to get texture interface, hr %#x.\n", hr);
1429     hr = IDirect3DTexture2_GetHandle(texture, device, &texture_handle);
1430     ok(SUCCEEDED(hr), "Failed to get texture handle, hr %#x.\n", hr);
1431     IDirect3DTexture2_Release(texture);
1432
1433     hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_TEXTUREHANDLE, texture_handle);
1434     ok(SUCCEEDED(hr), "Failed to set texture, hr %#x.\n", hr);
1435     hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA);
1436     ok(SUCCEEDED(hr), "Failed to enable alpha blending, hr %#x.\n", hr);
1437     hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA);
1438     ok(SUCCEEDED(hr), "Failed to enable alpha blending, hr %#x.\n", hr);
1439
1440     hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
1441     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
1442
1443     for (i = 0; i < sizeof(tests) / sizeof(*tests); ++i)
1444     {
1445         hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_COLORKEYENABLE, tests[i].color_key);
1446         ok(SUCCEEDED(hr), "Failed to enable color keying, hr %#x.\n", hr);
1447         hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ALPHABLENDENABLE, tests[i].blend);
1448         ok(SUCCEEDED(hr), "Failed to enable alpha blending, hr %#x.\n", hr);
1449
1450         memset(&fx, 0, sizeof(fx));
1451         fx.dwSize = sizeof(fx);
1452         U5(fx).dwFillColor = tests[i].fill_color;
1453         hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
1454         ok(SUCCEEDED(hr), "Failed to fill texture, hr %#x.\n", hr);
1455
1456         hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER);
1457         ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
1458         hr = IDirect3DDevice2_BeginScene(device);
1459         ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
1460         hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_TLVERTEX, &tquad[0], 4, 0);
1461         ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
1462         hr = IDirect3DDevice2_EndScene(device);
1463         ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1464
1465         color = get_surface_color(rt, 320, 240);
1466         if (i == 2)
1467             todo_wine ok(compare_color(color, tests[i].result1, 1), "Expected color 0x%08x for test %u, got 0x%08x.\n",
1468                     tests[i].result1, i, color);
1469         else
1470             ok(compare_color(color, tests[i].result1, 1), "Expected color 0x%08x for test %u, got 0x%08x.\n",
1471                     tests[i].result1, i, color);
1472
1473         U5(fx).dwFillColor = 0xff0000ff;
1474         hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
1475         ok(SUCCEEDED(hr), "Failed to fill texture, hr %#x.\n", hr);
1476
1477         hr = IDirect3DDevice2_BeginScene(device);
1478         ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
1479         hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_TLVERTEX, &tquad[4], 4, 0);
1480         ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
1481         hr = IDirect3DDevice2_EndScene(device);
1482         ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1483
1484         /* This tests that fragments that are masked out by the color key are
1485          * discarded, instead of just fully transparent. */
1486         color = get_surface_color(rt, 320, 240);
1487         if (i == 2)
1488             todo_wine ok(compare_color(color, tests[i].result2, 1), "Expected color 0x%08x for test %u, got 0x%08x.\n",
1489                     tests[i].result2, i, color);
1490         else
1491             ok(compare_color(color, tests[i].result2, 1), "Expected color 0x%08x for test %u, got 0x%08x.\n",
1492                     tests[i].result2, i, color);
1493     }
1494
1495     IDirectDrawSurface_Release(rt);
1496     hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_TEXTUREHANDLE, 0);
1497     ok(SUCCEEDED(hr), "Failed to unset texture, hr %#x.\n", hr);
1498     IDirectDrawSurface_Release(surface);
1499     destroy_viewport(device, viewport);
1500     destroy_material(background);
1501     IDirect3DDevice2_Release(device);
1502     IDirectDraw2_Release(ddraw);
1503     DestroyWindow(window);
1504 }
1505
1506 static void test_ck_default(void)
1507 {
1508     static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
1509     static D3DTLVERTEX tquad[] =
1510     {
1511         {{  0.0f}, {480.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {0.0f}},
1512         {{  0.0f}, {  0.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {1.0f}},
1513         {{640.0f}, {480.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {0.0f}},
1514         {{640.0f}, {  0.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {1.0f}},
1515     };
1516     IDirectDrawSurface *surface, *rt;
1517     D3DTEXTUREHANDLE texture_handle;
1518     IDirect3DMaterial2 *background;
1519     IDirect3DViewport2 *viewport;
1520     DDSURFACEDESC surface_desc;
1521     IDirect3DTexture2 *texture;
1522     IDirect3DDevice2 *device;
1523     IDirectDraw2 *ddraw;
1524     D3DCOLOR color;
1525     DWORD value;
1526     HWND window;
1527     DDBLTFX fx;
1528     HRESULT hr;
1529
1530     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1531             0, 0, 640, 480, 0, 0, 0, 0);
1532
1533     if (!(ddraw = create_ddraw()))
1534     {
1535         skip("Failed to create ddraw object, skipping test.\n");
1536         DestroyWindow(window);
1537         return;
1538     }
1539     if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
1540     {
1541         skip("Failed to create D3D device, skipping test.\n");
1542         IDirectDraw2_Release(ddraw);
1543         DestroyWindow(window);
1544         return;
1545     }
1546
1547     hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
1548     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
1549
1550     background = create_diffuse_material(device, 0.0, 1.0f, 0.0f, 1.0f);
1551     viewport = create_viewport(device, 0, 0, 640, 480);
1552     viewport_set_background(device, viewport, background);
1553     hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
1554     ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#x.\n", hr);
1555
1556     memset(&surface_desc, 0, sizeof(surface_desc));
1557     surface_desc.dwSize = sizeof(surface_desc);
1558     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CKSRCBLT;
1559     surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1560     surface_desc.dwWidth = 256;
1561     surface_desc.dwHeight = 256;
1562     surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
1563     surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
1564     U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
1565     U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
1566     U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
1567     U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
1568     surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0x000000ff;
1569     surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0x000000ff;
1570     hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
1571     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
1572     hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirect3DTexture2, (void **)&texture);
1573     ok(SUCCEEDED(hr), "Failed to get texture interface, hr %#x.\n", hr);
1574     hr = IDirect3DTexture2_GetHandle(texture, device, &texture_handle);
1575     ok(SUCCEEDED(hr), "Failed to get texture handle, hr %#x.\n", hr);
1576     IDirect3DTexture_Release(texture);
1577
1578     memset(&fx, 0, sizeof(fx));
1579     fx.dwSize = sizeof(fx);
1580     U5(fx).dwFillColor = 0x000000ff;
1581     hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
1582     ok(SUCCEEDED(hr), "Failed to fill surface, hr %#x.\n", hr);
1583
1584     hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
1585     ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
1586     hr = IDirect3DDevice2_BeginScene(device);
1587     ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
1588     hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_TEXTUREHANDLE, texture_handle);
1589     ok(SUCCEEDED(hr), "Failed to set texture handle, hr %#x.\n", hr);
1590     hr = IDirect3DDevice2_GetRenderState(device, D3DRENDERSTATE_COLORKEYENABLE, &value);
1591     ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr);
1592     ok(!value, "Got unexpected color keying state %#x.\n", value);
1593     hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_TLVERTEX, &tquad[0], 4, 0);
1594     ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
1595     hr = IDirect3DDevice2_EndScene(device);
1596     ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1597     color = get_surface_color(rt, 320, 240);
1598     ok(compare_color(color, 0x000000ff, 1), "Got unexpected color 0x%08x.\n", color);
1599
1600     hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
1601     ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
1602     hr = IDirect3DDevice2_BeginScene(device);
1603     ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
1604     hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_COLORKEYENABLE, TRUE);
1605     ok(SUCCEEDED(hr), "Failed to enable color keying, hr %#x.\n", hr);
1606     hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_TLVERTEX, &tquad[0], 4, 0);
1607     ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
1608     hr = IDirect3DDevice2_GetRenderState(device, D3DRENDERSTATE_COLORKEYENABLE, &value);
1609     ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr);
1610     ok(!!value, "Got unexpected color keying state %#x.\n", value);
1611     hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_TEXTUREHANDLE, 0);
1612     ok(SUCCEEDED(hr), "Failed to set texture handle, hr %#x.\n", hr);
1613     hr = IDirect3DDevice2_EndScene(device);
1614     ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1615     color = get_surface_color(rt, 320, 240);
1616     ok(compare_color(color, 0x0000ff00, 1), "Got unexpected color 0x%08x.\n", color);
1617
1618     IDirectDrawSurface_Release(surface);
1619     destroy_viewport(device, viewport);
1620     destroy_material(background);
1621     IDirectDrawSurface_Release(rt);
1622     IDirect3DDevice2_Release(device);
1623     IDirectDraw2_Release(ddraw);
1624     DestroyWindow(window);
1625 }
1626
1627 struct qi_test
1628 {
1629     REFIID iid;
1630     REFIID refcount_iid;
1631     HRESULT hr;
1632 };
1633
1634 static void test_qi(const char *test_name, IUnknown *base_iface,
1635         REFIID refcount_iid, const struct qi_test *tests, UINT entry_count)
1636 {
1637     ULONG refcount, expected_refcount;
1638     IUnknown *iface1, *iface2;
1639     HRESULT hr;
1640     UINT i, j;
1641
1642     for (i = 0; i < entry_count; ++i)
1643     {
1644         hr = IUnknown_QueryInterface(base_iface, tests[i].iid, (void **)&iface1);
1645         ok(hr == tests[i].hr, "Got hr %#x for test \"%s\" %u.\n", hr, test_name, i);
1646         if (SUCCEEDED(hr))
1647         {
1648             for (j = 0; j < entry_count; ++j)
1649             {
1650                 hr = IUnknown_QueryInterface(iface1, tests[j].iid, (void **)&iface2);
1651                 ok(hr == tests[j].hr, "Got hr %#x for test \"%s\" %u, %u.\n", hr, test_name, i, j);
1652                 if (SUCCEEDED(hr))
1653                 {
1654                     expected_refcount = 0;
1655                     if (IsEqualGUID(refcount_iid, tests[j].refcount_iid))
1656                         ++expected_refcount;
1657                     if (IsEqualGUID(tests[i].refcount_iid, tests[j].refcount_iid))
1658                         ++expected_refcount;
1659                     refcount = IUnknown_Release(iface2);
1660                     ok(refcount == expected_refcount, "Got refcount %u for test \"%s\" %u, %u, expected %u.\n",
1661                             refcount, test_name, i, j, expected_refcount);
1662                 }
1663             }
1664
1665             expected_refcount = 0;
1666             if (IsEqualGUID(refcount_iid, tests[i].refcount_iid))
1667                 ++expected_refcount;
1668             refcount = IUnknown_Release(iface1);
1669             ok(refcount == expected_refcount, "Got refcount %u for test \"%s\" %u, expected %u.\n",
1670                     refcount, test_name, i, expected_refcount);
1671         }
1672     }
1673 }
1674
1675 static void test_surface_qi(void)
1676 {
1677     static const struct qi_test tests[] =
1678     {
1679         {&IID_IDirect3DTexture2,        &IID_IDirectDrawSurface,        S_OK         },
1680         {&IID_IDirect3DTexture,         &IID_IDirectDrawSurface,        S_OK         },
1681         {&IID_IDirectDrawGammaControl,  &IID_IDirectDrawGammaControl,   S_OK         },
1682         {&IID_IDirectDrawColorControl,  NULL,                           E_NOINTERFACE},
1683         {&IID_IDirectDrawSurface7,      &IID_IDirectDrawSurface7,       S_OK         },
1684         {&IID_IDirectDrawSurface4,      &IID_IDirectDrawSurface4,       S_OK         },
1685         {&IID_IDirectDrawSurface3,      &IID_IDirectDrawSurface3,       S_OK         },
1686         {&IID_IDirectDrawSurface2,      &IID_IDirectDrawSurface2,       S_OK         },
1687         {&IID_IDirectDrawSurface,       &IID_IDirectDrawSurface,        S_OK         },
1688         {&IID_IDirect3DDevice7,         NULL,                           E_INVALIDARG },
1689         {&IID_IDirect3DDevice3,         NULL,                           E_INVALIDARG },
1690         {&IID_IDirect3DDevice2,         NULL,                           E_INVALIDARG },
1691         {&IID_IDirect3DDevice,          NULL,                           E_INVALIDARG },
1692         {&IID_IDirect3D7,               NULL,                           E_INVALIDARG },
1693         {&IID_IDirect3D3,               NULL,                           E_INVALIDARG },
1694         {&IID_IDirect3D2,               NULL,                           E_INVALIDARG },
1695         {&IID_IDirect3D,                NULL,                           E_INVALIDARG },
1696         {&IID_IDirectDraw7,             NULL,                           E_INVALIDARG },
1697         {&IID_IDirectDraw4,             NULL,                           E_INVALIDARG },
1698         {&IID_IDirectDraw3,             NULL,                           E_INVALIDARG },
1699         {&IID_IDirectDraw2,             NULL,                           E_INVALIDARG },
1700         {&IID_IDirectDraw,              NULL,                           E_INVALIDARG },
1701         {&IID_IDirect3DLight,           NULL,                           E_INVALIDARG },
1702         {&IID_IDirect3DMaterial,        NULL,                           E_INVALIDARG },
1703         {&IID_IDirect3DMaterial2,       NULL,                           E_INVALIDARG },
1704         {&IID_IDirect3DMaterial3,       NULL,                           E_INVALIDARG },
1705         {&IID_IDirect3DExecuteBuffer,   NULL,                           E_INVALIDARG },
1706         {&IID_IDirect3DViewport,        NULL,                           E_INVALIDARG },
1707         {&IID_IDirect3DViewport2,       NULL,                           E_INVALIDARG },
1708         {&IID_IDirect3DViewport3,       NULL,                           E_INVALIDARG },
1709         {&IID_IDirect3DVertexBuffer,    NULL,                           E_INVALIDARG },
1710         {&IID_IDirect3DVertexBuffer7,   NULL,                           E_INVALIDARG },
1711         {&IID_IDirectDrawPalette,       NULL,                           E_INVALIDARG },
1712         {&IID_IDirectDrawClipper,       NULL,                           E_INVALIDARG },
1713         {&IID_IUnknown,                 &IID_IDirectDrawSurface,        S_OK         },
1714     };
1715
1716     IDirectDrawSurface *surface;
1717     DDSURFACEDESC surface_desc;
1718     IDirect3DDevice2 *device;
1719     IDirectDraw2 *ddraw;
1720     HWND window;
1721     HRESULT hr;
1722
1723     if (!GetProcAddress(GetModuleHandleA("ddraw.dll"), "DirectDrawCreateEx"))
1724     {
1725         win_skip("DirectDrawCreateEx not available, skipping test.\n");
1726         return;
1727     }
1728
1729     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1730             0, 0, 640, 480, 0, 0, 0, 0);
1731     if (!(ddraw = create_ddraw()))
1732     {
1733         skip("Failed to create a ddraw object, skipping test.\n");
1734         DestroyWindow(window);
1735         return;
1736     }
1737     /* Try to create a D3D device to see if the ddraw implementation supports
1738      * D3D. 64-bit ddraw in particular doesn't seem to support D3D, and
1739      * doesn't support e.g. the IDirect3DTexture interfaces. */
1740     if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
1741     {
1742         skip("Failed to create D3D device, skipping test.\n");
1743         IDirectDraw2_Release(ddraw);
1744         DestroyWindow(window);
1745         return;
1746     }
1747     IDirect3DDevice_Release(device);
1748
1749     memset(&surface_desc, 0, sizeof(surface_desc));
1750     surface_desc.dwSize = sizeof(surface_desc);
1751     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
1752     surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1753     surface_desc.dwWidth = 512;
1754     surface_desc.dwHeight = 512;
1755     hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
1756     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
1757
1758     test_qi("surface_qi", (IUnknown *)surface, &IID_IDirectDrawSurface, tests, sizeof(tests) / sizeof(*tests));
1759
1760     IDirectDrawSurface_Release(surface);
1761     IDirectDraw2_Release(ddraw);
1762     DestroyWindow(window);
1763 }
1764
1765 static void test_device_qi(void)
1766 {
1767     static const struct qi_test tests[] =
1768     {
1769         {&IID_IDirect3DTexture2,        NULL,                           E_NOINTERFACE},
1770         {&IID_IDirect3DTexture,         NULL,                           E_NOINTERFACE},
1771         {&IID_IDirectDrawGammaControl,  NULL,                           E_NOINTERFACE},
1772         {&IID_IDirectDrawColorControl,  NULL,                           E_NOINTERFACE},
1773         {&IID_IDirectDrawSurface7,      NULL,                           E_NOINTERFACE},
1774         {&IID_IDirectDrawSurface4,      NULL,                           E_NOINTERFACE},
1775         {&IID_IDirectDrawSurface3,      NULL,                           E_NOINTERFACE},
1776         {&IID_IDirectDrawSurface2,      NULL,                           E_NOINTERFACE},
1777         {&IID_IDirectDrawSurface,       NULL,                           E_NOINTERFACE},
1778         {&IID_IDirect3DDevice7,         NULL,                           E_NOINTERFACE},
1779         {&IID_IDirect3DDevice3,         NULL,                           E_NOINTERFACE},
1780         {&IID_IDirect3DDevice2,         &IID_IDirect3DDevice2,          S_OK         },
1781         {&IID_IDirect3DDevice,          &IID_IDirect3DDevice2,          S_OK         },
1782         {&IID_IDirect3DRampDevice,      NULL,                           E_NOINTERFACE},
1783         {&IID_IDirect3DRGBDevice,       NULL,                           E_NOINTERFACE},
1784         {&IID_IDirect3DHALDevice,       NULL,                           E_NOINTERFACE},
1785         {&IID_IDirect3DMMXDevice,       NULL,                           E_NOINTERFACE},
1786         {&IID_IDirect3DRefDevice,       NULL,                           E_NOINTERFACE},
1787         {&IID_IDirect3DTnLHalDevice,    NULL,                           E_NOINTERFACE},
1788         {&IID_IDirect3DNullDevice,      NULL,                           E_NOINTERFACE},
1789         {&IID_IDirect3D7,               NULL,                           E_NOINTERFACE},
1790         {&IID_IDirect3D3,               NULL,                           E_NOINTERFACE},
1791         {&IID_IDirect3D2,               NULL,                           E_NOINTERFACE},
1792         {&IID_IDirect3D,                NULL,                           E_NOINTERFACE},
1793         {&IID_IDirectDraw7,             NULL,                           E_NOINTERFACE},
1794         {&IID_IDirectDraw4,             NULL,                           E_NOINTERFACE},
1795         {&IID_IDirectDraw3,             NULL,                           E_NOINTERFACE},
1796         {&IID_IDirectDraw2,             NULL,                           E_NOINTERFACE},
1797         {&IID_IDirectDraw,              NULL,                           E_NOINTERFACE},
1798         {&IID_IDirect3DLight,           NULL,                           E_NOINTERFACE},
1799         {&IID_IDirect3DMaterial,        NULL,                           E_NOINTERFACE},
1800         {&IID_IDirect3DMaterial2,       NULL,                           E_NOINTERFACE},
1801         {&IID_IDirect3DMaterial3,       NULL,                           E_NOINTERFACE},
1802         {&IID_IDirect3DExecuteBuffer,   NULL,                           E_NOINTERFACE},
1803         {&IID_IDirect3DViewport,        NULL,                           E_NOINTERFACE},
1804         {&IID_IDirect3DViewport2,       NULL,                           E_NOINTERFACE},
1805         {&IID_IDirect3DViewport3,       NULL,                           E_NOINTERFACE},
1806         {&IID_IDirect3DVertexBuffer,    NULL,                           E_NOINTERFACE},
1807         {&IID_IDirect3DVertexBuffer7,   NULL,                           E_NOINTERFACE},
1808         {&IID_IDirectDrawPalette,       NULL,                           E_NOINTERFACE},
1809         {&IID_IDirectDrawClipper,       NULL,                           E_NOINTERFACE},
1810         {&IID_IUnknown,                 &IID_IDirect3DDevice2,          S_OK         },
1811     };
1812
1813     IDirect3DDevice2 *device;
1814     IDirectDraw2 *ddraw;
1815     HWND window;
1816
1817     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1818             0, 0, 640, 480, 0, 0, 0, 0);
1819     if (!(ddraw = create_ddraw()))
1820     {
1821         skip("Failed to create ddraw object, skipping test.\n");
1822         DestroyWindow(window);
1823         return;
1824     }
1825     if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
1826     {
1827         skip("Failed to create D3D device, skipping test.\n");
1828         IDirectDraw2_Release(ddraw);
1829         DestroyWindow(window);
1830         return;
1831     }
1832
1833     test_qi("device_qi", (IUnknown *)device, &IID_IDirect3DDevice2, tests, sizeof(tests) / sizeof(*tests));
1834
1835     IDirect3DDevice2_Release(device);
1836     IDirectDraw2_Release(ddraw);
1837     DestroyWindow(window);
1838 }
1839
1840 static void test_wndproc(void)
1841 {
1842     LONG_PTR proc, ddraw_proc;
1843     IDirectDraw2 *ddraw;
1844     WNDCLASSA wc = {0};
1845     HWND window;
1846     HRESULT hr;
1847     ULONG ref;
1848
1849     static const UINT messages[] =
1850     {
1851         WM_WINDOWPOSCHANGING,
1852         WM_MOVE,
1853         WM_SIZE,
1854         WM_WINDOWPOSCHANGING,
1855         WM_ACTIVATE,
1856         WM_SETFOCUS,
1857         0,
1858     };
1859
1860     /* DDSCL_EXCLUSIVE replaces the window's window proc. */
1861     if (!(ddraw = create_ddraw()))
1862     {
1863         skip("Failed to create IDirectDraw2 object, skipping tests.\n");
1864         return;
1865     }
1866
1867     wc.lpfnWndProc = test_proc;
1868     wc.lpszClassName = "ddraw_test_wndproc_wc";
1869     ok(RegisterClassA(&wc), "Failed to register window class.\n");
1870
1871     window = CreateWindowA("ddraw_test_wndproc_wc", "ddraw_test",
1872             WS_MAXIMIZE | WS_CAPTION , 0, 0, 640, 480, 0, 0, 0, 0);
1873
1874     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
1875     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
1876             (LONG_PTR)test_proc, proc);
1877     expect_messages = messages;
1878     hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
1879     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
1880     ok(!*expect_messages, "Expected message %#x, but didn't receive it.\n", *expect_messages);
1881     expect_messages = NULL;
1882     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
1883     ok(proc != (LONG_PTR)test_proc, "Expected wndproc != %#lx, got %#lx.\n",
1884             (LONG_PTR)test_proc, proc);
1885     ref = IDirectDraw2_Release(ddraw);
1886     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
1887     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
1888     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
1889             (LONG_PTR)test_proc, proc);
1890
1891     /* DDSCL_NORMAL doesn't. */
1892     ddraw = create_ddraw();
1893     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
1894     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
1895             (LONG_PTR)test_proc, proc);
1896     hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL | DDSCL_FULLSCREEN);
1897     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
1898     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
1899     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
1900             (LONG_PTR)test_proc, proc);
1901     ref = IDirectDraw2_Release(ddraw);
1902     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
1903     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
1904     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
1905             (LONG_PTR)test_proc, proc);
1906
1907     /* The original window proc is only restored by ddraw if the current
1908      * window proc matches the one ddraw set. This also affects switching
1909      * from DDSCL_NORMAL to DDSCL_EXCLUSIVE. */
1910     ddraw = create_ddraw();
1911     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
1912     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
1913             (LONG_PTR)test_proc, proc);
1914     hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
1915     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
1916     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
1917     ok(proc != (LONG_PTR)test_proc, "Expected wndproc != %#lx, got %#lx.\n",
1918             (LONG_PTR)test_proc, proc);
1919     ddraw_proc = proc;
1920     hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
1921     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
1922     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
1923     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
1924             (LONG_PTR)test_proc, proc);
1925     hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
1926     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
1927     proc = SetWindowLongPtrA(window, GWLP_WNDPROC, (LONG_PTR)DefWindowProcA);
1928     ok(proc != (LONG_PTR)test_proc, "Expected wndproc != %#lx, got %#lx.\n",
1929             (LONG_PTR)test_proc, proc);
1930     hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
1931     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
1932     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
1933     ok(proc == (LONG_PTR)DefWindowProcA, "Expected wndproc %#lx, got %#lx.\n",
1934             (LONG_PTR)DefWindowProcA, proc);
1935     hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
1936     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
1937     proc = SetWindowLongPtrA(window, GWLP_WNDPROC, (LONG_PTR)ddraw_proc);
1938     ok(proc == (LONG_PTR)DefWindowProcA, "Expected wndproc %#lx, got %#lx.\n",
1939             (LONG_PTR)DefWindowProcA, proc);
1940     ref = IDirectDraw2_Release(ddraw);
1941     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
1942     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
1943     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
1944             (LONG_PTR)test_proc, proc);
1945
1946     ddraw = create_ddraw();
1947     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
1948     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
1949             (LONG_PTR)test_proc, proc);
1950     hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
1951     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
1952     proc = SetWindowLongPtrA(window, GWLP_WNDPROC, (LONG_PTR)DefWindowProcA);
1953     ok(proc != (LONG_PTR)test_proc, "Expected wndproc != %#lx, got %#lx.\n",
1954             (LONG_PTR)test_proc, proc);
1955     ref = IDirectDraw2_Release(ddraw);
1956     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
1957     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
1958     ok(proc == (LONG_PTR)DefWindowProcA, "Expected wndproc %#lx, got %#lx.\n",
1959             (LONG_PTR)DefWindowProcA, proc);
1960
1961     fix_wndproc(window, (LONG_PTR)test_proc);
1962     expect_messages = NULL;
1963     DestroyWindow(window);
1964     UnregisterClassA("ddraw_test_wndproc_wc", GetModuleHandleA(NULL));
1965 }
1966
1967 static void test_window_style(void)
1968 {
1969     LONG style, exstyle, tmp;
1970     RECT fullscreen_rect, r;
1971     IDirectDraw2 *ddraw;
1972     HWND window;
1973     HRESULT hr;
1974     ULONG ref;
1975
1976     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1977             0, 0, 100, 100, 0, 0, 0, 0);
1978     if (!(ddraw = create_ddraw()))
1979     {
1980         skip("Failed to create a ddraw object, skipping test.\n");
1981         DestroyWindow(window);
1982         return;
1983     }
1984
1985     style = GetWindowLongA(window, GWL_STYLE);
1986     exstyle = GetWindowLongA(window, GWL_EXSTYLE);
1987     SetRect(&fullscreen_rect, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
1988
1989     hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
1990     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
1991
1992     tmp = GetWindowLongA(window, GWL_STYLE);
1993     todo_wine ok(tmp == style, "Expected window style %#x, got %#x.\n", style, tmp);
1994     tmp = GetWindowLongA(window, GWL_EXSTYLE);
1995     todo_wine ok(tmp == exstyle, "Expected window extended style %#x, got %#x.\n", exstyle, tmp);
1996
1997     GetWindowRect(window, &r);
1998     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
1999             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2000             r.left, r.top, r.right, r.bottom);
2001     GetClientRect(window, &r);
2002     todo_wine ok(!EqualRect(&r, &fullscreen_rect), "Client rect and window rect are equal.\n");
2003
2004     ref = IDirectDraw2_Release(ddraw);
2005     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2006
2007     DestroyWindow(window);
2008 }
2009
2010 static void test_redundant_mode_set(void)
2011 {
2012     DDSURFACEDESC surface_desc = {0};
2013     IDirectDraw2 *ddraw;
2014     HWND window;
2015     HRESULT hr;
2016     RECT r, s;
2017     ULONG ref;
2018
2019     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
2020             0, 0, 100, 100, 0, 0, 0, 0);
2021     if (!(ddraw = create_ddraw()))
2022     {
2023         skip("Failed to create a ddraw object, skipping test.\n");
2024         DestroyWindow(window);
2025         return;
2026     }
2027
2028     hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2029     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2030
2031     surface_desc.dwSize = sizeof(surface_desc);
2032     hr = IDirectDraw2_GetDisplayMode(ddraw, &surface_desc);
2033     ok(SUCCEEDED(hr), "GetDipslayMode failed, hr %#x.\n", hr);
2034
2035     hr = IDirectDraw2_SetDisplayMode(ddraw, surface_desc.dwWidth, surface_desc.dwHeight,
2036             U1(surface_desc.ddpfPixelFormat).dwRGBBitCount, 0, 0);
2037     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
2038
2039     GetWindowRect(window, &r);
2040     r.right /= 2;
2041     r.bottom /= 2;
2042     SetWindowPos(window, HWND_TOP, r.left, r.top, r.right, r.bottom, 0);
2043     GetWindowRect(window, &s);
2044     ok(EqualRect(&r, &s), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2045             r.left, r.top, r.right, r.bottom,
2046             s.left, s.top, s.right, s.bottom);
2047
2048     hr = IDirectDraw2_SetDisplayMode(ddraw, surface_desc.dwWidth, surface_desc.dwHeight,
2049             U1(surface_desc.ddpfPixelFormat).dwRGBBitCount, 0, 0);
2050     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
2051
2052     GetWindowRect(window, &s);
2053     ok(EqualRect(&r, &s), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2054             r.left, r.top, r.right, r.bottom,
2055             s.left, s.top, s.right, s.bottom);
2056
2057     ref = IDirectDraw2_Release(ddraw);
2058     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2059
2060     DestroyWindow(window);
2061 }
2062
2063 static SIZE screen_size;
2064
2065 static LRESULT CALLBACK mode_set_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
2066 {
2067     if (message == WM_SIZE)
2068     {
2069         screen_size.cx = GetSystemMetrics(SM_CXSCREEN);
2070         screen_size.cy = GetSystemMetrics(SM_CYSCREEN);
2071     }
2072
2073     return test_proc(hwnd, message, wparam, lparam);
2074 }
2075
2076 static void test_coop_level_mode_set(void)
2077 {
2078     IDirectDrawSurface *primary;
2079     RECT fullscreen_rect, r, s;
2080     IDirectDraw2 *ddraw;
2081     DDSURFACEDESC ddsd;
2082     WNDCLASSA wc = {0};
2083     HWND window;
2084     HRESULT hr;
2085     ULONG ref;
2086
2087     static const UINT exclusive_messages[] =
2088     {
2089         WM_WINDOWPOSCHANGING,
2090         WM_WINDOWPOSCHANGED,
2091         WM_SIZE,
2092         WM_DISPLAYCHANGE,
2093         0,
2094     };
2095
2096     static const UINT normal_messages[] =
2097     {
2098         WM_DISPLAYCHANGE,
2099         0,
2100     };
2101
2102     if (!(ddraw = create_ddraw()))
2103     {
2104         skip("Failed to create a ddraw object, skipping test.\n");
2105         return;
2106     }
2107
2108     wc.lpfnWndProc = mode_set_proc;
2109     wc.lpszClassName = "ddraw_test_wndproc_wc";
2110     ok(RegisterClassA(&wc), "Failed to register window class.\n");
2111
2112     window = CreateWindowA("ddraw_test_wndproc_wc", "ddraw_test", WS_OVERLAPPEDWINDOW,
2113             0, 0, 100, 100, 0, 0, 0, 0);
2114
2115     SetRect(&fullscreen_rect, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
2116     SetRect(&s, 0, 0, 640, 480);
2117
2118     hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2119     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2120
2121     GetWindowRect(window, &r);
2122     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2123             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2124             r.left, r.top, r.right, r.bottom);
2125
2126     memset(&ddsd, 0, sizeof(ddsd));
2127     ddsd.dwSize = sizeof(ddsd);
2128     ddsd.dwFlags = DDSD_CAPS;
2129     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2130
2131     hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
2132     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2133     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2134     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2135     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2136             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2137     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2138             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2139
2140     GetWindowRect(window, &r);
2141     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2142             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2143             r.left, r.top, r.right, r.bottom);
2144
2145     expect_messages = exclusive_messages;
2146     screen_size.cx = 0;
2147     screen_size.cy = 0;
2148
2149     hr = IDirectDraw2_SetDisplayMode(ddraw, 640, 480, 32, 0, 0);
2150     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
2151
2152     ok(!*expect_messages, "Expected message %#x, but didn't receive it.\n", *expect_messages);
2153     expect_messages = NULL;
2154     ok(screen_size.cx == s.right && screen_size.cy == s.bottom,
2155             "Expected screen size %ux%u, got %ux%u.\n",
2156             s.right, s.bottom, screen_size.cx, screen_size.cy);
2157
2158     GetWindowRect(window, &r);
2159     ok(EqualRect(&r, &s), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2160             s.left, s.top, s.right, s.bottom,
2161             r.left, r.top, r.right, r.bottom);
2162
2163     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2164     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2165     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2166             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2167     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2168             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2169     IDirectDrawSurface_Release(primary);
2170
2171     memset(&ddsd, 0, sizeof(ddsd));
2172     ddsd.dwSize = sizeof(ddsd);
2173     ddsd.dwFlags = DDSD_CAPS;
2174     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2175
2176     hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
2177     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2178     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2179     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2180     ok(ddsd.dwWidth == s.right - s.left, "Expected surface width %u, got %u.\n",
2181             s.right - s.left, ddsd.dwWidth);
2182     ok(ddsd.dwHeight == s.bottom - s.top, "Expected surface height %u, got %u.\n",
2183             s.bottom - s.top, ddsd.dwHeight);
2184
2185     GetWindowRect(window, &r);
2186     ok(EqualRect(&r, &s), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2187             s.left, s.top, s.right, s.bottom,
2188             r.left, r.top, r.right, r.bottom);
2189
2190     expect_messages = exclusive_messages;
2191     screen_size.cx = 0;
2192     screen_size.cy = 0;
2193
2194     hr = IDirectDraw_RestoreDisplayMode(ddraw);
2195     ok(SUCCEEDED(hr), "RestoreDisplayMode failed, hr %#x.\n", hr);
2196
2197     ok(!*expect_messages, "Expected message %#x, but didn't receive it.\n", *expect_messages);
2198     expect_messages = NULL;
2199     ok(screen_size.cx == fullscreen_rect.right && screen_size.cy == fullscreen_rect.bottom,
2200             "Expected screen size %ux%u, got %ux%u.\n",
2201             fullscreen_rect.right, fullscreen_rect.bottom, screen_size.cx, screen_size.cy);
2202
2203     GetWindowRect(window, &r);
2204     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2205             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2206             r.left, r.top, r.right, r.bottom);
2207
2208     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2209     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2210     ok(ddsd.dwWidth == s.right - s.left, "Expected surface width %u, got %u.\n",
2211             s.right - s.left, ddsd.dwWidth);
2212     ok(ddsd.dwHeight == s.bottom - s.top, "Expected surface height %u, got %u.\n",
2213             s.bottom - s.top, ddsd.dwHeight);
2214     IDirectDrawSurface_Release(primary);
2215
2216     memset(&ddsd, 0, sizeof(ddsd));
2217     ddsd.dwSize = sizeof(ddsd);
2218     ddsd.dwFlags = DDSD_CAPS;
2219     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2220
2221     hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
2222     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2223     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2224     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2225     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2226             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2227     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2228             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2229
2230     GetWindowRect(window, &r);
2231     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2232             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2233             r.left, r.top, r.right, r.bottom);
2234
2235     hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
2236     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2237
2238     GetWindowRect(window, &r);
2239     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2240             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2241             r.left, r.top, r.right, r.bottom);
2242
2243     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2244     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2245     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2246             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2247     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2248             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2249     IDirectDrawSurface_Release(primary);
2250
2251     memset(&ddsd, 0, sizeof(ddsd));
2252     ddsd.dwSize = sizeof(ddsd);
2253     ddsd.dwFlags = DDSD_CAPS;
2254     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2255
2256     hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
2257     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2258     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2259     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2260     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2261             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2262     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2263             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2264
2265     GetWindowRect(window, &r);
2266     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2267             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2268             r.left, r.top, r.right, r.bottom);
2269
2270     expect_messages = normal_messages;
2271     screen_size.cx = 0;
2272     screen_size.cy = 0;
2273
2274     hr = IDirectDraw2_SetDisplayMode(ddraw, 640, 480, 32, 0, 0);
2275     ok(SUCCEEDED(hr) || broken(hr == DDERR_NOEXCLUSIVEMODE) /* NT4 testbot */,
2276         "SetDipslayMode failed, hr %#x.\n", hr);
2277     if (hr == DDERR_NOEXCLUSIVEMODE)
2278     {
2279         win_skip("Broken SetDisplayMode(), skipping remaining tests.\n");
2280         IDirectDrawSurface_Release(primary);
2281         IDirectDraw2_Release(ddraw);
2282         goto done;
2283     }
2284
2285     ok(!*expect_messages, "Expected message %#x, but didn't receive it.\n", *expect_messages);
2286     expect_messages = NULL;
2287     ok(!screen_size.cx && !screen_size.cy, "Got unxpected screen size %ux%u.\n", screen_size.cx, screen_size.cy);
2288
2289     GetWindowRect(window, &r);
2290     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2291             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2292             r.left, r.top, r.right, r.bottom);
2293
2294     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2295     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2296     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2297             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2298     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2299             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2300     IDirectDrawSurface_Release(primary);
2301
2302     memset(&ddsd, 0, sizeof(ddsd));
2303     ddsd.dwSize = sizeof(ddsd);
2304     ddsd.dwFlags = DDSD_CAPS;
2305     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2306
2307     hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
2308     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2309     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2310     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2311     ok(ddsd.dwWidth == s.right - s.left, "Expected surface width %u, got %u.\n",
2312             s.right - s.left, ddsd.dwWidth);
2313     ok(ddsd.dwHeight == s.bottom - s.top, "Expected surface height %u, got %u.\n",
2314             s.bottom - s.top, ddsd.dwHeight);
2315
2316     GetWindowRect(window, &r);
2317     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2318             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2319             r.left, r.top, r.right, r.bottom);
2320
2321     expect_messages = normal_messages;
2322     screen_size.cx = 0;
2323     screen_size.cy = 0;
2324
2325     hr = IDirectDraw_RestoreDisplayMode(ddraw);
2326     ok(SUCCEEDED(hr), "RestoreDisplayMode failed, hr %#x.\n", hr);
2327
2328     ok(!*expect_messages, "Expected message %#x, but didn't receive it.\n", *expect_messages);
2329     expect_messages = NULL;
2330     ok(!screen_size.cx && !screen_size.cy, "Got unxpected screen size %ux%u.\n", screen_size.cx, screen_size.cy);
2331
2332     GetWindowRect(window, &r);
2333     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2334             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2335             r.left, r.top, r.right, r.bottom);
2336
2337     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2338     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2339     ok(ddsd.dwWidth == s.right - s.left, "Expected surface width %u, got %u.\n",
2340             s.right - s.left, ddsd.dwWidth);
2341     ok(ddsd.dwHeight == s.bottom - s.top, "Expected surface height %u, got %u.\n",
2342             s.bottom - s.top, ddsd.dwHeight);
2343     IDirectDrawSurface_Release(primary);
2344
2345     memset(&ddsd, 0, sizeof(ddsd));
2346     ddsd.dwSize = sizeof(ddsd);
2347     ddsd.dwFlags = DDSD_CAPS;
2348     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2349
2350     hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
2351     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2352     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2353     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2354     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2355             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2356     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2357             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2358
2359     GetWindowRect(window, &r);
2360     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2361             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2362             r.left, r.top, r.right, r.bottom);
2363
2364     /* DDSCL_NORMAL | DDSCL_FULLSCREEN behaves the same as just DDSCL_NORMAL.
2365      * Resizing the window on mode changes is a property of DDSCL_EXCLUSIVE,
2366      * not DDSCL_FULLSCREEN. */
2367     hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL | DDSCL_FULLSCREEN);
2368     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2369
2370     GetWindowRect(window, &r);
2371     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2372             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2373             r.left, r.top, r.right, r.bottom);
2374
2375     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2376     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2377     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2378             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2379     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2380             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2381     IDirectDrawSurface_Release(primary);
2382
2383     memset(&ddsd, 0, sizeof(ddsd));
2384     ddsd.dwSize = sizeof(ddsd);
2385     ddsd.dwFlags = DDSD_CAPS;
2386     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2387
2388     hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
2389     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2390     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2391     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2392     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2393             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2394     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2395             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2396
2397     GetWindowRect(window, &r);
2398     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2399             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2400             r.left, r.top, r.right, r.bottom);
2401
2402     expect_messages = normal_messages;
2403     screen_size.cx = 0;
2404     screen_size.cy = 0;
2405
2406     hr = IDirectDraw2_SetDisplayMode(ddraw, 640, 480, 32, 0, 0);
2407     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
2408
2409     ok(!*expect_messages, "Expected message %#x, but didn't receive it.\n", *expect_messages);
2410     expect_messages = NULL;
2411     ok(!screen_size.cx && !screen_size.cy, "Got unxpected screen size %ux%u.\n", screen_size.cx, screen_size.cy);
2412
2413     GetWindowRect(window, &r);
2414     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2415             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2416             r.left, r.top, r.right, r.bottom);
2417
2418     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2419     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2420     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2421             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2422     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2423             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2424     IDirectDrawSurface_Release(primary);
2425
2426     memset(&ddsd, 0, sizeof(ddsd));
2427     ddsd.dwSize = sizeof(ddsd);
2428     ddsd.dwFlags = DDSD_CAPS;
2429     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2430
2431     hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
2432     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2433     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2434     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2435     ok(ddsd.dwWidth == s.right - s.left, "Expected surface width %u, got %u.\n",
2436             s.right - s.left, ddsd.dwWidth);
2437     ok(ddsd.dwHeight == s.bottom - s.top, "Expected surface height %u, got %u.\n",
2438             s.bottom - s.top, ddsd.dwHeight);
2439
2440     GetWindowRect(window, &r);
2441     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2442             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2443             r.left, r.top, r.right, r.bottom);
2444
2445     expect_messages = normal_messages;
2446     screen_size.cx = 0;
2447     screen_size.cy = 0;
2448
2449     hr = IDirectDraw_RestoreDisplayMode(ddraw);
2450     ok(SUCCEEDED(hr), "RestoreDisplayMode failed, hr %#x.\n", hr);
2451
2452     ok(!*expect_messages, "Expected message %#x, but didn't receive it.\n", *expect_messages);
2453     expect_messages = NULL;
2454     ok(!screen_size.cx && !screen_size.cy, "Got unxpected screen size %ux%u.\n", screen_size.cx, screen_size.cy);
2455
2456     GetWindowRect(window, &r);
2457     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2458             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2459             r.left, r.top, r.right, r.bottom);
2460
2461     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2462     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2463     ok(ddsd.dwWidth == s.right - s.left, "Expected surface width %u, got %u.\n",
2464             s.right - s.left, ddsd.dwWidth);
2465     ok(ddsd.dwHeight == s.bottom - s.top, "Expected surface height %u, got %u.\n",
2466             s.bottom - s.top, ddsd.dwHeight);
2467     IDirectDrawSurface_Release(primary);
2468
2469     memset(&ddsd, 0, sizeof(ddsd));
2470     ddsd.dwSize = sizeof(ddsd);
2471     ddsd.dwFlags = DDSD_CAPS;
2472     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2473
2474     hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
2475     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2476     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2477     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2478     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2479             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2480     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2481             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2482     IDirectDrawSurface_Release(primary);
2483
2484     GetWindowRect(window, &r);
2485     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2486             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2487             r.left, r.top, r.right, r.bottom);
2488
2489     ref = IDirectDraw2_Release(ddraw);
2490     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2491
2492     GetWindowRect(window, &r);
2493     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2494             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2495             r.left, r.top, r.right, r.bottom);
2496
2497 done:
2498     expect_messages = NULL;
2499     DestroyWindow(window);
2500     UnregisterClassA("ddraw_test_wndproc_wc", GetModuleHandleA(NULL));
2501 }
2502
2503 static void test_coop_level_mode_set_multi(void)
2504 {
2505     IDirectDraw2 *ddraw1, *ddraw2;
2506     UINT orig_w, orig_h, w, h;
2507     HWND window;
2508     HRESULT hr;
2509     ULONG ref;
2510
2511     if (!(ddraw1 = create_ddraw()))
2512     {
2513         skip("Failed to create a ddraw object, skipping test.\n");
2514         return;
2515     }
2516
2517     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
2518             0, 0, 100, 100, 0, 0, 0, 0);
2519
2520     orig_w = GetSystemMetrics(SM_CXSCREEN);
2521     orig_h = GetSystemMetrics(SM_CYSCREEN);
2522
2523     /* With just a single ddraw object, the display mode is restored on
2524      * release. */
2525     hr = IDirectDraw2_SetDisplayMode(ddraw1, 800, 600, 32, 0, 0);
2526     ok(SUCCEEDED(hr) || broken(hr == DDERR_NOEXCLUSIVEMODE) /* NT4 testbot */,
2527             "SetDipslayMode failed, hr %#x.\n", hr);
2528     if (hr == DDERR_NOEXCLUSIVEMODE)
2529     {
2530         win_skip("Broken SetDisplayMode(), skipping test.\n");
2531         IDirectDraw2_Release(ddraw1);
2532         DestroyWindow(window);
2533         return;
2534     }
2535     w = GetSystemMetrics(SM_CXSCREEN);
2536     ok(w == 800, "Got unexpected screen width %u.\n", w);
2537     h = GetSystemMetrics(SM_CYSCREEN);
2538     ok(h == 600, "Got unexpected screen height %u.\n", h);
2539
2540     ref = IDirectDraw2_Release(ddraw1);
2541     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2542     w = GetSystemMetrics(SM_CXSCREEN);
2543     ok(w == orig_w, "Got unexpected screen width %u.\n", w);
2544     h = GetSystemMetrics(SM_CYSCREEN);
2545     ok(h == orig_h, "Got unexpected screen height %u.\n", h);
2546
2547     /* When there are multiple ddraw objects, the display mode is restored to
2548      * the initial mode, before the first SetDisplayMode() call. */
2549     ddraw1 = create_ddraw();
2550     hr = IDirectDraw2_SetDisplayMode(ddraw1, 800, 600, 32, 0, 0);
2551     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
2552     w = GetSystemMetrics(SM_CXSCREEN);
2553     ok(w == 800, "Got unexpected screen width %u.\n", w);
2554     h = GetSystemMetrics(SM_CYSCREEN);
2555     ok(h == 600, "Got unexpected screen height %u.\n", h);
2556
2557     ddraw2 = create_ddraw();
2558     hr = IDirectDraw2_SetDisplayMode(ddraw2, 640, 480, 32, 0, 0);
2559     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
2560     w = GetSystemMetrics(SM_CXSCREEN);
2561     ok(w == 640, "Got unexpected screen width %u.\n", w);
2562     h = GetSystemMetrics(SM_CYSCREEN);
2563     ok(h == 480, "Got unexpected screen height %u.\n", h);
2564
2565     ref = IDirectDraw2_Release(ddraw2);
2566     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2567     w = GetSystemMetrics(SM_CXSCREEN);
2568     ok(w == orig_w, "Got unexpected screen width %u.\n", w);
2569     h = GetSystemMetrics(SM_CYSCREEN);
2570     ok(h == orig_h, "Got unexpected screen height %u.\n", h);
2571
2572     ref = IDirectDraw2_Release(ddraw1);
2573     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2574     w = GetSystemMetrics(SM_CXSCREEN);
2575     ok(w == orig_w, "Got unexpected screen width %u.\n", w);
2576     h = GetSystemMetrics(SM_CYSCREEN);
2577     ok(h == orig_h, "Got unexpected screen height %u.\n", h);
2578
2579     /* Regardless of release ordering. */
2580     ddraw1 = create_ddraw();
2581     hr = IDirectDraw2_SetDisplayMode(ddraw1, 800, 600, 32, 0, 0);
2582     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
2583     w = GetSystemMetrics(SM_CXSCREEN);
2584     ok(w == 800, "Got unexpected screen width %u.\n", w);
2585     h = GetSystemMetrics(SM_CYSCREEN);
2586     ok(h == 600, "Got unexpected screen height %u.\n", h);
2587
2588     ddraw2 = create_ddraw();
2589     hr = IDirectDraw2_SetDisplayMode(ddraw2, 640, 480, 32, 0, 0);
2590     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
2591     w = GetSystemMetrics(SM_CXSCREEN);
2592     ok(w == 640, "Got unexpected screen width %u.\n", w);
2593     h = GetSystemMetrics(SM_CYSCREEN);
2594     ok(h == 480, "Got unexpected screen height %u.\n", h);
2595
2596     ref = IDirectDraw2_Release(ddraw1);
2597     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2598     w = GetSystemMetrics(SM_CXSCREEN);
2599     ok(w == orig_w, "Got unexpected screen width %u.\n", w);
2600     h = GetSystemMetrics(SM_CYSCREEN);
2601     ok(h == orig_h, "Got unexpected screen height %u.\n", h);
2602
2603     ref = IDirectDraw2_Release(ddraw2);
2604     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2605     w = GetSystemMetrics(SM_CXSCREEN);
2606     ok(w == orig_w, "Got unexpected screen width %u.\n", w);
2607     h = GetSystemMetrics(SM_CYSCREEN);
2608     ok(h == orig_h, "Got unexpected screen height %u.\n", h);
2609
2610     /* But only for ddraw objects that called SetDisplayMode(). */
2611     ddraw1 = create_ddraw();
2612     ddraw2 = create_ddraw();
2613     hr = IDirectDraw2_SetDisplayMode(ddraw2, 640, 480, 32, 0, 0);
2614     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
2615     w = GetSystemMetrics(SM_CXSCREEN);
2616     ok(w == 640, "Got unexpected screen width %u.\n", w);
2617     h = GetSystemMetrics(SM_CYSCREEN);
2618     ok(h == 480, "Got unexpected screen height %u.\n", h);
2619
2620     ref = IDirectDraw2_Release(ddraw1);
2621     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2622     w = GetSystemMetrics(SM_CXSCREEN);
2623     ok(w == 640, "Got unexpected screen width %u.\n", w);
2624     h = GetSystemMetrics(SM_CYSCREEN);
2625     ok(h == 480, "Got unexpected screen height %u.\n", h);
2626
2627     ref = IDirectDraw2_Release(ddraw2);
2628     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2629     w = GetSystemMetrics(SM_CXSCREEN);
2630     ok(w == orig_w, "Got unexpected screen width %u.\n", w);
2631     h = GetSystemMetrics(SM_CYSCREEN);
2632     ok(h == orig_h, "Got unexpected screen height %u.\n", h);
2633
2634     /* If there's a ddraw object that's currently in exclusive mode, it blocks
2635      * restoring the display mode. */
2636     ddraw1 = create_ddraw();
2637     hr = IDirectDraw2_SetDisplayMode(ddraw1, 800, 600, 32, 0, 0);
2638     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
2639     w = GetSystemMetrics(SM_CXSCREEN);
2640     ok(w == 800, "Got unexpected screen width %u.\n", w);
2641     h = GetSystemMetrics(SM_CYSCREEN);
2642     ok(h == 600, "Got unexpected screen height %u.\n", h);
2643
2644     ddraw2 = create_ddraw();
2645     hr = IDirectDraw2_SetDisplayMode(ddraw2, 640, 480, 32, 0, 0);
2646     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
2647     w = GetSystemMetrics(SM_CXSCREEN);
2648     ok(w == 640, "Got unexpected screen width %u.\n", w);
2649     h = GetSystemMetrics(SM_CYSCREEN);
2650     ok(h == 480, "Got unexpected screen height %u.\n", h);
2651
2652     hr = IDirectDraw2_SetCooperativeLevel(ddraw2, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2653     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2654
2655     ref = IDirectDraw2_Release(ddraw1);
2656     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2657     w = GetSystemMetrics(SM_CXSCREEN);
2658     ok(w == 640, "Got unexpected screen width %u.\n", w);
2659     h = GetSystemMetrics(SM_CYSCREEN);
2660     ok(h == 480, "Got unexpected screen height %u.\n", h);
2661
2662     ref = IDirectDraw2_Release(ddraw2);
2663     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2664     w = GetSystemMetrics(SM_CXSCREEN);
2665     ok(w == orig_w, "Got unexpected screen width %u.\n", w);
2666     h = GetSystemMetrics(SM_CYSCREEN);
2667     ok(h == orig_h, "Got unexpected screen height %u.\n", h);
2668
2669     /* Exclusive mode blocks mode setting on other ddraw objects in general. */
2670     ddraw1 = create_ddraw();
2671     hr = IDirectDraw2_SetDisplayMode(ddraw1, 800, 600, 32, 0, 0);
2672     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
2673     w = GetSystemMetrics(SM_CXSCREEN);
2674     ok(w == 800, "Got unexpected screen width %u.\n", w);
2675     h = GetSystemMetrics(SM_CYSCREEN);
2676     ok(h == 600, "Got unexpected screen height %u.\n", h);
2677
2678     hr = IDirectDraw2_SetCooperativeLevel(ddraw1, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2679     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2680
2681     ddraw2 = create_ddraw();
2682     hr = IDirectDraw2_SetDisplayMode(ddraw2, 640, 480, 32, 0, 0);
2683     ok(hr == DDERR_NOEXCLUSIVEMODE, "Got unexpected hr %#x.\n", hr);
2684
2685     ref = IDirectDraw2_Release(ddraw1);
2686     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2687     w = GetSystemMetrics(SM_CXSCREEN);
2688     ok(w == orig_w, "Got unexpected screen width %u.\n", w);
2689     h = GetSystemMetrics(SM_CYSCREEN);
2690     ok(h == orig_h, "Got unexpected screen height %u.\n", h);
2691
2692     ref = IDirectDraw2_Release(ddraw2);
2693     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2694     w = GetSystemMetrics(SM_CXSCREEN);
2695     ok(w == orig_w, "Got unexpected screen width %u.\n", w);
2696     h = GetSystemMetrics(SM_CYSCREEN);
2697     ok(h == orig_h, "Got unexpected screen height %u.\n", h);
2698
2699     DestroyWindow(window);
2700 }
2701
2702 static void test_initialize(void)
2703 {
2704     IDirectDraw2 *ddraw;
2705     HRESULT hr;
2706
2707     if (!(ddraw = create_ddraw()))
2708     {
2709         skip("Failed to create a ddraw object, skipping test.\n");
2710         return;
2711     }
2712
2713     hr = IDirectDraw2_Initialize(ddraw, NULL);
2714     ok(hr == DDERR_ALREADYINITIALIZED, "Initialize returned hr %#x.\n", hr);
2715     IDirectDraw2_Release(ddraw);
2716
2717     CoInitialize(NULL);
2718     hr = CoCreateInstance(&CLSID_DirectDraw, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectDraw2, (void **)&ddraw);
2719     ok(SUCCEEDED(hr), "Failed to create IDirectDraw2 instance, hr %#x.\n", hr);
2720     hr = IDirectDraw2_Initialize(ddraw, NULL);
2721     ok(hr == DD_OK, "Initialize returned hr %#x, expected DD_OK.\n", hr);
2722     hr = IDirectDraw2_Initialize(ddraw, NULL);
2723     ok(hr == DDERR_ALREADYINITIALIZED, "Initialize returned hr %#x, expected DDERR_ALREADYINITIALIZED.\n", hr);
2724     IDirectDraw2_Release(ddraw);
2725     CoUninitialize();
2726 }
2727
2728 static void test_coop_level_surf_create(void)
2729 {
2730     IDirectDrawSurface *surface;
2731     IDirectDraw2 *ddraw;
2732     DDSURFACEDESC ddsd;
2733     HRESULT hr;
2734
2735     if (!(ddraw = create_ddraw()))
2736     {
2737         skip("Failed to create a ddraw object, skipping test.\n");
2738         return;
2739     }
2740
2741     memset(&ddsd, 0, sizeof(ddsd));
2742     ddsd.dwSize = sizeof(ddsd);
2743     ddsd.dwFlags = DDSD_CAPS;
2744     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2745     hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &surface, NULL);
2746     ok(hr == DDERR_NOCOOPERATIVELEVELSET, "Surface creation returned hr %#x.\n", hr);
2747
2748     IDirectDraw2_Release(ddraw);
2749 }
2750
2751 START_TEST(ddraw2)
2752 {
2753     test_coop_level_create_device_window();
2754     test_clipper_blt();
2755     test_coop_level_d3d_state();
2756     test_surface_interface_mismatch();
2757     test_coop_level_threaded();
2758     test_depth_blit();
2759     test_texture_load_ckey();
2760     test_viewport_interfaces();
2761     test_zenable();
2762     test_ck_rgba();
2763     test_ck_default();
2764     test_surface_qi();
2765     test_device_qi();
2766     test_wndproc();
2767     test_window_style();
2768     test_redundant_mode_set();
2769     test_coop_level_mode_set();
2770     test_coop_level_mode_set_multi();
2771     test_initialize();
2772     test_coop_level_surf_create();
2773 }