wbemprox: Add support for enumerating class properties.
[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, *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(rgn_data->rdh.nRgnSize == 16 || broken(rgn_data->rdh.nRgnSize == 168 /* NT4 */),
549             "Got unexpected region size %u.\n", rgn_data->rdh.nRgnSize);
550     ok(EqualRect(&rgn_data->rdh.rcBound, &client_rect),
551             "Got unexpected bounding rect {%d, %d, %d, %d}, expected {%d, %d, %d, %d}.\n",
552             rgn_data->rdh.rcBound.left, rgn_data->rdh.rcBound.top,
553             rgn_data->rdh.rcBound.right, rgn_data->rdh.rcBound.bottom,
554             client_rect.left, client_rect.top, client_rect.right, client_rect.bottom);
555     rect = (RECT *)&rgn_data->Buffer[0];
556     ok(EqualRect(rect, &client_rect),
557             "Got unexpected clip rect {%d, %d, %d, %d}, expected {%d, %d, %d, %d}.\n",
558             rect->left, rect->top, rect->right, rect->bottom,
559             client_rect.left, client_rect.top, client_rect.right, client_rect.bottom);
560     HeapFree(GetProcessHeap(), 0, rgn_data);
561
562     r1 = CreateRectRgn(0, 0, 320, 240);
563     ok(!!r1, "Failed to create region.\n");
564     r2 = CreateRectRgn(320, 240, 640, 480);
565     ok(!!r2, "Failed to create region.\n");
566     CombineRgn(r1, r1, r2, RGN_OR);
567     ret = GetRegionData(r1, 0, NULL);
568     rgn_data = HeapAlloc(GetProcessHeap(), 0, ret);
569     ret = GetRegionData(r1, ret, rgn_data);
570     ok(!!ret, "Failed to get region data.\n");
571
572     DeleteObject(r2);
573     DeleteObject(r1);
574
575     hr = IDirectDrawClipper_SetClipList(clipper, rgn_data, 0);
576     ok(hr == DDERR_CLIPPERISUSINGHWND, "Got unexpected hr %#x.\n", hr);
577     hr = IDirectDrawClipper_SetHWnd(clipper, 0, NULL);
578     ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
579     hr = IDirectDrawClipper_SetClipList(clipper, rgn_data, 0);
580     ok(SUCCEEDED(hr), "Failed to set clip list, hr %#x.\n", hr);
581
582     HeapFree(GetProcessHeap(), 0, rgn_data);
583
584     memset(&surface_desc, 0, sizeof(surface_desc));
585     surface_desc.dwSize = sizeof(surface_desc);
586     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
587     surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
588     surface_desc.dwWidth = 640;
589     surface_desc.dwHeight = 480;
590     surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
591     surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
592     U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
593     U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
594     U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
595     U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
596
597     hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &src_surface, NULL);
598     ok(SUCCEEDED(hr), "Failed to create source surface, hr %#x.\n", hr);
599     hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &dst_surface, NULL);
600     ok(SUCCEEDED(hr), "Failed to create destination surface, hr %#x.\n", hr);
601
602     memset(&fx, 0, sizeof(fx));
603     fx.dwSize = sizeof(fx);
604     hr = IDirectDrawSurface_Blt(src_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
605     ok(SUCCEEDED(hr), "Failed to clear source surface, hr %#x.\n", hr);
606     hr = IDirectDrawSurface_Blt(dst_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
607     ok(SUCCEEDED(hr), "Failed to clear destination surface, hr %#x.\n", hr);
608
609     hr = IDirectDrawSurface_Lock(src_surface, NULL, &surface_desc, DDLOCK_WAIT, NULL);
610     ok(SUCCEEDED(hr), "Failed to lock source surface, hr %#x.\n", hr);
611     ok(U1(surface_desc).lPitch == 2560, "Got unexpected surface pitch %u.\n", U1(surface_desc).lPitch);
612     ptr = surface_desc.lpSurface;
613     memcpy(&ptr[   0], &src_data[ 0], 6 * sizeof(DWORD));
614     memcpy(&ptr[ 640], &src_data[ 6], 6 * sizeof(DWORD));
615     memcpy(&ptr[1280], &src_data[12], 6 * sizeof(DWORD));
616     hr = IDirectDrawSurface_Unlock(src_surface, NULL);
617     ok(SUCCEEDED(hr), "Failed to unlock source surface, hr %#x.\n", hr);
618
619     hr = IDirectDrawSurface_SetClipper(dst_surface, clipper);
620     ok(SUCCEEDED(hr), "Failed to set clipper, hr %#x.\n", hr);
621
622     SetRect(&src_rect, 1, 1, 5, 2);
623     hr = IDirectDrawSurface_Blt(dst_surface, NULL, src_surface, &src_rect, DDBLT_WAIT, NULL);
624     ok(SUCCEEDED(hr), "Failed to blit, hr %#x.\n", hr);
625     for (i = 0; i < 4; ++i)
626     {
627         for (j = 0; j < 4; ++j)
628         {
629             x = 80 * ((2 * j) + 1);
630             y = 60 * ((2 * i) + 1);
631             color = get_surface_color(dst_surface, x, y);
632             ok(compare_color(color, expected1[i * 4 + j], 1),
633                     "Expected color 0x%08x at %u,%u, got 0x%08x.\n", expected1[i * 4 + j], x, y, color);
634         }
635     }
636
637     U5(fx).dwFillColor = 0xff0000ff;
638     hr = IDirectDrawSurface_Blt(dst_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
639     ok(SUCCEEDED(hr), "Failed to clear destination surface, hr %#x.\n", hr);
640     for (i = 0; i < 4; ++i)
641     {
642         for (j = 0; j < 4; ++j)
643         {
644             x = 80 * ((2 * j) + 1);
645             y = 60 * ((2 * i) + 1);
646             color = get_surface_color(dst_surface, x, y);
647             ok(compare_color(color, expected2[i * 4 + j], 1),
648                     "Expected color 0x%08x at %u,%u, got 0x%08x.\n", expected2[i * 4 + j], x, y, color);
649         }
650     }
651
652     hr = IDirectDrawSurface_BltFast(dst_surface, 0, 0, src_surface, NULL, DDBLTFAST_WAIT);
653     ok(hr == DDERR_BLTFASTCANTCLIP || broken(hr == E_NOTIMPL /* NT4 */), "Got unexpected hr %#x.\n", hr);
654
655     hr = IDirectDrawClipper_SetHWnd(clipper, 0, window);
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     DestroyWindow(window);
660     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
661     ok(hr == E_FAIL, "Got unexpected hr %#x.\n", hr);
662     hr = IDirectDrawClipper_SetHWnd(clipper, 0, NULL);
663     ok(SUCCEEDED(hr), "Failed to set clipper window, hr %#x.\n", hr);
664     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
665     ok(SUCCEEDED(hr), "Failed to get clip list size, hr %#x.\n", hr);
666     hr = IDirectDrawClipper_SetClipList(clipper, NULL, 0);
667     ok(SUCCEEDED(hr), "Failed to set clip list, hr %#x.\n", hr);
668     hr = IDirectDrawClipper_GetClipList(clipper, NULL, NULL, &ret);
669     ok(hr == DDERR_NOCLIPLIST, "Got unexpected hr %#x.\n", hr);
670     hr = IDirectDrawSurface_Blt(dst_surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
671     ok(hr == DDERR_NOCLIPLIST, "Got unexpected hr %#x.\n", hr);
672
673     IDirectDrawSurface_Release(dst_surface);
674     IDirectDrawSurface_Release(src_surface);
675     IDirectDrawClipper_Release(clipper);
676     IDirectDraw2_Release(ddraw);
677 }
678
679 static void test_coop_level_d3d_state(void)
680 {
681     D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
682     IDirectDrawSurface *rt, *surface;
683     IDirect3DMaterial2 *background;
684     IDirect3DViewport2 *viewport;
685     IDirect3DDevice2 *device;
686     D3DMATERIAL material;
687     IDirectDraw2 *ddraw;
688     D3DCOLOR color;
689     DWORD value;
690     HWND window;
691     HRESULT hr;
692
693     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
694             0, 0, 640, 480, 0, 0, 0, 0);
695     if (!(ddraw = create_ddraw()))
696     {
697         skip("Failed to create ddraw object, skipping test.\n");
698         DestroyWindow(window);
699         return;
700     }
701     if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
702     {
703         skip("Failed to create D3D device, skipping test.\n");
704         IDirectDraw2_Release(ddraw);
705         DestroyWindow(window);
706         return;
707     }
708
709     background = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
710     viewport = create_viewport(device, 0, 0, 640, 480);
711     viewport_set_background(device, viewport, background);
712
713     hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
714     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
715     hr = IDirect3DDevice2_GetRenderState(device, D3DRENDERSTATE_ZENABLE, &value);
716     ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr);
717     ok(!!value, "Got unexpected z-enable state %#x.\n", value);
718     hr = IDirect3DDevice2_GetRenderState(device, D3DRENDERSTATE_ALPHABLENDENABLE, &value);
719     ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr);
720     ok(!value, "Got unexpected alpha blend enable state %#x.\n", value);
721     hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);
722     ok(SUCCEEDED(hr), "Failed to set render state, hr %#x.\n", hr);
723     hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
724     ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
725     color = get_surface_color(rt, 320, 240);
726     ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
727
728     hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
729     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
730     hr = IDirectDrawSurface_IsLost(rt);
731     ok(hr == DDERR_SURFACELOST, "Got unexpected hr %#x.\n", hr);
732     hr = restore_surfaces(ddraw);
733     ok(SUCCEEDED(hr), "Failed to restore surfaces, hr %#x.\n", hr);
734
735     memset(&material, 0, sizeof(material));
736     material.dwSize = sizeof(material);
737     U1(U(material).diffuse).r = 0.0f;
738     U2(U(material).diffuse).g = 1.0f;
739     U3(U(material).diffuse).b = 0.0f;
740     U4(U(material).diffuse).a = 1.0f;
741     hr = IDirect3DMaterial2_SetMaterial(background, &material);
742     ok(SUCCEEDED(hr), "Failed to set material data, hr %#x.\n", hr);
743
744     hr = IDirect3DDevice2_GetRenderTarget(device, &surface);
745     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
746     ok(surface == rt, "Got unexpected surface %p.\n", surface);
747     hr = IDirect3DDevice2_GetRenderState(device, D3DRENDERSTATE_ZENABLE, &value);
748     ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr);
749     ok(!!value, "Got unexpected z-enable state %#x.\n", value);
750     hr = IDirect3DDevice2_GetRenderState(device, D3DRENDERSTATE_ALPHABLENDENABLE, &value);
751     ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr);
752     ok(!!value, "Got unexpected alpha blend enable state %#x.\n", value);
753     hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
754     ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
755     color = get_surface_color(rt, 320, 240);
756     ok(compare_color(color, 0x0000ff00, 1), "Got unexpected color 0x%08x.\n", color);
757
758     destroy_viewport(device, viewport);
759     destroy_material(background);
760     IDirectDrawSurface_Release(surface);
761     IDirectDrawSurface_Release(rt);
762     IDirect3DDevice2_Release(device);
763     IDirectDraw2_Release(ddraw);
764     DestroyWindow(window);
765 }
766
767 static void test_surface_interface_mismatch(void)
768 {
769     IDirectDraw2 *ddraw = NULL;
770     IDirect3D2 *d3d = NULL;
771     IDirectDrawSurface *surface = NULL, *ds;
772     IDirectDrawSurface3 *surface3 = NULL;
773     IDirect3DDevice2 *device = NULL;
774     IDirect3DViewport2 *viewport = NULL;
775     IDirect3DMaterial2 *background = NULL;
776     DDSURFACEDESC surface_desc;
777     DWORD z_depth = 0;
778     ULONG refcount;
779     HRESULT hr;
780     D3DCOLOR color;
781     HWND window;
782     D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
783
784     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
785             0, 0, 640, 480, 0, 0, 0, 0);
786
787     if (!(ddraw = create_ddraw()))
788     {
789         skip("Failed to create a ddraw object, skipping test.\n");
790         goto cleanup;
791     }
792
793     hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
794     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
795
796     memset(&surface_desc, 0, sizeof(surface_desc));
797     surface_desc.dwSize = sizeof(surface_desc);
798     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
799     surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
800     surface_desc.dwWidth = 640;
801     surface_desc.dwHeight = 480;
802
803     hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
804     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
805
806     hr = IDirectDrawSurface2_QueryInterface(surface, &IID_IDirectDrawSurface3, (void **)&surface3);
807     if (FAILED(hr))
808     {
809         skip("Failed to get the IDirectDrawSurface3 interface, skipping test.\n");
810         goto cleanup;
811     }
812
813     hr = IDirectDraw2_QueryInterface(ddraw, &IID_IDirect3D2, (void **)&d3d);
814     if (FAILED(hr))
815     {
816         skip("Failed to get the IDirect3D2 interface, skipping test.\n");
817         goto cleanup;
818     }
819
820     hr = IDirect3D2_EnumDevices(d3d, enum_z_fmt, &z_depth);
821     if (FAILED(hr) || !z_depth)
822     {
823         skip("No depth buffer formats available, skipping test.\n");
824         goto cleanup;
825     }
826
827     memset(&surface_desc, 0, sizeof(surface_desc));
828     surface_desc.dwSize = sizeof(surface_desc);
829     surface_desc.dwFlags = DDSD_CAPS | DDSD_ZBUFFERBITDEPTH | DDSD_WIDTH | DDSD_HEIGHT;
830     surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
831     U2(surface_desc).dwZBufferBitDepth = z_depth;
832     surface_desc.dwWidth = 640;
833     surface_desc.dwHeight = 480;
834     hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &ds, NULL);
835     ok(SUCCEEDED(hr), "Failed to create depth buffer, hr %#x.\n", hr);
836     if (FAILED(hr))
837         goto cleanup;
838
839     /* Using a different surface interface version still works */
840     hr = IDirectDrawSurface3_AddAttachedSurface(surface3, (IDirectDrawSurface3 *)ds);
841     ok(SUCCEEDED(hr), "Failed to attach depth buffer, hr %#x.\n", hr);
842     refcount = IDirectDrawSurface_Release(ds);
843     ok(refcount == 1, "Got unexpected refcount %u.\n", refcount);
844     if (FAILED(hr))
845         goto cleanup;
846
847     /* Here too */
848     hr = IDirect3D2_CreateDevice(d3d, &IID_IDirect3DHALDevice, (IDirectDrawSurface *)surface3, &device);
849     ok(SUCCEEDED(hr), "Failed to create d3d device.\n");
850     if (FAILED(hr))
851         goto cleanup;
852
853     background = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
854     viewport = create_viewport(device, 0, 0, 640, 480);
855     viewport_set_background(device, viewport, background);
856
857     hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
858     ok(SUCCEEDED(hr), "Failed to clear render target, hr %#x.\n", hr);
859     color = get_surface_color(surface, 320, 240);
860     ok(compare_color(color, 0x00ff0000, 1), "Got unexpected color 0x%08x.\n", color);
861
862 cleanup:
863     if (viewport)
864         destroy_viewport(device, viewport);
865     if (background)
866         destroy_material(background);
867     if (surface3) IDirectDrawSurface3_Release(surface3);
868     if (surface) IDirectDrawSurface_Release(surface);
869     if (device) IDirect3DDevice2_Release(device);
870     if (d3d) IDirect3D2_Release(d3d);
871     if (ddraw) IDirectDraw2_Release(ddraw);
872     DestroyWindow(window);
873 }
874
875 static void test_coop_level_threaded(void)
876 {
877     struct create_window_thread_param p;
878     IDirectDraw2 *ddraw;
879     HRESULT hr;
880
881     if (!(ddraw = create_ddraw()))
882     {
883         skip("Failed to create a ddraw object, skipping test.\n");
884         return;
885     }
886     create_window_thread(&p);
887
888     hr = IDirectDraw2_SetCooperativeLevel(ddraw, p.window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
889     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
890
891     IDirectDraw2_Release(ddraw);
892     destroy_window_thread(&p);
893 }
894
895 static void test_depth_blit(void)
896 {
897     static D3DLVERTEX quad1[] =
898     {
899         {{-1.0}, { 1.0}, {0.50f}, 0, {0xff00ff00}},
900         {{ 1.0}, { 1.0}, {0.50f}, 0, {0xff00ff00}},
901         {{-1.0}, {-1.0}, {0.50f}, 0, {0xff00ff00}},
902         {{ 1.0}, {-1.0}, {0.50f}, 0, {0xff00ff00}},
903     };
904     static const D3DCOLOR expected_colors[4][4] =
905     {
906         {0x00ff0000, 0x00ff0000, 0x0000ff00, 0x0000ff00},
907         {0x00ff0000, 0x00ff0000, 0x0000ff00, 0x0000ff00},
908         {0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00},
909         {0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00},
910     };
911     static const BOOL todo[4][4] =
912     {
913         {FALSE, FALSE, TRUE, TRUE},
914         {FALSE, FALSE, TRUE, TRUE},
915         {TRUE,  TRUE,  TRUE, TRUE},
916         {TRUE,  TRUE,  TRUE, TRUE},
917     };
918     DDSURFACEDESC ddsd_new, ddsd_existing;
919
920     IDirect3DDevice2 *device;
921     IDirectDrawSurface *ds1, *ds2, *ds3, *rt;
922     IDirect3DViewport2 *viewport;
923     RECT src_rect, dst_rect;
924     unsigned int i, j;
925     D3DCOLOR color;
926     HRESULT hr;
927     IDirectDraw2 *ddraw;
928     DDBLTFX fx;
929     HWND window;
930     D3DRECT d3drect;
931     IDirect3DMaterial2 *background;
932
933     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
934             0, 0, 640, 480, 0, 0, 0, 0);
935     if (!(ddraw = create_ddraw()))
936     {
937         skip("Failed to create ddraw object, skipping test.\n");
938         DestroyWindow(window);
939         return;
940     }
941     if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
942     {
943         skip("Failed to create D3D device, skipping test.\n");
944         IDirectDraw2_Release(ddraw);
945         DestroyWindow(window);
946         return;
947     }
948
949     ds1 = get_depth_stencil(device);
950
951     memset(&ddsd_new, 0, sizeof(ddsd_new));
952     ddsd_new.dwSize = sizeof(ddsd_new);
953     memset(&ddsd_existing, 0, sizeof(ddsd_existing));
954     ddsd_existing.dwSize = sizeof(ddsd_existing);
955     hr = IDirectDrawSurface_GetSurfaceDesc(ds1, &ddsd_existing);
956     ddsd_new.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
957     ddsd_new.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
958     ddsd_new.dwWidth = ddsd_existing.dwWidth;
959     ddsd_new.dwHeight = ddsd_existing.dwHeight;
960     ddsd_new.ddpfPixelFormat = ddsd_existing.ddpfPixelFormat;
961     hr = IDirectDraw2_CreateSurface(ddraw, &ddsd_new, &ds2, NULL);
962     ok(SUCCEEDED(hr), "Failed to create a surface, hr %#x.\n", hr);
963     hr = IDirectDraw2_CreateSurface(ddraw, &ddsd_new, &ds3, NULL);
964     ok(SUCCEEDED(hr), "Failed to create a surface, hr %#x.\n", hr);
965
966     background = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
967     viewport = create_viewport(device, 0, 0, ddsd_existing.dwWidth, ddsd_existing.dwHeight);
968     viewport_set_background(device, viewport, background);
969     hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
970     ok(SUCCEEDED(hr), "Failed to activate the viewport, hr %#x.\n", hr);
971
972     hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ZENABLE, D3DZB_TRUE);
973     ok(SUCCEEDED(hr), "Failed to enable z testing, hr %#x.\n", hr);
974     hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ZFUNC, D3DCMP_LESSEQUAL);
975     ok(SUCCEEDED(hr), "Failed to set the z function, hr %#x.\n", hr);
976
977     U1(d3drect).x1 = U2(d3drect).y1 = 0;
978     U3(d3drect).x2 = ddsd_existing.dwWidth; U4(d3drect).y2 = ddsd_existing.dwHeight;
979     hr = IDirect3DViewport2_Clear(viewport, 1, &d3drect, D3DCLEAR_ZBUFFER);
980     ok(SUCCEEDED(hr), "Failed to clear the z buffer, hr %#x.\n", hr);
981
982     /* Partial blit. */
983     SetRect(&src_rect, 0, 0, 320, 240);
984     SetRect(&dst_rect, 0, 0, 320, 240);
985     hr = IDirectDrawSurface_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
986     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
987     /* Different locations. */
988     SetRect(&src_rect, 0, 0, 320, 240);
989     SetRect(&dst_rect, 320, 240, 640, 480);
990     hr = IDirectDrawSurface_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
991     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
992     /* Streched. */
993     SetRect(&src_rect, 0, 0, 320, 240);
994     SetRect(&dst_rect, 0, 0, 640, 480);
995     hr = IDirectDrawSurface_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
996     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
997     /* Flipped. */
998     SetRect(&src_rect, 0, 480, 640, 0);
999     SetRect(&dst_rect, 0, 0, 640, 480);
1000     hr = IDirectDrawSurface_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
1001     ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#x.\n", hr);
1002     SetRect(&src_rect, 0, 0, 640, 480);
1003     SetRect(&dst_rect, 0, 480, 640, 0);
1004     hr = IDirectDrawSurface_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
1005     ok(hr == DDERR_INVALIDRECT, "Got unexpected hr %#x.\n", hr);
1006     /* Full, explicit. */
1007     SetRect(&src_rect, 0, 0, 640, 480);
1008     SetRect(&dst_rect, 0, 0, 640, 480);
1009     hr = IDirectDrawSurface_Blt(ds2, &dst_rect, ds1, &src_rect, DDBLT_WAIT, NULL);
1010     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1011     /* Depth -> color blit: Succeeds on Win7 + Radeon HD 5700, fails on WinXP + Radeon X1600 */
1012
1013     /* Depth blit inside a BeginScene / EndScene pair */
1014     hr = IDirect3DDevice2_BeginScene(device);
1015     ok(SUCCEEDED(hr), "Failed to start a scene, hr %#x.\n", hr);
1016     /* From the current depth stencil */
1017     hr = IDirectDrawSurface_Blt(ds2, NULL, ds1, NULL, DDBLT_WAIT, NULL);
1018     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1019     /* To the current depth stencil */
1020     hr = IDirectDrawSurface_Blt(ds1, NULL, ds2, NULL, DDBLT_WAIT, NULL);
1021     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1022     /* Between unbound surfaces */
1023     hr = IDirectDrawSurface_Blt(ds3, NULL, ds2, NULL, DDBLT_WAIT, NULL);
1024     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1025     hr = IDirect3DDevice2_EndScene(device);
1026     ok(SUCCEEDED(hr), "Failed to end a scene, hr %#x.\n", hr);
1027
1028     /* Avoid changing the depth stencil, it doesn't work properly on Windows.
1029      * Instead use DDBLT_DEPTHFILL to clear the depth stencil. Unfortunately
1030      * drivers disagree on the meaning of dwFillDepth. Only 0 seems to produce
1031      * a reliable result(z = 0.0) */
1032     memset(&fx, 0, sizeof(fx));
1033     fx.dwSize = sizeof(fx);
1034     U5(fx).dwFillDepth = 0;
1035     hr = IDirectDrawSurface_Blt(ds2, NULL, NULL, NULL, DDBLT_DEPTHFILL | DDBLT_WAIT, &fx);
1036     ok(SUCCEEDED(hr), "Failed to clear the source z buffer, hr %#x.\n", hr);
1037
1038     /* This clears the Z buffer with 1.0 */
1039     hr = IDirect3DViewport2_Clear(viewport, 1, &d3drect, D3DCLEAR_ZBUFFER | D3DCLEAR_TARGET);
1040     ok(SUCCEEDED(hr), "Failed to clear the color and z buffers, hr %#x.\n", hr);
1041
1042     SetRect(&dst_rect, 0, 0, 320, 240);
1043     hr = IDirectDrawSurface_Blt(ds1, &dst_rect, ds2, NULL, DDBLT_WAIT, NULL);
1044     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1045     IDirectDrawSurface_Release(ds3);
1046     IDirectDrawSurface_Release(ds2);
1047     IDirectDrawSurface_Release(ds1);
1048
1049     hr = IDirect3DDevice2_BeginScene(device);
1050     ok(SUCCEEDED(hr), "Failed to start a scene, hr %#x.\n", hr);
1051     hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_LVERTEX, quad1, 4, 0);
1052     ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
1053     hr = IDirect3DDevice2_EndScene(device);
1054     ok(SUCCEEDED(hr), "Failed to end a scene, hr %#x.\n", hr);
1055
1056     hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
1057     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
1058     for (i = 0; i < 4; ++i)
1059     {
1060         for (j = 0; j < 4; ++j)
1061         {
1062             unsigned int x = 80 * ((2 * j) + 1);
1063             unsigned int y = 60 * ((2 * i) + 1);
1064             color = get_surface_color(rt, x, y);
1065             if (todo[i][j])
1066                 todo_wine ok(compare_color(color, expected_colors[i][j], 1),
1067                         "Expected color 0x%08x at %u,%u, got 0x%08x.\n", expected_colors[i][j], x, y, color);
1068             else
1069                 ok(compare_color(color, expected_colors[i][j], 1),
1070                         "Expected color 0x%08x at %u,%u, got 0x%08x.\n", expected_colors[i][j], x, y, color);
1071         }
1072     }
1073     IDirectDrawSurface_Release(rt);
1074
1075     destroy_viewport(device, viewport);
1076     destroy_material(background);
1077     IDirect3DDevice2_Release(device);
1078     IDirectDraw2_Release(ddraw);
1079     DestroyWindow(window);
1080 }
1081
1082 static void test_texture_load_ckey(void)
1083 {
1084     IDirectDraw2 *ddraw = NULL;
1085     IDirectDrawSurface *src = NULL;
1086     IDirectDrawSurface *dst = NULL;
1087     IDirect3DTexture *src_tex = NULL;
1088     IDirect3DTexture *dst_tex = NULL;
1089     DDSURFACEDESC ddsd;
1090     HRESULT hr;
1091     DDCOLORKEY ckey;
1092
1093     if (!(ddraw = create_ddraw()))
1094     {
1095         skip("Failed to create ddraw object, skipping test.\n");
1096         return;
1097     }
1098     hr = IDirectDraw2_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL);
1099     ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
1100
1101     memset(&ddsd, 0, sizeof(ddsd));
1102     ddsd.dwSize = sizeof(ddsd);
1103     ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
1104     ddsd.dwHeight = 128;
1105     ddsd.dwWidth = 128;
1106     ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_SYSTEMMEMORY;
1107     hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &src, NULL);
1108     ok(SUCCEEDED(hr), "Failed to create source texture, hr %#x.\n", hr);
1109     ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1110     hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &dst, NULL);
1111     ok(SUCCEEDED(hr), "Failed to create destination texture, hr %#x.\n", hr);
1112
1113     hr = IDirectDrawSurface_QueryInterface(src, &IID_IDirect3DTexture, (void **)&src_tex);
1114     ok(SUCCEEDED(hr) || hr == E_NOINTERFACE, "Failed to get Direct3DTexture interface, hr %#x.\n", hr);
1115     if (FAILED(hr))
1116     {
1117         /* 64 bit ddraw does not support d3d */
1118         skip("Could not get Direct3DTexture interface, skipping texture::Load color keying tests.\n");
1119         goto done;
1120     }
1121     hr = IDirectDrawSurface_QueryInterface(dst, &IID_IDirect3DTexture, (void **)&dst_tex);
1122     ok(SUCCEEDED(hr), "Failed to get Direct3DTexture interface, hr %#x.\n", hr);
1123
1124     /* No surface has a color key */
1125     hr = IDirect3DTexture_Load(dst_tex, src_tex);
1126     ok(SUCCEEDED(hr) || broken(hr == DDERR_INVALIDCAPS), "Got unexpected hr %#x.\n", hr);
1127     if (FAILED(hr))
1128     {
1129         /* Testbot Windows NT VMs */
1130         skip("IDirect3DTexture::Load does not work, skipping color keying tests.\n");
1131         goto done;
1132     }
1133
1134     ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0xdeadbeef;
1135     hr = IDirectDrawSurface_GetColorKey(dst, DDCKEY_SRCBLT, &ckey);
1136     ok(hr == DDERR_NOCOLORKEY, "Got unexpected hr %#x.\n", hr);
1137     ok(ckey.dwColorSpaceLowValue == 0xdeadbeef, "dwColorSpaceLowValue is %#x.\n", ckey.dwColorSpaceLowValue);
1138     ok(ckey.dwColorSpaceHighValue == 0xdeadbeef, "dwColorSpaceHighValue is %#x.\n", ckey.dwColorSpaceHighValue);
1139
1140     /* Source surface has a color key */
1141     ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0x0000ff00;
1142     hr = IDirectDrawSurface_SetColorKey(src, DDCKEY_SRCBLT, &ckey);
1143     ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
1144     hr = IDirect3DTexture_Load(dst_tex, src_tex);
1145     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1146     hr = IDirectDrawSurface_GetColorKey(dst, DDCKEY_SRCBLT, &ckey);
1147     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1148     ok(ckey.dwColorSpaceLowValue == 0x0000ff00, "dwColorSpaceLowValue is %#x.\n", ckey.dwColorSpaceLowValue);
1149     ok(ckey.dwColorSpaceHighValue == 0x0000ff00, "dwColorSpaceHighValue is %#x.\n", ckey.dwColorSpaceHighValue);
1150
1151     /* Both surfaces have a color key: Dest ckey is overwritten */
1152     ckey.dwColorSpaceLowValue = ckey.dwColorSpaceHighValue = 0x000000ff;
1153     hr = IDirectDrawSurface_SetColorKey(dst, DDCKEY_SRCBLT, &ckey);
1154     ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
1155     hr = IDirect3DTexture_Load(dst_tex, src_tex);
1156     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1157     hr = IDirectDrawSurface_GetColorKey(dst, DDCKEY_SRCBLT, &ckey);
1158     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1159     ok(ckey.dwColorSpaceLowValue == 0x0000ff00, "dwColorSpaceLowValue is %#x.\n", ckey.dwColorSpaceLowValue);
1160     ok(ckey.dwColorSpaceHighValue == 0x0000ff00, "dwColorSpaceHighValue is %#x.\n", ckey.dwColorSpaceHighValue);
1161
1162     /* Only the destination has a color key: It is not deleted */
1163     hr = IDirectDrawSurface_SetColorKey(src, DDCKEY_SRCBLT, NULL);
1164     ok(SUCCEEDED(hr), "Failed to set color key, hr %#x.\n", hr);
1165     hr = IDirectDrawSurface_GetColorKey(src, DDCKEY_SRCBLT, &ckey);
1166     ok(hr == DDERR_NOCOLORKEY, "Got unexpected hr %#x.\n", hr);
1167     hr = IDirect3DTexture_Load(dst_tex, src_tex);
1168     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1169     hr = IDirectDrawSurface_GetColorKey(dst, DDCKEY_SRCBLT, &ckey);
1170     ok(SUCCEEDED(hr), "Got unexpected hr %#x.\n", hr);
1171     ok(ckey.dwColorSpaceLowValue == 0x0000ff00, "dwColorSpaceLowValue is %#x.\n", ckey.dwColorSpaceLowValue);
1172     ok(ckey.dwColorSpaceHighValue == 0x0000ff00, "dwColorSpaceHighValue is %#x.\n", ckey.dwColorSpaceHighValue);
1173
1174 done:
1175     if (dst_tex) IDirect3DTexture_Release(dst_tex);
1176     if (src_tex) IDirect3DTexture_Release(src_tex);
1177     if (dst) IDirectDrawSurface_Release(dst);
1178     if (src) IDirectDrawSurface_Release(src);
1179     if (ddraw) IDirectDraw2_Release(ddraw);
1180 }
1181
1182 static ULONG get_refcount(IUnknown *test_iface)
1183 {
1184     IUnknown_AddRef(test_iface);
1185     return IUnknown_Release(test_iface);
1186 }
1187
1188 static void test_viewport_interfaces(void)
1189 {
1190     IDirectDraw2 *ddraw;
1191     IDirect3D2 *d3d;
1192     HRESULT hr;
1193     ULONG ref, old_d3d_ref;
1194     IDirect3DViewport *viewport;
1195     IDirect3DViewport2 *viewport2;
1196     IDirect3DViewport3 *viewport3;
1197     IDirectDrawGammaControl *gamma;
1198     IUnknown *unknown;
1199
1200     if (!(ddraw = create_ddraw()))
1201     {
1202         skip("Failed to create ddraw object, skipping test.\n");
1203         return;
1204     }
1205
1206     hr = IDirectDraw2_QueryInterface(ddraw, &IID_IDirect3D2, (void **)&d3d);
1207     ok(SUCCEEDED(hr) || hr == E_NOINTERFACE, "Failed to get d3d interface, hr %#x.\n", hr);
1208     if (FAILED(hr))
1209     {
1210         skip("Direct3D not available, skipping tests\n");
1211         IDirectDraw2_Release(ddraw);
1212         return;
1213     }
1214     old_d3d_ref = get_refcount((IUnknown *)d3d);
1215
1216     hr = IDirect3D2_CreateViewport(d3d, &viewport2, NULL);
1217     ok(SUCCEEDED(hr), "Failed to create viewport, hr %#x.\n", hr);
1218     ref = get_refcount((IUnknown *)viewport2);
1219     ok(ref == 1, "Initial IDirect3DViewport2 refcount is %u\n", ref);
1220     ref = get_refcount((IUnknown *)d3d);
1221     ok(ref == old_d3d_ref, "IDirect3D2 refcount is %u\n", ref);
1222
1223     gamma = (IDirectDrawGammaControl *)0xdeadbeef;
1224     hr = IDirect3DViewport2_QueryInterface(viewport2, &IID_IDirectDrawGammaControl, (void **)&gamma);
1225     ok(hr == E_NOINTERFACE, "Got unexpected hr %#x.\n", hr);
1226     ok(gamma == NULL, "Interface not set to NULL by failed QI call: %p\n", gamma);
1227     if (SUCCEEDED(hr)) IDirectDrawGammaControl_Release(gamma);
1228     /* NULL iid: Segfaults */
1229
1230     hr = IDirect3DViewport2_QueryInterface(viewport2, &IID_IDirect3DViewport, (void **)&viewport);
1231     ok(SUCCEEDED(hr), "Failed to QI IDirect3DViewport, hr %#x.\n", hr);
1232     if (viewport)
1233     {
1234         ref = get_refcount((IUnknown *)viewport);
1235         ok(ref == 2, "IDirect3DViewport refcount is %u\n", ref);
1236         ref = get_refcount((IUnknown *)viewport2);
1237         ok(ref == 2, "IDirect3DViewport2 refcount is %u\n", ref);
1238         IDirect3DViewport_Release(viewport);
1239         viewport = NULL;
1240     }
1241
1242     hr = IDirect3DViewport2_QueryInterface(viewport2, &IID_IDirect3DViewport3, (void **)&viewport3);
1243     ok(SUCCEEDED(hr) || hr == E_NOINTERFACE, "Failed to QI IDirect3DViewport3, hr %#x.\n", hr);
1244     if (viewport3)
1245     {
1246         ref = get_refcount((IUnknown *)viewport2);
1247         ok(ref == 2, "IDirect3DViewport2 refcount is %u\n", ref);
1248         ref = get_refcount((IUnknown *)viewport3);
1249         ok(ref == 2, "IDirect3DViewport3 refcount is %u\n", ref);
1250         IDirect3DViewport3_Release(viewport3);
1251     }
1252
1253     hr = IDirect3DViewport2_QueryInterface(viewport2, &IID_IUnknown, (void **)&unknown);
1254     ok(SUCCEEDED(hr), "Failed to QI IUnknown, hr %#x.\n", hr);
1255     if (unknown)
1256     {
1257         ref = get_refcount((IUnknown *)viewport2);
1258         ok(ref == 2, "IDirect3DViewport2 refcount is %u\n", ref);
1259         ref = get_refcount(unknown);
1260         ok(ref == 2, "IUnknown refcount is %u\n", ref);
1261         IUnknown_Release(unknown);
1262     }
1263
1264     IDirect3DViewport2_Release(viewport2);
1265     IDirect3D2_Release(d3d);
1266     IDirectDraw2_Release(ddraw);
1267 }
1268
1269 static void test_zenable(void)
1270 {
1271     static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
1272     static D3DTLVERTEX tquad[] =
1273     {
1274         {{  0.0f}, {480.0f}, {-0.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}},
1275         {{  0.0f}, {  0.0f}, {-0.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}},
1276         {{640.0f}, {480.0f}, { 1.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}},
1277         {{640.0f}, {  0.0f}, { 1.5f}, {1.0f}, {0xff00ff00}, {0x00000000}, {0.0f}, {0.0f}},
1278     };
1279     IDirect3DMaterial2 *background;
1280     IDirect3DViewport2 *viewport;
1281     IDirect3DDevice2 *device;
1282     IDirectDrawSurface *rt;
1283     IDirectDraw2 *ddraw;
1284     D3DCOLOR color;
1285     HWND window;
1286     HRESULT hr;
1287     UINT x, y;
1288     UINT i, j;
1289
1290     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1291             0, 0, 640, 480, 0, 0, 0, 0);
1292     if (!(ddraw = create_ddraw()))
1293     {
1294         skip("Failed to create ddraw object, skipping test.\n");
1295         DestroyWindow(window);
1296         return;
1297     }
1298     if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
1299     {
1300         skip("Failed to create D3D device, skipping test.\n");
1301         IDirectDraw2_Release(ddraw);
1302         DestroyWindow(window);
1303         return;
1304     }
1305
1306     background = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
1307     viewport = create_viewport(device, 0, 0, 640, 480);
1308     viewport_set_background(device, viewport, background);
1309     hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
1310     ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#x.\n", hr);
1311
1312     hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ZENABLE, D3DZB_FALSE);
1313     ok(SUCCEEDED(hr), "Failed to disable z-buffering, hr %#x.\n", hr);
1314
1315     hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
1316     ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
1317     hr = IDirect3DDevice2_BeginScene(device);
1318     ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
1319     hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_TLVERTEX, tquad, 4, 0);
1320     ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
1321     hr = IDirect3DDevice2_EndScene(device);
1322     ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1323
1324     hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
1325     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
1326     for (i = 0; i < 4; ++i)
1327     {
1328         for (j = 0; j < 4; ++j)
1329         {
1330             x = 80 * ((2 * j) + 1);
1331             y = 60 * ((2 * i) + 1);
1332             color = get_surface_color(rt, x, y);
1333             ok(compare_color(color, 0x0000ff00, 1),
1334                     "Expected color 0x0000ff00 at %u, %u, got 0x%08x.\n", x, y, color);
1335         }
1336     }
1337     IDirectDrawSurface_Release(rt);
1338
1339     destroy_viewport(device, viewport);
1340     destroy_material(background);
1341     IDirect3DDevice2_Release(device);
1342     IDirectDraw2_Release(ddraw);
1343     DestroyWindow(window);
1344 }
1345
1346 static void test_ck_rgba(void)
1347 {
1348     static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
1349     static D3DTLVERTEX tquad[] =
1350     {
1351         {{  0.0f}, {480.0f}, {0.25f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {0.0f}},
1352         {{  0.0f}, {  0.0f}, {0.25f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {1.0f}},
1353         {{640.0f}, {480.0f}, {0.25f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {0.0f}},
1354         {{640.0f}, {  0.0f}, {0.25f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {1.0f}},
1355         {{  0.0f}, {480.0f}, {0.75f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {0.0f}},
1356         {{  0.0f}, {  0.0f}, {0.75f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {1.0f}},
1357         {{640.0f}, {480.0f}, {0.75f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {0.0f}},
1358         {{640.0f}, {  0.0f}, {0.75f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {1.0f}},
1359     };
1360     static const struct
1361     {
1362         D3DCOLOR fill_color;
1363         BOOL color_key;
1364         BOOL blend;
1365         D3DCOLOR result1;
1366         D3DCOLOR result2;
1367     }
1368     tests[] =
1369     {
1370         {0xff00ff00, TRUE,  TRUE,  0x00ff0000, 0x000000ff},
1371         {0xff00ff00, TRUE,  FALSE, 0x00ff0000, 0x000000ff},
1372         {0xff00ff00, FALSE, TRUE,  0x0000ff00, 0x0000ff00},
1373         {0xff00ff00, FALSE, FALSE, 0x0000ff00, 0x0000ff00},
1374         {0x7f00ff00, TRUE,  TRUE,  0x00807f00, 0x00807f00},
1375         {0x7f00ff00, TRUE,  FALSE, 0x0000ff00, 0x0000ff00},
1376         {0x7f00ff00, FALSE, TRUE,  0x00807f00, 0x00807f00},
1377         {0x7f00ff00, FALSE, FALSE, 0x0000ff00, 0x0000ff00},
1378     };
1379
1380     D3DTEXTUREHANDLE texture_handle;
1381     IDirect3DMaterial2 *background;
1382     IDirectDrawSurface *surface;
1383     IDirect3DViewport2 *viewport;
1384     IDirect3DTexture2 *texture;
1385     DDSURFACEDESC surface_desc;
1386     IDirect3DDevice2 *device;
1387     IDirectDrawSurface *rt;
1388     IDirectDraw2 *ddraw;
1389     D3DCOLOR color;
1390     HWND window;
1391     DDBLTFX fx;
1392     HRESULT hr;
1393     UINT i;
1394
1395     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1396             0, 0, 640, 480, 0, 0, 0, 0);
1397     if (!(ddraw = create_ddraw()))
1398     {
1399         skip("Failed to create ddraw object, skipping test.\n");
1400         DestroyWindow(window);
1401         return;
1402     }
1403     if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
1404     {
1405         skip("Failed to create D3D device, skipping test.\n");
1406         IDirectDraw2_Release(ddraw);
1407         DestroyWindow(window);
1408         return;
1409     }
1410
1411     background = create_diffuse_material(device, 1.0f, 0.0f, 0.0f, 1.0f);
1412     viewport = create_viewport(device, 0, 0, 640, 480);
1413     viewport_set_background(device, viewport, background);
1414     hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
1415     ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#x.\n", hr);
1416
1417     memset(&surface_desc, 0, sizeof(surface_desc));
1418     surface_desc.dwSize = sizeof(surface_desc);
1419     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CKSRCBLT;
1420     surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1421     surface_desc.dwWidth = 256;
1422     surface_desc.dwHeight = 256;
1423     surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
1424     surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
1425     U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
1426     U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
1427     U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
1428     U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
1429     U5(surface_desc.ddpfPixelFormat).dwRGBAlphaBitMask = 0xff000000;
1430     surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0xff00ff00;
1431     surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0xff00ff00;
1432     hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
1433     ok(SUCCEEDED(hr), "Failed to create destination surface, hr %#x.\n", hr);
1434     hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirect3DTexture2, (void **)&texture);
1435     ok(SUCCEEDED(hr), "Failed to get texture interface, hr %#x.\n", hr);
1436     hr = IDirect3DTexture2_GetHandle(texture, device, &texture_handle);
1437     ok(SUCCEEDED(hr), "Failed to get texture handle, hr %#x.\n", hr);
1438     IDirect3DTexture2_Release(texture);
1439
1440     hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_TEXTUREHANDLE, texture_handle);
1441     ok(SUCCEEDED(hr), "Failed to set texture, hr %#x.\n", hr);
1442     hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA);
1443     ok(SUCCEEDED(hr), "Failed to enable alpha blending, hr %#x.\n", hr);
1444     hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA);
1445     ok(SUCCEEDED(hr), "Failed to enable alpha blending, hr %#x.\n", hr);
1446
1447     hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
1448     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
1449
1450     for (i = 0; i < sizeof(tests) / sizeof(*tests); ++i)
1451     {
1452         hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_COLORKEYENABLE, tests[i].color_key);
1453         ok(SUCCEEDED(hr), "Failed to enable color keying, hr %#x.\n", hr);
1454         hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_ALPHABLENDENABLE, tests[i].blend);
1455         ok(SUCCEEDED(hr), "Failed to enable alpha blending, hr %#x.\n", hr);
1456
1457         memset(&fx, 0, sizeof(fx));
1458         fx.dwSize = sizeof(fx);
1459         U5(fx).dwFillColor = tests[i].fill_color;
1460         hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
1461         ok(SUCCEEDED(hr), "Failed to fill texture, hr %#x.\n", hr);
1462
1463         hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER);
1464         ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
1465         hr = IDirect3DDevice2_BeginScene(device);
1466         ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
1467         hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_TLVERTEX, &tquad[0], 4, 0);
1468         ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
1469         hr = IDirect3DDevice2_EndScene(device);
1470         ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1471
1472         color = get_surface_color(rt, 320, 240);
1473         if (i == 2)
1474             todo_wine ok(compare_color(color, tests[i].result1, 1), "Expected color 0x%08x for test %u, got 0x%08x.\n",
1475                     tests[i].result1, i, color);
1476         else
1477             ok(compare_color(color, tests[i].result1, 1), "Expected color 0x%08x for test %u, got 0x%08x.\n",
1478                     tests[i].result1, i, color);
1479
1480         U5(fx).dwFillColor = 0xff0000ff;
1481         hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
1482         ok(SUCCEEDED(hr), "Failed to fill texture, hr %#x.\n", hr);
1483
1484         hr = IDirect3DDevice2_BeginScene(device);
1485         ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
1486         hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_TLVERTEX, &tquad[4], 4, 0);
1487         ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
1488         hr = IDirect3DDevice2_EndScene(device);
1489         ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1490
1491         /* This tests that fragments that are masked out by the color key are
1492          * discarded, instead of just fully transparent. */
1493         color = get_surface_color(rt, 320, 240);
1494         if (i == 2)
1495             todo_wine ok(compare_color(color, tests[i].result2, 1), "Expected color 0x%08x for test %u, got 0x%08x.\n",
1496                     tests[i].result2, i, color);
1497         else
1498             ok(compare_color(color, tests[i].result2, 1), "Expected color 0x%08x for test %u, got 0x%08x.\n",
1499                     tests[i].result2, i, color);
1500     }
1501
1502     IDirectDrawSurface_Release(rt);
1503     hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_TEXTUREHANDLE, 0);
1504     ok(SUCCEEDED(hr), "Failed to unset texture, hr %#x.\n", hr);
1505     IDirectDrawSurface_Release(surface);
1506     destroy_viewport(device, viewport);
1507     destroy_material(background);
1508     IDirect3DDevice2_Release(device);
1509     IDirectDraw2_Release(ddraw);
1510     DestroyWindow(window);
1511 }
1512
1513 static void test_ck_default(void)
1514 {
1515     static D3DRECT clear_rect = {{0}, {0}, {640}, {480}};
1516     static D3DTLVERTEX tquad[] =
1517     {
1518         {{  0.0f}, {480.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {0.0f}},
1519         {{  0.0f}, {  0.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0x00000000}, {0.0f}, {1.0f}},
1520         {{640.0f}, {480.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {0.0f}},
1521         {{640.0f}, {  0.0f}, {0.0f}, {1.0f}, {0xffffffff}, {0x00000000}, {1.0f}, {1.0f}},
1522     };
1523     IDirectDrawSurface *surface, *rt;
1524     D3DTEXTUREHANDLE texture_handle;
1525     IDirect3DMaterial2 *background;
1526     IDirect3DViewport2 *viewport;
1527     DDSURFACEDESC surface_desc;
1528     IDirect3DTexture2 *texture;
1529     IDirect3DDevice2 *device;
1530     IDirectDraw2 *ddraw;
1531     D3DCOLOR color;
1532     DWORD value;
1533     HWND window;
1534     DDBLTFX fx;
1535     HRESULT hr;
1536
1537     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1538             0, 0, 640, 480, 0, 0, 0, 0);
1539
1540     if (!(ddraw = create_ddraw()))
1541     {
1542         skip("Failed to create ddraw object, skipping test.\n");
1543         DestroyWindow(window);
1544         return;
1545     }
1546     if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
1547     {
1548         skip("Failed to create D3D device, skipping test.\n");
1549         IDirectDraw2_Release(ddraw);
1550         DestroyWindow(window);
1551         return;
1552     }
1553
1554     hr = IDirect3DDevice2_GetRenderTarget(device, &rt);
1555     ok(SUCCEEDED(hr), "Failed to get render target, hr %#x.\n", hr);
1556
1557     background = create_diffuse_material(device, 0.0, 1.0f, 0.0f, 1.0f);
1558     viewport = create_viewport(device, 0, 0, 640, 480);
1559     viewport_set_background(device, viewport, background);
1560     hr = IDirect3DDevice2_SetCurrentViewport(device, viewport);
1561     ok(SUCCEEDED(hr), "Failed to set current viewport, hr %#x.\n", hr);
1562
1563     memset(&surface_desc, 0, sizeof(surface_desc));
1564     surface_desc.dwSize = sizeof(surface_desc);
1565     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CKSRCBLT;
1566     surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1567     surface_desc.dwWidth = 256;
1568     surface_desc.dwHeight = 256;
1569     surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
1570     surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB;
1571     U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 32;
1572     U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0x00ff0000;
1573     U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x0000ff00;
1574     U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x000000ff;
1575     surface_desc.ddckCKSrcBlt.dwColorSpaceLowValue = 0x000000ff;
1576     surface_desc.ddckCKSrcBlt.dwColorSpaceHighValue = 0x000000ff;
1577     hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
1578     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
1579     hr = IDirectDrawSurface_QueryInterface(surface, &IID_IDirect3DTexture2, (void **)&texture);
1580     ok(SUCCEEDED(hr), "Failed to get texture interface, hr %#x.\n", hr);
1581     hr = IDirect3DTexture2_GetHandle(texture, device, &texture_handle);
1582     ok(SUCCEEDED(hr), "Failed to get texture handle, hr %#x.\n", hr);
1583     IDirect3DTexture_Release(texture);
1584
1585     memset(&fx, 0, sizeof(fx));
1586     fx.dwSize = sizeof(fx);
1587     U5(fx).dwFillColor = 0x000000ff;
1588     hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
1589     ok(SUCCEEDED(hr), "Failed to fill surface, hr %#x.\n", hr);
1590
1591     hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
1592     ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
1593     hr = IDirect3DDevice2_BeginScene(device);
1594     ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
1595     hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_TEXTUREHANDLE, texture_handle);
1596     ok(SUCCEEDED(hr), "Failed to set texture handle, hr %#x.\n", hr);
1597     hr = IDirect3DDevice2_GetRenderState(device, D3DRENDERSTATE_COLORKEYENABLE, &value);
1598     ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr);
1599     ok(!value, "Got unexpected color keying state %#x.\n", value);
1600     hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_TLVERTEX, &tquad[0], 4, 0);
1601     ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
1602     hr = IDirect3DDevice2_EndScene(device);
1603     ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1604     color = get_surface_color(rt, 320, 240);
1605     ok(compare_color(color, 0x000000ff, 1), "Got unexpected color 0x%08x.\n", color);
1606
1607     hr = IDirect3DViewport2_Clear(viewport, 1, &clear_rect, D3DCLEAR_TARGET);
1608     ok(SUCCEEDED(hr), "Failed to clear viewport, hr %#x.\n", hr);
1609     hr = IDirect3DDevice2_BeginScene(device);
1610     ok(SUCCEEDED(hr), "Failed to begin scene, hr %#x.\n", hr);
1611     hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_COLORKEYENABLE, TRUE);
1612     ok(SUCCEEDED(hr), "Failed to enable color keying, hr %#x.\n", hr);
1613     hr = IDirect3DDevice2_DrawPrimitive(device, D3DPT_TRIANGLESTRIP, D3DVT_TLVERTEX, &tquad[0], 4, 0);
1614     ok(SUCCEEDED(hr), "Failed to draw, hr %#x.\n", hr);
1615     hr = IDirect3DDevice2_GetRenderState(device, D3DRENDERSTATE_COLORKEYENABLE, &value);
1616     ok(SUCCEEDED(hr), "Failed to get render state, hr %#x.\n", hr);
1617     ok(!!value, "Got unexpected color keying state %#x.\n", value);
1618     hr = IDirect3DDevice2_SetRenderState(device, D3DRENDERSTATE_TEXTUREHANDLE, 0);
1619     ok(SUCCEEDED(hr), "Failed to set texture handle, hr %#x.\n", hr);
1620     hr = IDirect3DDevice2_EndScene(device);
1621     ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
1622     color = get_surface_color(rt, 320, 240);
1623     ok(compare_color(color, 0x0000ff00, 1), "Got unexpected color 0x%08x.\n", color);
1624
1625     IDirectDrawSurface_Release(surface);
1626     destroy_viewport(device, viewport);
1627     destroy_material(background);
1628     IDirectDrawSurface_Release(rt);
1629     IDirect3DDevice2_Release(device);
1630     IDirectDraw2_Release(ddraw);
1631     DestroyWindow(window);
1632 }
1633
1634 struct qi_test
1635 {
1636     REFIID iid;
1637     REFIID refcount_iid;
1638     HRESULT hr;
1639 };
1640
1641 static void test_qi(const char *test_name, IUnknown *base_iface,
1642         REFIID refcount_iid, const struct qi_test *tests, UINT entry_count)
1643 {
1644     ULONG refcount, expected_refcount;
1645     IUnknown *iface1, *iface2;
1646     HRESULT hr;
1647     UINT i, j;
1648
1649     for (i = 0; i < entry_count; ++i)
1650     {
1651         hr = IUnknown_QueryInterface(base_iface, tests[i].iid, (void **)&iface1);
1652         ok(hr == tests[i].hr, "Got hr %#x for test \"%s\" %u.\n", hr, test_name, i);
1653         if (SUCCEEDED(hr))
1654         {
1655             for (j = 0; j < entry_count; ++j)
1656             {
1657                 hr = IUnknown_QueryInterface(iface1, tests[j].iid, (void **)&iface2);
1658                 ok(hr == tests[j].hr, "Got hr %#x for test \"%s\" %u, %u.\n", hr, test_name, i, j);
1659                 if (SUCCEEDED(hr))
1660                 {
1661                     expected_refcount = 0;
1662                     if (IsEqualGUID(refcount_iid, tests[j].refcount_iid))
1663                         ++expected_refcount;
1664                     if (IsEqualGUID(tests[i].refcount_iid, tests[j].refcount_iid))
1665                         ++expected_refcount;
1666                     refcount = IUnknown_Release(iface2);
1667                     ok(refcount == expected_refcount, "Got refcount %u for test \"%s\" %u, %u, expected %u.\n",
1668                             refcount, test_name, i, j, expected_refcount);
1669                 }
1670             }
1671
1672             expected_refcount = 0;
1673             if (IsEqualGUID(refcount_iid, tests[i].refcount_iid))
1674                 ++expected_refcount;
1675             refcount = IUnknown_Release(iface1);
1676             ok(refcount == expected_refcount, "Got refcount %u for test \"%s\" %u, expected %u.\n",
1677                     refcount, test_name, i, expected_refcount);
1678         }
1679     }
1680 }
1681
1682 static void test_surface_qi(void)
1683 {
1684     static const struct qi_test tests[] =
1685     {
1686         {&IID_IDirect3DTexture2,        &IID_IDirectDrawSurface,        S_OK         },
1687         {&IID_IDirect3DTexture,         &IID_IDirectDrawSurface,        S_OK         },
1688         {&IID_IDirectDrawGammaControl,  &IID_IDirectDrawGammaControl,   S_OK         },
1689         {&IID_IDirectDrawColorControl,  NULL,                           E_NOINTERFACE},
1690         {&IID_IDirectDrawSurface7,      &IID_IDirectDrawSurface7,       S_OK         },
1691         {&IID_IDirectDrawSurface4,      &IID_IDirectDrawSurface4,       S_OK         },
1692         {&IID_IDirectDrawSurface3,      &IID_IDirectDrawSurface3,       S_OK         },
1693         {&IID_IDirectDrawSurface2,      &IID_IDirectDrawSurface2,       S_OK         },
1694         {&IID_IDirectDrawSurface,       &IID_IDirectDrawSurface,        S_OK         },
1695         {&IID_IDirect3DDevice7,         NULL,                           E_INVALIDARG },
1696         {&IID_IDirect3DDevice3,         NULL,                           E_INVALIDARG },
1697         {&IID_IDirect3DDevice2,         NULL,                           E_INVALIDARG },
1698         {&IID_IDirect3DDevice,          NULL,                           E_INVALIDARG },
1699         {&IID_IDirect3D7,               NULL,                           E_INVALIDARG },
1700         {&IID_IDirect3D3,               NULL,                           E_INVALIDARG },
1701         {&IID_IDirect3D2,               NULL,                           E_INVALIDARG },
1702         {&IID_IDirect3D,                NULL,                           E_INVALIDARG },
1703         {&IID_IDirectDraw7,             NULL,                           E_INVALIDARG },
1704         {&IID_IDirectDraw4,             NULL,                           E_INVALIDARG },
1705         {&IID_IDirectDraw3,             NULL,                           E_INVALIDARG },
1706         {&IID_IDirectDraw2,             NULL,                           E_INVALIDARG },
1707         {&IID_IDirectDraw,              NULL,                           E_INVALIDARG },
1708         {&IID_IDirect3DLight,           NULL,                           E_INVALIDARG },
1709         {&IID_IDirect3DMaterial,        NULL,                           E_INVALIDARG },
1710         {&IID_IDirect3DMaterial2,       NULL,                           E_INVALIDARG },
1711         {&IID_IDirect3DMaterial3,       NULL,                           E_INVALIDARG },
1712         {&IID_IDirect3DExecuteBuffer,   NULL,                           E_INVALIDARG },
1713         {&IID_IDirect3DViewport,        NULL,                           E_INVALIDARG },
1714         {&IID_IDirect3DViewport2,       NULL,                           E_INVALIDARG },
1715         {&IID_IDirect3DViewport3,       NULL,                           E_INVALIDARG },
1716         {&IID_IDirect3DVertexBuffer,    NULL,                           E_INVALIDARG },
1717         {&IID_IDirect3DVertexBuffer7,   NULL,                           E_INVALIDARG },
1718         {&IID_IDirectDrawPalette,       NULL,                           E_INVALIDARG },
1719         {&IID_IDirectDrawClipper,       NULL,                           E_INVALIDARG },
1720         {&IID_IUnknown,                 &IID_IDirectDrawSurface,        S_OK         },
1721     };
1722
1723     IDirectDrawSurface *surface;
1724     DDSURFACEDESC surface_desc;
1725     IDirect3DDevice2 *device;
1726     IDirectDraw2 *ddraw;
1727     HWND window;
1728     HRESULT hr;
1729
1730     if (!GetProcAddress(GetModuleHandleA("ddraw.dll"), "DirectDrawCreateEx"))
1731     {
1732         win_skip("DirectDrawCreateEx not available, skipping test.\n");
1733         return;
1734     }
1735
1736     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1737             0, 0, 640, 480, 0, 0, 0, 0);
1738     if (!(ddraw = create_ddraw()))
1739     {
1740         skip("Failed to create a ddraw object, skipping test.\n");
1741         DestroyWindow(window);
1742         return;
1743     }
1744     /* Try to create a D3D device to see if the ddraw implementation supports
1745      * D3D. 64-bit ddraw in particular doesn't seem to support D3D, and
1746      * doesn't support e.g. the IDirect3DTexture interfaces. */
1747     if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
1748     {
1749         skip("Failed to create D3D device, skipping test.\n");
1750         IDirectDraw2_Release(ddraw);
1751         DestroyWindow(window);
1752         return;
1753     }
1754     IDirect3DDevice_Release(device);
1755
1756     memset(&surface_desc, 0, sizeof(surface_desc));
1757     surface_desc.dwSize = sizeof(surface_desc);
1758     surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
1759     surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1760     surface_desc.dwWidth = 512;
1761     surface_desc.dwHeight = 512;
1762     hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface, NULL);
1763     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
1764
1765     test_qi("surface_qi", (IUnknown *)surface, &IID_IDirectDrawSurface, tests, sizeof(tests) / sizeof(*tests));
1766
1767     IDirectDrawSurface_Release(surface);
1768     IDirectDraw2_Release(ddraw);
1769     DestroyWindow(window);
1770 }
1771
1772 static void test_device_qi(void)
1773 {
1774     static const struct qi_test tests[] =
1775     {
1776         {&IID_IDirect3DTexture2,        NULL,                           E_NOINTERFACE},
1777         {&IID_IDirect3DTexture,         NULL,                           E_NOINTERFACE},
1778         {&IID_IDirectDrawGammaControl,  NULL,                           E_NOINTERFACE},
1779         {&IID_IDirectDrawColorControl,  NULL,                           E_NOINTERFACE},
1780         {&IID_IDirectDrawSurface7,      NULL,                           E_NOINTERFACE},
1781         {&IID_IDirectDrawSurface4,      NULL,                           E_NOINTERFACE},
1782         {&IID_IDirectDrawSurface3,      NULL,                           E_NOINTERFACE},
1783         {&IID_IDirectDrawSurface2,      NULL,                           E_NOINTERFACE},
1784         {&IID_IDirectDrawSurface,       NULL,                           E_NOINTERFACE},
1785         {&IID_IDirect3DDevice7,         NULL,                           E_NOINTERFACE},
1786         {&IID_IDirect3DDevice3,         NULL,                           E_NOINTERFACE},
1787         {&IID_IDirect3DDevice2,         &IID_IDirect3DDevice2,          S_OK         },
1788         {&IID_IDirect3DDevice,          &IID_IDirect3DDevice2,          S_OK         },
1789         {&IID_IDirect3DRampDevice,      NULL,                           E_NOINTERFACE},
1790         {&IID_IDirect3DRGBDevice,       NULL,                           E_NOINTERFACE},
1791         {&IID_IDirect3DHALDevice,       NULL,                           E_NOINTERFACE},
1792         {&IID_IDirect3DMMXDevice,       NULL,                           E_NOINTERFACE},
1793         {&IID_IDirect3DRefDevice,       NULL,                           E_NOINTERFACE},
1794         {&IID_IDirect3DTnLHalDevice,    NULL,                           E_NOINTERFACE},
1795         {&IID_IDirect3DNullDevice,      NULL,                           E_NOINTERFACE},
1796         {&IID_IDirect3D7,               NULL,                           E_NOINTERFACE},
1797         {&IID_IDirect3D3,               NULL,                           E_NOINTERFACE},
1798         {&IID_IDirect3D2,               NULL,                           E_NOINTERFACE},
1799         {&IID_IDirect3D,                NULL,                           E_NOINTERFACE},
1800         {&IID_IDirectDraw7,             NULL,                           E_NOINTERFACE},
1801         {&IID_IDirectDraw4,             NULL,                           E_NOINTERFACE},
1802         {&IID_IDirectDraw3,             NULL,                           E_NOINTERFACE},
1803         {&IID_IDirectDraw2,             NULL,                           E_NOINTERFACE},
1804         {&IID_IDirectDraw,              NULL,                           E_NOINTERFACE},
1805         {&IID_IDirect3DLight,           NULL,                           E_NOINTERFACE},
1806         {&IID_IDirect3DMaterial,        NULL,                           E_NOINTERFACE},
1807         {&IID_IDirect3DMaterial2,       NULL,                           E_NOINTERFACE},
1808         {&IID_IDirect3DMaterial3,       NULL,                           E_NOINTERFACE},
1809         {&IID_IDirect3DExecuteBuffer,   NULL,                           E_NOINTERFACE},
1810         {&IID_IDirect3DViewport,        NULL,                           E_NOINTERFACE},
1811         {&IID_IDirect3DViewport2,       NULL,                           E_NOINTERFACE},
1812         {&IID_IDirect3DViewport3,       NULL,                           E_NOINTERFACE},
1813         {&IID_IDirect3DVertexBuffer,    NULL,                           E_NOINTERFACE},
1814         {&IID_IDirect3DVertexBuffer7,   NULL,                           E_NOINTERFACE},
1815         {&IID_IDirectDrawPalette,       NULL,                           E_NOINTERFACE},
1816         {&IID_IDirectDrawClipper,       NULL,                           E_NOINTERFACE},
1817         {&IID_IUnknown,                 &IID_IDirect3DDevice2,          S_OK         },
1818     };
1819
1820     IDirect3DDevice2 *device;
1821     IDirectDraw2 *ddraw;
1822     HWND window;
1823
1824     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1825             0, 0, 640, 480, 0, 0, 0, 0);
1826     if (!(ddraw = create_ddraw()))
1827     {
1828         skip("Failed to create ddraw object, skipping test.\n");
1829         DestroyWindow(window);
1830         return;
1831     }
1832     if (!(device = create_device(ddraw, window, DDSCL_NORMAL)))
1833     {
1834         skip("Failed to create D3D device, skipping test.\n");
1835         IDirectDraw2_Release(ddraw);
1836         DestroyWindow(window);
1837         return;
1838     }
1839
1840     test_qi("device_qi", (IUnknown *)device, &IID_IDirect3DDevice2, tests, sizeof(tests) / sizeof(*tests));
1841
1842     IDirect3DDevice2_Release(device);
1843     IDirectDraw2_Release(ddraw);
1844     DestroyWindow(window);
1845 }
1846
1847 static void test_wndproc(void)
1848 {
1849     LONG_PTR proc, ddraw_proc;
1850     IDirectDraw2 *ddraw;
1851     WNDCLASSA wc = {0};
1852     HWND window;
1853     HRESULT hr;
1854     ULONG ref;
1855
1856     static const UINT messages[] =
1857     {
1858         WM_WINDOWPOSCHANGING,
1859         WM_MOVE,
1860         WM_SIZE,
1861         WM_WINDOWPOSCHANGING,
1862         WM_ACTIVATE,
1863         WM_SETFOCUS,
1864         0,
1865     };
1866
1867     /* DDSCL_EXCLUSIVE replaces the window's window proc. */
1868     if (!(ddraw = create_ddraw()))
1869     {
1870         skip("Failed to create IDirectDraw2 object, skipping tests.\n");
1871         return;
1872     }
1873
1874     wc.lpfnWndProc = test_proc;
1875     wc.lpszClassName = "ddraw_test_wndproc_wc";
1876     ok(RegisterClassA(&wc), "Failed to register window class.\n");
1877
1878     window = CreateWindowA("ddraw_test_wndproc_wc", "ddraw_test",
1879             WS_MAXIMIZE | WS_CAPTION , 0, 0, 640, 480, 0, 0, 0, 0);
1880
1881     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
1882     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
1883             (LONG_PTR)test_proc, proc);
1884     expect_messages = messages;
1885     hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
1886     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
1887     ok(!*expect_messages, "Expected message %#x, but didn't receive it.\n", *expect_messages);
1888     expect_messages = NULL;
1889     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
1890     ok(proc != (LONG_PTR)test_proc, "Expected wndproc != %#lx, got %#lx.\n",
1891             (LONG_PTR)test_proc, proc);
1892     ref = IDirectDraw2_Release(ddraw);
1893     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
1894     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
1895     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
1896             (LONG_PTR)test_proc, proc);
1897
1898     /* DDSCL_NORMAL doesn't. */
1899     ddraw = create_ddraw();
1900     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
1901     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
1902             (LONG_PTR)test_proc, proc);
1903     hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL | DDSCL_FULLSCREEN);
1904     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
1905     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
1906     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
1907             (LONG_PTR)test_proc, proc);
1908     ref = IDirectDraw2_Release(ddraw);
1909     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
1910     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
1911     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
1912             (LONG_PTR)test_proc, proc);
1913
1914     /* The original window proc is only restored by ddraw if the current
1915      * window proc matches the one ddraw set. This also affects switching
1916      * from DDSCL_NORMAL to DDSCL_EXCLUSIVE. */
1917     ddraw = create_ddraw();
1918     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
1919     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
1920             (LONG_PTR)test_proc, proc);
1921     hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
1922     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
1923     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
1924     ok(proc != (LONG_PTR)test_proc, "Expected wndproc != %#lx, got %#lx.\n",
1925             (LONG_PTR)test_proc, proc);
1926     ddraw_proc = proc;
1927     hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
1928     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
1929     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
1930     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
1931             (LONG_PTR)test_proc, proc);
1932     hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
1933     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
1934     proc = SetWindowLongPtrA(window, GWLP_WNDPROC, (LONG_PTR)DefWindowProcA);
1935     ok(proc != (LONG_PTR)test_proc, "Expected wndproc != %#lx, got %#lx.\n",
1936             (LONG_PTR)test_proc, proc);
1937     hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
1938     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
1939     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
1940     ok(proc == (LONG_PTR)DefWindowProcA, "Expected wndproc %#lx, got %#lx.\n",
1941             (LONG_PTR)DefWindowProcA, proc);
1942     hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
1943     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
1944     proc = SetWindowLongPtrA(window, GWLP_WNDPROC, (LONG_PTR)ddraw_proc);
1945     ok(proc == (LONG_PTR)DefWindowProcA, "Expected wndproc %#lx, got %#lx.\n",
1946             (LONG_PTR)DefWindowProcA, proc);
1947     ref = IDirectDraw2_Release(ddraw);
1948     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
1949     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
1950     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
1951             (LONG_PTR)test_proc, proc);
1952
1953     ddraw = create_ddraw();
1954     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
1955     ok(proc == (LONG_PTR)test_proc, "Expected wndproc %#lx, got %#lx.\n",
1956             (LONG_PTR)test_proc, proc);
1957     hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
1958     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
1959     proc = SetWindowLongPtrA(window, GWLP_WNDPROC, (LONG_PTR)DefWindowProcA);
1960     ok(proc != (LONG_PTR)test_proc, "Expected wndproc != %#lx, got %#lx.\n",
1961             (LONG_PTR)test_proc, proc);
1962     ref = IDirectDraw2_Release(ddraw);
1963     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
1964     proc = GetWindowLongPtrA(window, GWLP_WNDPROC);
1965     ok(proc == (LONG_PTR)DefWindowProcA, "Expected wndproc %#lx, got %#lx.\n",
1966             (LONG_PTR)DefWindowProcA, proc);
1967
1968     fix_wndproc(window, (LONG_PTR)test_proc);
1969     expect_messages = NULL;
1970     DestroyWindow(window);
1971     UnregisterClassA("ddraw_test_wndproc_wc", GetModuleHandleA(NULL));
1972 }
1973
1974 static void test_window_style(void)
1975 {
1976     LONG style, exstyle, tmp;
1977     RECT fullscreen_rect, r;
1978     IDirectDraw2 *ddraw;
1979     HWND window;
1980     HRESULT hr;
1981     ULONG ref;
1982
1983     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
1984             0, 0, 100, 100, 0, 0, 0, 0);
1985     if (!(ddraw = create_ddraw()))
1986     {
1987         skip("Failed to create a ddraw object, skipping test.\n");
1988         DestroyWindow(window);
1989         return;
1990     }
1991
1992     style = GetWindowLongA(window, GWL_STYLE);
1993     exstyle = GetWindowLongA(window, GWL_EXSTYLE);
1994     SetRect(&fullscreen_rect, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
1995
1996     hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
1997     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
1998
1999     tmp = GetWindowLongA(window, GWL_STYLE);
2000     todo_wine ok(tmp == style, "Expected window style %#x, got %#x.\n", style, tmp);
2001     tmp = GetWindowLongA(window, GWL_EXSTYLE);
2002     todo_wine ok(tmp == exstyle, "Expected window extended style %#x, got %#x.\n", exstyle, tmp);
2003
2004     GetWindowRect(window, &r);
2005     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2006             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2007             r.left, r.top, r.right, r.bottom);
2008     GetClientRect(window, &r);
2009     todo_wine ok(!EqualRect(&r, &fullscreen_rect), "Client rect and window rect are equal.\n");
2010
2011     ref = IDirectDraw2_Release(ddraw);
2012     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2013
2014     DestroyWindow(window);
2015 }
2016
2017 static void test_redundant_mode_set(void)
2018 {
2019     DDSURFACEDESC surface_desc = {0};
2020     IDirectDraw2 *ddraw;
2021     HWND window;
2022     HRESULT hr;
2023     RECT r, s;
2024     ULONG ref;
2025
2026     window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
2027             0, 0, 100, 100, 0, 0, 0, 0);
2028     if (!(ddraw = create_ddraw()))
2029     {
2030         skip("Failed to create a ddraw object, skipping test.\n");
2031         DestroyWindow(window);
2032         return;
2033     }
2034
2035     hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2036     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2037
2038     surface_desc.dwSize = sizeof(surface_desc);
2039     hr = IDirectDraw2_GetDisplayMode(ddraw, &surface_desc);
2040     ok(SUCCEEDED(hr), "GetDipslayMode failed, hr %#x.\n", hr);
2041
2042     hr = IDirectDraw2_SetDisplayMode(ddraw, surface_desc.dwWidth, surface_desc.dwHeight,
2043             U1(surface_desc.ddpfPixelFormat).dwRGBBitCount, 0, 0);
2044     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
2045
2046     GetWindowRect(window, &r);
2047     r.right /= 2;
2048     r.bottom /= 2;
2049     SetWindowPos(window, HWND_TOP, r.left, r.top, r.right, r.bottom, 0);
2050     GetWindowRect(window, &s);
2051     ok(EqualRect(&r, &s), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2052             r.left, r.top, r.right, r.bottom,
2053             s.left, s.top, s.right, s.bottom);
2054
2055     hr = IDirectDraw2_SetDisplayMode(ddraw, surface_desc.dwWidth, surface_desc.dwHeight,
2056             U1(surface_desc.ddpfPixelFormat).dwRGBBitCount, 0, 0);
2057     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
2058
2059     GetWindowRect(window, &s);
2060     ok(EqualRect(&r, &s), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2061             r.left, r.top, r.right, r.bottom,
2062             s.left, s.top, s.right, s.bottom);
2063
2064     ref = IDirectDraw2_Release(ddraw);
2065     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2066
2067     DestroyWindow(window);
2068 }
2069
2070 static SIZE screen_size;
2071
2072 static LRESULT CALLBACK mode_set_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
2073 {
2074     if (message == WM_SIZE)
2075     {
2076         screen_size.cx = GetSystemMetrics(SM_CXSCREEN);
2077         screen_size.cy = GetSystemMetrics(SM_CYSCREEN);
2078     }
2079
2080     return test_proc(hwnd, message, wparam, lparam);
2081 }
2082
2083 static void test_coop_level_mode_set(void)
2084 {
2085     IDirectDrawSurface *primary;
2086     RECT fullscreen_rect, r, s;
2087     IDirectDraw2 *ddraw;
2088     DDSURFACEDESC ddsd;
2089     WNDCLASSA wc = {0};
2090     HWND window;
2091     HRESULT hr;
2092     ULONG ref;
2093
2094     static const UINT exclusive_messages[] =
2095     {
2096         WM_WINDOWPOSCHANGING,
2097         WM_WINDOWPOSCHANGED,
2098         WM_SIZE,
2099         WM_DISPLAYCHANGE,
2100         0,
2101     };
2102
2103     static const UINT normal_messages[] =
2104     {
2105         WM_DISPLAYCHANGE,
2106         0,
2107     };
2108
2109     if (!(ddraw = create_ddraw()))
2110     {
2111         skip("Failed to create a ddraw object, skipping test.\n");
2112         return;
2113     }
2114
2115     wc.lpfnWndProc = mode_set_proc;
2116     wc.lpszClassName = "ddraw_test_wndproc_wc";
2117     ok(RegisterClassA(&wc), "Failed to register window class.\n");
2118
2119     window = CreateWindowA("ddraw_test_wndproc_wc", "ddraw_test", WS_OVERLAPPEDWINDOW,
2120             0, 0, 100, 100, 0, 0, 0, 0);
2121
2122     SetRect(&fullscreen_rect, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
2123     SetRect(&s, 0, 0, 640, 480);
2124
2125     hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
2126     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2127
2128     GetWindowRect(window, &r);
2129     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2130             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2131             r.left, r.top, r.right, r.bottom);
2132
2133     memset(&ddsd, 0, sizeof(ddsd));
2134     ddsd.dwSize = sizeof(ddsd);
2135     ddsd.dwFlags = DDSD_CAPS;
2136     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2137
2138     hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
2139     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2140     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2141     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2142     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2143             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2144     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2145             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2146
2147     GetWindowRect(window, &r);
2148     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2149             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2150             r.left, r.top, r.right, r.bottom);
2151
2152     expect_messages = exclusive_messages;
2153     screen_size.cx = 0;
2154     screen_size.cy = 0;
2155
2156     hr = IDirectDraw2_SetDisplayMode(ddraw, 640, 480, 32, 0, 0);
2157     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
2158
2159     ok(!*expect_messages, "Expected message %#x, but didn't receive it.\n", *expect_messages);
2160     expect_messages = NULL;
2161     ok(screen_size.cx == s.right && screen_size.cy == s.bottom,
2162             "Expected screen size %ux%u, got %ux%u.\n",
2163             s.right, s.bottom, screen_size.cx, screen_size.cy);
2164
2165     GetWindowRect(window, &r);
2166     ok(EqualRect(&r, &s), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2167             s.left, s.top, s.right, s.bottom,
2168             r.left, r.top, r.right, r.bottom);
2169
2170     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2171     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2172     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2173             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2174     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2175             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2176     IDirectDrawSurface_Release(primary);
2177
2178     memset(&ddsd, 0, sizeof(ddsd));
2179     ddsd.dwSize = sizeof(ddsd);
2180     ddsd.dwFlags = DDSD_CAPS;
2181     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2182
2183     hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
2184     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2185     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2186     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2187     ok(ddsd.dwWidth == s.right - s.left, "Expected surface width %u, got %u.\n",
2188             s.right - s.left, ddsd.dwWidth);
2189     ok(ddsd.dwHeight == s.bottom - s.top, "Expected surface height %u, got %u.\n",
2190             s.bottom - s.top, ddsd.dwHeight);
2191
2192     GetWindowRect(window, &r);
2193     ok(EqualRect(&r, &s), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2194             s.left, s.top, s.right, s.bottom,
2195             r.left, r.top, r.right, r.bottom);
2196
2197     expect_messages = exclusive_messages;
2198     screen_size.cx = 0;
2199     screen_size.cy = 0;
2200
2201     hr = IDirectDraw_RestoreDisplayMode(ddraw);
2202     ok(SUCCEEDED(hr), "RestoreDisplayMode failed, hr %#x.\n", hr);
2203
2204     ok(!*expect_messages, "Expected message %#x, but didn't receive it.\n", *expect_messages);
2205     expect_messages = NULL;
2206     ok(screen_size.cx == fullscreen_rect.right && screen_size.cy == fullscreen_rect.bottom,
2207             "Expected screen size %ux%u, got %ux%u.\n",
2208             fullscreen_rect.right, fullscreen_rect.bottom, screen_size.cx, screen_size.cy);
2209
2210     GetWindowRect(window, &r);
2211     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2212             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2213             r.left, r.top, r.right, r.bottom);
2214
2215     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2216     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2217     ok(ddsd.dwWidth == s.right - s.left, "Expected surface width %u, got %u.\n",
2218             s.right - s.left, ddsd.dwWidth);
2219     ok(ddsd.dwHeight == s.bottom - s.top, "Expected surface height %u, got %u.\n",
2220             s.bottom - s.top, ddsd.dwHeight);
2221     IDirectDrawSurface_Release(primary);
2222
2223     memset(&ddsd, 0, sizeof(ddsd));
2224     ddsd.dwSize = sizeof(ddsd);
2225     ddsd.dwFlags = DDSD_CAPS;
2226     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2227
2228     hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
2229     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2230     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2231     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2232     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2233             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2234     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2235             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2236
2237     GetWindowRect(window, &r);
2238     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2239             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2240             r.left, r.top, r.right, r.bottom);
2241
2242     hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
2243     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2244
2245     GetWindowRect(window, &r);
2246     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2247             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2248             r.left, r.top, r.right, r.bottom);
2249
2250     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2251     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2252     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2253             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2254     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2255             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2256     IDirectDrawSurface_Release(primary);
2257
2258     memset(&ddsd, 0, sizeof(ddsd));
2259     ddsd.dwSize = sizeof(ddsd);
2260     ddsd.dwFlags = DDSD_CAPS;
2261     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2262
2263     hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
2264     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2265     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2266     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2267     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2268             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2269     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2270             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2271
2272     GetWindowRect(window, &r);
2273     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2274             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2275             r.left, r.top, r.right, r.bottom);
2276
2277     expect_messages = normal_messages;
2278     screen_size.cx = 0;
2279     screen_size.cy = 0;
2280
2281     hr = IDirectDraw2_SetDisplayMode(ddraw, 640, 480, 32, 0, 0);
2282     ok(SUCCEEDED(hr) || broken(hr == DDERR_NOEXCLUSIVEMODE) /* NT4 testbot */,
2283         "SetDipslayMode failed, hr %#x.\n", hr);
2284     if (hr == DDERR_NOEXCLUSIVEMODE)
2285     {
2286         win_skip("Broken SetDisplayMode(), skipping remaining tests.\n");
2287         IDirectDrawSurface_Release(primary);
2288         IDirectDraw2_Release(ddraw);
2289         goto done;
2290     }
2291
2292     ok(!*expect_messages, "Expected message %#x, but didn't receive it.\n", *expect_messages);
2293     expect_messages = NULL;
2294     ok(!screen_size.cx && !screen_size.cy, "Got unxpected screen size %ux%u.\n", screen_size.cx, screen_size.cy);
2295
2296     GetWindowRect(window, &r);
2297     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2298             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2299             r.left, r.top, r.right, r.bottom);
2300
2301     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2302     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2303     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2304             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2305     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2306             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2307     IDirectDrawSurface_Release(primary);
2308
2309     memset(&ddsd, 0, sizeof(ddsd));
2310     ddsd.dwSize = sizeof(ddsd);
2311     ddsd.dwFlags = DDSD_CAPS;
2312     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2313
2314     hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
2315     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2316     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2317     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2318     ok(ddsd.dwWidth == s.right - s.left, "Expected surface width %u, got %u.\n",
2319             s.right - s.left, ddsd.dwWidth);
2320     ok(ddsd.dwHeight == s.bottom - s.top, "Expected surface height %u, got %u.\n",
2321             s.bottom - s.top, ddsd.dwHeight);
2322
2323     GetWindowRect(window, &r);
2324     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2325             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2326             r.left, r.top, r.right, r.bottom);
2327
2328     expect_messages = normal_messages;
2329     screen_size.cx = 0;
2330     screen_size.cy = 0;
2331
2332     hr = IDirectDraw_RestoreDisplayMode(ddraw);
2333     ok(SUCCEEDED(hr), "RestoreDisplayMode failed, hr %#x.\n", hr);
2334
2335     ok(!*expect_messages, "Expected message %#x, but didn't receive it.\n", *expect_messages);
2336     expect_messages = NULL;
2337     ok(!screen_size.cx && !screen_size.cy, "Got unxpected screen size %ux%u.\n", screen_size.cx, screen_size.cy);
2338
2339     GetWindowRect(window, &r);
2340     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2341             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2342             r.left, r.top, r.right, r.bottom);
2343
2344     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2345     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2346     ok(ddsd.dwWidth == s.right - s.left, "Expected surface width %u, got %u.\n",
2347             s.right - s.left, ddsd.dwWidth);
2348     ok(ddsd.dwHeight == s.bottom - s.top, "Expected surface height %u, got %u.\n",
2349             s.bottom - s.top, ddsd.dwHeight);
2350     IDirectDrawSurface_Release(primary);
2351
2352     memset(&ddsd, 0, sizeof(ddsd));
2353     ddsd.dwSize = sizeof(ddsd);
2354     ddsd.dwFlags = DDSD_CAPS;
2355     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2356
2357     hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
2358     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2359     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2360     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2361     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2362             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2363     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2364             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2365
2366     GetWindowRect(window, &r);
2367     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2368             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2369             r.left, r.top, r.right, r.bottom);
2370
2371     /* DDSCL_NORMAL | DDSCL_FULLSCREEN behaves the same as just DDSCL_NORMAL.
2372      * Resizing the window on mode changes is a property of DDSCL_EXCLUSIVE,
2373      * not DDSCL_FULLSCREEN. */
2374     hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL | DDSCL_FULLSCREEN);
2375     ok(SUCCEEDED(hr), "SetCooperativeLevel failed, hr %#x.\n", hr);
2376
2377     GetWindowRect(window, &r);
2378     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2379             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2380             r.left, r.top, r.right, r.bottom);
2381
2382     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2383     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2384     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2385             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2386     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2387             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2388     IDirectDrawSurface_Release(primary);
2389
2390     memset(&ddsd, 0, sizeof(ddsd));
2391     ddsd.dwSize = sizeof(ddsd);
2392     ddsd.dwFlags = DDSD_CAPS;
2393     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2394
2395     hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
2396     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2397     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2398     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2399     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2400             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2401     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2402             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2403
2404     GetWindowRect(window, &r);
2405     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2406             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2407             r.left, r.top, r.right, r.bottom);
2408
2409     expect_messages = normal_messages;
2410     screen_size.cx = 0;
2411     screen_size.cy = 0;
2412
2413     hr = IDirectDraw2_SetDisplayMode(ddraw, 640, 480, 32, 0, 0);
2414     ok(SUCCEEDED(hr), "SetDipslayMode failed, hr %#x.\n", hr);
2415
2416     ok(!*expect_messages, "Expected message %#x, but didn't receive it.\n", *expect_messages);
2417     expect_messages = NULL;
2418     ok(!screen_size.cx && !screen_size.cy, "Got unxpected screen size %ux%u.\n", screen_size.cx, screen_size.cy);
2419
2420     GetWindowRect(window, &r);
2421     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2422             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2423             r.left, r.top, r.right, r.bottom);
2424
2425     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2426     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2427     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2428             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2429     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2430             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2431     IDirectDrawSurface_Release(primary);
2432
2433     memset(&ddsd, 0, sizeof(ddsd));
2434     ddsd.dwSize = sizeof(ddsd);
2435     ddsd.dwFlags = DDSD_CAPS;
2436     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2437
2438     hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
2439     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2440     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2441     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2442     ok(ddsd.dwWidth == s.right - s.left, "Expected surface width %u, got %u.\n",
2443             s.right - s.left, ddsd.dwWidth);
2444     ok(ddsd.dwHeight == s.bottom - s.top, "Expected surface height %u, got %u.\n",
2445             s.bottom - s.top, ddsd.dwHeight);
2446
2447     GetWindowRect(window, &r);
2448     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2449             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2450             r.left, r.top, r.right, r.bottom);
2451
2452     expect_messages = normal_messages;
2453     screen_size.cx = 0;
2454     screen_size.cy = 0;
2455
2456     hr = IDirectDraw_RestoreDisplayMode(ddraw);
2457     ok(SUCCEEDED(hr), "RestoreDisplayMode failed, hr %#x.\n", hr);
2458
2459     ok(!*expect_messages, "Expected message %#x, but didn't receive it.\n", *expect_messages);
2460     expect_messages = NULL;
2461     ok(!screen_size.cx && !screen_size.cy, "Got unxpected screen size %ux%u.\n", screen_size.cx, screen_size.cy);
2462
2463     GetWindowRect(window, &r);
2464     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2465             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2466             r.left, r.top, r.right, r.bottom);
2467
2468     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2469     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2470     ok(ddsd.dwWidth == s.right - s.left, "Expected surface width %u, got %u.\n",
2471             s.right - s.left, ddsd.dwWidth);
2472     ok(ddsd.dwHeight == s.bottom - s.top, "Expected surface height %u, got %u.\n",
2473             s.bottom - s.top, ddsd.dwHeight);
2474     IDirectDrawSurface_Release(primary);
2475
2476     memset(&ddsd, 0, sizeof(ddsd));
2477     ddsd.dwSize = sizeof(ddsd);
2478     ddsd.dwFlags = DDSD_CAPS;
2479     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2480
2481     hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &primary, NULL);
2482     ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n",hr);
2483     hr = IDirectDrawSurface_GetSurfaceDesc(primary, &ddsd);
2484     ok(SUCCEEDED(hr), "Failed to get surface desc, hr %#x.\n", hr);
2485     ok(ddsd.dwWidth == fullscreen_rect.right - fullscreen_rect.left, "Expected surface width %u, got %u.\n",
2486             fullscreen_rect.right - fullscreen_rect.left, ddsd.dwWidth);
2487     ok(ddsd.dwHeight == fullscreen_rect.bottom - fullscreen_rect.top, "Expected surface height %u, got %u.\n",
2488             fullscreen_rect.bottom - fullscreen_rect.top, ddsd.dwHeight);
2489     IDirectDrawSurface_Release(primary);
2490
2491     GetWindowRect(window, &r);
2492     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2493             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2494             r.left, r.top, r.right, r.bottom);
2495
2496     ref = IDirectDraw2_Release(ddraw);
2497     ok(ref == 0, "The ddraw object was not properly freed: refcount %u.\n", ref);
2498
2499     GetWindowRect(window, &r);
2500     ok(EqualRect(&r, &fullscreen_rect), "Expected {%d, %d, %d, %d}, got {%d, %d, %d, %d}.\n",
2501             fullscreen_rect.left, fullscreen_rect.top, fullscreen_rect.right, fullscreen_rect.bottom,
2502             r.left, r.top, r.right, r.bottom);
2503
2504 done:
2505     expect_messages = NULL;
2506     DestroyWindow(window);
2507     UnregisterClassA("ddraw_test_wndproc_wc", GetModuleHandleA(NULL));
2508 }
2509
2510 static void test_initialize(void)
2511 {
2512     IDirectDraw2 *ddraw;
2513     HRESULT hr;
2514
2515     if (!(ddraw = create_ddraw()))
2516     {
2517         skip("Failed to create a ddraw object, skipping test.\n");
2518         return;
2519     }
2520
2521     hr = IDirectDraw2_Initialize(ddraw, NULL);
2522     ok(hr == DDERR_ALREADYINITIALIZED, "Initialize returned hr %#x.\n", hr);
2523     IDirectDraw2_Release(ddraw);
2524
2525     CoInitialize(NULL);
2526     hr = CoCreateInstance(&CLSID_DirectDraw, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectDraw2, (void **)&ddraw);
2527     ok(SUCCEEDED(hr), "Failed to create IDirectDraw2 instance, hr %#x.\n", hr);
2528     hr = IDirectDraw2_Initialize(ddraw, NULL);
2529     ok(hr == DD_OK, "Initialize returned hr %#x, expected DD_OK.\n", hr);
2530     hr = IDirectDraw2_Initialize(ddraw, NULL);
2531     ok(hr == DDERR_ALREADYINITIALIZED, "Initialize returned hr %#x, expected DDERR_ALREADYINITIALIZED.\n", hr);
2532     IDirectDraw2_Release(ddraw);
2533     CoUninitialize();
2534 }
2535
2536 static void test_coop_level_surf_create(void)
2537 {
2538     IDirectDrawSurface *surface;
2539     IDirectDraw2 *ddraw;
2540     DDSURFACEDESC ddsd;
2541     HRESULT hr;
2542
2543     if (!(ddraw = create_ddraw()))
2544     {
2545         skip("Failed to create a ddraw object, skipping test.\n");
2546         return;
2547     }
2548
2549     memset(&ddsd, 0, sizeof(ddsd));
2550     ddsd.dwSize = sizeof(ddsd);
2551     ddsd.dwFlags = DDSD_CAPS;
2552     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
2553     hr = IDirectDraw2_CreateSurface(ddraw, &ddsd, &surface, NULL);
2554     ok(hr == DDERR_NOCOOPERATIVELEVELSET, "Surface creation returned hr %#x.\n", hr);
2555
2556     IDirectDraw2_Release(ddraw);
2557 }
2558
2559 START_TEST(ddraw2)
2560 {
2561     test_coop_level_create_device_window();
2562     test_clipper_blt();
2563     test_coop_level_d3d_state();
2564     test_surface_interface_mismatch();
2565     test_coop_level_threaded();
2566     test_depth_blit();
2567     test_texture_load_ckey();
2568     test_viewport_interfaces();
2569     test_zenable();
2570     test_ck_rgba();
2571     test_ck_default();
2572     test_surface_qi();
2573     test_device_qi();
2574     test_wndproc();
2575     test_window_style();
2576     test_redundant_mode_set();
2577     test_coop_level_mode_set();
2578     test_initialize();
2579     test_coop_level_surf_create();
2580 }