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