ddraw: Implement and test DirectDrawEnumerateExW.
[wine] / dlls / ddraw / tests / ddrawmodes.c
1 /*
2  * Unit tests for ddraw functions
3  *
4  *
5  * Part of this test involves changing the screen resolution. But this is
6  * really disrupting if the user is doing something else and is not very nice
7  * to CRT screens. Plus, ideally it needs someone watching it to check that
8  * each mode displays correctly.
9  * So this is only done if the test is being run in interactive mode.
10  *
11  * Copyright (C) 2003 Sami Aario
12  *
13  * This library is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU Lesser General Public
15  * License as published by the Free Software Foundation; either
16  * version 2.1 of the License, or (at your option) any later version.
17  *
18  * This library is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21  * Lesser General Public License for more details.
22  *
23  * You should have received a copy of the GNU Lesser General Public
24  * License along with this library; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26  */
27
28 #include <assert.h>
29 #include "wine/test.h"
30 #include "ddraw.h"
31
32 static LPDIRECTDRAW lpDD = NULL;
33 static LPDIRECTDRAWSURFACE lpDDSPrimary = NULL;
34 static LPDIRECTDRAWSURFACE lpDDSBack = NULL;
35 static WNDCLASS wc;
36 static HWND hwnd;
37 static int modes_cnt;
38 static int modes_size;
39 static LPDDSURFACEDESC modes;
40
41 static HRESULT (WINAPI *pDirectDrawEnumerateA)(LPDDENUMCALLBACKA,LPVOID);
42 static HRESULT (WINAPI *pDirectDrawEnumerateW)(LPDDENUMCALLBACKW,LPVOID);
43 static HRESULT (WINAPI *pDirectDrawEnumerateExA)(LPDDENUMCALLBACKEXA,LPVOID,DWORD);
44 static HRESULT (WINAPI *pDirectDrawEnumerateExW)(LPDDENUMCALLBACKEXW,LPVOID,DWORD);
45
46 static void init_function_pointers(void)
47 {
48     HMODULE hmod = GetModuleHandleA("ddraw.dll");
49     pDirectDrawEnumerateA = (void*)GetProcAddress(hmod, "DirectDrawEnumerateA");
50     pDirectDrawEnumerateW = (void*)GetProcAddress(hmod, "DirectDrawEnumerateW");
51     pDirectDrawEnumerateExA = (void*)GetProcAddress(hmod, "DirectDrawEnumerateExA");
52     pDirectDrawEnumerateExW = (void*)GetProcAddress(hmod, "DirectDrawEnumerateExW");
53 }
54
55 static void createwindow(void)
56 {
57     wc.style = CS_HREDRAW | CS_VREDRAW;
58     wc.lpfnWndProc = DefWindowProcA;
59     wc.cbClsExtra = 0;
60     wc.cbWndExtra = 0;
61     wc.hInstance = GetModuleHandleA(0);
62     wc.hIcon = LoadIconA(wc.hInstance, IDI_APPLICATION);
63     wc.hCursor = LoadCursorA(NULL, IDC_ARROW);
64     wc.hbrBackground = GetStockObject(BLACK_BRUSH);
65     wc.lpszMenuName = NULL;
66     wc.lpszClassName = "TestWindowClass";
67     if(!RegisterClassA(&wc))
68         assert(0);
69
70     hwnd = CreateWindowExA(0, "TestWindowClass", "TestWindowClass",
71         WS_POPUP, 0, 0,
72         GetSystemMetrics(SM_CXSCREEN),
73         GetSystemMetrics(SM_CYSCREEN),
74         NULL, NULL, GetModuleHandleA(0), NULL);
75     assert(hwnd != NULL);
76
77     ShowWindow(hwnd, SW_HIDE);
78     UpdateWindow(hwnd);
79     SetFocus(hwnd);
80 }
81
82 static BOOL createdirectdraw(void)
83 {
84     HRESULT rc;
85
86     rc = DirectDrawCreate(NULL, &lpDD, NULL);
87     ok(rc==DD_OK || rc==DDERR_NODIRECTDRAWSUPPORT, "DirectDrawCreateEx returned: %x\n", rc);
88     if (!lpDD) {
89         trace("DirectDrawCreateEx() failed with an error %x\n", rc);
90         return FALSE;
91     }
92     return TRUE;
93 }
94
95
96 static void releasedirectdraw(void)
97 {
98         if( lpDD != NULL )
99         {
100                 IDirectDraw_Release(lpDD);
101                 lpDD = NULL;
102         }
103 }
104
105 static BOOL WINAPI crash_callbackA(GUID *lpGUID, LPSTR lpDriverDescription,
106                                   LPSTR lpDriverName, LPVOID lpContext)
107 {
108     *(volatile char*)0 = 2;
109     return TRUE;
110 }
111
112 static BOOL WINAPI test_nullcontext_callbackA(GUID *lpGUID, LPSTR lpDriverDescription,
113                                               LPSTR lpDriverName, LPVOID lpContext)
114 {
115     trace("test_nullcontext_callbackA: %p %s %s %p\n",
116           lpGUID, lpDriverDescription, lpDriverName, lpContext);
117
118     ok(!lpContext, "Expected NULL lpContext\n");
119
120     return TRUE;
121 }
122
123 static BOOL WINAPI test_context_callbackA(GUID *lpGUID, LPSTR lpDriverDescription,
124                                           LPSTR lpDriverName, LPVOID lpContext)
125 {
126     trace("test_context_callbackA: %p %s %s %p\n",
127           lpGUID, lpDriverDescription, lpDriverName, lpContext);
128
129     ok(lpContext == (LPVOID)0xdeadbeef, "Expected non-NULL lpContext\n");
130
131     return TRUE;
132 }
133
134 static void test_DirectDrawEnumerateA(void)
135 {
136     HRESULT ret;
137
138     if (!pDirectDrawEnumerateA)
139     {
140         win_skip("DirectDrawEnumerateA is not available\n");
141         return;
142     }
143
144     /* Test with NULL callback parameter. */
145     ret = pDirectDrawEnumerateA(NULL, NULL);
146     ok(ret == DDERR_INVALIDPARAMS, "Expected DDERR_INVALIDPARAMS, got %d\n", ret);
147
148     /* Test with invalid callback parameter. */
149     ret = pDirectDrawEnumerateA((LPDDENUMCALLBACKA)0xdeadbeef, NULL);
150     ok(ret == DDERR_INVALIDPARAMS, "Expected DDERR_INVALIDPARAMS, got %d\n", ret);
151
152     /* Test with callback that crashes. */
153     ret = pDirectDrawEnumerateA(crash_callbackA, NULL);
154     ok(ret == DDERR_INVALIDPARAMS, "Expected DDERR_INVALIDPARAMS, got %d\n", ret);
155
156     /* Test with valid callback parameter and NULL context parameter. */
157     trace("Calling DirectDrawEnumerateA with test_nullcontext_callbackA callback and NULL context.\n");
158     ret = pDirectDrawEnumerateA(test_nullcontext_callbackA, NULL);
159     ok(ret == DD_OK, "Expected DD_OK, got %d\n", ret);
160
161     /* Test with valid callback parameter and valid context parameter. */
162     trace("Calling DirectDrawEnumerateA with test_context_callbackA callback and non-NULL context.\n");
163     ret = pDirectDrawEnumerateA(test_context_callbackA, (LPVOID)0xdeadbeef);
164     ok(ret == DD_OK, "Expected DD_OK, got %d\n", ret);
165 }
166
167 static BOOL WINAPI test_callbackW(GUID *lpGUID, LPWSTR lpDriverDescription,
168                                   LPWSTR lpDriverName, LPVOID lpContext)
169 {
170     ok(0, "The callback should not be invoked by DirectDrawEnumerateW\n");
171     return TRUE;
172 }
173
174 static void test_DirectDrawEnumerateW(void)
175 {
176     HRESULT ret;
177
178     if (!pDirectDrawEnumerateW)
179     {
180         win_skip("DirectDrawEnumerateW is not available\n");
181         return;
182     }
183
184     /* DirectDrawEnumerateW is not implemented on Windows. */
185
186     /* Test with NULL callback parameter. */
187     ret = pDirectDrawEnumerateW(NULL, NULL);
188     ok(ret == DDERR_INVALIDPARAMS, "Expected DDERR_INVALIDPARAMS, got %d\n", ret);
189
190     /* Test with invalid callback parameter. */
191     ret = pDirectDrawEnumerateW((LPDDENUMCALLBACKW)0xdeadbeef, NULL);
192     ok(ret == DDERR_INVALIDPARAMS /* XP */ ||
193        ret == DDERR_UNSUPPORTED /* Win7 */,
194        "Expected DDERR_INVALIDPARAMS or DDERR_UNSUPPORTED, got %d\n", ret);
195
196     /* Test with valid callback parameter and NULL context parameter. */
197     ret = pDirectDrawEnumerateW(test_callbackW, NULL);
198     ok(ret == DDERR_UNSUPPORTED, "Expected DDERR_UNSUPPORTED, got %d\n", ret);
199 }
200
201 static BOOL WINAPI crash_callbackExA(GUID *lpGUID, LPSTR lpDriverDescription,
202                                      LPSTR lpDriverName, LPVOID lpContext,
203                                      HMONITOR hm)
204 {
205     *(volatile char*)0 = 2;
206     return TRUE;
207 }
208
209 static BOOL WINAPI test_nullcontext_callbackExA(GUID *lpGUID, LPSTR lpDriverDescription,
210                                                 LPSTR lpDriverName, LPVOID lpContext,
211                                                 HMONITOR hm)
212 {
213     trace("test_nullcontext_callbackExA: %p %s %s %p %p\n", lpGUID,
214           lpDriverDescription, lpDriverName, lpContext, hm);
215
216     ok(!lpContext, "Expected NULL lpContext\n");
217
218     return TRUE;
219 }
220
221 static BOOL WINAPI test_context_callbackExA(GUID *lpGUID, LPSTR lpDriverDescription,
222                                             LPSTR lpDriverName, LPVOID lpContext,
223                                             HMONITOR hm)
224 {
225     trace("test_context_callbackExA: %p %s %s %p %p\n", lpGUID,
226           lpDriverDescription, lpDriverName, lpContext, hm);
227
228     ok(lpContext == (LPVOID)0xdeadbeef, "Expected non-NULL lpContext\n");
229
230     return TRUE;
231 }
232
233 static void test_DirectDrawEnumerateExA(void)
234 {
235     HRESULT ret;
236
237     if (!pDirectDrawEnumerateExA)
238     {
239         win_skip("DirectDrawEnumerateExA is not available\n");
240         return;
241     }
242
243     /* Test with NULL callback parameter. */
244     ret = pDirectDrawEnumerateExA(NULL, NULL, 0);
245     ok(ret == DDERR_INVALIDPARAMS, "Expected DDERR_INVALIDPARAMS, got %d\n", ret);
246
247     /* Test with invalid callback parameter. */
248     ret = pDirectDrawEnumerateExA((LPDDENUMCALLBACKEXA)0xdeadbeef, NULL, 0);
249     ok(ret == DDERR_INVALIDPARAMS, "Expected DDERR_INVALIDPARAMS, got %d\n", ret);
250
251     /* Test with callback that crashes. */
252     ret = pDirectDrawEnumerateExA(crash_callbackExA, NULL, 0);
253     ok(ret == DDERR_INVALIDPARAMS, "Expected DDERR_INVALIDPARAMS, got %d\n", ret);
254
255     /* Test with valid callback parameter and invalid flags */
256     ret = pDirectDrawEnumerateExA(test_nullcontext_callbackExA, NULL, ~0);
257     ok(ret == DDERR_INVALIDPARAMS, "Expected DDERR_INVALIDPARAMS, got %d\n", ret);
258
259     /* Test with valid callback parameter and NULL context parameter. */
260     trace("Calling DirectDrawEnumerateExA with empty flags and NULL context.\n");
261     ret = pDirectDrawEnumerateExA(test_nullcontext_callbackExA, NULL, 0);
262     ok(ret == DD_OK, "Expected DD_OK, got %d\n", ret);
263
264     /* Test with valid callback parameter and non-NULL context parameter. */
265     trace("Calling DirectDrawEnumerateExA with empty flags and non-NULL context.\n");
266     ret = pDirectDrawEnumerateExA(test_context_callbackExA, (LPVOID)0xdeadbeef, 0);
267     ok(ret == DD_OK, "Expected DD_OK, got %d\n", ret);
268
269     /* Test with valid callback parameter, NULL context parameter, and all flags set. */
270     trace("Calling DirectDrawEnumerateExA with all flags set and NULL context.\n");
271     ret = pDirectDrawEnumerateExA(test_nullcontext_callbackExA, NULL,
272                                   DDENUM_ATTACHEDSECONDARYDEVICES |
273                                   DDENUM_DETACHEDSECONDARYDEVICES |
274                                   DDENUM_NONDISPLAYDEVICES);
275     ok(ret == DD_OK, "Expected DD_OK, got %d\n", ret);
276 }
277
278 static BOOL WINAPI test_callbackExW(GUID *lpGUID, LPWSTR lpDriverDescription,
279                                     LPWSTR lpDriverName, LPVOID lpContext,
280                                     HMONITOR hm)
281 {
282     ok(0, "The callback should not be invoked by DirectDrawEnumerateExW.\n");
283     return TRUE;
284 }
285
286 static void test_DirectDrawEnumerateExW(void)
287 {
288     HRESULT ret;
289
290     if (!pDirectDrawEnumerateExW)
291     {
292         win_skip("DirectDrawEnumerateExW is not available\n");
293         return;
294     }
295
296     /* DirectDrawEnumerateExW is not implemented on Windows. */
297
298     /* Test with NULL callback parameter. */
299     ret = pDirectDrawEnumerateExW(NULL, NULL, 0);
300     ok(ret == DDERR_UNSUPPORTED, "Expected DDERR_UNSUPPORTED, got %d\n", ret);
301
302     /* Test with invalid callback parameter. */
303     ret = pDirectDrawEnumerateExW((LPDDENUMCALLBACKEXW)0xdeadbeef, NULL, 0);
304     ok(ret == DDERR_UNSUPPORTED, "Expected DDERR_UNSUPPORTED, got %d\n", ret);
305
306     /* Test with valid callback parameter and invalid flags */
307     ret = pDirectDrawEnumerateExW(test_callbackExW, NULL, ~0);
308     ok(ret == DDERR_UNSUPPORTED, "Expected DDERR_UNSUPPORTED, got %d\n", ret);
309
310     /* Test with valid callback parameter and NULL context parameter. */
311     ret = pDirectDrawEnumerateExW(test_callbackExW, NULL, 0);
312     ok(ret == DDERR_UNSUPPORTED, "Expected DDERR_UNSUPPORTED, got %d\n", ret);
313
314     /* Test with valid callback parameter, NULL context parameter, and all flags set. */
315     ret = pDirectDrawEnumerateExW(test_callbackExW, NULL,
316                                   DDENUM_ATTACHEDSECONDARYDEVICES |
317                                   DDENUM_DETACHEDSECONDARYDEVICES |
318                                   DDENUM_NONDISPLAYDEVICES);
319     ok(ret == DDERR_UNSUPPORTED, "Expected DDERR_UNSUPPORTED, got %d\n", ret);
320 }
321
322 static void adddisplaymode(LPDDSURFACEDESC lpddsd)
323 {
324     if (!modes)
325         modes = HeapAlloc(GetProcessHeap(), 0, (modes_size = 2) * sizeof(DDSURFACEDESC));
326     if (modes_cnt == modes_size)
327         modes = HeapReAlloc(GetProcessHeap(), 0, modes, (modes_size *= 2) * sizeof(DDSURFACEDESC));
328     assert(modes);
329     modes[modes_cnt++] = *lpddsd;
330 }
331
332 static void flushdisplaymodes(void)
333 {
334     HeapFree(GetProcessHeap(), 0, modes);
335     modes = 0;
336     modes_cnt = modes_size = 0;
337 }
338
339 static HRESULT WINAPI enummodescallback(LPDDSURFACEDESC lpddsd, LPVOID lpContext)
340 {
341     trace("Width = %i, Height = %i, Refresh Rate = %i, Pitch = %i, flags =%02X\r\n",
342         lpddsd->dwWidth, lpddsd->dwHeight,
343           U2(*lpddsd).dwRefreshRate, U1(*lpddsd).lPitch, lpddsd->dwFlags);
344
345     /* Check that the pitch is valid if applicable */
346     if(lpddsd->dwFlags & DDSD_PITCH)
347     {
348         ok(U1(*lpddsd).lPitch != 0, "EnumDisplayModes callback with bad pitch\n");
349     }
350
351     /* Check that frequency is valid if applicable
352      *
353      * This fails on some Windows drivers or Windows versions, so it isn't important
354      * apparently
355     if(lpddsd->dwFlags & DDSD_REFRESHRATE)
356     {
357         ok(U2(*lpddsd).dwRefreshRate != 0, "EnumDisplayModes callback with bad refresh rate\n");
358     }
359      */
360
361     adddisplaymode(lpddsd);
362
363     return DDENUMRET_OK;
364 }
365
366 static void enumdisplaymodes(void)
367 {
368     DDSURFACEDESC ddsd;
369     HRESULT rc;
370
371     ZeroMemory(&ddsd, sizeof(DDSURFACEDESC));
372     ddsd.dwSize = sizeof(DDSURFACEDESC);
373     ddsd.dwFlags = DDSD_CAPS;
374     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
375
376     rc = IDirectDraw_EnumDisplayModes(lpDD,
377         DDEDM_STANDARDVGAMODES, &ddsd, 0, enummodescallback);
378     ok(rc==DD_OK || rc==E_INVALIDARG,"EnumDisplayModes returned: %x\n",rc);
379 }
380
381 static void setdisplaymode(int i)
382 {
383     HRESULT rc;
384
385     rc = IDirectDraw_SetCooperativeLevel(lpDD,
386         hwnd, DDSCL_ALLOWMODEX | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
387     ok(rc==DD_OK,"SetCooperativeLevel returned: %x\n",rc);
388     if (modes[i].dwFlags & DDSD_PIXELFORMAT)
389     {
390         if (modes[i].ddpfPixelFormat.dwFlags & DDPF_RGB)
391         {
392             rc = IDirectDraw_SetDisplayMode(lpDD,
393                 modes[i].dwWidth, modes[i].dwHeight,
394                 U1(modes[i].ddpfPixelFormat).dwRGBBitCount);
395             ok(DD_OK==rc || DDERR_UNSUPPORTED==rc,"SetDisplayMode returned: %x\n",rc);
396             if (rc == DD_OK)
397             {
398                 RECT r, scrn, virt;
399
400                 SetRect(&virt, 0, 0, GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN));
401                 OffsetRect(&virt, GetSystemMetrics(SM_XVIRTUALSCREEN), GetSystemMetrics(SM_YVIRTUALSCREEN));
402                 SetRect(&scrn, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
403                 trace("Mode (%dx%d) [%dx%d] (%d %d)x(%d %d)\n", modes[i].dwWidth, modes[i].dwHeight,
404                       scrn.right, scrn.bottom, virt.left, virt.top, virt.right, virt.bottom);
405
406                 ok(GetClipCursor(&r), "GetClipCursor() failed\n");
407                 /* ddraw sets clip rect here to the screen size, even for
408                    multiple monitors */
409                 ok(EqualRect(&r, &scrn), "Invalid clip rect: (%d %d) x (%d %d)\n",
410                    r.left, r.top, r.right, r.bottom);
411
412                 ok(ClipCursor(NULL), "ClipCursor() failed\n");
413                 ok(GetClipCursor(&r), "GetClipCursor() failed\n");
414                 ok(EqualRect(&r, &virt), "Invalid clip rect: (%d %d) x (%d %d)\n",
415                    r.left, r.top, r.right, r.bottom);
416
417                 rc = IDirectDraw_RestoreDisplayMode(lpDD);
418                 ok(DD_OK==rc,"RestoreDisplayMode returned: %x\n",rc);
419             }
420         }
421     }
422 }
423
424 static void createsurface(void)
425 {
426     DDSURFACEDESC ddsd;
427     DDSCAPS ddscaps;
428     HRESULT rc;
429
430     ddsd.dwSize = sizeof(ddsd);
431     ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
432     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
433         DDSCAPS_FLIP |
434         DDSCAPS_COMPLEX;
435     ddsd.dwBackBufferCount = 1;
436     rc = IDirectDraw_CreateSurface(lpDD, &ddsd, &lpDDSPrimary, NULL );
437     ok(rc==DD_OK,"CreateSurface returned: %x\n",rc);
438     ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
439     rc = IDirectDrawSurface_GetAttachedSurface(lpDDSPrimary, &ddscaps, &lpDDSBack);
440     ok(rc==DD_OK,"GetAttachedSurface returned: %x\n",rc);
441 }
442
443 static void destroysurface(void)
444 {
445     if( lpDDSPrimary != NULL )
446     {
447         IDirectDrawSurface_Release(lpDDSPrimary);
448         lpDDSPrimary = NULL;
449     }
450 }
451
452 static void testsurface(void)
453 {
454     const char* testMsg = "ddraw device context test";
455     HDC hdc;
456     HRESULT rc;
457
458     rc = IDirectDrawSurface_GetDC(lpDDSBack, &hdc);
459     ok(rc==DD_OK, "IDirectDrawSurface_GetDC returned: %x\n",rc);
460     SetBkColor(hdc, RGB(0, 0, 255));
461     SetTextColor(hdc, RGB(255, 255, 0));
462     TextOut(hdc, 0, 0, testMsg, lstrlen(testMsg));
463     IDirectDrawSurface_ReleaseDC(lpDDSBack, hdc);
464     ok(rc==DD_OK, "IDirectDrawSurface_ReleaseDC returned: %x\n",rc);
465
466     while (1)
467     {
468         rc = IDirectDrawSurface_Flip(lpDDSPrimary, NULL, DDFLIP_WAIT);
469         ok(rc==DD_OK || rc==DDERR_SURFACELOST, "IDirectDrawSurface_BltFast returned: %x\n",rc);
470
471         if (rc == DD_OK)
472         {
473             break;
474         }
475         else if (rc == DDERR_SURFACELOST)
476         {
477             rc = IDirectDrawSurface_Restore(lpDDSPrimary);
478             ok(rc==DD_OK, "IDirectDrawSurface_Restore returned: %x\n",rc);
479         }
480     }
481 }
482
483 static void testdisplaymodes(void)
484 {
485     int i;
486
487     for (i = 0; i < modes_cnt; ++i)
488     {
489         setdisplaymode(i);
490         createsurface();
491         testsurface();
492         destroysurface();
493     }
494 }
495
496 static void testcooperativelevels_normal(void)
497 {
498     HRESULT rc;
499     DDSURFACEDESC surfacedesc;
500     IDirectDrawSurface *surface = (IDirectDrawSurface *) 0xdeadbeef;
501
502     memset(&surfacedesc, 0, sizeof(surfacedesc));
503     surfacedesc.dwSize = sizeof(surfacedesc);
504     surfacedesc.ddpfPixelFormat.dwSize = sizeof(surfacedesc.ddpfPixelFormat);
505     surfacedesc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
506     surfacedesc.dwBackBufferCount = 1;
507     surfacedesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;
508
509     /* Do some tests with DDSCL_NORMAL mode */
510
511     rc = IDirectDraw_SetCooperativeLevel(lpDD,
512         hwnd, DDSCL_NORMAL);
513     ok(rc==DD_OK,"SetCooperativeLevel(DDSCL_NORMAL) returned: %x\n",rc);
514
515     /* Try creating a double buffered primary in normal mode */
516     rc = IDirectDraw_CreateSurface(lpDD, &surfacedesc, &surface, NULL);
517     if (rc == DDERR_UNSUPPORTEDMODE)
518         skip("Unsupported mode\n");
519     else
520     {
521         ok(rc == DDERR_NOEXCLUSIVEMODE, "IDirectDraw_CreateSurface returned %08x\n", rc);
522         ok(surface == NULL, "Returned surface pointer is %p\n", surface);
523     }
524     if(surface && surface != (IDirectDrawSurface *)0xdeadbeef) IDirectDrawSurface_Release(surface);
525
526     /* Set the focus window */
527     rc = IDirectDraw_SetCooperativeLevel(lpDD,
528         hwnd, DDSCL_SETFOCUSWINDOW);
529
530     if (rc == DDERR_INVALIDPARAMS)
531     {
532         win_skip("NT4/Win95 do not support cooperative levels DDSCL_SETDEVICEWINDOW and DDSCL_SETFOCUSWINDOW\n");
533         return;
534     }
535
536     ok(rc==DD_OK,"SetCooperativeLevel(DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
537
538     /* Set the focus window a second time*/
539     rc = IDirectDraw_SetCooperativeLevel(lpDD,
540         hwnd, DDSCL_SETFOCUSWINDOW);
541     ok(rc==DD_OK,"SetCooperativeLevel(DDSCL_SETFOCUSWINDOW) the second time returned: %x\n",rc);
542
543     /* Test DDSCL_SETFOCUSWINDOW with the other flags. They should all fail, except of DDSCL_NOWINDOWCHANGES */
544     rc = IDirectDraw_SetCooperativeLevel(lpDD,
545         hwnd, DDSCL_NORMAL | DDSCL_SETFOCUSWINDOW);
546     ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_NORMAL | DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
547
548     rc = IDirectDraw_SetCooperativeLevel(lpDD,
549         hwnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_SETFOCUSWINDOW);
550     ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
551
552     /* This one succeeds */
553     rc = IDirectDraw_SetCooperativeLevel(lpDD,
554         hwnd, DDSCL_NOWINDOWCHANGES | DDSCL_SETFOCUSWINDOW);
555     ok(rc==DD_OK,"SetCooperativeLevel(DDSCL_NOWINDOWCHANGES | DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
556
557     rc = IDirectDraw_SetCooperativeLevel(lpDD,
558         hwnd, DDSCL_MULTITHREADED | DDSCL_SETFOCUSWINDOW);
559     ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_MULTITHREADED | DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
560
561     rc = IDirectDraw_SetCooperativeLevel(lpDD,
562         hwnd, DDSCL_FPUSETUP | DDSCL_SETFOCUSWINDOW);
563     ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_FPUSETUP | DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
564
565     rc = IDirectDraw_SetCooperativeLevel(lpDD,
566         hwnd, DDSCL_FPUPRESERVE | DDSCL_SETFOCUSWINDOW);
567     ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_FPUPRESERVE | DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
568
569     rc = IDirectDraw_SetCooperativeLevel(lpDD,
570         hwnd, DDSCL_ALLOWREBOOT | DDSCL_SETFOCUSWINDOW);
571     ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_ALLOWREBOOT | DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
572
573     rc = IDirectDraw_SetCooperativeLevel(lpDD,
574         hwnd, DDSCL_ALLOWMODEX | DDSCL_SETFOCUSWINDOW);
575     ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_ALLOWMODEX | DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
576
577     /* Set the device window without any other flags. Should give an error */
578     rc = IDirectDraw_SetCooperativeLevel(lpDD,
579         hwnd, DDSCL_SETDEVICEWINDOW);
580     ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_SETDEVICEWINDOW) returned: %x\n",rc);
581
582     /* Set device window with DDSCL_NORMAL */
583     rc = IDirectDraw_SetCooperativeLevel(lpDD,
584         hwnd, DDSCL_NORMAL | DDSCL_SETDEVICEWINDOW);
585     ok(rc==DD_OK,"SetCooperativeLevel(DDSCL_NORMAL | DDSCL_SETDEVICEWINDOW) returned: %x\n",rc);
586
587     /* Also set the focus window. Should give an error */
588     rc = IDirectDraw_SetCooperativeLevel(lpDD,
589         hwnd, DDSCL_ALLOWMODEX | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_SETDEVICEWINDOW | DDSCL_SETFOCUSWINDOW);
590     ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_NORMAL | DDSCL_SETDEVICEWINDOW | DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
591
592     /* All done */
593 }
594
595 static void testcooperativelevels_exclusive(void)
596 {
597     HRESULT rc;
598
599     /* Do some tests with DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN mode */
600
601     /* Try to set exclusive mode only */
602     rc = IDirectDraw_SetCooperativeLevel(lpDD,
603         hwnd, DDSCL_EXCLUSIVE);
604     ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_EXCLUSIVE) returned: %x\n",rc);
605
606     /* Full screen mode only */
607     rc = IDirectDraw_SetCooperativeLevel(lpDD,
608         hwnd, DDSCL_FULLSCREEN);
609     ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_FULLSCREEN) returned: %x\n",rc);
610
611     /* Full screen mode + exclusive mode */
612     rc = IDirectDraw_SetCooperativeLevel(lpDD,
613         hwnd, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE);
614     ok(rc==DD_OK,"SetCooperativeLevel(DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN) returned: %x\n",rc);
615
616     /* Set the focus window. Should fail */
617     rc = IDirectDraw_SetCooperativeLevel(lpDD,
618         hwnd, DDSCL_SETFOCUSWINDOW);
619     ok(rc==DDERR_HWNDALREADYSET ||
620        broken(rc==DDERR_INVALIDPARAMS) /* NT4/Win95 */,"SetCooperativeLevel(DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
621
622
623     /* All done */
624 }
625
626 static void testddraw3(void)
627 {
628     const GUID My_IID_IDirectDraw3 = {
629         0x618f8ad4,
630         0x8b7a,
631         0x11d0,
632         { 0x8f,0xcc,0x0,0xc0,0x4f,0xd9,0x18,0x9d }
633     };
634     IDirectDraw3 *dd3;
635     HRESULT hr;
636     hr = IDirectDraw_QueryInterface(lpDD, &My_IID_IDirectDraw3, (void **) &dd3);
637     ok(hr == E_NOINTERFACE, "QueryInterface for IID_IDirectDraw3 returned 0x%08x, expected E_NOINTERFACE\n", hr);
638     if(SUCCEEDED(hr) && dd3) IDirectDraw3_Release(dd3);
639 }
640
641 START_TEST(ddrawmodes)
642 {
643     init_function_pointers();
644
645     createwindow();
646     if (!createdirectdraw())
647         return;
648
649     test_DirectDrawEnumerateA();
650     test_DirectDrawEnumerateW();
651     test_DirectDrawEnumerateExA();
652     test_DirectDrawEnumerateExW();
653
654     enumdisplaymodes();
655     if (winetest_interactive)
656         testdisplaymodes();
657     flushdisplaymodes();
658     testddraw3();
659     releasedirectdraw();
660
661     createdirectdraw();
662     testcooperativelevels_normal();
663     releasedirectdraw();
664
665     createdirectdraw();
666     testcooperativelevels_exclusive();
667     releasedirectdraw();
668 }