ddraw: Setup the device window in SetCooperativeLevel().
[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, hwnd2;
37 static int modes_cnt;
38 static int modes_size;
39 static LPDDSURFACEDESC modes;
40 static RECT rect_before_create;
41 static RECT rect_after_delete;
42
43 static HRESULT (WINAPI *pDirectDrawEnumerateA)(LPDDENUMCALLBACKA,LPVOID);
44 static HRESULT (WINAPI *pDirectDrawEnumerateW)(LPDDENUMCALLBACKW,LPVOID);
45 static HRESULT (WINAPI *pDirectDrawEnumerateExA)(LPDDENUMCALLBACKEXA,LPVOID,DWORD);
46 static HRESULT (WINAPI *pDirectDrawEnumerateExW)(LPDDENUMCALLBACKEXW,LPVOID,DWORD);
47
48 static void init_function_pointers(void)
49 {
50     HMODULE hmod = GetModuleHandleA("ddraw.dll");
51     pDirectDrawEnumerateA = (void*)GetProcAddress(hmod, "DirectDrawEnumerateA");
52     pDirectDrawEnumerateW = (void*)GetProcAddress(hmod, "DirectDrawEnumerateW");
53     pDirectDrawEnumerateExA = (void*)GetProcAddress(hmod, "DirectDrawEnumerateExA");
54     pDirectDrawEnumerateExW = (void*)GetProcAddress(hmod, "DirectDrawEnumerateExW");
55 }
56
57 static HWND createwindow(void)
58 {
59     HWND hwnd;
60
61     hwnd = CreateWindowExA(0, "TestWindowClass", "TestWindowClass",
62         WS_POPUP, 0, 0,
63         GetSystemMetrics(SM_CXSCREEN),
64         GetSystemMetrics(SM_CYSCREEN),
65         NULL, NULL, GetModuleHandleA(0), NULL);
66
67     ShowWindow(hwnd, SW_HIDE);
68     UpdateWindow(hwnd);
69     SetFocus(hwnd);
70
71     return hwnd;
72 }
73
74 static BOOL createdirectdraw(void)
75 {
76     HRESULT rc;
77
78     SetRect(&rect_before_create, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
79
80     rc = DirectDrawCreate(NULL, &lpDD, NULL);
81     ok(rc==DD_OK || rc==DDERR_NODIRECTDRAWSUPPORT, "DirectDrawCreateEx returned: %x\n", rc);
82     if (!lpDD) {
83         trace("DirectDrawCreateEx() failed with an error %x\n", rc);
84         return FALSE;
85     }
86     return TRUE;
87 }
88
89
90 static void releasedirectdraw(void)
91 {
92     if( lpDD != NULL )
93     {
94         IDirectDraw_Release(lpDD);
95         lpDD = NULL;
96         SetRect(&rect_after_delete, 0, 0,
97                 GetSystemMetrics(SM_CXSCREEN),
98                 GetSystemMetrics(SM_CYSCREEN));
99         ok(EqualRect(&rect_before_create, &rect_after_delete) != 0,
100            "Original display mode was not restored\n");
101     }
102 }
103
104 static BOOL WINAPI crash_callbackA(GUID *lpGUID, LPSTR lpDriverDescription,
105                                   LPSTR lpDriverName, LPVOID lpContext)
106 {
107     *(volatile char*)0 = 2;
108     return TRUE;
109 }
110
111 static BOOL WINAPI test_nullcontext_callbackA(GUID *lpGUID, LPSTR lpDriverDescription,
112                                               LPSTR lpDriverName, LPVOID lpContext)
113 {
114     trace("test_nullcontext_callbackA: %p %s %s %p\n",
115           lpGUID, lpDriverDescription, lpDriverName, lpContext);
116
117     ok(!lpContext, "Expected NULL lpContext\n");
118
119     return TRUE;
120 }
121
122 static BOOL WINAPI test_context_callbackA(GUID *lpGUID, LPSTR lpDriverDescription,
123                                           LPSTR lpDriverName, LPVOID lpContext)
124 {
125     trace("test_context_callbackA: %p %s %s %p\n",
126           lpGUID, lpDriverDescription, lpDriverName, lpContext);
127
128     ok(lpContext == (LPVOID)0xdeadbeef, "Expected non-NULL lpContext\n");
129
130     return TRUE;
131 }
132
133 static void test_DirectDrawEnumerateA(void)
134 {
135     HRESULT ret;
136
137     if (!pDirectDrawEnumerateA)
138     {
139         win_skip("DirectDrawEnumerateA is not available\n");
140         return;
141     }
142
143     /* Test with NULL callback parameter. */
144     ret = pDirectDrawEnumerateA(NULL, NULL);
145     ok(ret == DDERR_INVALIDPARAMS, "Expected DDERR_INVALIDPARAMS, got %d\n", ret);
146
147     /* Test with invalid callback parameter. */
148     ret = pDirectDrawEnumerateA((LPDDENUMCALLBACKA)0xdeadbeef, NULL);
149     ok(ret == DDERR_INVALIDPARAMS, "Expected DDERR_INVALIDPARAMS, got %d\n", ret);
150
151     if (pDirectDrawEnumerateExA)
152     {
153         /* Test with callback that crashes. */
154         ret = pDirectDrawEnumerateA(crash_callbackA, NULL);
155         ok(ret == DDERR_INVALIDPARAMS, "Expected DDERR_INVALIDPARAMS, got %d\n", ret);
156     }
157     else
158         win_skip("Test would crash on older ddraw\n");
159
160     /* Test with valid callback parameter and NULL context parameter. */
161     trace("Calling DirectDrawEnumerateA with test_nullcontext_callbackA callback and NULL context.\n");
162     ret = pDirectDrawEnumerateA(test_nullcontext_callbackA, NULL);
163     ok(ret == DD_OK, "Expected DD_OK, got %d\n", ret);
164
165     /* Test with valid callback parameter and valid context parameter. */
166     trace("Calling DirectDrawEnumerateA with test_context_callbackA callback and non-NULL context.\n");
167     ret = pDirectDrawEnumerateA(test_context_callbackA, (LPVOID)0xdeadbeef);
168     ok(ret == DD_OK, "Expected DD_OK, got %d\n", ret);
169 }
170
171 static BOOL WINAPI test_callbackW(GUID *lpGUID, LPWSTR lpDriverDescription,
172                                   LPWSTR lpDriverName, LPVOID lpContext)
173 {
174     ok(0, "The callback should not be invoked by DirectDrawEnumerateW\n");
175     return TRUE;
176 }
177
178 static void test_DirectDrawEnumerateW(void)
179 {
180     HRESULT ret;
181
182     if (!pDirectDrawEnumerateW)
183     {
184         win_skip("DirectDrawEnumerateW is not available\n");
185         return;
186     }
187
188     /* DirectDrawEnumerateW is not implemented on Windows. */
189
190     /* Test with NULL callback parameter. */
191     ret = pDirectDrawEnumerateW(NULL, NULL);
192     ok(ret == DDERR_INVALIDPARAMS ||
193        ret == DDERR_UNSUPPORTED, /* Older ddraw */
194        "Expected DDERR_INVALIDPARAMS or DDERR_UNSUPPORTED, got %d\n", ret);
195
196     /* Test with invalid callback parameter. */
197     ret = pDirectDrawEnumerateW((LPDDENUMCALLBACKW)0xdeadbeef, NULL);
198     ok(ret == DDERR_INVALIDPARAMS /* XP */ ||
199        ret == DDERR_UNSUPPORTED /* Win7 */,
200        "Expected DDERR_INVALIDPARAMS or DDERR_UNSUPPORTED, got %d\n", ret);
201
202     /* Test with valid callback parameter and NULL context parameter. */
203     ret = pDirectDrawEnumerateW(test_callbackW, NULL);
204     ok(ret == DDERR_UNSUPPORTED, "Expected DDERR_UNSUPPORTED, got %d\n", ret);
205 }
206
207 static BOOL WINAPI crash_callbackExA(GUID *lpGUID, LPSTR lpDriverDescription,
208                                      LPSTR lpDriverName, LPVOID lpContext,
209                                      HMONITOR hm)
210 {
211     *(volatile char*)0 = 2;
212     return TRUE;
213 }
214
215 static BOOL WINAPI test_nullcontext_callbackExA(GUID *lpGUID, LPSTR lpDriverDescription,
216                                                 LPSTR lpDriverName, LPVOID lpContext,
217                                                 HMONITOR hm)
218 {
219     trace("test_nullcontext_callbackExA: %p %s %s %p %p\n", lpGUID,
220           lpDriverDescription, lpDriverName, lpContext, hm);
221
222     ok(!lpContext, "Expected NULL lpContext\n");
223
224     return TRUE;
225 }
226
227 static BOOL WINAPI test_context_callbackExA(GUID *lpGUID, LPSTR lpDriverDescription,
228                                             LPSTR lpDriverName, LPVOID lpContext,
229                                             HMONITOR hm)
230 {
231     trace("test_context_callbackExA: %p %s %s %p %p\n", lpGUID,
232           lpDriverDescription, lpDriverName, lpContext, hm);
233
234     ok(lpContext == (LPVOID)0xdeadbeef, "Expected non-NULL lpContext\n");
235
236     return TRUE;
237 }
238
239 static void test_DirectDrawEnumerateExA(void)
240 {
241     HRESULT ret;
242
243     if (!pDirectDrawEnumerateExA)
244     {
245         win_skip("DirectDrawEnumerateExA is not available\n");
246         return;
247     }
248
249     /* Test with NULL callback parameter. */
250     ret = pDirectDrawEnumerateExA(NULL, NULL, 0);
251     ok(ret == DDERR_INVALIDPARAMS, "Expected DDERR_INVALIDPARAMS, got %d\n", ret);
252
253     /* Test with invalid callback parameter. */
254     ret = pDirectDrawEnumerateExA((LPDDENUMCALLBACKEXA)0xdeadbeef, NULL, 0);
255     ok(ret == DDERR_INVALIDPARAMS, "Expected DDERR_INVALIDPARAMS, got %d\n", ret);
256
257     /* Test with callback that crashes. */
258     ret = pDirectDrawEnumerateExA(crash_callbackExA, NULL, 0);
259     ok(ret == DDERR_INVALIDPARAMS, "Expected DDERR_INVALIDPARAMS, got %d\n", ret);
260
261     /* Test with valid callback parameter and invalid flags */
262     ret = pDirectDrawEnumerateExA(test_nullcontext_callbackExA, NULL, ~0);
263     ok(ret == DDERR_INVALIDPARAMS, "Expected DDERR_INVALIDPARAMS, got %d\n", ret);
264
265     /* Test with valid callback parameter and NULL context parameter. */
266     trace("Calling DirectDrawEnumerateExA with empty flags and NULL context.\n");
267     ret = pDirectDrawEnumerateExA(test_nullcontext_callbackExA, NULL, 0);
268     ok(ret == DD_OK, "Expected DD_OK, got %d\n", ret);
269
270     /* Test with valid callback parameter and non-NULL context parameter. */
271     trace("Calling DirectDrawEnumerateExA with empty flags and non-NULL context.\n");
272     ret = pDirectDrawEnumerateExA(test_context_callbackExA, (LPVOID)0xdeadbeef, 0);
273     ok(ret == DD_OK, "Expected DD_OK, got %d\n", ret);
274
275     /* Test with valid callback parameter, NULL context parameter, and all flags set. */
276     trace("Calling DirectDrawEnumerateExA with all flags set and NULL context.\n");
277     ret = pDirectDrawEnumerateExA(test_nullcontext_callbackExA, NULL,
278                                   DDENUM_ATTACHEDSECONDARYDEVICES |
279                                   DDENUM_DETACHEDSECONDARYDEVICES |
280                                   DDENUM_NONDISPLAYDEVICES);
281     ok(ret == DD_OK, "Expected DD_OK, got %d\n", ret);
282 }
283
284 static BOOL WINAPI test_callbackExW(GUID *lpGUID, LPWSTR lpDriverDescription,
285                                     LPWSTR lpDriverName, LPVOID lpContext,
286                                     HMONITOR hm)
287 {
288     ok(0, "The callback should not be invoked by DirectDrawEnumerateExW.\n");
289     return TRUE;
290 }
291
292 static void test_DirectDrawEnumerateExW(void)
293 {
294     HRESULT ret;
295
296     if (!pDirectDrawEnumerateExW)
297     {
298         win_skip("DirectDrawEnumerateExW is not available\n");
299         return;
300     }
301
302     /* DirectDrawEnumerateExW is not implemented on Windows. */
303
304     /* Test with NULL callback parameter. */
305     ret = pDirectDrawEnumerateExW(NULL, NULL, 0);
306     ok(ret == DDERR_UNSUPPORTED, "Expected DDERR_UNSUPPORTED, got %d\n", ret);
307
308     /* Test with invalid callback parameter. */
309     ret = pDirectDrawEnumerateExW((LPDDENUMCALLBACKEXW)0xdeadbeef, NULL, 0);
310     ok(ret == DDERR_UNSUPPORTED, "Expected DDERR_UNSUPPORTED, got %d\n", ret);
311
312     /* Test with valid callback parameter and invalid flags */
313     ret = pDirectDrawEnumerateExW(test_callbackExW, NULL, ~0);
314     ok(ret == DDERR_UNSUPPORTED, "Expected DDERR_UNSUPPORTED, got %d\n", ret);
315
316     /* Test with valid callback parameter and NULL context parameter. */
317     ret = pDirectDrawEnumerateExW(test_callbackExW, NULL, 0);
318     ok(ret == DDERR_UNSUPPORTED, "Expected DDERR_UNSUPPORTED, got %d\n", ret);
319
320     /* Test with valid callback parameter, NULL context parameter, and all flags set. */
321     ret = pDirectDrawEnumerateExW(test_callbackExW, NULL,
322                                   DDENUM_ATTACHEDSECONDARYDEVICES |
323                                   DDENUM_DETACHEDSECONDARYDEVICES |
324                                   DDENUM_NONDISPLAYDEVICES);
325     ok(ret == DDERR_UNSUPPORTED, "Expected DDERR_UNSUPPORTED, got %d\n", ret);
326 }
327
328 static void adddisplaymode(LPDDSURFACEDESC lpddsd)
329 {
330     if (!modes)
331         modes = HeapAlloc(GetProcessHeap(), 0, (modes_size = 2) * sizeof(DDSURFACEDESC));
332     if (modes_cnt == modes_size)
333         modes = HeapReAlloc(GetProcessHeap(), 0, modes, (modes_size *= 2) * sizeof(DDSURFACEDESC));
334     assert(modes);
335     modes[modes_cnt++] = *lpddsd;
336 }
337
338 static void flushdisplaymodes(void)
339 {
340     HeapFree(GetProcessHeap(), 0, modes);
341     modes = 0;
342     modes_cnt = modes_size = 0;
343 }
344
345 static HRESULT WINAPI enummodescallback(LPDDSURFACEDESC lpddsd, LPVOID lpContext)
346 {
347     trace("Width = %i, Height = %i, Refresh Rate = %i, Pitch = %i, flags =%02X\n",
348         lpddsd->dwWidth, lpddsd->dwHeight,
349           U2(*lpddsd).dwRefreshRate, U1(*lpddsd).lPitch, lpddsd->dwFlags);
350
351     /* Check that the pitch is valid if applicable */
352     if(lpddsd->dwFlags & DDSD_PITCH)
353     {
354         ok(U1(*lpddsd).lPitch != 0, "EnumDisplayModes callback with bad pitch\n");
355     }
356
357     /* Check that frequency is valid if applicable
358      *
359      * This fails on some Windows drivers or Windows versions, so it isn't important
360      * apparently
361     if(lpddsd->dwFlags & DDSD_REFRESHRATE)
362     {
363         ok(U2(*lpddsd).dwRefreshRate != 0, "EnumDisplayModes callback with bad refresh rate\n");
364     }
365      */
366
367     adddisplaymode(lpddsd);
368
369     return DDENUMRET_OK;
370 }
371
372 static void enumdisplaymodes(void)
373 {
374     DDSURFACEDESC ddsd;
375     HRESULT rc;
376
377     ZeroMemory(&ddsd, sizeof(DDSURFACEDESC));
378     ddsd.dwSize = sizeof(DDSURFACEDESC);
379     ddsd.dwFlags = DDSD_CAPS;
380     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
381
382     rc = IDirectDraw_EnumDisplayModes(lpDD,
383         DDEDM_STANDARDVGAMODES, &ddsd, 0, enummodescallback);
384     ok(rc==DD_OK || rc==E_INVALIDARG,"EnumDisplayModes returned: %x\n",rc);
385 }
386
387 static void setdisplaymode(int i)
388 {
389     HRESULT rc;
390     RECT orig_rect;
391
392     SetRect(&orig_rect, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
393
394     rc = IDirectDraw_SetCooperativeLevel(lpDD,
395         hwnd, DDSCL_ALLOWMODEX | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
396     ok(rc==DD_OK,"SetCooperativeLevel returned: %x\n",rc);
397     if (modes[i].dwFlags & DDSD_PIXELFORMAT)
398     {
399         if (modes[i].ddpfPixelFormat.dwFlags & DDPF_RGB)
400         {
401             rc = IDirectDraw_SetDisplayMode(lpDD,
402                 modes[i].dwWidth, modes[i].dwHeight,
403                 U1(modes[i].ddpfPixelFormat).dwRGBBitCount);
404             ok(DD_OK==rc || DDERR_UNSUPPORTED==rc,"SetDisplayMode returned: %x\n",rc);
405             if (rc == DD_OK)
406             {
407                 RECT r, scrn, test, virt;
408
409                 SetRect(&virt, 0, 0, GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN));
410                 OffsetRect(&virt, GetSystemMetrics(SM_XVIRTUALSCREEN), GetSystemMetrics(SM_YVIRTUALSCREEN));
411                 SetRect(&scrn, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
412                 trace("Mode (%dx%d) [%dx%d] (%d %d)x(%d %d)\n", modes[i].dwWidth, modes[i].dwHeight,
413                       scrn.right, scrn.bottom, virt.left, virt.top, virt.right, virt.bottom);
414                 if (!EqualRect(&scrn, &orig_rect))
415                 {
416                     HRESULT rect_result;
417
418                     /* Check that the client rect was resized */
419                     rc = GetClientRect(hwnd, &test);
420                     ok(rc!=0, "GetClientRect returned %x\n", rc);
421                     rc = EqualRect(&scrn, &test);
422                     todo_wine ok(rc!=0, "Fullscreen window has wrong size\n");
423
424                     /* Check that switching to normal cooperative level
425                        does not restore the display mode */
426                     rc = IDirectDraw_SetCooperativeLevel(lpDD, hwnd, DDSCL_NORMAL);
427                     ok(rc==DD_OK, "SetCooperativeLevel returned %x\n", rc);
428                     SetRect(&test, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
429                     rect_result = EqualRect(&scrn, &test);
430                     ok(rect_result!=0, "Setting cooperative level to DDSCL_NORMAL changed the display mode\n");
431
432                     /* Go back to fullscreen */
433                     rc = IDirectDraw_SetCooperativeLevel(lpDD,
434                         hwnd, DDSCL_ALLOWMODEX | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
435                     ok(rc==DD_OK, "SetCooperativeLevel returned: %x\n",rc);
436
437                     /* If the display mode was changed, set the correct mode
438                        to avoid irrelevant failures */
439                     if (rect_result == 0)
440                     {
441                         rc = IDirectDraw_SetDisplayMode(lpDD,
442                             modes[i].dwWidth, modes[i].dwHeight,
443                             U1(modes[i].ddpfPixelFormat).dwRGBBitCount);
444                         ok(DD_OK==rc, "SetDisplayMode returned: %x\n",rc);
445                     }
446                 }
447                 ok(GetClipCursor(&r), "GetClipCursor() failed\n");
448                 /* ddraw sets clip rect here to the screen size, even for
449                    multiple monitors */
450                 ok(EqualRect(&r, &scrn), "Invalid clip rect: (%d %d) x (%d %d)\n",
451                    r.left, r.top, r.right, r.bottom);
452
453                 ok(ClipCursor(NULL), "ClipCursor() failed\n");
454                 ok(GetClipCursor(&r), "GetClipCursor() failed\n");
455                 ok(EqualRect(&r, &virt), "Invalid clip rect: (%d %d) x (%d %d)\n",
456                    r.left, r.top, r.right, r.bottom);
457
458                 rc = IDirectDraw_RestoreDisplayMode(lpDD);
459                 ok(DD_OK==rc,"RestoreDisplayMode returned: %x\n",rc);
460             }
461         }
462     }
463 }
464
465 static void createsurface(void)
466 {
467     DDSURFACEDESC ddsd;
468     DDSCAPS ddscaps;
469     HRESULT rc;
470
471     ddsd.dwSize = sizeof(ddsd);
472     ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
473     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
474         DDSCAPS_FLIP |
475         DDSCAPS_COMPLEX;
476     ddsd.dwBackBufferCount = 1;
477     rc = IDirectDraw_CreateSurface(lpDD, &ddsd, &lpDDSPrimary, NULL );
478     ok(rc==DD_OK,"CreateSurface returned: %x\n",rc);
479     ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
480     rc = IDirectDrawSurface_GetAttachedSurface(lpDDSPrimary, &ddscaps, &lpDDSBack);
481     ok(rc==DD_OK,"GetAttachedSurface returned: %x\n",rc);
482 }
483
484 static void destroysurface(void)
485 {
486     if( lpDDSPrimary != NULL )
487     {
488         IDirectDrawSurface_Release(lpDDSPrimary);
489         lpDDSPrimary = NULL;
490     }
491 }
492
493 static void testsurface(void)
494 {
495     const char* testMsg = "ddraw device context test";
496     HDC hdc;
497     HRESULT rc;
498
499     rc = IDirectDrawSurface_GetDC(lpDDSBack, &hdc);
500     ok(rc==DD_OK, "IDirectDrawSurface_GetDC returned: %x\n",rc);
501     SetBkColor(hdc, RGB(0, 0, 255));
502     SetTextColor(hdc, RGB(255, 255, 0));
503     TextOut(hdc, 0, 0, testMsg, lstrlen(testMsg));
504     IDirectDrawSurface_ReleaseDC(lpDDSBack, hdc);
505     ok(rc==DD_OK, "IDirectDrawSurface_ReleaseDC returned: %x\n",rc);
506
507     while (1)
508     {
509         rc = IDirectDrawSurface_Flip(lpDDSPrimary, NULL, DDFLIP_WAIT);
510         ok(rc==DD_OK || rc==DDERR_SURFACELOST, "IDirectDrawSurface_BltFast returned: %x\n",rc);
511
512         if (rc == DD_OK)
513         {
514             break;
515         }
516         else if (rc == DDERR_SURFACELOST)
517         {
518             rc = IDirectDrawSurface_Restore(lpDDSPrimary);
519             ok(rc==DD_OK, "IDirectDrawSurface_Restore returned: %x\n",rc);
520         }
521     }
522 }
523
524 static void testdisplaymodes(void)
525 {
526     int i;
527
528     for (i = 0; i < modes_cnt; ++i)
529     {
530         setdisplaymode(i);
531         createsurface();
532         testsurface();
533         destroysurface();
534     }
535 }
536
537 static void testcooperativelevels_normal(void)
538 {
539     BOOL sfw;
540     HRESULT rc;
541     DDSURFACEDESC surfacedesc;
542     IDirectDrawSurface *surface = (IDirectDrawSurface *) 0xdeadbeef;
543
544     memset(&surfacedesc, 0, sizeof(surfacedesc));
545     surfacedesc.dwSize = sizeof(surfacedesc);
546     surfacedesc.ddpfPixelFormat.dwSize = sizeof(surfacedesc.ddpfPixelFormat);
547     surfacedesc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
548     surfacedesc.dwBackBufferCount = 1;
549     surfacedesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;
550
551     rc = IDirectDraw_SetCooperativeLevel(lpDD, hwnd, DDSCL_SETFOCUSWINDOW | DDSCL_CREATEDEVICEWINDOW);
552     ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_SETFOCUSWINDOW | DDSCL_CREATEDEVICEWINDOW) returned: %x\n",rc);
553
554     /* Do some tests with DDSCL_NORMAL mode */
555
556     /* Fullscreen mode + normal mode + exclusive mode */
557
558     rc = IDirectDraw_SetCooperativeLevel(lpDD, NULL, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE | DDSCL_NORMAL);
559     ok(rc==DDERR_INVALIDPARAMS, "Expected DDERR_INVALIDPARAMS, received: %x\n", rc);
560
561     sfw=FALSE;
562     if(hwnd2)
563         sfw=SetForegroundWindow(hwnd2);
564     else
565         skip("Failed to create the second window\n");
566
567     rc = IDirectDraw_SetCooperativeLevel(lpDD, hwnd, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE | DDSCL_NORMAL);
568     ok(rc==DD_OK,"SetCooperativeLevel(DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE | DDSCL_NORMAL) returned: %x\n",rc);
569
570     if(sfw)
571         ok(GetForegroundWindow()==hwnd,"Expected the main windows (%p) for foreground, received the second one (%p)\n",hwnd, hwnd2);
572
573     /* Try creating a double buffered primary in fullscreen + exclusive + normal mode */
574     rc = IDirectDraw_CreateSurface(lpDD, &surfacedesc, &surface, NULL);
575
576     if (rc == DDERR_UNSUPPORTEDMODE)
577         skip("Unsupported mode\n");
578     else
579     {
580         ok(rc == DD_OK, "IDirectDraw_CreateSurface returned %08x\n", rc);
581         ok(surface!=NULL, "Returned NULL surface pointer\n");
582     }
583     if(surface && surface != (IDirectDrawSurface *)0xdeadbeef) IDirectDrawSurface_Release(surface);
584
585     /* Exclusive mode + normal mode */
586     rc = IDirectDraw_SetCooperativeLevel(lpDD, hwnd, DDSCL_EXCLUSIVE | DDSCL_NORMAL);
587     ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_EXCLUSIVE | DDSCL_NORMAL) returned: %x\n",rc);
588
589     /* Fullscreen mode + normal mode */
590
591     sfw=FALSE;
592     if(hwnd2) sfw=SetForegroundWindow(hwnd2);
593
594     rc = IDirectDraw_SetCooperativeLevel(lpDD, hwnd, DDSCL_FULLSCREEN | DDSCL_NORMAL);
595     ok(rc==DD_OK,"SetCooperativeLevel(DDSCL_FULLSCREEN | DDSCL_NORMAL) returned: %x\n",rc);
596
597     if(sfw)
598         ok(GetForegroundWindow()==hwnd2,"Expected the second windows (%p) for foreground, received the main one (%p)\n",hwnd2, hwnd);
599
600     rc = IDirectDraw_SetCooperativeLevel(lpDD, NULL, DDSCL_FULLSCREEN | DDSCL_NORMAL);
601     ok(rc==DD_OK, "Expected DD_OK, received %x\n", rc);
602
603     /* Try creating a double buffered primary in fullscreen + normal mode */
604     rc = IDirectDraw_CreateSurface(lpDD, &surfacedesc, &surface, NULL);
605     if (rc == DDERR_UNSUPPORTEDMODE)
606         skip("Unsupported mode\n");
607     else
608     {
609         ok(rc == DDERR_NOEXCLUSIVEMODE, "IDirectDraw_CreateSurface returned %08x\n", rc);
610         ok(surface == NULL, "Returned surface pointer is %p\n", surface);
611     }
612
613     if(surface && surface != (IDirectDrawSurface *)0xdeadbeef) IDirectDrawSurface_Release(surface);
614
615     /* switching from Fullscreen mode to Normal mode */
616
617     sfw=FALSE;
618     if(hwnd2) sfw=SetForegroundWindow(hwnd2);
619
620     rc = IDirectDraw_SetCooperativeLevel(lpDD,
621         hwnd, DDSCL_NORMAL);
622     ok(rc==DD_OK,"SetCooperativeLevel(DDSCL_NORMAL) returned: %x\n",rc);
623
624     if(sfw)
625         ok(GetForegroundWindow()==hwnd2,"Expected the second windows (%p) for foreground, received the main one (%p)\n",hwnd2, hwnd);
626
627     rc = IDirectDraw_SetCooperativeLevel(lpDD, NULL, DDSCL_NORMAL);
628     ok(rc==DD_OK, "Expected DD_OK, received %x\n", rc);
629
630     /* Try creating a double buffered primary in normal mode */
631     rc = IDirectDraw_CreateSurface(lpDD, &surfacedesc, &surface, NULL);
632     if (rc == DDERR_UNSUPPORTEDMODE)
633         skip("Unsupported mode\n");
634     else
635     {
636         ok(rc == DDERR_NOEXCLUSIVEMODE, "IDirectDraw_CreateSurface returned %08x\n", rc);
637         ok(surface == NULL, "Returned surface pointer is %p\n", surface);
638     }
639     if(surface && surface != (IDirectDrawSurface *)0xdeadbeef) IDirectDrawSurface_Release(surface);
640
641     /* switching from Normal mode to Fullscreen + Normal mode */
642
643     sfw=FALSE;
644     if(hwnd2) sfw=SetForegroundWindow(hwnd2);
645
646     rc = IDirectDraw_SetCooperativeLevel(lpDD,
647         hwnd, DDSCL_NORMAL | DDSCL_FULLSCREEN);
648     ok(rc==DD_OK,"SetCooperativeLevel(DDSCL_NORMAL | FULLSCREEN) returned: %x\n",rc);
649
650     if(sfw)
651         ok(GetForegroundWindow()==hwnd2,"Expected the second windows (%p) for foreground, received the main one (%p)\n",hwnd2, hwnd);
652
653     rc = IDirectDraw_SetCooperativeLevel(lpDD, NULL, DDSCL_NORMAL | DDSCL_FULLSCREEN);
654     ok(rc==DD_OK, "Expected DD_OK, received %x\n", rc);
655
656     /* Set the focus window */
657
658     rc = IDirectDraw_SetCooperativeLevel(lpDD, hwnd, DDSCL_SETFOCUSWINDOW | DDSCL_CREATEDEVICEWINDOW);
659     ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_SETFOCUSWINDOW | DDSCL_CREATEDEVICEWINDOW) returned: %x\n",rc);
660
661     rc = IDirectDraw_SetCooperativeLevel(lpDD, NULL, DDSCL_SETFOCUSWINDOW);
662
663     if (rc == DDERR_INVALIDPARAMS)
664     {
665         win_skip("NT4/Win95 do not support cooperative levels DDSCL_SETDEVICEWINDOW and DDSCL_SETFOCUSWINDOW\n");
666         return;
667     }
668
669     ok(rc==DD_OK, "Expected DD_OK, received %x\n", rc);
670
671     rc = IDirectDraw_SetCooperativeLevel(lpDD,
672         hwnd, DDSCL_SETFOCUSWINDOW);
673
674     if (rc == DDERR_INVALIDPARAMS)
675     {
676         win_skip("NT4/Win95 do not support cooperative levels DDSCL_SETDEVICEWINDOW and DDSCL_SETFOCUSWINDOW\n");
677         return;
678     }
679
680     ok(rc==DD_OK,"SetCooperativeLevel(DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
681
682     /* Set the focus window a second time*/
683     rc = IDirectDraw_SetCooperativeLevel(lpDD,
684         hwnd, DDSCL_SETFOCUSWINDOW);
685     ok(rc==DD_OK,"SetCooperativeLevel(DDSCL_SETFOCUSWINDOW) the second time returned: %x\n",rc);
686
687     /* Test DDSCL_SETFOCUSWINDOW with the other flags. They should all fail, except of DDSCL_NOWINDOWCHANGES */
688     rc = IDirectDraw_SetCooperativeLevel(lpDD,
689         hwnd, DDSCL_NORMAL | DDSCL_SETFOCUSWINDOW);
690     ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_NORMAL | DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
691
692     rc = IDirectDraw_SetCooperativeLevel(lpDD,
693         hwnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_SETFOCUSWINDOW);
694     ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
695
696     /* This one succeeds */
697     rc = IDirectDraw_SetCooperativeLevel(lpDD,
698         hwnd, DDSCL_NOWINDOWCHANGES | DDSCL_SETFOCUSWINDOW);
699     ok(rc==DD_OK,"SetCooperativeLevel(DDSCL_NOWINDOWCHANGES | DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
700
701     rc = IDirectDraw_SetCooperativeLevel(lpDD,
702         hwnd, DDSCL_MULTITHREADED | DDSCL_SETFOCUSWINDOW);
703     ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_MULTITHREADED | DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
704
705     rc = IDirectDraw_SetCooperativeLevel(lpDD,
706         hwnd, DDSCL_FPUSETUP | DDSCL_SETFOCUSWINDOW);
707     ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_FPUSETUP | DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
708
709     rc = IDirectDraw_SetCooperativeLevel(lpDD,
710         hwnd, DDSCL_FPUPRESERVE | DDSCL_SETFOCUSWINDOW);
711     ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_FPUPRESERVE | DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
712
713     rc = IDirectDraw_SetCooperativeLevel(lpDD,
714         hwnd, DDSCL_ALLOWREBOOT | DDSCL_SETFOCUSWINDOW);
715     ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_ALLOWREBOOT | DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
716
717     rc = IDirectDraw_SetCooperativeLevel(lpDD,
718         hwnd, DDSCL_ALLOWMODEX | DDSCL_SETFOCUSWINDOW);
719     ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_ALLOWMODEX | DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
720
721     /* Set the device window without any other flags. Should give an error */
722     rc = IDirectDraw_SetCooperativeLevel(lpDD,
723         hwnd, DDSCL_SETDEVICEWINDOW);
724     ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_SETDEVICEWINDOW) returned: %x\n",rc);
725
726     /* Set device window with DDSCL_NORMAL */
727     rc = IDirectDraw_SetCooperativeLevel(lpDD,
728         hwnd, DDSCL_NORMAL | DDSCL_SETDEVICEWINDOW);
729     ok(rc==DD_OK,"SetCooperativeLevel(DDSCL_NORMAL | DDSCL_SETDEVICEWINDOW) returned: %x\n",rc);
730
731     /* Also set the focus window. Should give an error */
732     rc = IDirectDraw_SetCooperativeLevel(lpDD,
733         hwnd, DDSCL_ALLOWMODEX | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_SETDEVICEWINDOW | DDSCL_SETFOCUSWINDOW);
734     ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_NORMAL | DDSCL_SETDEVICEWINDOW | DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
735
736     /* All done */
737 }
738
739 static void testcooperativelevels_exclusive(void)
740 {
741     BOOL sfw, success;
742     HRESULT rc;
743     RECT window_rect;
744
745     /* Do some tests with DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN mode */
746
747     /* First, resize the window so it is not the same size as any screen */
748     success = SetWindowPos(hwnd, 0, 0, 0, 281, 92, 0);
749     ok(success, "SetWindowPos failed\n");
750
751     /* Try to set exclusive mode only */
752     rc = IDirectDraw_SetCooperativeLevel(lpDD,
753         hwnd, DDSCL_EXCLUSIVE);
754     ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_EXCLUSIVE) returned: %x\n",rc);
755
756     /* Full screen mode only */
757     rc = IDirectDraw_SetCooperativeLevel(lpDD,
758         hwnd, DDSCL_FULLSCREEN);
759     ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_FULLSCREEN) returned: %x\n",rc);
760
761     /* Full screen mode + exclusive mode */
762
763     rc = IDirectDraw_SetCooperativeLevel(lpDD, NULL, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE);
764     ok(rc==DDERR_INVALIDPARAMS, "Expected DDERR_INVALIDPARAMS, received %x\n", rc);
765
766     sfw=FALSE;
767     if(hwnd2)
768         sfw=SetForegroundWindow(hwnd2);
769     else
770         skip("Failed to create the second window\n");
771
772     rc = IDirectDraw_SetCooperativeLevel(lpDD,
773         hwnd, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE);
774     ok(rc==DD_OK,"SetCooperativeLevel(DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN) returned: %x\n",rc);
775
776     if(sfw)
777         ok(GetForegroundWindow()==hwnd,"Expected the main windows (%p) for foreground, received the second one (%p)\n",hwnd, hwnd2);
778
779     /* rect_before_create is assumed to hold the screen rect */
780     GetClientRect(hwnd, &window_rect);
781     rc = EqualRect(&rect_before_create, &window_rect);
782     ok(rc, "Fullscreen window has wrong size.\n");
783
784     /* Set the focus window. Should fail */
785     rc = IDirectDraw_SetCooperativeLevel(lpDD,
786         hwnd, DDSCL_SETFOCUSWINDOW);
787     ok(rc==DDERR_HWNDALREADYSET ||
788        broken(rc==DDERR_INVALIDPARAMS) /* NT4/Win95 */,"SetCooperativeLevel(DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
789
790
791     /* All done */
792 }
793
794 static void testddraw3(void)
795 {
796     const GUID My_IID_IDirectDraw3 = {
797         0x618f8ad4,
798         0x8b7a,
799         0x11d0,
800         { 0x8f,0xcc,0x0,0xc0,0x4f,0xd9,0x18,0x9d }
801     };
802     IDirectDraw3 *dd3;
803     HRESULT hr;
804     hr = IDirectDraw_QueryInterface(lpDD, &My_IID_IDirectDraw3, (void **) &dd3);
805     ok(hr == E_NOINTERFACE, "QueryInterface for IID_IDirectDraw3 returned 0x%08x, expected E_NOINTERFACE\n", hr);
806     if(SUCCEEDED(hr) && dd3) IDirectDraw3_Release(dd3);
807 }
808
809 static void testddraw7(void)
810 {
811     IDirectDraw7 *dd7;
812     HRESULT hr;
813     DDDEVICEIDENTIFIER2 *pdddi2;
814     DWORD dddi2Bytes;
815     DWORD *pend;
816
817     hr = IDirectDraw_QueryInterface(lpDD, &IID_IDirectDraw7, (void **) &dd7);
818     if (hr==E_NOINTERFACE)
819     {
820         win_skip("DirectDraw7 is not supported\n");
821         return;
822     }
823     ok(hr==DD_OK, "IDirectDraw7_QueryInterface returned %08x\n", hr);
824
825     if (hr==DD_OK)
826     {
827          dddi2Bytes = FIELD_OFFSET(DDDEVICEIDENTIFIER2, dwWHQLLevel) + sizeof(DWORD);
828
829          pdddi2 = HeapAlloc( GetProcessHeap(), 0, dddi2Bytes + 2*sizeof(DWORD) );
830          pend = (DWORD *)((char *)pdddi2 + dddi2Bytes);
831          pend[0] = 0xdeadbeef;
832          pend[1] = 0xdeadbeef;
833
834          hr = IDirectDraw7_GetDeviceIdentifier(dd7, pdddi2, 0);
835          ok(hr==DD_OK, "get device identifier failed with %08x\n", hr);
836
837          if (hr==DD_OK)
838          {
839              /* check how strings are copied into the structure */
840              ok(pdddi2->szDriver[MAX_DDDEVICEID_STRING - 1]==0, "szDriver not cleared\n");
841              ok(pdddi2->szDescription[MAX_DDDEVICEID_STRING - 1]==0, "szDescription not cleared\n");
842              /* verify that 8 byte structure size alignment will not overwrite memory */
843              ok(pend[0]==0xdeadbeef || broken(pend[0] != 0xdeadbeef), /* win2k */
844                 "memory beyond DDDEVICEIDENTIFIER2 overwritten\n");
845              ok(pend[1]==0xdeadbeef, "memory beyond DDDEVICEIDENTIFIER2 overwritten\n");
846          }
847
848          IDirectDraw_Release(dd7);
849          HeapFree( GetProcessHeap(), 0, pdddi2 );
850     }
851 }
852
853 START_TEST(ddrawmodes)
854 {
855     init_function_pointers();
856
857     wc.style = CS_HREDRAW | CS_VREDRAW;
858     wc.lpfnWndProc = DefWindowProcA;
859     wc.cbClsExtra = 0;
860     wc.cbWndExtra = 0;
861     wc.hInstance = GetModuleHandleA(0);
862     wc.hIcon = LoadIconA(wc.hInstance, IDI_APPLICATION);
863     wc.hCursor = LoadCursorA(NULL, IDC_ARROW);
864     wc.hbrBackground = GetStockObject(BLACK_BRUSH);
865     wc.lpszMenuName = NULL;
866     wc.lpszClassName = "TestWindowClass";
867     if (!RegisterClassA(&wc))
868     {
869         skip("RegisterClassA failed\n");
870         return;
871     }
872
873     hwnd2=createwindow();
874     hwnd=createwindow();
875
876     if (!hwnd)
877     {
878         skip("Failed to create the main window\n");
879         return;
880     }
881
882     if (!createdirectdraw())
883     {
884         skip("Failed to create the direct draw object\n");
885         return;
886     }
887
888     test_DirectDrawEnumerateA();
889     test_DirectDrawEnumerateW();
890     test_DirectDrawEnumerateExA();
891     test_DirectDrawEnumerateExW();
892
893     enumdisplaymodes();
894     if (winetest_interactive)
895         testdisplaymodes();
896     flushdisplaymodes();
897     testddraw3();
898     testddraw7();
899     releasedirectdraw();
900
901     createdirectdraw();
902     testcooperativelevels_normal();
903     releasedirectdraw();
904
905     createdirectdraw();
906     testcooperativelevels_exclusive();
907     releasedirectdraw();
908 }