ddraw: Simplify and test DirectDrawEnumerateA.
[wine/multimedia.git] / dlls / ddraw / tests / ddrawmodes.c
blob013862bbff2af56ec991d0e0492b01213473a4ea
1 /*
2 * Unit tests for ddraw functions
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.
11 * Copyright (C) 2003 Sami Aario
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.
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.
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
28 #include <assert.h>
29 #include "wine/test.h"
30 #include "ddraw.h"
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;
41 static HRESULT (WINAPI *pDirectDrawEnumerateA)(LPDDENUMCALLBACKA,LPVOID);
43 static void init_function_pointers(void)
45 HMODULE hmod = GetModuleHandleA("ddraw.dll");
46 pDirectDrawEnumerateA = (void*)GetProcAddress(hmod, "DirectDrawEnumerateA");
49 static void createwindow(void)
51 wc.style = CS_HREDRAW | CS_VREDRAW;
52 wc.lpfnWndProc = DefWindowProcA;
53 wc.cbClsExtra = 0;
54 wc.cbWndExtra = 0;
55 wc.hInstance = GetModuleHandleA(0);
56 wc.hIcon = LoadIconA(wc.hInstance, IDI_APPLICATION);
57 wc.hCursor = LoadCursorA(NULL, IDC_ARROW);
58 wc.hbrBackground = GetStockObject(BLACK_BRUSH);
59 wc.lpszMenuName = NULL;
60 wc.lpszClassName = "TestWindowClass";
61 if(!RegisterClassA(&wc))
62 assert(0);
64 hwnd = CreateWindowExA(0, "TestWindowClass", "TestWindowClass",
65 WS_POPUP, 0, 0,
66 GetSystemMetrics(SM_CXSCREEN),
67 GetSystemMetrics(SM_CYSCREEN),
68 NULL, NULL, GetModuleHandleA(0), NULL);
69 assert(hwnd != NULL);
71 ShowWindow(hwnd, SW_HIDE);
72 UpdateWindow(hwnd);
73 SetFocus(hwnd);
76 static BOOL createdirectdraw(void)
78 HRESULT rc;
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;
86 return TRUE;
90 static void releasedirectdraw(void)
92 if( lpDD != NULL )
94 IDirectDraw_Release(lpDD);
95 lpDD = NULL;
99 static BOOL WINAPI crash_callbackA(GUID *lpGUID, LPSTR lpDriverDescription,
100 LPSTR lpDriverName, LPVOID lpContext)
102 *(volatile char*)0 = 2;
103 return TRUE;
106 static BOOL WINAPI test_nullcontext_callbackA(GUID *lpGUID, LPSTR lpDriverDescription,
107 LPSTR lpDriverName, LPVOID lpContext)
109 trace("test_nullcontext_callbackA: %p %s %s %p\n",
110 lpGUID, lpDriverDescription, lpDriverName, lpContext);
112 ok(!lpContext, "Expected NULL lpContext\n");
114 return TRUE;
117 static BOOL WINAPI test_context_callbackA(GUID *lpGUID, LPSTR lpDriverDescription,
118 LPSTR lpDriverName, LPVOID lpContext)
120 trace("test_context_callbackA: %p %s %s %p\n",
121 lpGUID, lpDriverDescription, lpDriverName, lpContext);
123 ok(lpContext == (LPVOID)0xdeadbeef, "Expected non-NULL lpContext\n");
125 return TRUE;
128 static void test_DirectDrawEnumerateA(void)
130 HRESULT ret;
132 if (!pDirectDrawEnumerateA)
134 win_skip("DirectDrawEnumerateA is not available\n");
135 return;
138 /* Test with NULL callback parameter. */
139 ret = pDirectDrawEnumerateA(NULL, NULL);
140 ok(ret == DDERR_INVALIDPARAMS, "Expected DDERR_INVALIDPARAMS, got %d\n", ret);
142 /* Test with invalid callback parameter. */
143 ret = pDirectDrawEnumerateA((LPDDENUMCALLBACKA)0xdeadbeef, NULL);
144 ok(ret == DDERR_INVALIDPARAMS, "Expected DDERR_INVALIDPARAMS, got %d\n", ret);
146 /* Test with callback that crashes. */
147 ret = pDirectDrawEnumerateA(crash_callbackA, NULL);
148 ok(ret == DDERR_INVALIDPARAMS, "Expected DDERR_INVALIDPARAMS, got %d\n", ret);
150 /* Test with valid callback parameter and NULL context parameter. */
151 trace("Calling DirectDrawEnumerateA with test_nullcontext_callbackA callback and NULL context.\n");
152 ret = pDirectDrawEnumerateA(test_nullcontext_callbackA, NULL);
153 ok(ret == DD_OK, "Expected DD_OK, got %d\n", ret);
155 /* Test with valid callback parameter and valid context parameter. */
156 trace("Calling DirectDrawEnumerateA with test_context_callbackA callback and non-NULL context.\n");
157 ret = pDirectDrawEnumerateA(test_context_callbackA, (LPVOID)0xdeadbeef);
158 ok(ret == DD_OK, "Expected DD_OK, got %d\n", ret);
161 static void adddisplaymode(LPDDSURFACEDESC lpddsd)
163 if (!modes)
164 modes = HeapAlloc(GetProcessHeap(), 0, (modes_size = 2) * sizeof(DDSURFACEDESC));
165 if (modes_cnt == modes_size)
166 modes = HeapReAlloc(GetProcessHeap(), 0, modes, (modes_size *= 2) * sizeof(DDSURFACEDESC));
167 assert(modes);
168 modes[modes_cnt++] = *lpddsd;
171 static void flushdisplaymodes(void)
173 HeapFree(GetProcessHeap(), 0, modes);
174 modes = 0;
175 modes_cnt = modes_size = 0;
178 static HRESULT WINAPI enummodescallback(LPDDSURFACEDESC lpddsd, LPVOID lpContext)
180 trace("Width = %i, Height = %i, Refresh Rate = %i, Pitch = %i, flags =%02X\r\n",
181 lpddsd->dwWidth, lpddsd->dwHeight,
182 U2(*lpddsd).dwRefreshRate, U1(*lpddsd).lPitch, lpddsd->dwFlags);
184 /* Check that the pitch is valid if applicable */
185 if(lpddsd->dwFlags & DDSD_PITCH)
187 ok(U1(*lpddsd).lPitch != 0, "EnumDisplayModes callback with bad pitch\n");
190 /* Check that frequency is valid if applicable
192 * This fails on some Windows drivers or Windows versions, so it isn't important
193 * apparently
194 if(lpddsd->dwFlags & DDSD_REFRESHRATE)
196 ok(U2(*lpddsd).dwRefreshRate != 0, "EnumDisplayModes callback with bad refresh rate\n");
200 adddisplaymode(lpddsd);
202 return DDENUMRET_OK;
205 static void enumdisplaymodes(void)
207 DDSURFACEDESC ddsd;
208 HRESULT rc;
210 ZeroMemory(&ddsd, sizeof(DDSURFACEDESC));
211 ddsd.dwSize = sizeof(DDSURFACEDESC);
212 ddsd.dwFlags = DDSD_CAPS;
213 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
215 rc = IDirectDraw_EnumDisplayModes(lpDD,
216 DDEDM_STANDARDVGAMODES, &ddsd, 0, enummodescallback);
217 ok(rc==DD_OK || rc==E_INVALIDARG,"EnumDisplayModes returned: %x\n",rc);
220 static void setdisplaymode(int i)
222 HRESULT rc;
224 rc = IDirectDraw_SetCooperativeLevel(lpDD,
225 hwnd, DDSCL_ALLOWMODEX | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
226 ok(rc==DD_OK,"SetCooperativeLevel returned: %x\n",rc);
227 if (modes[i].dwFlags & DDSD_PIXELFORMAT)
229 if (modes[i].ddpfPixelFormat.dwFlags & DDPF_RGB)
231 rc = IDirectDraw_SetDisplayMode(lpDD,
232 modes[i].dwWidth, modes[i].dwHeight,
233 U1(modes[i].ddpfPixelFormat).dwRGBBitCount);
234 ok(DD_OK==rc || DDERR_UNSUPPORTED==rc,"SetDisplayMode returned: %x\n",rc);
235 if (rc == DD_OK)
237 RECT r, scrn, virt;
239 SetRect(&virt, 0, 0, GetSystemMetrics(SM_CXVIRTUALSCREEN), GetSystemMetrics(SM_CYVIRTUALSCREEN));
240 OffsetRect(&virt, GetSystemMetrics(SM_XVIRTUALSCREEN), GetSystemMetrics(SM_YVIRTUALSCREEN));
241 SetRect(&scrn, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
242 trace("Mode (%dx%d) [%dx%d] (%d %d)x(%d %d)\n", modes[i].dwWidth, modes[i].dwHeight,
243 scrn.right, scrn.bottom, virt.left, virt.top, virt.right, virt.bottom);
245 ok(GetClipCursor(&r), "GetClipCursor() failed\n");
246 /* ddraw sets clip rect here to the screen size, even for
247 multiple monitors */
248 ok(EqualRect(&r, &scrn), "Invalid clip rect: (%d %d) x (%d %d)\n",
249 r.left, r.top, r.right, r.bottom);
251 ok(ClipCursor(NULL), "ClipCursor() failed\n");
252 ok(GetClipCursor(&r), "GetClipCursor() failed\n");
253 ok(EqualRect(&r, &virt), "Invalid clip rect: (%d %d) x (%d %d)\n",
254 r.left, r.top, r.right, r.bottom);
256 rc = IDirectDraw_RestoreDisplayMode(lpDD);
257 ok(DD_OK==rc,"RestoreDisplayMode returned: %x\n",rc);
263 static void createsurface(void)
265 DDSURFACEDESC ddsd;
266 DDSCAPS ddscaps;
267 HRESULT rc;
269 ddsd.dwSize = sizeof(ddsd);
270 ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
271 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
272 DDSCAPS_FLIP |
273 DDSCAPS_COMPLEX;
274 ddsd.dwBackBufferCount = 1;
275 rc = IDirectDraw_CreateSurface(lpDD, &ddsd, &lpDDSPrimary, NULL );
276 ok(rc==DD_OK,"CreateSurface returned: %x\n",rc);
277 ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
278 rc = IDirectDrawSurface_GetAttachedSurface(lpDDSPrimary, &ddscaps, &lpDDSBack);
279 ok(rc==DD_OK,"GetAttachedSurface returned: %x\n",rc);
282 static void destroysurface(void)
284 if( lpDDSPrimary != NULL )
286 IDirectDrawSurface_Release(lpDDSPrimary);
287 lpDDSPrimary = NULL;
291 static void testsurface(void)
293 const char* testMsg = "ddraw device context test";
294 HDC hdc;
295 HRESULT rc;
297 rc = IDirectDrawSurface_GetDC(lpDDSBack, &hdc);
298 ok(rc==DD_OK, "IDirectDrawSurface_GetDC returned: %x\n",rc);
299 SetBkColor(hdc, RGB(0, 0, 255));
300 SetTextColor(hdc, RGB(255, 255, 0));
301 TextOut(hdc, 0, 0, testMsg, lstrlen(testMsg));
302 IDirectDrawSurface_ReleaseDC(lpDDSBack, hdc);
303 ok(rc==DD_OK, "IDirectDrawSurface_ReleaseDC returned: %x\n",rc);
305 while (1)
307 rc = IDirectDrawSurface_Flip(lpDDSPrimary, NULL, DDFLIP_WAIT);
308 ok(rc==DD_OK || rc==DDERR_SURFACELOST, "IDirectDrawSurface_BltFast returned: %x\n",rc);
310 if (rc == DD_OK)
312 break;
314 else if (rc == DDERR_SURFACELOST)
316 rc = IDirectDrawSurface_Restore(lpDDSPrimary);
317 ok(rc==DD_OK, "IDirectDrawSurface_Restore returned: %x\n",rc);
322 static void testdisplaymodes(void)
324 int i;
326 for (i = 0; i < modes_cnt; ++i)
328 setdisplaymode(i);
329 createsurface();
330 testsurface();
331 destroysurface();
335 static void testcooperativelevels_normal(void)
337 HRESULT rc;
338 DDSURFACEDESC surfacedesc;
339 IDirectDrawSurface *surface = (IDirectDrawSurface *) 0xdeadbeef;
341 memset(&surfacedesc, 0, sizeof(surfacedesc));
342 surfacedesc.dwSize = sizeof(surfacedesc);
343 surfacedesc.ddpfPixelFormat.dwSize = sizeof(surfacedesc.ddpfPixelFormat);
344 surfacedesc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
345 surfacedesc.dwBackBufferCount = 1;
346 surfacedesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;
348 /* Do some tests with DDSCL_NORMAL mode */
350 rc = IDirectDraw_SetCooperativeLevel(lpDD,
351 hwnd, DDSCL_NORMAL);
352 ok(rc==DD_OK,"SetCooperativeLevel(DDSCL_NORMAL) returned: %x\n",rc);
354 /* Try creating a double buffered primary in normal mode */
355 rc = IDirectDraw_CreateSurface(lpDD, &surfacedesc, &surface, NULL);
356 if (rc == DDERR_UNSUPPORTEDMODE)
357 skip("Unsupported mode\n");
358 else
360 ok(rc == DDERR_NOEXCLUSIVEMODE, "IDirectDraw_CreateSurface returned %08x\n", rc);
361 ok(surface == NULL, "Returned surface pointer is %p\n", surface);
363 if(surface && surface != (IDirectDrawSurface *)0xdeadbeef) IDirectDrawSurface_Release(surface);
365 /* Set the focus window */
366 rc = IDirectDraw_SetCooperativeLevel(lpDD,
367 hwnd, DDSCL_SETFOCUSWINDOW);
369 if (rc == DDERR_INVALIDPARAMS)
371 win_skip("NT4/Win95 do not support cooperative levels DDSCL_SETDEVICEWINDOW and DDSCL_SETFOCUSWINDOW\n");
372 return;
375 ok(rc==DD_OK,"SetCooperativeLevel(DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
377 /* Set the focus window a second time*/
378 rc = IDirectDraw_SetCooperativeLevel(lpDD,
379 hwnd, DDSCL_SETFOCUSWINDOW);
380 ok(rc==DD_OK,"SetCooperativeLevel(DDSCL_SETFOCUSWINDOW) the second time returned: %x\n",rc);
382 /* Test DDSCL_SETFOCUSWINDOW with the other flags. They should all fail, except of DDSCL_NOWINDOWCHANGES */
383 rc = IDirectDraw_SetCooperativeLevel(lpDD,
384 hwnd, DDSCL_NORMAL | DDSCL_SETFOCUSWINDOW);
385 ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_NORMAL | DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
387 rc = IDirectDraw_SetCooperativeLevel(lpDD,
388 hwnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_SETFOCUSWINDOW);
389 ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
391 /* This one succeeds */
392 rc = IDirectDraw_SetCooperativeLevel(lpDD,
393 hwnd, DDSCL_NOWINDOWCHANGES | DDSCL_SETFOCUSWINDOW);
394 ok(rc==DD_OK,"SetCooperativeLevel(DDSCL_NOWINDOWCHANGES | DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
396 rc = IDirectDraw_SetCooperativeLevel(lpDD,
397 hwnd, DDSCL_MULTITHREADED | DDSCL_SETFOCUSWINDOW);
398 ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_MULTITHREADED | DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
400 rc = IDirectDraw_SetCooperativeLevel(lpDD,
401 hwnd, DDSCL_FPUSETUP | DDSCL_SETFOCUSWINDOW);
402 ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_FPUSETUP | DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
404 rc = IDirectDraw_SetCooperativeLevel(lpDD,
405 hwnd, DDSCL_FPUPRESERVE | DDSCL_SETFOCUSWINDOW);
406 ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_FPUPRESERVE | DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
408 rc = IDirectDraw_SetCooperativeLevel(lpDD,
409 hwnd, DDSCL_ALLOWREBOOT | DDSCL_SETFOCUSWINDOW);
410 ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_ALLOWREBOOT | DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
412 rc = IDirectDraw_SetCooperativeLevel(lpDD,
413 hwnd, DDSCL_ALLOWMODEX | DDSCL_SETFOCUSWINDOW);
414 ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_ALLOWMODEX | DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
416 /* Set the device window without any other flags. Should give an error */
417 rc = IDirectDraw_SetCooperativeLevel(lpDD,
418 hwnd, DDSCL_SETDEVICEWINDOW);
419 ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_SETDEVICEWINDOW) returned: %x\n",rc);
421 /* Set device window with DDSCL_NORMAL */
422 rc = IDirectDraw_SetCooperativeLevel(lpDD,
423 hwnd, DDSCL_NORMAL | DDSCL_SETDEVICEWINDOW);
424 ok(rc==DD_OK,"SetCooperativeLevel(DDSCL_NORMAL | DDSCL_SETDEVICEWINDOW) returned: %x\n",rc);
426 /* Also set the focus window. Should give an error */
427 rc = IDirectDraw_SetCooperativeLevel(lpDD,
428 hwnd, DDSCL_ALLOWMODEX | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_SETDEVICEWINDOW | DDSCL_SETFOCUSWINDOW);
429 ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_NORMAL | DDSCL_SETDEVICEWINDOW | DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
431 /* All done */
434 static void testcooperativelevels_exclusive(void)
436 HRESULT rc;
438 /* Do some tests with DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN mode */
440 /* Try to set exclusive mode only */
441 rc = IDirectDraw_SetCooperativeLevel(lpDD,
442 hwnd, DDSCL_EXCLUSIVE);
443 ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_EXCLUSIVE) returned: %x\n",rc);
445 /* Full screen mode only */
446 rc = IDirectDraw_SetCooperativeLevel(lpDD,
447 hwnd, DDSCL_FULLSCREEN);
448 ok(rc==DDERR_INVALIDPARAMS,"SetCooperativeLevel(DDSCL_FULLSCREEN) returned: %x\n",rc);
450 /* Full screen mode + exclusive mode */
451 rc = IDirectDraw_SetCooperativeLevel(lpDD,
452 hwnd, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE);
453 ok(rc==DD_OK,"SetCooperativeLevel(DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN) returned: %x\n",rc);
455 /* Set the focus window. Should fail */
456 rc = IDirectDraw_SetCooperativeLevel(lpDD,
457 hwnd, DDSCL_SETFOCUSWINDOW);
458 ok(rc==DDERR_HWNDALREADYSET ||
459 broken(rc==DDERR_INVALIDPARAMS) /* NT4/Win95 */,"SetCooperativeLevel(DDSCL_SETFOCUSWINDOW) returned: %x\n",rc);
462 /* All done */
465 static void testddraw3(void)
467 const GUID My_IID_IDirectDraw3 = {
468 0x618f8ad4,
469 0x8b7a,
470 0x11d0,
471 { 0x8f,0xcc,0x0,0xc0,0x4f,0xd9,0x18,0x9d }
473 IDirectDraw3 *dd3;
474 HRESULT hr;
475 hr = IDirectDraw_QueryInterface(lpDD, &My_IID_IDirectDraw3, (void **) &dd3);
476 ok(hr == E_NOINTERFACE, "QueryInterface for IID_IDirectDraw3 returned 0x%08x, expected E_NOINTERFACE\n", hr);
477 if(SUCCEEDED(hr) && dd3) IDirectDraw3_Release(dd3);
480 START_TEST(ddrawmodes)
482 init_function_pointers();
484 createwindow();
485 if (!createdirectdraw())
486 return;
488 test_DirectDrawEnumerateA();
490 enumdisplaymodes();
491 if (winetest_interactive)
492 testdisplaymodes();
493 flushdisplaymodes();
494 testddraw3();
495 releasedirectdraw();
497 createdirectdraw();
498 testcooperativelevels_normal();
499 releasedirectdraw();
501 createdirectdraw();
502 testcooperativelevels_exclusive();
503 releasedirectdraw();