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