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