Fix crash in GetAvailableVidMem function when TRACE is activated.
[wine] / dlls / ddraw / ddraw / main.c
1 /*              DirectDraw IDirectDraw interface (generic)
2  *
3  * Copyright 1997-2000 Marcus Meissner
4  * Copyright 1998-2000 Lionel Ulmer (most of Direct3D stuff)
5  * Copyright 2000-2001 TransGaming Technologies Inc.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 /*
23  * This file contains all the interface functions that are shared between
24  * all interfaces. Or better, it is a "common stub" library for the
25  * IDirectDraw* objects
26  */
27
28 #include "config.h"
29 #include "wine/port.h"
30
31 #include <assert.h>
32 #include <string.h>
33
34 #include "winerror.h"
35 #include "ddraw.h"
36 #include "d3d.h"
37 #include "wine/debug.h"
38
39 #include "ddraw_private.h"
40 #include "mesa_private.h" /* To have the D3D creation function */
41 #include "ddraw/main.h"
42 #include "dclipper/main.h"
43 #include "dpalette/main.h"
44 #include "dsurface/main.h"
45 #include "dsurface/dib.h"
46 #include "dsurface/fakezbuffer.h"
47
48 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
49
50 extern ICOM_VTABLE(IDirectDraw) DDRAW_IDirectDraw_VTable;
51 extern ICOM_VTABLE(IDirectDraw2) DDRAW_IDirectDraw2_VTable;
52 extern ICOM_VTABLE(IDirectDraw4) DDRAW_IDirectDraw4_VTable;
53
54 static void DDRAW_UnsubclassWindow(IDirectDrawImpl* This);
55
56 static void Main_DirectDraw_DeleteSurfaces(IDirectDrawImpl* This);
57 static void Main_DirectDraw_DeleteClippers(IDirectDrawImpl* This);
58 static void Main_DirectDraw_DeletePalettes(IDirectDrawImpl* This);
59 static void LosePrimarySurface(IDirectDrawImpl* This);
60
61 static INT32 allocate_memory(IDirectDrawImpl *This, DWORD mem) ;
62 static void free_memory(IDirectDrawImpl *This, DWORD mem) ;
63
64
65 static const char ddProp[] = "WINE_DDRAW_Property";
66
67 /* Not called from the vtable. */
68 HRESULT Main_DirectDraw_Construct(IDirectDrawImpl *This, BOOL ex)
69 {
70     /* NOTE: The creator must use HEAP_ZERO_MEMORY or equivalent. */
71     This->ref = 1;
72     This->ex = ex;
73
74     if (ex) This->local.dwLocalFlags |= DDRAWILCL_DIRECTDRAW7;
75     This->local.dwProcessId = GetCurrentProcessId();
76
77     This->final_release = Main_DirectDraw_final_release;
78
79     This->create_palette = Main_DirectDrawPalette_Create;
80
81     This->create_offscreen = Main_create_offscreen;
82     This->create_texture   = Main_create_texture;
83     This->create_zbuffer   = Main_create_zbuffer;
84     /* There are no generic versions of create_{primary,backbuffer}. */
85
86     ICOM_INIT_INTERFACE(This, IDirectDraw,  DDRAW_IDirectDraw_VTable);
87     ICOM_INIT_INTERFACE(This, IDirectDraw2, DDRAW_IDirectDraw2_VTable);
88     ICOM_INIT_INTERFACE(This, IDirectDraw4, DDRAW_IDirectDraw4_VTable);
89     /* There is no generic implementation of IDD7 */
90
91     /* This is for the moment here... */
92     This->free_memory = free_memory;
93     This->allocate_memory = allocate_memory;
94     This->total_vidmem = 16 * 1024 * 1024;
95     This->available_vidmem = This->total_vidmem;
96       
97     return DD_OK;
98 }
99
100 void Main_DirectDraw_final_release(IDirectDrawImpl* This)
101 {
102     if (IsWindow(This->window))
103     {
104         if (GetPropA(This->window, ddProp))
105             DDRAW_UnsubclassWindow(This);
106         else
107             FIXME("this shouldn't happen, right?\n");
108     }
109
110     Main_DirectDraw_DeleteSurfaces(This);
111     Main_DirectDraw_DeleteClippers(This);
112     Main_DirectDraw_DeletePalettes(This);
113     if (This->local.lpGbl && This->local.lpGbl->lpExclusiveOwner == &This->local)
114     {
115         This->local.lpGbl->lpExclusiveOwner = NULL;
116         if (This->set_exclusive_mode)
117             This->set_exclusive_mode(This, FALSE);
118     }
119 }
120
121 /* There is no Main_DirectDraw_Create. */
122
123 ULONG WINAPI Main_DirectDraw_AddRef(LPDIRECTDRAW7 iface) {
124     ICOM_THIS(IDirectDrawImpl,iface);
125     TRACE("(%p)->() incrementing from %lu.\n", This, This->ref );
126
127     return ++This->ref;
128 }
129
130 ULONG WINAPI Main_DirectDraw_Release(LPDIRECTDRAW7 iface) {
131     ULONG ref;
132     ICOM_THIS(IDirectDrawImpl,iface);
133     TRACE("(%p)->() decrementing from %lu.\n", This, This->ref );
134
135     ref = --This->ref;
136
137     if (ref == 0)
138     {
139         if (This->final_release != NULL)
140             This->final_release(This);
141
142         /* We free the private. This is an artifact of the fact that I don't
143          * have the destructors set up correctly. */
144         if (This->private != (This+1))
145             HeapFree(GetProcessHeap(), 0, This->private);
146
147         HeapFree(GetProcessHeap(), 0, This);
148     }
149
150     return ref;
151 }
152
153 HRESULT WINAPI Main_DirectDraw_QueryInterface(
154     LPDIRECTDRAW7 iface,REFIID refiid,LPVOID *obj
155 ) {
156     ICOM_THIS(IDirectDrawImpl,iface);
157     TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(refiid), obj);
158
159     /* According to COM docs, if the QueryInterface fails, obj should be set to NULL */
160     *obj = NULL;
161     
162     if ( IsEqualGUID( &IID_IUnknown, refiid )
163          || IsEqualGUID( &IID_IDirectDraw7, refiid ) )
164     {
165         *obj = ICOM_INTERFACE(This, IDirectDraw7);
166     }
167     else if ( IsEqualGUID( &IID_IDirectDraw, refiid ) )
168     {
169         *obj = ICOM_INTERFACE(This, IDirectDraw);
170     }
171     else if ( IsEqualGUID( &IID_IDirectDraw2, refiid ) )
172     {
173         *obj = ICOM_INTERFACE(This, IDirectDraw2);
174     }
175     else if ( IsEqualGUID( &IID_IDirectDraw4, refiid ) )
176     {
177         *obj = ICOM_INTERFACE(This, IDirectDraw4);
178     }
179 #ifdef HAVE_OPENGL
180     else if ( IsEqualGUID( &IID_IDirect3D  , refiid ) ||
181               IsEqualGUID( &IID_IDirect3D2 , refiid ) ||
182               IsEqualGUID( &IID_IDirect3D3 , refiid ) ||
183               IsEqualGUID( &IID_IDirect3D7 , refiid ) )
184     {
185         IDirect3DImpl *d3d_impl;
186         HRESULT ret_value;
187
188         ret_value = direct3d_create(&d3d_impl, This);
189         if (FAILED(ret_value)) return ret_value;
190
191         if ( IsEqualGUID( &IID_IDirect3D  , refiid ) ) {
192             *obj = ICOM_INTERFACE(d3d_impl, IDirect3D);
193             TRACE(" returning Direct3D interface at %p.\n", *obj);          
194         } else  if ( IsEqualGUID( &IID_IDirect3D2  , refiid ) ) {
195             *obj = ICOM_INTERFACE(d3d_impl, IDirect3D2);
196             TRACE(" returning Direct3D2 interface at %p.\n", *obj);         
197         } else  if ( IsEqualGUID( &IID_IDirect3D3  , refiid ) ) {
198             *obj = ICOM_INTERFACE(d3d_impl, IDirect3D3);
199             TRACE(" returning Direct3D3 interface at %p.\n", *obj);         
200         } else {
201             *obj = ICOM_INTERFACE(d3d_impl, IDirect3D7);
202             TRACE(" returning Direct3D7 interface at %p.\n", *obj);         
203         }
204
205         /* And store the D3D object */
206         This->d3d = d3d_impl;
207     }
208 #endif
209     else
210     {
211         FIXME("(%p)->(%s,%p): no interface\n",This,debugstr_guid(refiid),obj);
212         return E_NOINTERFACE;
213     }
214
215     IDirectDraw7_AddRef(iface);
216     return S_OK;
217 }
218
219 /* MSDN: "not currently implemented". */
220 HRESULT WINAPI Main_DirectDraw_Compact(LPDIRECTDRAW7 iface)
221 {
222     TRACE("(%p)\n", iface);
223
224     return DD_OK;
225 }
226
227 HRESULT WINAPI Main_DirectDraw_CreateClipper(LPDIRECTDRAW7 iface,
228                                              DWORD dwFlags,
229                                              LPDIRECTDRAWCLIPPER *ppClipper,
230                                              IUnknown *pUnkOuter)
231 {
232     ICOM_THIS(IDirectDrawImpl, iface);
233     HRESULT hr;
234
235     TRACE("(%p)->(0x%lx, %p, %p)\n", iface, dwFlags, ppClipper, pUnkOuter);
236
237     hr = DirectDrawCreateClipper(dwFlags, ppClipper, pUnkOuter);
238     if (FAILED(hr)) return hr;
239
240     /* dwFlags is passed twice, apparently an API wart. */
241     hr = IDirectDrawClipper_Initialize(*ppClipper,
242                                        ICOM_INTERFACE(This, IDirectDraw),
243                                        dwFlags);
244     if (FAILED(hr))
245     {
246         IDirectDrawClipper_Release(*ppClipper);
247         return hr;
248     }
249
250     return DD_OK;
251 }
252
253 HRESULT WINAPI
254 Main_DirectDraw_CreatePalette(LPDIRECTDRAW7 iface, DWORD dwFlags,
255                               LPPALETTEENTRY palent,
256                               LPDIRECTDRAWPALETTE* ppPalette,
257                               LPUNKNOWN pUnknown)
258 {
259     ICOM_THIS(IDirectDrawImpl,iface);
260     LPDIRECTDRAWPALETTE pPalette;
261     HRESULT hr;
262
263     TRACE("(%p)->(%08lx,%p,%p,%p)\n",This,dwFlags,palent,ppPalette,pUnknown);
264
265     if (ppPalette == NULL) return E_POINTER; /* unchecked */
266     if (pUnknown != NULL) return CLASS_E_NOAGGREGATION; /* unchecked */
267
268     hr = This->create_palette(This, dwFlags, &pPalette, pUnknown);
269     if (FAILED(hr)) return hr;
270
271     hr = IDirectDrawPalette_SetEntries(pPalette, 0, 0,
272                                        Main_DirectDrawPalette_Size(dwFlags),
273                                        palent);
274     if (FAILED(hr))
275     {
276         IDirectDrawPalette_Release(pPalette);
277         return hr;
278     }
279     else
280     {
281         *ppPalette = pPalette;
282         return DD_OK;
283     }
284 }
285
286 HRESULT
287 Main_create_offscreen(IDirectDrawImpl* This, const DDSURFACEDESC2* pDDSD,
288                       LPDIRECTDRAWSURFACE7* ppSurf, LPUNKNOWN pOuter)
289 {
290     assert(pOuter == NULL);
291
292     return DIB_DirectDrawSurface_Create(This, pDDSD, ppSurf, pOuter);
293 }
294
295 HRESULT
296 Main_create_texture(IDirectDrawImpl* This, const DDSURFACEDESC2* pDDSD,
297                     LPDIRECTDRAWSURFACE7* ppSurf, LPUNKNOWN pOuter,
298                     DWORD dwMipMapLevel)
299 {
300     assert(pOuter == NULL);
301
302     return DIB_DirectDrawSurface_Create(This, pDDSD, ppSurf, pOuter);
303 }
304
305 HRESULT
306 Main_create_zbuffer(IDirectDrawImpl* This, const DDSURFACEDESC2* pDDSD,
307                     LPDIRECTDRAWSURFACE7* ppSurf, LPUNKNOWN pOuter)
308 {
309     assert(pOuter == NULL);
310
311     return FakeZBuffer_DirectDrawSurface_Create(This, pDDSD, ppSurf, pOuter);
312 }
313
314 /* Does the texture surface described in pDDSD have any smaller mipmaps? */
315 static BOOL more_mipmaps(const DDSURFACEDESC2 *pDDSD)
316 {
317     return ((pDDSD->dwFlags & DDSD_MIPMAPCOUNT) && pDDSD->u2.dwMipMapCount > 1
318             && (pDDSD->dwWidth > 1 || pDDSD->dwHeight > 1));
319 }
320
321 /* Create a texture surface along with any of its mipmaps. */
322 static HRESULT
323 create_texture(IDirectDrawImpl* This, const DDSURFACEDESC2 *pDDSD,
324                LPDIRECTDRAWSURFACE7* ppSurf, LPUNKNOWN pUnkOuter)
325 {
326     DDSURFACEDESC2 ddsd;
327     DWORD mipmap_level = 0;
328     HRESULT hr;
329
330     assert(pUnkOuter == NULL);
331
332     /* is this check right? (pixelformat can be copied from primary) */
333     if ((pDDSD->dwFlags&(DDSD_HEIGHT|DDSD_WIDTH)) != (DDSD_HEIGHT|DDSD_WIDTH))
334         return DDERR_INVALIDPARAMS;
335
336     ddsd.dwSize = sizeof(ddsd);
337     DD_STRUCT_COPY_BYSIZE((&ddsd),pDDSD);
338
339     if (!(ddsd.dwFlags & DDSD_PIXELFORMAT))
340     {
341         ddsd.u4.ddpfPixelFormat = This->pixelformat;
342     }
343
344     /* We do not support for now compressed texture formats... */
345     if (ddsd.u4.ddpfPixelFormat.dwFlags & DDPF_FOURCC)
346     {
347         return DDERR_INVALIDPIXELFORMAT;
348     }
349     
350     if (!(ddsd.dwFlags & DDSD_PITCH))
351     {
352         ddsd.u1.lPitch = DDRAW_width_bpp_to_pitch(ddsd.dwWidth,
353                                                   GET_BPP(ddsd)*8);
354     }
355
356     ddsd.dwFlags |= DDSD_PITCH | DDSD_PIXELFORMAT;
357
358     hr = This->create_texture(This, &ddsd, ppSurf, pUnkOuter, mipmap_level);
359     if (FAILED(hr)) return hr;
360
361     if (This->d3d) This->d3d->create_texture(This->d3d, ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, *ppSurf), TRUE, 
362                                              ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, *ppSurf), mipmap_level);
363
364     /* Create attached mipmaps if required. */
365     if (more_mipmaps(&ddsd))
366     {
367         LPDIRECTDRAWSURFACE7 mipmap;
368         LPDIRECTDRAWSURFACE7 prev_mipmap;
369         DDSURFACEDESC2 mipmap_surface_desc;
370
371         prev_mipmap = *ppSurf;
372         IDirectDrawSurface7_AddRef(prev_mipmap);
373         mipmap_surface_desc = ddsd;
374         mipmap_surface_desc.ddsCaps.dwCaps2 |= DDSCAPS2_MIPMAPSUBLEVEL;
375
376         while (more_mipmaps(&mipmap_surface_desc))
377         {
378             mipmap_level++;
379
380             mipmap_surface_desc.u2.dwMipMapCount--;
381
382             if (mipmap_surface_desc.dwWidth > 1)
383                 mipmap_surface_desc.dwWidth /= 2;
384
385             if (mipmap_surface_desc.dwHeight > 1)
386                 mipmap_surface_desc.dwHeight /= 2;
387
388             mipmap_surface_desc.u1.lPitch
389                 = DDRAW_width_bpp_to_pitch(mipmap_surface_desc.dwWidth,
390                                            GET_BPP(ddsd)*8);
391
392             hr = This->create_texture(This, &mipmap_surface_desc, &mipmap,
393                                       pUnkOuter, mipmap_level);
394             if (FAILED(hr))
395             {
396                 IDirectDrawSurface7_Release(prev_mipmap);
397                 IDirectDrawSurface7_Release(*ppSurf);
398                 return hr;
399             }
400             if (This->d3d) This->d3d->create_texture(This->d3d, ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, mipmap), TRUE,
401                                                      ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, *ppSurf), mipmap_level);
402
403             IDirectDrawSurface7_AddAttachedSurface(prev_mipmap, mipmap);
404             IDirectDrawSurface7_Release(prev_mipmap);
405             prev_mipmap = mipmap;
406         }
407
408         IDirectDrawSurface7_Release(prev_mipmap);
409     }
410
411     return DD_OK;
412 }
413
414 /* Creates a primary surface and any indicated backbuffers. */
415 static HRESULT
416 create_primary(IDirectDrawImpl* This, LPDDSURFACEDESC2 pDDSD,
417                LPDIRECTDRAWSURFACE7* ppSurf, LPUNKNOWN pUnkOuter)
418 {
419     DDSURFACEDESC2 ddsd;
420     HRESULT hr;
421
422     assert(pUnkOuter == NULL);
423
424     if (This->primary_surface != NULL)
425         return DDERR_PRIMARYSURFACEALREADYEXISTS;
426
427     /* as documented (what about pitch?) */
428     if (pDDSD->dwFlags & (DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT))
429         return DDERR_INVALIDPARAMS;
430
431     ddsd.dwSize = sizeof(ddsd);
432     DD_STRUCT_COPY_BYSIZE((&ddsd),pDDSD);
433     ddsd.dwFlags |= DDSD_HEIGHT | DDSD_WIDTH | DDSD_PITCH | DDSD_PIXELFORMAT;
434     ddsd.dwHeight = This->height;
435     ddsd.dwWidth = This->width;
436     ddsd.u1.lPitch = This->pitch;
437     ddsd.u4.ddpfPixelFormat = This->pixelformat;
438     ddsd.ddsCaps.dwCaps |= DDSCAPS_LOCALVIDMEM | DDSCAPS_VIDEOMEMORY
439         | DDSCAPS_VISIBLE | DDSCAPS_FRONTBUFFER;
440
441     if ((ddsd.dwFlags & DDSD_BACKBUFFERCOUNT) && ddsd.dwBackBufferCount > 0)
442         ddsd.ddsCaps.dwCaps |= DDSCAPS_FLIP;
443
444     hr = This->create_primary(This, &ddsd, ppSurf, pUnkOuter);
445     if (FAILED(hr)) return hr;
446
447     if (ddsd.dwFlags & DDSD_BACKBUFFERCOUNT)
448     {
449         IDirectDrawSurfaceImpl* primary;
450         LPDIRECTDRAWSURFACE7 pPrev;
451         DWORD i;
452
453         ddsd.dwFlags &= ~DDSD_BACKBUFFERCOUNT;
454         ddsd.ddsCaps.dwCaps &= ~(DDSCAPS_VISIBLE | DDSCAPS_PRIMARYSURFACE
455                                  | DDSCAPS_BACKBUFFER | DDSCAPS_FRONTBUFFER);
456
457         primary = ICOM_OBJECT(IDirectDrawSurfaceImpl,IDirectDrawSurface7,
458                               *ppSurf);
459         pPrev = *ppSurf;
460         IDirectDrawSurface7_AddRef(pPrev);
461
462         for (i=0; i < ddsd.dwBackBufferCount; i++)
463         {
464             LPDIRECTDRAWSURFACE7 pBack;
465
466             if (i == 0)
467                 ddsd.ddsCaps.dwCaps |= DDSCAPS_BACKBUFFER;
468             else
469                 ddsd.ddsCaps.dwCaps &= ~DDSCAPS_BACKBUFFER;
470
471             hr = This->create_backbuffer(This, &ddsd, &pBack, pUnkOuter,
472                                          primary);
473
474             if (FAILED(hr))
475             {
476                 IDirectDraw7_Release(pPrev);
477                 IDirectDraw7_Release(*ppSurf);
478                 return hr;
479             }
480
481             IDirectDrawSurface7_AddAttachedSurface(pPrev, pBack);
482             IDirectDrawSurface7_Release(pPrev);
483             pPrev = pBack;
484         }
485
486         IDirectDrawSurface7_Release(pPrev);
487     }
488
489     This->primary_surface = (IDirectDrawSurfaceImpl *)*ppSurf;
490
491     return DD_OK;
492 }
493
494 static HRESULT
495 create_offscreen(IDirectDrawImpl* This, LPDDSURFACEDESC2 pDDSD,
496                  LPDIRECTDRAWSURFACE7* ppSurf, LPUNKNOWN pUnkOuter)
497 {
498     DDSURFACEDESC2 ddsd;
499     HRESULT hr;
500
501     /* is this check right? (pixelformat can be copied from primary) */
502     if ((pDDSD->dwFlags&(DDSD_HEIGHT|DDSD_WIDTH)) != (DDSD_HEIGHT|DDSD_WIDTH))
503         return DDERR_INVALIDPARAMS;
504
505     ddsd.dwSize = sizeof(ddsd);
506     DD_STRUCT_COPY_BYSIZE((&ddsd),pDDSD);
507
508     if (!(ddsd.dwFlags & DDSD_PIXELFORMAT))
509     {
510         ddsd.u4.ddpfPixelFormat = This->pixelformat;
511     }
512
513     if (!(ddsd.dwFlags & DDSD_PITCH))
514     {
515         ddsd.u1.lPitch = DDRAW_width_bpp_to_pitch(ddsd.dwWidth,
516                                                   GET_BPP(ddsd)*8);
517     }
518
519     ddsd.dwFlags |= DDSD_PITCH | DDSD_PIXELFORMAT;
520
521     hr = This->create_offscreen(This, &ddsd, ppSurf, pUnkOuter);
522     if (FAILED(hr)) return hr;
523
524     return hr;
525 }
526
527 HRESULT WINAPI
528 Main_DirectDraw_CreateSurface(LPDIRECTDRAW7 iface, LPDDSURFACEDESC2 pDDSD,
529                               LPDIRECTDRAWSURFACE7 *ppSurf,
530                               IUnknown *pUnkOuter)
531 {
532     HRESULT hr;
533     ICOM_THIS(IDirectDrawImpl, iface);
534
535     TRACE("(%p)->(%p,%p,%p)\n",This,pDDSD,ppSurf,pUnkOuter);
536     if (TRACE_ON(ddraw)) {
537         DPRINTF("Requesting surface desc :\n");
538         DDRAW_dump_surface_desc(pDDSD);
539     }
540
541     if (pUnkOuter != NULL) {
542         FIXME("outer != NULL?\n");
543         return CLASS_E_NOAGGREGATION; /* unchecked */
544     }
545
546     if (!(pDDSD->dwFlags & DDSD_CAPS)) {
547         /* DVIDEO.DLL does forget the DDSD_CAPS flag ... *sigh* */
548         pDDSD->dwFlags |= DDSD_CAPS;
549     }
550
551     if (ppSurf == NULL) {
552         FIXME("You want to get back a surface? Don't give NULL ptrs!\n");
553         return E_POINTER; /* unchecked */
554     }
555
556     if (pDDSD->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
557     {
558         /* create primary surface & backbuffers */
559         hr = create_primary(This, pDDSD, ppSurf, pUnkOuter);
560     }
561     else if (pDDSD->ddsCaps.dwCaps & DDSCAPS_BACKBUFFER)
562     {
563        /* create backbuffer surface */
564        hr = This->create_backbuffer(This, pDDSD, ppSurf, pUnkOuter, NULL);
565     }
566     else if (pDDSD->ddsCaps.dwCaps & DDSCAPS_TEXTURE)
567     {
568         /* create texture */
569         hr = create_texture(This, pDDSD, ppSurf, pUnkOuter);
570     }
571     else if ((pDDSD->ddsCaps.dwCaps & DDSCAPS_OFFSCREENPLAIN) ||
572              (pDDSD->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)) /* No difference in Wine right now */
573     {
574         /* create offscreenplain surface */
575         hr = create_offscreen(This, pDDSD, ppSurf, pUnkOuter);
576     }
577     else if (pDDSD->ddsCaps.dwCaps & DDSCAPS_ZBUFFER)
578     {
579         /* create z-buffer */
580         hr = This->create_zbuffer(This, pDDSD, ppSurf, pUnkOuter);
581     }
582     else
583     {
584         /* Otherwise, assume offscreenplain surface */
585         FIXME("App didn't request a valid surface type - assuming offscreenplain\n");
586         hr = create_offscreen(This, pDDSD, ppSurf, pUnkOuter);
587     }
588
589     if (FAILED(hr)) {
590         FIXME("failed surface creation with code 0x%08lx\n",hr);
591         return hr;
592     }
593
594     return DD_OK;
595 }
596
597 HRESULT WINAPI
598 Main_DirectDraw_DuplicateSurface(LPDIRECTDRAW7 iface, LPDIRECTDRAWSURFACE7 src,
599                                  LPDIRECTDRAWSURFACE7* dst)
600 {
601     ICOM_THIS(IDirectDrawImpl,iface);
602
603     IDirectDrawSurfaceImpl *pSrc = ICOM_OBJECT(IDirectDrawSurfaceImpl,
604                                                IDirectDrawSurface7, src);
605
606     TRACE("(%p)->(%p,%p)\n",This,src,dst);
607
608     return pSrc->duplicate_surface(pSrc, dst);
609 }
610
611 /* EnumDisplayModes */
612
613 BOOL Main_DirectDraw_DDPIXELFORMAT_Match(const DDPIXELFORMAT *requested,
614                                          const DDPIXELFORMAT *provided)
615 {
616     /* Some flags must be present in both or neither for a match. */
617     static const DWORD must_match = DDPF_PALETTEINDEXED1 | DDPF_PALETTEINDEXED2
618         | DDPF_PALETTEINDEXED4 | DDPF_PALETTEINDEXED8 | DDPF_FOURCC
619         | DDPF_ZBUFFER | DDPF_STENCILBUFFER;
620
621     if ((requested->dwFlags & provided->dwFlags) != requested->dwFlags)
622         return FALSE;
623
624     if ((requested->dwFlags & must_match) != (provided->dwFlags & must_match))
625         return FALSE;
626
627     if (requested->dwFlags & DDPF_FOURCC)
628         if (requested->dwFourCC != provided->dwFourCC)
629             return FALSE;
630
631     if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_ZBUFFER|DDPF_ALPHA
632                               |DDPF_LUMINANCE|DDPF_BUMPDUDV))
633         if (requested->u1.dwRGBBitCount != provided->u1.dwRGBBitCount)
634             return FALSE;
635
636     if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_STENCILBUFFER
637                               |DDPF_LUMINANCE|DDPF_BUMPDUDV))
638         if (requested->u2.dwRBitMask != provided->u2.dwRBitMask)
639             return FALSE;
640
641     if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_ZBUFFER|DDPF_BUMPDUDV))
642         if (requested->u3.dwGBitMask != provided->u3.dwGBitMask)
643             return FALSE;
644
645     /* I could be wrong about the bumpmapping. MSDN docs are vague. */
646     if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_STENCILBUFFER
647                               |DDPF_BUMPDUDV))
648         if (requested->u4.dwBBitMask != provided->u4.dwBBitMask)
649             return FALSE;
650
651     if (requested->dwFlags & (DDPF_ALPHAPIXELS|DDPF_ZPIXELS))
652         if (requested->u5.dwRGBAlphaBitMask != provided->u5.dwRGBAlphaBitMask)
653             return FALSE;
654
655     return TRUE;
656 }
657
658 BOOL Main_DirectDraw_DDSD_Match(const DDSURFACEDESC2* requested,
659                                 const DDSURFACEDESC2* provided)
660 {
661     struct compare_info
662     {
663         DWORD flag;
664         ptrdiff_t offset;
665         size_t size;
666     };
667
668 #define CMP(FLAG, FIELD)                                \
669         { DDSD_##FLAG, offsetof(DDSURFACEDESC2, FIELD), \
670           sizeof(((DDSURFACEDESC2 *)(NULL))->FIELD) }
671
672     static const struct compare_info compare[] = {
673         CMP(ALPHABITDEPTH, dwAlphaBitDepth),
674         CMP(BACKBUFFERCOUNT, dwBackBufferCount),
675         CMP(CAPS, ddsCaps),
676         CMP(CKDESTBLT, ddckCKDestBlt),
677         CMP(CKDESTOVERLAY, u3.ddckCKDestOverlay),
678         CMP(CKSRCBLT, ddckCKSrcBlt),
679         CMP(CKSRCOVERLAY, ddckCKSrcOverlay),
680         CMP(HEIGHT, dwHeight),
681         CMP(LINEARSIZE, u1.dwLinearSize),
682         CMP(LPSURFACE, lpSurface),
683         CMP(MIPMAPCOUNT, u2.dwMipMapCount),
684         CMP(PITCH, u1.lPitch),
685         /* PIXELFORMAT: manual */
686         CMP(REFRESHRATE, u2.dwRefreshRate),
687         CMP(TEXTURESTAGE, dwTextureStage),
688         CMP(WIDTH, dwWidth),
689         /* ZBUFFERBITDEPTH: "obsolete" */
690     };
691
692 #undef CMP
693
694     int i;
695
696     if ((requested->dwFlags & provided->dwFlags) != requested->dwFlags)
697         return FALSE;
698
699     for (i=0; i < sizeof(compare)/sizeof(compare[0]); i++)
700     {
701         if (requested->dwFlags & compare[i].flag
702             && memcmp((const char *)provided + compare[i].offset,
703                       (const char *)requested + compare[i].offset,
704                       compare[i].size) != 0)
705             return FALSE;
706     }
707
708     if (requested->dwFlags & DDSD_PIXELFORMAT)
709     {
710         if (!Main_DirectDraw_DDPIXELFORMAT_Match(&requested->u4.ddpfPixelFormat,
711                                                  &provided->u4.ddpfPixelFormat))
712             return FALSE;
713     }
714
715     return TRUE;
716 }
717
718 #define DDENUMSURFACES_SEARCHTYPE (DDENUMSURFACES_CANBECREATED|DDENUMSURFACES_DOESEXIST)
719 #define DDENUMSURFACES_MATCHTYPE (DDENUMSURFACES_ALL|DDENUMSURFACES_MATCH|DDENUMSURFACES_NOMATCH)
720
721 /* This should be extended so that it can be used by
722  * IDirectDrawSurface7::EnumAttachedSurfaces. */
723 HRESULT
724 Main_DirectDraw_EnumExistingSurfaces(IDirectDrawImpl *This, DWORD dwFlags,
725                                      LPDDSURFACEDESC2 lpDDSD2, LPVOID context,
726                                      LPDDENUMSURFACESCALLBACK7 callback)
727 {
728     IDirectDrawSurfaceImpl *surf;
729     BOOL all, nomatch;
730
731     /* A NULL lpDDSD2 is permitted if we are enumerating all surfaces anyway */
732     if (lpDDSD2 == NULL && !(dwFlags & DDENUMSURFACES_ALL))
733         return DDERR_INVALIDPARAMS;
734
735     all = dwFlags & DDENUMSURFACES_ALL;
736     nomatch = dwFlags & DDENUMSURFACES_NOMATCH;
737
738     for (surf = This->surfaces; surf != NULL; surf = surf->next_ddraw)
739     {
740         if (all
741             || (nomatch != Main_DirectDraw_DDSD_Match(lpDDSD2,
742                                                       &surf->surface_desc)))
743         {
744             LPDIRECTDRAWSURFACE7 surface = ICOM_INTERFACE(surf,
745                                                           IDirectDrawSurface7);
746
747             /* BOGUS! Violates COM rules, but MSDN says so. */
748             IDirectDrawSurface7_AddRef(surface);
749
750             if (callback(surface, &surf->surface_desc, context)
751                 == DDENUMRET_CANCEL)
752                 break;
753         }
754     }
755
756     return DD_OK;
757 }
758
759 /* I really don't understand how this is supposed to work.
760  * We only consider dwHeight, dwWidth and ddpfPixelFormat.dwFlags. */
761 HRESULT
762 Main_DirectDraw_EnumCreateableSurfaces(IDirectDrawImpl *This, DWORD dwFlags,
763                                        LPDDSURFACEDESC2 lpDDSD2,
764                                        LPVOID context,
765                                        LPDDENUMSURFACESCALLBACK7 callback)
766 {
767     FIXME("This isn't going to work.\n");
768
769     if ((dwFlags & DDENUMSURFACES_MATCHTYPE) != DDENUMSURFACES_MATCH)
770         return DDERR_INVALIDPARAMS;
771
772     /* TODO: implement this.
773      * Does this work before SCL is called?
774      * Does it only consider off-screen surfaces?
775      */
776
777     return E_FAIL;
778 }
779
780 /* For unsigned x. 0 is not a power of 2. */
781 #define IS_POW_2(x) (((x) & ((x) - 1)) == 0)
782
783 HRESULT WINAPI
784 Main_DirectDraw_EnumSurfaces(LPDIRECTDRAW7 iface, DWORD dwFlags,
785                              LPDDSURFACEDESC2 lpDDSD2, LPVOID context,
786                              LPDDENUMSURFACESCALLBACK7 callback)
787 {
788     ICOM_THIS(IDirectDrawImpl, iface);
789     TRACE("(%p)->(0x%lx, %p, %p, %p)\n", iface, dwFlags, lpDDSD2, context,
790           callback);
791
792     if (callback == NULL)
793         return DDERR_INVALIDPARAMS;
794
795     if (dwFlags & ~(DDENUMSURFACES_SEARCHTYPE|DDENUMSURFACES_MATCHTYPE))
796         return DDERR_INVALIDPARAMS;
797
798     if (!IS_POW_2(dwFlags & DDENUMSURFACES_SEARCHTYPE)
799         || !IS_POW_2(dwFlags & DDENUMSURFACES_MATCHTYPE))
800         return DDERR_INVALIDPARAMS;
801
802     if (dwFlags & DDENUMSURFACES_DOESEXIST)
803     {
804         return Main_DirectDraw_EnumExistingSurfaces(This, dwFlags, lpDDSD2,
805                                                     context, callback);
806     }
807     else
808     {
809         return Main_DirectDraw_EnumCreateableSurfaces(This, dwFlags, lpDDSD2,
810                                                       context, callback);
811     }
812 }
813
814 HRESULT WINAPI
815 Main_DirectDraw_EvaluateMode(LPDIRECTDRAW7 iface,DWORD a,DWORD* b)
816 {
817     ICOM_THIS(IDirectDrawImpl,iface);
818     FIXME("(%p)->() stub\n", This);
819
820     return DD_OK;
821 }
822
823 HRESULT WINAPI
824 Main_DirectDraw_FlipToGDISurface(LPDIRECTDRAW7 iface)
825 {
826     ICOM_THIS(IDirectDrawImpl,iface);
827     TRACE("(%p)->()\n",This);
828     return DD_OK;
829 }
830
831 HRESULT WINAPI
832 Main_DirectDraw_GetCaps(LPDIRECTDRAW7 iface, LPDDCAPS pDriverCaps,
833                         LPDDCAPS pHELCaps)
834 {
835     ICOM_THIS(IDirectDrawImpl,iface);
836     TRACE("(%p,%p,%p), stub\n",This,pDriverCaps,pHELCaps);
837     if (pDriverCaps != NULL) {
838         DD_STRUCT_COPY_BYSIZE(pDriverCaps,&This->caps);
839         if (TRACE_ON(ddraw)) {
840           DPRINTF("Driver Caps : \n");
841           DDRAW_dump_DDCAPS(pDriverCaps);
842         }
843     }
844     if (pHELCaps != NULL) {
845         DD_STRUCT_COPY_BYSIZE(pHELCaps,&This->caps);
846         if (TRACE_ON(ddraw)) {
847           DPRINTF("HEL Caps : \n");
848           DDRAW_dump_DDCAPS(pHELCaps);
849         }
850     }
851     return DD_OK;
852 }
853
854 /* GetCaps */
855 /* GetDeviceIdentifier */
856 /* GetDIsplayMode */
857
858 HRESULT WINAPI
859 Main_DirectDraw_GetFourCCCodes(LPDIRECTDRAW7 iface, LPDWORD pNumCodes,
860                                LPDWORD pCodes)
861 {
862     ICOM_THIS(IDirectDrawImpl,iface);
863     if (*pNumCodes) {
864             *pNumCodes=0;
865     }
866     FIXME("(%p,%p,%p), stub\n",This,pNumCodes,pCodes);
867     return DD_OK;
868 }
869
870 HRESULT WINAPI
871 Main_DirectDraw_GetGDISurface(LPDIRECTDRAW7 iface,
872                               LPDIRECTDRAWSURFACE7 *lplpGDIDDSSurface)
873 {
874     ICOM_THIS(IDirectDrawImpl,iface);
875     TRACE("(%p)->(%p)\n", This, lplpGDIDDSSurface);
876     TRACE("returning primary (%p)\n", This->primary_surface);
877     *lplpGDIDDSSurface = ICOM_INTERFACE(This->primary_surface, IDirectDrawSurface7);
878     if (*lplpGDIDDSSurface)
879         IDirectDrawSurface7_AddRef(*lplpGDIDDSSurface);
880     return DD_OK;
881 }
882
883 HRESULT WINAPI
884 Main_DirectDraw_GetMonitorFrequency(LPDIRECTDRAW7 iface,LPDWORD freq)
885 {
886     ICOM_THIS(IDirectDrawImpl,iface);
887     FIXME("(%p)->(%p) returns 60 Hz always\n",This,freq);
888     *freq = 60*100; /* 60 Hz */
889     return DD_OK;
890 }
891
892 HRESULT WINAPI
893 Main_DirectDraw_GetScanLine(LPDIRECTDRAW7 iface, LPDWORD lpdwScanLine)
894 {
895     ICOM_THIS(IDirectDrawImpl,iface);
896     FIXME("(%p)->(%p)\n", This, lpdwScanLine);
897
898     *lpdwScanLine = 1;
899
900     return DD_OK;
901 }
902
903 HRESULT WINAPI
904 Main_DirectDraw_GetSurfaceFromDC(LPDIRECTDRAW7 iface, HDC hdc,
905                                  LPDIRECTDRAWSURFACE7 *lpDDS)
906 {
907     ICOM_THIS(IDirectDrawImpl,iface);
908     FIXME("(%p)->(%08ld,%p)\n", This, (DWORD) hdc, lpDDS);
909
910     return DD_OK;
911 }
912
913 HRESULT WINAPI
914 Main_DirectDraw_GetVerticalBlankStatus(LPDIRECTDRAW7 iface, LPBOOL status)
915 {
916     ICOM_THIS(IDirectDrawImpl,iface);
917     TRACE("(%p)->(%p)\n",This,status);
918     *status = TRUE;
919     return DD_OK;
920 }
921
922 /* If we were not initialised then Uninit_Main_IDirectDraw7_Initialize would
923  * have been called instead. */
924 HRESULT WINAPI
925 Main_DirectDraw_Initialize(LPDIRECTDRAW7 iface, LPGUID lpGuid)
926 {
927     TRACE("(%p)->(%s)\n", iface, debugstr_guid(lpGuid));
928
929     return DDERR_ALREADYINITIALIZED;
930 }
931
932 HRESULT WINAPI
933 Main_DirectDraw_RestoreAllSurfaces(LPDIRECTDRAW7 iface)
934 {
935     ICOM_THIS(IDirectDrawImpl,iface);
936     IDirectDrawSurfaceImpl* surf;
937
938     TRACE("(%p)->()\n", This);
939
940     for (surf = This->surfaces; surf != NULL; surf = surf->next_ddraw)
941         IDirectDrawSurface7_Restore(ICOM_INTERFACE(surf, IDirectDrawSurface7));
942
943     return DD_OK;
944 }
945
946 static void DDRAW_SubclassWindow(IDirectDrawImpl* This)
947 {
948     /* Well we don't actually subclass the window yet. */
949     SetPropA(This->window, ddProp, This);
950 }
951
952 static void DDRAW_UnsubclassWindow(IDirectDrawImpl* This)
953 {
954     RemovePropA(This->window, ddProp);
955 }
956
957 HRESULT WINAPI
958 Main_DirectDraw_SetCooperativeLevel(LPDIRECTDRAW7 iface, HWND hwnd,
959                                     DWORD cooplevel)
960 {
961     ICOM_THIS(IDirectDrawImpl,iface);
962
963     FIXME("(%p)->(%08lx,%08lx)\n",This,(DWORD)hwnd,cooplevel);
964     DDRAW_dump_cooperativelevel(cooplevel);
965
966     /* Makes realMYST test happy. */
967     if (This->cooperative_level == cooplevel
968         && This->window == hwnd)
969         return DD_OK;
970
971     /* XXX "It cannot be reset while the process has surfaces or palettes
972      * created." Otherwise the window can be changed???
973      *
974      * This appears to be wrong - comment it out for now.
975     if (This->window)
976         return DDERR_HWNDALREADYSET;
977     */
978
979     if (!(cooplevel & (DDSCL_EXCLUSIVE|DDSCL_NORMAL)))
980         return DDERR_INVALIDPARAMS;
981
982     This->window = hwnd;
983     This->cooperative_level = cooplevel;
984
985     This->local.hWnd = (ULONG_PTR)hwnd;
986     This->local.dwLocalFlags |= DDRAWILCL_SETCOOPCALLED;
987     /* not entirely sure about these */
988     if (cooplevel & DDSCL_EXCLUSIVE)     This->local.dwLocalFlags |= DDRAWILCL_HASEXCLUSIVEMODE;
989     if (cooplevel & DDSCL_FULLSCREEN)    This->local.dwLocalFlags |= DDRAWILCL_ISFULLSCREEN;
990     if (cooplevel & DDSCL_ALLOWMODEX)    This->local.dwLocalFlags |= DDRAWILCL_ALLOWMODEX;
991     if (cooplevel & DDSCL_MULTITHREADED) This->local.dwLocalFlags |= DDRAWILCL_MULTITHREADED;
992     if (cooplevel & DDSCL_FPUSETUP)      This->local.dwLocalFlags |= DDRAWILCL_FPUSETUP;
993     if (cooplevel & DDSCL_FPUPRESERVE)   This->local.dwLocalFlags |= DDRAWILCL_FPUPRESERVE;
994
995     if (This->local.lpGbl) {
996         /* assume that this app is the active app (in wine, there's
997          * probably only one app per global ddraw object anyway) */
998         if (cooplevel & DDSCL_EXCLUSIVE) This->local.lpGbl->lpExclusiveOwner = &This->local;
999         else if (This->local.lpGbl->lpExclusiveOwner == &This->local)
1000             This->local.lpGbl->lpExclusiveOwner = NULL;
1001         if (This->set_exclusive_mode)
1002             This->set_exclusive_mode(This, (cooplevel & DDSCL_EXCLUSIVE) != 0);
1003     }
1004
1005     ShowWindow(hwnd, SW_SHOW);
1006
1007     DDRAW_SubclassWindow(This);
1008
1009     /* TODO Does it also get resized to the current screen size? */
1010
1011     return DD_OK;
1012 }
1013
1014 HRESULT WINAPI
1015 Main_DirectDraw_SetDisplayMode(LPDIRECTDRAW7 iface, DWORD dwWidth,
1016                                DWORD dwHeight, LONG lPitch,
1017                                DWORD dwRefreshRate, DWORD dwFlags,
1018                                const DDPIXELFORMAT* pixelformat)
1019 {
1020     short screenX;
1021     short screenY;
1022
1023     ICOM_THIS(IDirectDrawImpl,iface);
1024
1025     TRACE("(%p)->SetDisplayMode(%ld,%ld)\n",This,dwWidth,dwHeight);
1026
1027     if (!(This->cooperative_level & DDSCL_EXCLUSIVE))
1028         return DDERR_NOEXCLUSIVEMODE;
1029
1030     if (!IsWindow(This->window))
1031         return DDERR_GENERIC; /* unchecked */
1032
1033     LosePrimarySurface(This);
1034
1035     screenX = GetSystemMetrics(SM_CXSCREEN);
1036     screenY = GetSystemMetrics(SM_CYSCREEN);
1037
1038     This->width = dwWidth;
1039     This->height = dwHeight;
1040     This->pitch = lPitch;
1041     This->pixelformat = *pixelformat;
1042
1043     /* Position the window in the center of the screen - don't center for now */
1044     /* MoveWindow(This->window, (screenX-dwWidth)/2, (screenY-dwHeight)/2,
1045                   dwWidth, dwHeight, TRUE);*/
1046     MoveWindow(This->window, 0, 0, dwWidth, dwHeight, TRUE);
1047
1048     SetFocus(This->window);
1049
1050     return DD_OK;
1051 }
1052
1053 HRESULT WINAPI
1054 Main_DirectDraw_RestoreDisplayMode(LPDIRECTDRAW7 iface)
1055 {
1056     ICOM_THIS(IDirectDrawImpl,iface);
1057
1058     TRACE("(%p)\n",This);
1059     if (!(This->cooperative_level & DDSCL_EXCLUSIVE))
1060         return DDERR_NOEXCLUSIVEMODE;
1061
1062     /* Lose the primary surface if the resolution changes. */
1063     if (This->orig_width != This->width || This->orig_height != This->height
1064         || This->orig_pitch != This->pitch
1065         || This->orig_pixelformat.dwFlags != This->pixelformat.dwFlags
1066         || !Main_DirectDraw_DDPIXELFORMAT_Match(&This->pixelformat,
1067                                                 &This->orig_pixelformat))
1068     {
1069         LosePrimarySurface(This);
1070     }
1071
1072     /* TODO Move the window back where it belongs. */
1073
1074     return DD_OK;
1075 }
1076
1077 HRESULT WINAPI
1078 Main_DirectDraw_WaitForVerticalBlank(LPDIRECTDRAW7 iface, DWORD dwFlags,
1079                                      HANDLE h)
1080 {
1081     ICOM_THIS(IDirectDrawImpl,iface);
1082     FIXME("(%p)->(flags=0x%08lx,handle=%p)\n",This,dwFlags,h);
1083     return DD_OK;
1084 }
1085
1086 HRESULT WINAPI
1087 Main_DirectDraw_GetDisplayMode(LPDIRECTDRAW7 iface, LPDDSURFACEDESC2 pDDSD)
1088 {
1089     ICOM_THIS(IDirectDrawImpl,iface);
1090     TRACE("(%p)->GetDisplayMode(%p)\n",This,pDDSD);
1091
1092     pDDSD->dwFlags = DDSD_HEIGHT|DDSD_WIDTH|DDSD_PITCH|DDSD_PIXELFORMAT|DDSD_REFRESHRATE;
1093     pDDSD->dwHeight = This->height;
1094     pDDSD->dwWidth = This->width;
1095     pDDSD->u1.lPitch = This->pitch;
1096     pDDSD->u2.dwRefreshRate = 60;
1097     pDDSD->u4.ddpfPixelFormat = This->pixelformat;
1098     pDDSD->ddsCaps.dwCaps = 0;
1099
1100     return DD_OK;
1101 }
1102
1103 static INT32 allocate_memory(IDirectDrawImpl *This, DWORD mem)
1104 {
1105     if (mem > This->available_vidmem) return -1;
1106     This->available_vidmem -= mem;
1107     return This->available_vidmem;
1108 }
1109
1110 static void free_memory(IDirectDrawImpl *This, DWORD mem)
1111 {
1112     This->available_vidmem += mem;
1113 }
1114
1115 HRESULT WINAPI
1116 Main_DirectDraw_GetAvailableVidMem(LPDIRECTDRAW7 iface, LPDDSCAPS2 ddscaps,
1117                                    LPDWORD total, LPDWORD free)
1118 {
1119     ICOM_THIS(IDirectDrawImpl,iface);
1120     TRACE("(%p)->(%p,%p,%p)\n", This,ddscaps,total,free);
1121
1122     if (TRACE_ON(ddraw)) {
1123         TRACE(" Asking for memory of type : ");
1124         DDRAW_dump_DDSCAPS2(ddscaps); DPRINTF("\n");
1125     }
1126
1127     /* We have 16 MB videomemory */
1128     if (total)  *total= This->total_vidmem;
1129     if (free)   *free = This->available_vidmem;
1130
1131     TRACE(" returning (total) %ld / (free) %ld\n", 
1132           total != NULL ? *total : 0, 
1133           free  != NULL ? *free  : 0);
1134     
1135     return DD_OK;
1136 }
1137
1138 HRESULT WINAPI Main_DirectDraw_TestCooperativeLevel(LPDIRECTDRAW7 iface) {
1139     ICOM_THIS(IDirectDrawImpl,iface);
1140     TRACE("(%p)->(): stub\n", This);
1141
1142     return DD_OK;
1143 }
1144
1145 HRESULT WINAPI
1146 Main_DirectDraw_StartModeTest(LPDIRECTDRAW7 iface, LPSIZE pModes,
1147                               DWORD dwNumModes, DWORD dwFlags)
1148 {
1149     ICOM_THIS(IDirectDrawImpl,iface);
1150     FIXME("(%p)->() stub\n", This);
1151
1152     return DD_OK;
1153 }
1154
1155 /*** Owned object management. */
1156
1157 void Main_DirectDraw_AddSurface(IDirectDrawImpl* This,
1158                                 IDirectDrawSurfaceImpl* surface)
1159 {
1160     assert(surface->ddraw_owner == NULL || surface->ddraw_owner == This);
1161
1162     surface->ddraw_owner = This;
1163
1164     /* where should it go? */
1165     surface->next_ddraw = This->surfaces;
1166     surface->prev_ddraw = NULL;
1167     if (This->surfaces)
1168         This->surfaces->prev_ddraw = surface;
1169     This->surfaces = surface;
1170 }
1171
1172 void Main_DirectDraw_RemoveSurface(IDirectDrawImpl* This,
1173                                    IDirectDrawSurfaceImpl* surface)
1174 {
1175     assert(surface->ddraw_owner == This);
1176
1177     if (This->surfaces == surface)
1178         This->surfaces = surface->next_ddraw;
1179
1180     if (This->primary_surface == surface)
1181         This->primary_surface = NULL;
1182
1183     if (surface->next_ddraw)
1184         surface->next_ddraw->prev_ddraw = surface->prev_ddraw;
1185     if (surface->prev_ddraw)
1186         surface->prev_ddraw->next_ddraw = surface->next_ddraw;
1187 }
1188
1189 static void Main_DirectDraw_DeleteSurfaces(IDirectDrawImpl* This)
1190 {
1191     while (This->surfaces != NULL)
1192         Main_DirectDrawSurface_ForceDestroy(This->surfaces);
1193 }
1194
1195 void Main_DirectDraw_AddClipper(IDirectDrawImpl* This,
1196                                 IDirectDrawClipperImpl* clipper)
1197 {
1198     assert(clipper->ddraw_owner == NULL || clipper->ddraw_owner == This);
1199
1200     clipper->ddraw_owner = This;
1201
1202     clipper->next_ddraw = This->clippers;
1203     clipper->prev_ddraw = NULL;
1204     if (This->clippers)
1205         This->clippers->prev_ddraw = clipper;
1206     This->clippers = clipper;
1207 }
1208
1209 void Main_DirectDraw_RemoveClipper(IDirectDrawImpl* This,
1210                                    IDirectDrawClipperImpl* clipper)
1211 {
1212     assert(clipper->ddraw_owner == This);
1213
1214     if (This->clippers == clipper)
1215         This->clippers = clipper->next_ddraw;
1216
1217     if (clipper->next_ddraw)
1218         clipper->next_ddraw->prev_ddraw = clipper->prev_ddraw;
1219     if (clipper->prev_ddraw)
1220         clipper->prev_ddraw->next_ddraw = clipper->next_ddraw;
1221 }
1222
1223 static void Main_DirectDraw_DeleteClippers(IDirectDrawImpl* This)
1224 {
1225     while (This->clippers != NULL)
1226         Main_DirectDrawClipper_ForceDestroy(This->clippers);
1227 }
1228
1229 void Main_DirectDraw_AddPalette(IDirectDrawImpl* This,
1230                                 IDirectDrawPaletteImpl* palette)
1231 {
1232     assert(palette->ddraw_owner == NULL || palette->ddraw_owner == This);
1233
1234     palette->ddraw_owner = This;
1235
1236     /* where should it go? */
1237     palette->next_ddraw = This->palettes;
1238     palette->prev_ddraw = NULL;
1239     if (This->palettes)
1240         This->palettes->prev_ddraw = palette;
1241     This->palettes = palette;
1242 }
1243
1244 void Main_DirectDraw_RemovePalette(IDirectDrawImpl* This,
1245                                    IDirectDrawPaletteImpl* palette)
1246 {
1247     assert(palette->ddraw_owner == This);
1248
1249     if (This->palettes == palette)
1250         This->palettes = palette->next_ddraw;
1251
1252     if (palette->next_ddraw)
1253         palette->next_ddraw->prev_ddraw = palette->prev_ddraw;
1254     if (palette->prev_ddraw)
1255         palette->prev_ddraw->next_ddraw = palette->next_ddraw;
1256 }
1257
1258 static void Main_DirectDraw_DeletePalettes(IDirectDrawImpl* This)
1259 {
1260     while (This->palettes != NULL)
1261         Main_DirectDrawPalette_ForceDestroy(This->palettes);
1262 }
1263
1264 /*** ??? */
1265
1266 static void
1267 LoseSurface(IDirectDrawSurfaceImpl *surface)
1268 {
1269     if (surface != NULL) surface->lose_surface(surface);
1270 }
1271
1272 static void
1273 LosePrimarySurface(IDirectDrawImpl *This)
1274 {
1275     /* MSDN: "If another application changes the display mode, the primary
1276      * surface is lost, and the method returns DDERR_SURFACELOST until the
1277      * primary surface is recreated to match the new display mode."
1278      *
1279      * We mark all the primary surfaces as lost as soon as the display
1280      * mode is changed (by any application). */
1281
1282     LoseSurface(This->primary_surface);
1283 }
1284
1285 /******************************************************************************
1286  * Uninitialised DirectDraw functions
1287  *
1288  * This vtable is used when a DirectDraw object is created with
1289  * CoCreateInstance. The only usable method is Initialize.
1290  */
1291
1292 void Uninit_DirectDraw_final_release(IDirectDrawImpl *This)
1293 {
1294     Main_DirectDraw_final_release(This);
1295 }
1296
1297 static ICOM_VTABLE(IDirectDraw7) Uninit_DirectDraw_VTable;
1298
1299 /* Not called from the vtable. */
1300 HRESULT Uninit_DirectDraw_Construct(IDirectDrawImpl *This, BOOL ex)
1301 {
1302     HRESULT hr;
1303
1304     hr = Main_DirectDraw_Construct(This, ex);
1305     if (FAILED(hr)) return hr;
1306
1307     This->final_release = Uninit_DirectDraw_final_release;
1308     ICOM_INIT_INTERFACE(This, IDirectDraw7, Uninit_DirectDraw_VTable);
1309
1310     return S_OK;
1311 }
1312
1313 HRESULT Uninit_DirectDraw_Create(const GUID* pGUID,
1314                                        LPDIRECTDRAW7* pIface,
1315                                        IUnknown* pUnkOuter, BOOL ex)
1316 {
1317     HRESULT hr;
1318     IDirectDrawImpl* This;
1319
1320     assert(pUnkOuter == NULL); /* XXX no: we must check this */
1321
1322     This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1323                      sizeof(IDirectDrawImpl));
1324     if (This == NULL) return E_OUTOFMEMORY;
1325
1326     hr = Uninit_DirectDraw_Construct(This, ex);
1327     if (FAILED(hr))
1328         HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY, This);
1329     else
1330         *pIface = ICOM_INTERFACE(This, IDirectDraw7);
1331
1332     return hr;
1333 }
1334
1335 static HRESULT WINAPI
1336 Uninit_DirectDraw_Initialize(LPDIRECTDRAW7 iface, LPGUID pDeviceGuid)
1337 {
1338     const ddraw_driver* driver;
1339     ICOM_THIS(IDirectDrawImpl, iface);
1340
1341     TRACE("(%p)->(%p)\n", iface, pDeviceGuid);
1342
1343     driver = DDRAW_FindDriver(pDeviceGuid);
1344     /* XXX This return value is not documented. (Not checked.) */
1345     if (driver == NULL) return DDERR_INVALIDDIRECTDRAWGUID;
1346
1347     return driver->init(This, pDeviceGuid);
1348 }
1349
1350 static HRESULT WINAPI
1351 Uninit_DirectDraw_Compact(LPDIRECTDRAW7 iface)
1352 {
1353     return DDERR_NOTINITIALIZED;
1354 }
1355
1356 static HRESULT WINAPI
1357 Uninit_DirectDraw_CreateClipper(LPDIRECTDRAW7 iface, DWORD dwFlags,
1358                                 LPDIRECTDRAWCLIPPER *lplpDDClipper,
1359                                 IUnknown *pUnkOuter)
1360
1361 {
1362     return DDERR_NOTINITIALIZED;
1363 }
1364
1365 static HRESULT WINAPI
1366 Uninit_DirectDraw_CreatePalette(LPDIRECTDRAW7 iface, DWORD dwFlags,
1367                                 LPPALETTEENTRY lpColorTable,
1368                                 LPDIRECTDRAWPALETTE *lplpDDPalette,
1369                                 IUnknown *pUnkOuter)
1370 {
1371     return DDERR_NOTINITIALIZED;
1372 }
1373
1374 static HRESULT WINAPI
1375 Uninit_DirectDraw_CreateSurface(LPDIRECTDRAW7 iface,
1376                                 LPDDSURFACEDESC2 lpDDSurfaceDesc,
1377                                 LPDIRECTDRAWSURFACE7 *lplpDDSurface,
1378                                 IUnknown *pUnkOuter)
1379 {
1380     return DDERR_NOTINITIALIZED;
1381 }
1382
1383 static HRESULT WINAPI
1384 Uninit_DirectDraw_DuplicateSurface(LPDIRECTDRAW7 iface,
1385                                    LPDIRECTDRAWSURFACE7 pSurf,
1386                                    LPDIRECTDRAWSURFACE7 *pDupSurf)
1387
1388 {
1389     return DDERR_NOTINITIALIZED;
1390 }
1391
1392 static HRESULT WINAPI
1393 Uninit_DirectDraw_EnumDisplayModes(LPDIRECTDRAW7 iface, DWORD dwFlags,
1394                                    LPDDSURFACEDESC2 lpDDSD,
1395                                    LPVOID context,
1396                                    LPDDENUMMODESCALLBACK2 cb)
1397 {
1398     return DDERR_NOTINITIALIZED;
1399 }
1400
1401 static HRESULT WINAPI
1402 Uninit_DirectDraw_EnumSurfaces(LPDIRECTDRAW7 iface, DWORD dwFlags,
1403                                LPDDSURFACEDESC2 pDDSD, LPVOID context,
1404                                LPDDENUMSURFACESCALLBACK7 cb)
1405 {
1406     return DDERR_NOTINITIALIZED;
1407 }
1408
1409 static HRESULT WINAPI
1410 Uninit_DirectDraw_FlipToGDISurface(LPDIRECTDRAW7 iface)
1411 {
1412     return DDERR_NOTINITIALIZED;
1413 }
1414
1415 static HRESULT WINAPI
1416 Uninit_DirectDraw_GetCaps(LPDIRECTDRAW7 iface, LPDDCAPS pDriverCaps,
1417                           LPDDCAPS pHELCaps)
1418 {
1419     return DDERR_NOTINITIALIZED;
1420 }
1421
1422 static HRESULT WINAPI
1423 Uninit_DirectDraw_GetDisplayMode(LPDIRECTDRAW7 iface,
1424                                  LPDDSURFACEDESC2 pDDSD)
1425 {
1426     return DDERR_NOTINITIALIZED;
1427 }
1428
1429 static HRESULT WINAPI
1430 Uninit_DirectDraw_GetFourCCCodes(LPDIRECTDRAW7 iface, LPDWORD pNumCodes,
1431                                  LPDWORD pCodes)
1432 {
1433     return DDERR_NOTINITIALIZED;
1434 }
1435
1436 static HRESULT WINAPI
1437 Uninit_DirectDraw_GetGDISurface(LPDIRECTDRAW7 iface,
1438                                 LPDIRECTDRAWSURFACE7 *pGDISurf)
1439 {
1440     return DDERR_NOTINITIALIZED;
1441 }
1442
1443 static HRESULT WINAPI
1444 Uninit_DirectDraw_GetMonitorFrequency(LPDIRECTDRAW7 iface, LPDWORD pdwFreq)
1445 {
1446     return DDERR_NOTINITIALIZED;
1447 }
1448
1449 static HRESULT WINAPI
1450 Uninit_DirectDraw_GetScanLine(LPDIRECTDRAW7 iface, LPDWORD pdwScanLine)
1451 {
1452     return DDERR_NOTINITIALIZED;
1453 }
1454
1455 static HRESULT WINAPI
1456 Uninit_DirectDraw_GetVerticalBlankStatus(LPDIRECTDRAW7 iface, PBOOL pbIsInVB)
1457 {
1458     return DDERR_NOTINITIALIZED;
1459 }
1460
1461 static HRESULT WINAPI
1462 Uninit_DirectDraw_RestoreDisplayMode(LPDIRECTDRAW7 iface)
1463 {
1464     return DDERR_NOTINITIALIZED;
1465 }
1466
1467 static HRESULT WINAPI
1468 Uninit_DirectDraw_SetCooperativeLevel(LPDIRECTDRAW7 iface, HWND hWnd,
1469                                       DWORD dwFlags)
1470 {
1471     return DDERR_NOTINITIALIZED;
1472 }
1473
1474 static HRESULT WINAPI
1475 Uninit_DirectDraw_SetDisplayMode(LPDIRECTDRAW7 iface, DWORD dwWidth,
1476                                  DWORD dwHeight, DWORD dwBPP,
1477                                  DWORD dwRefreshRate, DWORD dwFlags)
1478 {
1479     return DDERR_NOTINITIALIZED;
1480 }
1481
1482 static HRESULT WINAPI
1483 Uninit_DirectDraw_WaitForVerticalBlank(LPDIRECTDRAW7 iface, DWORD dwFlags,
1484                                        HANDLE hEvent)
1485 {
1486     return DDERR_NOTINITIALIZED;
1487 }
1488
1489 static HRESULT WINAPI
1490 Uninit_DirectDraw_GetAvailableVidMem(LPDIRECTDRAW7 iface, LPDDSCAPS2 pDDCaps,
1491                                      LPDWORD pdwTotal, LPDWORD pdwFree)
1492 {
1493     return DDERR_NOTINITIALIZED;
1494 }
1495
1496 static HRESULT WINAPI
1497 Uninit_DirectDraw_GetSurfaceFromDC(LPDIRECTDRAW7 iface, HDC hDC,
1498                                    LPDIRECTDRAWSURFACE7 *pSurf)
1499 {
1500     return DDERR_NOTINITIALIZED;
1501 }
1502
1503 static HRESULT WINAPI
1504 Uninit_DirectDraw_RestoreAllSurfaces(LPDIRECTDRAW7 iface)
1505 {
1506     return DDERR_NOTINITIALIZED;
1507 }
1508
1509 static HRESULT WINAPI
1510 Uninit_DirectDraw_TestCooperativeLevel(LPDIRECTDRAW7 iface)
1511 {
1512     return DDERR_NOTINITIALIZED;
1513 }
1514
1515 static HRESULT WINAPI
1516 Uninit_DirectDraw_GetDeviceIdentifier(LPDIRECTDRAW7 iface,
1517                                       LPDDDEVICEIDENTIFIER2 pDDDI,
1518                                       DWORD dwFlags)
1519 {
1520     return DDERR_NOTINITIALIZED;
1521 }
1522
1523 static HRESULT WINAPI
1524 Uninit_DirectDraw_StartModeTest(LPDIRECTDRAW7 iface, LPSIZE pszModes,
1525                                 DWORD cModes, DWORD dwFlags)
1526 {
1527     return DDERR_NOTINITIALIZED;
1528 }
1529
1530 static HRESULT WINAPI
1531 Uninit_DirectDraw_EvaluateMode(LPDIRECTDRAW7 iface, DWORD dwFlags,
1532                                LPDWORD pTimeout)
1533 {
1534     return DDERR_NOTINITIALIZED;
1535 }
1536
1537 static ICOM_VTABLE(IDirectDraw7) Uninit_DirectDraw_VTable =
1538 {
1539     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1540     Main_DirectDraw_QueryInterface,
1541     Main_DirectDraw_AddRef,
1542     Main_DirectDraw_Release,
1543     Uninit_DirectDraw_Compact,
1544     Uninit_DirectDraw_CreateClipper,
1545     Uninit_DirectDraw_CreatePalette,
1546     Uninit_DirectDraw_CreateSurface,
1547     Uninit_DirectDraw_DuplicateSurface,
1548     Uninit_DirectDraw_EnumDisplayModes,
1549     Uninit_DirectDraw_EnumSurfaces,
1550     Uninit_DirectDraw_FlipToGDISurface,
1551     Uninit_DirectDraw_GetCaps,
1552     Uninit_DirectDraw_GetDisplayMode,
1553     Uninit_DirectDraw_GetFourCCCodes,
1554     Uninit_DirectDraw_GetGDISurface,
1555     Uninit_DirectDraw_GetMonitorFrequency,
1556     Uninit_DirectDraw_GetScanLine,
1557     Uninit_DirectDraw_GetVerticalBlankStatus,
1558     Uninit_DirectDraw_Initialize,
1559     Uninit_DirectDraw_RestoreDisplayMode,
1560     Uninit_DirectDraw_SetCooperativeLevel,
1561     Uninit_DirectDraw_SetDisplayMode,
1562     Uninit_DirectDraw_WaitForVerticalBlank,
1563     Uninit_DirectDraw_GetAvailableVidMem,
1564     Uninit_DirectDraw_GetSurfaceFromDC,
1565     Uninit_DirectDraw_RestoreAllSurfaces,
1566     Uninit_DirectDraw_TestCooperativeLevel,
1567     Uninit_DirectDraw_GetDeviceIdentifier,
1568     Uninit_DirectDraw_StartModeTest,
1569     Uninit_DirectDraw_EvaluateMode
1570 };