Make 16-bit task properly inherit the current directory of their
[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 surface = ICOM_INTERFACE(surf,
878                                                           IDirectDrawSurface7);
879
880             /* BOGUS! Violates COM rules, but MSDN says so. */
881             IDirectDrawSurface7_AddRef(surface);
882
883             if (callback(surface, &surf->surface_desc, context)
884                 == DDENUMRET_CANCEL)
885                 break;
886         }
887     }
888
889     return DD_OK;
890 }
891
892 /* I really don't understand how this is supposed to work.
893  * We only consider dwHeight, dwWidth and ddpfPixelFormat.dwFlags. */
894 HRESULT
895 Main_DirectDraw_EnumCreateableSurfaces(IDirectDrawImpl *This, DWORD dwFlags,
896                                        LPDDSURFACEDESC2 lpDDSD2,
897                                        LPVOID context,
898                                        LPDDENUMSURFACESCALLBACK7 callback)
899 {
900     FIXME("This isn't going to work.\n");
901
902     if ((dwFlags & DDENUMSURFACES_MATCHTYPE) != DDENUMSURFACES_MATCH)
903         return DDERR_INVALIDPARAMS;
904
905     /* TODO: implement this.
906      * Does this work before SCL is called?
907      * Does it only consider off-screen surfaces?
908      */
909
910     return E_FAIL;
911 }
912
913 /* For unsigned x. 0 is not a power of 2. */
914 #define IS_POW_2(x) (((x) & ((x) - 1)) == 0)
915
916 HRESULT WINAPI
917 Main_DirectDraw_EnumSurfaces(LPDIRECTDRAW7 iface, DWORD dwFlags,
918                              LPDDSURFACEDESC2 lpDDSD2, LPVOID context,
919                              LPDDENUMSURFACESCALLBACK7 callback)
920 {
921     IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
922     TRACE("(%p)->(0x%lx, %p, %p, %p)\n", iface, dwFlags, lpDDSD2, context,
923           callback);
924
925     if (callback == NULL)
926         return DDERR_INVALIDPARAMS;
927
928     if (dwFlags & ~(DDENUMSURFACES_SEARCHTYPE|DDENUMSURFACES_MATCHTYPE))
929         return DDERR_INVALIDPARAMS;
930
931     if (!IS_POW_2(dwFlags & DDENUMSURFACES_SEARCHTYPE)
932         || !IS_POW_2(dwFlags & DDENUMSURFACES_MATCHTYPE))
933         return DDERR_INVALIDPARAMS;
934
935     if (dwFlags & DDENUMSURFACES_DOESEXIST)
936     {
937         return Main_DirectDraw_EnumExistingSurfaces(This, dwFlags, lpDDSD2,
938                                                     context, callback);
939     }
940     else
941     {
942         return Main_DirectDraw_EnumCreateableSurfaces(This, dwFlags, lpDDSD2,
943                                                       context, callback);
944     }
945 }
946
947 HRESULT WINAPI
948 Main_DirectDraw_EvaluateMode(LPDIRECTDRAW7 iface,DWORD a,DWORD* b)
949 {
950     IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
951     FIXME("(%p)->() stub\n", This);
952
953     return DD_OK;
954 }
955
956 HRESULT WINAPI
957 Main_DirectDraw_FlipToGDISurface(LPDIRECTDRAW7 iface)
958 {
959     IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
960     TRACE("(%p)->()\n",This);
961     return DD_OK;
962 }
963
964 HRESULT WINAPI
965 Main_DirectDraw_GetCaps(LPDIRECTDRAW7 iface, LPDDCAPS pDriverCaps,
966                         LPDDCAPS pHELCaps)
967 {
968     IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
969     TRACE("(%p,%p,%p)\n",This,pDriverCaps,pHELCaps);
970     if (pDriverCaps != NULL) {
971         DD_STRUCT_COPY_BYSIZE(pDriverCaps,&This->caps);
972         if (TRACE_ON(ddraw)) {
973           TRACE("Driver Caps : \n");
974           DDRAW_dump_DDCAPS(pDriverCaps);
975         }
976     }
977     if (pHELCaps != NULL) {
978         DD_STRUCT_COPY_BYSIZE(pHELCaps,&This->caps);
979         if (TRACE_ON(ddraw)) {
980           TRACE("HEL Caps : \n");
981           DDRAW_dump_DDCAPS(pHELCaps);
982         }
983     }
984     return DD_OK;
985 }
986
987 /* GetCaps */
988 /* GetDeviceIdentifier */
989 /* GetDIsplayMode */
990
991 HRESULT WINAPI
992 Main_DirectDraw_GetFourCCCodes(LPDIRECTDRAW7 iface, LPDWORD pNumCodes,
993                                LPDWORD pCodes)
994 {
995     IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
996     if (*pNumCodes) {
997             *pNumCodes=0;
998     }
999     FIXME("(%p,%p,%p), stub\n",This,pNumCodes,pCodes);
1000     return DD_OK;
1001 }
1002
1003 HRESULT WINAPI
1004 Main_DirectDraw_GetGDISurface(LPDIRECTDRAW7 iface,
1005                               LPDIRECTDRAWSURFACE7 *lplpGDIDDSSurface)
1006 {
1007     IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1008     TRACE("(%p)->(%p)\n", This, lplpGDIDDSSurface);
1009     TRACE("returning primary (%p)\n", This->primary_surface);
1010     *lplpGDIDDSSurface = ICOM_INTERFACE(This->primary_surface, IDirectDrawSurface7);
1011     if (*lplpGDIDDSSurface)
1012         IDirectDrawSurface7_AddRef(*lplpGDIDDSSurface);
1013     return DD_OK;
1014 }
1015
1016 HRESULT WINAPI
1017 Main_DirectDraw_GetMonitorFrequency(LPDIRECTDRAW7 iface,LPDWORD freq)
1018 {
1019     IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1020     FIXME("(%p)->(%p) returns 60 Hz always\n",This,freq);
1021     *freq = 60*100; /* 60 Hz */
1022     return DD_OK;
1023 }
1024
1025 HRESULT WINAPI
1026 Main_DirectDraw_GetScanLine(LPDIRECTDRAW7 iface, LPDWORD lpdwScanLine)
1027 {
1028     IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1029     static BOOL hide;
1030
1031     /* Since this method is called often, show the fixme only once */
1032     if (!hide) {
1033         FIXME("(%p)->(%p) semi-stub\n", This, lpdwScanLine);
1034         hide = TRUE;
1035     }
1036
1037     /* Fake the line sweeping of the monitor */
1038     /* FIXME: We should synchronize with a source to keep the refresh rate */ 
1039     *lpdwScanLine = This->cur_scanline++;
1040     /* Assume 20 scan lines in the vertical blank */
1041     if (This->cur_scanline >= This->height + 20)
1042         This->cur_scanline = 0;
1043
1044     return DD_OK;
1045 }
1046
1047 HRESULT WINAPI
1048 Main_DirectDraw_GetSurfaceFromDC(LPDIRECTDRAW7 iface, HDC hdc,
1049                                  LPDIRECTDRAWSURFACE7 *lpDDS)
1050 {
1051     IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1052     FIXME("(%p)->(%08ld,%p)\n", This, (DWORD) hdc, lpDDS);
1053
1054     return DD_OK;
1055 }
1056
1057 HRESULT WINAPI
1058 Main_DirectDraw_GetVerticalBlankStatus(LPDIRECTDRAW7 iface, LPBOOL status)
1059 {
1060     IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1061     TRACE("(%p)->(%p)\n",This,status);
1062     *status = TRUE;
1063     return DD_OK;
1064 }
1065
1066 /* If we were not initialised then Uninit_Main_IDirectDraw7_Initialize would
1067  * have been called instead. */
1068 HRESULT WINAPI
1069 Main_DirectDraw_Initialize(LPDIRECTDRAW7 iface, LPGUID lpGuid)
1070 {
1071     TRACE("(%p)->(%s)\n", iface, debugstr_guid(lpGuid));
1072
1073     return DDERR_ALREADYINITIALIZED;
1074 }
1075
1076 HRESULT WINAPI
1077 Main_DirectDraw_RestoreAllSurfaces(LPDIRECTDRAW7 iface)
1078 {
1079     IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1080     IDirectDrawSurfaceImpl* surf;
1081
1082     TRACE("(%p)->()\n", This);
1083
1084     for (surf = This->surfaces; surf != NULL; surf = surf->next_ddraw)
1085         IDirectDrawSurface7_Restore(ICOM_INTERFACE(surf, IDirectDrawSurface7));
1086
1087     return DD_OK;
1088 }
1089
1090 static void DDRAW_SubclassWindow(IDirectDrawImpl* This)
1091 {
1092     /* Well we don't actually subclass the window yet. */
1093     SetPropA(This->window, ddProp, This);
1094 }
1095
1096 static void DDRAW_UnsubclassWindow(IDirectDrawImpl* This)
1097 {
1098     RemovePropA(This->window, ddProp);
1099 }
1100
1101 HRESULT WINAPI
1102 Main_DirectDraw_SetCooperativeLevel(LPDIRECTDRAW7 iface, HWND hwnd,
1103                                     DWORD cooplevel)
1104 {
1105     IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1106
1107     FIXME("(%p)->(%08lx,%08lx)\n",This,(DWORD)hwnd,cooplevel);
1108     DDRAW_dump_cooperativelevel(cooplevel);
1109
1110     /* Makes realMYST test happy. */
1111     if (This->cooperative_level == cooplevel
1112         && This->window == hwnd)
1113         return DD_OK;
1114
1115     /* XXX "It cannot be reset while the process has surfaces or palettes
1116      * created." Otherwise the window can be changed???
1117      *
1118      * This appears to be wrong - comment it out for now.
1119     if (This->window)
1120         return DDERR_HWNDALREADYSET;
1121     */
1122
1123     if (!(cooplevel & (DDSCL_EXCLUSIVE|DDSCL_NORMAL)))
1124         return DDERR_INVALIDPARAMS;
1125
1126     This->window = hwnd;
1127     This->cooperative_level = cooplevel;
1128
1129     This->local.hWnd = (ULONG_PTR)hwnd;
1130     This->local.dwLocalFlags |= DDRAWILCL_SETCOOPCALLED;
1131     /* not entirely sure about these */
1132     if (cooplevel & DDSCL_EXCLUSIVE)     This->local.dwLocalFlags |= DDRAWILCL_HASEXCLUSIVEMODE;
1133     if (cooplevel & DDSCL_FULLSCREEN)    This->local.dwLocalFlags |= DDRAWILCL_ISFULLSCREEN;
1134     if (cooplevel & DDSCL_ALLOWMODEX)    This->local.dwLocalFlags |= DDRAWILCL_ALLOWMODEX;
1135     if (cooplevel & DDSCL_MULTITHREADED) This->local.dwLocalFlags |= DDRAWILCL_MULTITHREADED;
1136     if (cooplevel & DDSCL_FPUSETUP)      This->local.dwLocalFlags |= DDRAWILCL_FPUSETUP;
1137     if (cooplevel & DDSCL_FPUPRESERVE)   This->local.dwLocalFlags |= DDRAWILCL_FPUPRESERVE;
1138
1139     if (This->local.lpGbl) {
1140         /* assume that this app is the active app (in wine, there's
1141          * probably only one app per global ddraw object anyway) */
1142         if (cooplevel & DDSCL_EXCLUSIVE) This->local.lpGbl->lpExclusiveOwner = &This->local;
1143         else if (This->local.lpGbl->lpExclusiveOwner == &This->local)
1144             This->local.lpGbl->lpExclusiveOwner = NULL;
1145         if (This->set_exclusive_mode)
1146             This->set_exclusive_mode(This, (cooplevel & DDSCL_EXCLUSIVE) != 0);
1147     }
1148
1149     ShowWindow(hwnd, SW_SHOW);
1150
1151     DDRAW_SubclassWindow(This);
1152
1153     /* TODO Does it also get resized to the current screen size? */
1154
1155     return DD_OK;
1156 }
1157
1158 HRESULT WINAPI
1159 Main_DirectDraw_SetDisplayMode(LPDIRECTDRAW7 iface, DWORD dwWidth,
1160                                DWORD dwHeight, LONG lPitch,
1161                                DWORD dwRefreshRate, DWORD dwFlags,
1162                                const DDPIXELFORMAT* pixelformat)
1163 {
1164     short screenX;
1165     short screenY;
1166
1167     IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1168
1169     TRACE("(%p)->SetDisplayMode(%ld,%ld)\n",This,dwWidth,dwHeight);
1170
1171     if (!(This->cooperative_level & DDSCL_EXCLUSIVE))
1172         return DDERR_NOEXCLUSIVEMODE;
1173
1174     if (!IsWindow(This->window))
1175         return DDERR_GENERIC; /* unchecked */
1176
1177     LosePrimarySurface(This);
1178
1179     screenX = GetSystemMetrics(SM_CXSCREEN);
1180     screenY = GetSystemMetrics(SM_CYSCREEN);
1181
1182     This->width = dwWidth;
1183     This->height = dwHeight;
1184     This->pitch = lPitch;
1185     This->pixelformat = *pixelformat;
1186
1187     /* Position the window in the center of the screen - don't center for now */
1188     /* MoveWindow(This->window, (screenX-dwWidth)/2, (screenY-dwHeight)/2,
1189                   dwWidth, dwHeight, TRUE);*/
1190     MoveWindow(This->window, 0, 0, dwWidth, dwHeight, TRUE);
1191
1192     SetFocus(This->window);
1193
1194     return DD_OK;
1195 }
1196
1197 HRESULT WINAPI
1198 Main_DirectDraw_RestoreDisplayMode(LPDIRECTDRAW7 iface)
1199 {
1200     IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1201
1202     TRACE("(%p)\n",This);
1203     if (!(This->cooperative_level & DDSCL_EXCLUSIVE))
1204         return DDERR_NOEXCLUSIVEMODE;
1205
1206     /* Lose the primary surface if the resolution changes. */
1207     if (This->orig_width != This->width || This->orig_height != This->height
1208         || This->orig_pitch != This->pitch
1209         || This->orig_pixelformat.dwFlags != This->pixelformat.dwFlags
1210         || !Main_DirectDraw_DDPIXELFORMAT_Match(&This->pixelformat,
1211                                                 &This->orig_pixelformat))
1212     {
1213         LosePrimarySurface(This);
1214     }
1215
1216     /* TODO Move the window back where it belongs. */
1217
1218     return DD_OK;
1219 }
1220
1221 HRESULT WINAPI
1222 Main_DirectDraw_WaitForVerticalBlank(LPDIRECTDRAW7 iface, DWORD dwFlags,
1223                                      HANDLE h)
1224 {
1225     IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1226     FIXME("(%p)->(flags=0x%08lx,handle=%p)\n",This,dwFlags,h);
1227     return DD_OK;
1228 }
1229
1230 HRESULT WINAPI
1231 Main_DirectDraw_GetDisplayMode(LPDIRECTDRAW7 iface, LPDDSURFACEDESC2 pDDSD)
1232 {
1233     IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1234     TRACE("(%p)->GetDisplayMode(%p)\n",This,pDDSD);
1235
1236     pDDSD->dwFlags = DDSD_HEIGHT|DDSD_WIDTH|DDSD_PITCH|DDSD_PIXELFORMAT|DDSD_REFRESHRATE;
1237     pDDSD->dwHeight = This->height;
1238     pDDSD->dwWidth = This->width;
1239     pDDSD->u1.lPitch = This->pitch;
1240     pDDSD->u2.dwRefreshRate = 60;
1241     pDDSD->u4.ddpfPixelFormat = This->pixelformat;
1242     pDDSD->ddsCaps.dwCaps = 0;
1243
1244     return DD_OK;
1245 }
1246
1247 static INT32 allocate_memory(IDirectDrawImpl *This, DWORD mem)
1248 {
1249     if (mem > This->available_vidmem) return -1;
1250     This->available_vidmem -= mem;
1251     return This->available_vidmem;
1252 }
1253
1254 static void free_memory(IDirectDrawImpl *This, DWORD mem)
1255 {
1256     This->available_vidmem += mem;
1257 }
1258
1259 HRESULT WINAPI
1260 Main_DirectDraw_GetAvailableVidMem(LPDIRECTDRAW7 iface, LPDDSCAPS2 ddscaps,
1261                                    LPDWORD total, LPDWORD free)
1262 {
1263     IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1264     TRACE("(%p)->(%p,%p,%p)\n", This,ddscaps,total,free);
1265
1266     if (TRACE_ON(ddraw)) {
1267         TRACE(" Asking for memory of type : ");
1268         DDRAW_dump_DDSCAPS2(ddscaps); TRACE("\n");
1269     }
1270
1271     /* We have 16 MB videomemory */
1272     if (total)  *total= This->total_vidmem;
1273     if (free)   *free = This->available_vidmem;
1274
1275     TRACE(" returning (total) %ld / (free) %ld\n", 
1276           total != NULL ? *total : 0, 
1277           free  != NULL ? *free  : 0);
1278     
1279     return DD_OK;
1280 }
1281
1282 HRESULT WINAPI Main_DirectDraw_TestCooperativeLevel(LPDIRECTDRAW7 iface) {
1283     IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1284     TRACE("(%p)->(): stub\n", This);
1285
1286     return DD_OK;
1287 }
1288
1289 HRESULT WINAPI
1290 Main_DirectDraw_StartModeTest(LPDIRECTDRAW7 iface, LPSIZE pModes,
1291                               DWORD dwNumModes, DWORD dwFlags)
1292 {
1293     IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1294     FIXME("(%p)->() stub\n", This);
1295
1296     return DD_OK;
1297 }
1298
1299 /*** Owned object management. */
1300
1301 void Main_DirectDraw_AddSurface(IDirectDrawImpl* This,
1302                                 IDirectDrawSurfaceImpl* surface)
1303 {
1304     assert(surface->ddraw_owner == NULL || surface->ddraw_owner == This);
1305
1306     surface->ddraw_owner = This;
1307
1308     /* where should it go? */
1309     surface->next_ddraw = This->surfaces;
1310     surface->prev_ddraw = NULL;
1311     if (This->surfaces)
1312         This->surfaces->prev_ddraw = surface;
1313     This->surfaces = surface;
1314 }
1315
1316 void Main_DirectDraw_RemoveSurface(IDirectDrawImpl* This,
1317                                    IDirectDrawSurfaceImpl* surface)
1318 {
1319     assert(surface->ddraw_owner == This);
1320
1321     if (This->surfaces == surface)
1322         This->surfaces = surface->next_ddraw;
1323
1324     if (This->primary_surface == surface)
1325         This->primary_surface = NULL;
1326
1327     if (surface->next_ddraw)
1328         surface->next_ddraw->prev_ddraw = surface->prev_ddraw;
1329     if (surface->prev_ddraw)
1330         surface->prev_ddraw->next_ddraw = surface->next_ddraw;
1331 }
1332
1333 static void Main_DirectDraw_DeleteSurfaces(IDirectDrawImpl* This)
1334 {
1335     while (This->surfaces != NULL)
1336         Main_DirectDrawSurface_ForceDestroy(This->surfaces);
1337 }
1338
1339 void Main_DirectDraw_AddClipper(IDirectDrawImpl* This,
1340                                 IDirectDrawClipperImpl* clipper)
1341 {
1342     assert(clipper->ddraw_owner == NULL || clipper->ddraw_owner == This);
1343
1344     clipper->ddraw_owner = This;
1345
1346     clipper->next_ddraw = This->clippers;
1347     clipper->prev_ddraw = NULL;
1348     if (This->clippers)
1349         This->clippers->prev_ddraw = clipper;
1350     This->clippers = clipper;
1351 }
1352
1353 void Main_DirectDraw_RemoveClipper(IDirectDrawImpl* This,
1354                                    IDirectDrawClipperImpl* clipper)
1355 {
1356     assert(clipper->ddraw_owner == This);
1357
1358     if (This->clippers == clipper)
1359         This->clippers = clipper->next_ddraw;
1360
1361     if (clipper->next_ddraw)
1362         clipper->next_ddraw->prev_ddraw = clipper->prev_ddraw;
1363     if (clipper->prev_ddraw)
1364         clipper->prev_ddraw->next_ddraw = clipper->next_ddraw;
1365 }
1366
1367 static void Main_DirectDraw_DeleteClippers(IDirectDrawImpl* This)
1368 {
1369     while (This->clippers != NULL)
1370         Main_DirectDrawClipper_ForceDestroy(This->clippers);
1371 }
1372
1373 void Main_DirectDraw_AddPalette(IDirectDrawImpl* This,
1374                                 IDirectDrawPaletteImpl* palette)
1375 {
1376     assert(palette->ddraw_owner == NULL || palette->ddraw_owner == This);
1377
1378     palette->ddraw_owner = This;
1379
1380     /* where should it go? */
1381     palette->next_ddraw = This->palettes;
1382     palette->prev_ddraw = NULL;
1383     if (This->palettes)
1384         This->palettes->prev_ddraw = palette;
1385     This->palettes = palette;
1386 }
1387
1388 void Main_DirectDraw_RemovePalette(IDirectDrawImpl* This,
1389                                    IDirectDrawPaletteImpl* palette)
1390 {
1391     IDirectDrawSurfaceImpl *surf;
1392
1393     assert(palette->ddraw_owner == This);
1394
1395     if (This->palettes == palette)
1396         This->palettes = palette->next_ddraw;
1397
1398     if (palette->next_ddraw)
1399         palette->next_ddraw->prev_ddraw = palette->prev_ddraw;
1400     if (palette->prev_ddraw)
1401         palette->prev_ddraw->next_ddraw = palette->next_ddraw;
1402
1403     /* Here we need also to remove tha palette from any surface which has it as the
1404      * current palette (checked on Windows)
1405      */
1406     for (surf = This->surfaces; surf != NULL; surf = surf->next_ddraw) {
1407         if (surf->palette == palette) {
1408             TRACE("Palette %p attached to surface %p.\n", palette, surf);
1409             surf->palette = NULL;
1410             surf->set_palette(surf, NULL);
1411         }
1412     }
1413 }
1414
1415 static void Main_DirectDraw_DeletePalettes(IDirectDrawImpl* This)
1416 {
1417     while (This->palettes != NULL)
1418         Main_DirectDrawPalette_ForceDestroy(This->palettes);
1419 }
1420
1421 /*** ??? */
1422
1423 static void
1424 LoseSurface(IDirectDrawSurfaceImpl *surface)
1425 {
1426     if (surface != NULL) surface->lose_surface(surface);
1427 }
1428
1429 static void
1430 LosePrimarySurface(IDirectDrawImpl *This)
1431 {
1432     /* MSDN: "If another application changes the display mode, the primary
1433      * surface is lost, and the method returns DDERR_SURFACELOST until the
1434      * primary surface is recreated to match the new display mode."
1435      *
1436      * We mark all the primary surfaces as lost as soon as the display
1437      * mode is changed (by any application). */
1438
1439     LoseSurface(This->primary_surface);
1440 }
1441
1442 /******************************************************************************
1443  * Uninitialised DirectDraw functions
1444  *
1445  * This vtable is used when a DirectDraw object is created with
1446  * CoCreateInstance. The only usable method is Initialize.
1447  */
1448
1449 void Uninit_DirectDraw_final_release(IDirectDrawImpl *This)
1450 {
1451     Main_DirectDraw_final_release(This);
1452 }
1453
1454 static const IDirectDraw7Vtbl Uninit_DirectDraw_VTable;
1455
1456 /* Not called from the vtable. */
1457 HRESULT Uninit_DirectDraw_Construct(IDirectDrawImpl *This, BOOL ex)
1458 {
1459     HRESULT hr;
1460
1461     hr = Main_DirectDraw_Construct(This, ex);
1462     if (FAILED(hr)) return hr;
1463
1464     This->final_release = Uninit_DirectDraw_final_release;
1465     ICOM_INIT_INTERFACE(This, IDirectDraw7, Uninit_DirectDraw_VTable);
1466
1467     return S_OK;
1468 }
1469
1470 HRESULT Uninit_DirectDraw_Create(const GUID* pGUID,
1471                                        LPDIRECTDRAW7* pIface,
1472                                        IUnknown* pUnkOuter, BOOL ex)
1473 {
1474     HRESULT hr;
1475     IDirectDrawImpl* This;
1476
1477     assert(pUnkOuter == NULL); /* XXX no: we must check this */
1478
1479     This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1480                      sizeof(IDirectDrawImpl));
1481     if (This == NULL) return E_OUTOFMEMORY;
1482
1483     hr = Uninit_DirectDraw_Construct(This, ex);
1484     if (FAILED(hr))
1485         HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY, This);
1486     else
1487         *pIface = ICOM_INTERFACE(This, IDirectDraw7);
1488
1489     return hr;
1490 }
1491
1492 static HRESULT WINAPI
1493 Uninit_DirectDraw_Initialize(LPDIRECTDRAW7 iface, LPGUID pDeviceGuid)
1494 {
1495     const ddraw_driver* driver;
1496     IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1497
1498     TRACE("(%p)->(%p)\n", iface, pDeviceGuid);
1499
1500     driver = DDRAW_FindDriver(pDeviceGuid);
1501     /* XXX This return value is not documented. (Not checked.) */
1502     if (driver == NULL) return DDERR_INVALIDDIRECTDRAWGUID;
1503
1504     return driver->init(This, pDeviceGuid);
1505 }
1506
1507 static HRESULT WINAPI
1508 Uninit_DirectDraw_Compact(LPDIRECTDRAW7 iface)
1509 {
1510     return DDERR_NOTINITIALIZED;
1511 }
1512
1513 static HRESULT WINAPI
1514 Uninit_DirectDraw_CreateClipper(LPDIRECTDRAW7 iface, DWORD dwFlags,
1515                                 LPDIRECTDRAWCLIPPER *lplpDDClipper,
1516                                 IUnknown *pUnkOuter)
1517
1518 {
1519     return DDERR_NOTINITIALIZED;
1520 }
1521
1522 static HRESULT WINAPI
1523 Uninit_DirectDraw_CreatePalette(LPDIRECTDRAW7 iface, DWORD dwFlags,
1524                                 LPPALETTEENTRY lpColorTable,
1525                                 LPDIRECTDRAWPALETTE *lplpDDPalette,
1526                                 IUnknown *pUnkOuter)
1527 {
1528     return DDERR_NOTINITIALIZED;
1529 }
1530
1531 static HRESULT WINAPI
1532 Uninit_DirectDraw_CreateSurface(LPDIRECTDRAW7 iface,
1533                                 LPDDSURFACEDESC2 lpDDSurfaceDesc,
1534                                 LPDIRECTDRAWSURFACE7 *lplpDDSurface,
1535                                 IUnknown *pUnkOuter)
1536 {
1537     return DDERR_NOTINITIALIZED;
1538 }
1539
1540 static HRESULT WINAPI
1541 Uninit_DirectDraw_DuplicateSurface(LPDIRECTDRAW7 iface,
1542                                    LPDIRECTDRAWSURFACE7 pSurf,
1543                                    LPDIRECTDRAWSURFACE7 *pDupSurf)
1544
1545 {
1546     return DDERR_NOTINITIALIZED;
1547 }
1548
1549 static HRESULT WINAPI
1550 Uninit_DirectDraw_EnumDisplayModes(LPDIRECTDRAW7 iface, DWORD dwFlags,
1551                                    LPDDSURFACEDESC2 lpDDSD,
1552                                    LPVOID context,
1553                                    LPDDENUMMODESCALLBACK2 cb)
1554 {
1555     return DDERR_NOTINITIALIZED;
1556 }
1557
1558 static HRESULT WINAPI
1559 Uninit_DirectDraw_EnumSurfaces(LPDIRECTDRAW7 iface, DWORD dwFlags,
1560                                LPDDSURFACEDESC2 pDDSD, LPVOID context,
1561                                LPDDENUMSURFACESCALLBACK7 cb)
1562 {
1563     return DDERR_NOTINITIALIZED;
1564 }
1565
1566 static HRESULT WINAPI
1567 Uninit_DirectDraw_FlipToGDISurface(LPDIRECTDRAW7 iface)
1568 {
1569     return DDERR_NOTINITIALIZED;
1570 }
1571
1572 static HRESULT WINAPI
1573 Uninit_DirectDraw_GetCaps(LPDIRECTDRAW7 iface, LPDDCAPS pDriverCaps,
1574                           LPDDCAPS pHELCaps)
1575 {
1576     return DDERR_NOTINITIALIZED;
1577 }
1578
1579 static HRESULT WINAPI
1580 Uninit_DirectDraw_GetDisplayMode(LPDIRECTDRAW7 iface,
1581                                  LPDDSURFACEDESC2 pDDSD)
1582 {
1583     return DDERR_NOTINITIALIZED;
1584 }
1585
1586 static HRESULT WINAPI
1587 Uninit_DirectDraw_GetFourCCCodes(LPDIRECTDRAW7 iface, LPDWORD pNumCodes,
1588                                  LPDWORD pCodes)
1589 {
1590     return DDERR_NOTINITIALIZED;
1591 }
1592
1593 static HRESULT WINAPI
1594 Uninit_DirectDraw_GetGDISurface(LPDIRECTDRAW7 iface,
1595                                 LPDIRECTDRAWSURFACE7 *pGDISurf)
1596 {
1597     return DDERR_NOTINITIALIZED;
1598 }
1599
1600 static HRESULT WINAPI
1601 Uninit_DirectDraw_GetMonitorFrequency(LPDIRECTDRAW7 iface, LPDWORD pdwFreq)
1602 {
1603     return DDERR_NOTINITIALIZED;
1604 }
1605
1606 static HRESULT WINAPI
1607 Uninit_DirectDraw_GetScanLine(LPDIRECTDRAW7 iface, LPDWORD pdwScanLine)
1608 {
1609     return DDERR_NOTINITIALIZED;
1610 }
1611
1612 static HRESULT WINAPI
1613 Uninit_DirectDraw_GetVerticalBlankStatus(LPDIRECTDRAW7 iface, PBOOL pbIsInVB)
1614 {
1615     return DDERR_NOTINITIALIZED;
1616 }
1617
1618 static HRESULT WINAPI
1619 Uninit_DirectDraw_RestoreDisplayMode(LPDIRECTDRAW7 iface)
1620 {
1621     return DDERR_NOTINITIALIZED;
1622 }
1623
1624 static HRESULT WINAPI
1625 Uninit_DirectDraw_SetCooperativeLevel(LPDIRECTDRAW7 iface, HWND hWnd,
1626                                       DWORD dwFlags)
1627 {
1628     return DDERR_NOTINITIALIZED;
1629 }
1630
1631 static HRESULT WINAPI
1632 Uninit_DirectDraw_SetDisplayMode(LPDIRECTDRAW7 iface, DWORD dwWidth,
1633                                  DWORD dwHeight, DWORD dwBPP,
1634                                  DWORD dwRefreshRate, DWORD dwFlags)
1635 {
1636     return DDERR_NOTINITIALIZED;
1637 }
1638
1639 static HRESULT WINAPI
1640 Uninit_DirectDraw_WaitForVerticalBlank(LPDIRECTDRAW7 iface, DWORD dwFlags,
1641                                        HANDLE hEvent)
1642 {
1643     return DDERR_NOTINITIALIZED;
1644 }
1645
1646 static HRESULT WINAPI
1647 Uninit_DirectDraw_GetAvailableVidMem(LPDIRECTDRAW7 iface, LPDDSCAPS2 pDDCaps,
1648                                      LPDWORD pdwTotal, LPDWORD pdwFree)
1649 {
1650     return DDERR_NOTINITIALIZED;
1651 }
1652
1653 static HRESULT WINAPI
1654 Uninit_DirectDraw_GetSurfaceFromDC(LPDIRECTDRAW7 iface, HDC hDC,
1655                                    LPDIRECTDRAWSURFACE7 *pSurf)
1656 {
1657     return DDERR_NOTINITIALIZED;
1658 }
1659
1660 static HRESULT WINAPI
1661 Uninit_DirectDraw_RestoreAllSurfaces(LPDIRECTDRAW7 iface)
1662 {
1663     return DDERR_NOTINITIALIZED;
1664 }
1665
1666 static HRESULT WINAPI
1667 Uninit_DirectDraw_TestCooperativeLevel(LPDIRECTDRAW7 iface)
1668 {
1669     return DDERR_NOTINITIALIZED;
1670 }
1671
1672 static HRESULT WINAPI
1673 Uninit_DirectDraw_GetDeviceIdentifier(LPDIRECTDRAW7 iface,
1674                                       LPDDDEVICEIDENTIFIER2 pDDDI,
1675                                       DWORD dwFlags)
1676 {
1677     return DDERR_NOTINITIALIZED;
1678 }
1679
1680 static HRESULT WINAPI
1681 Uninit_DirectDraw_StartModeTest(LPDIRECTDRAW7 iface, LPSIZE pszModes,
1682                                 DWORD cModes, DWORD dwFlags)
1683 {
1684     return DDERR_NOTINITIALIZED;
1685 }
1686
1687 static HRESULT WINAPI
1688 Uninit_DirectDraw_EvaluateMode(LPDIRECTDRAW7 iface, DWORD dwFlags,
1689                                LPDWORD pTimeout)
1690 {
1691     return DDERR_NOTINITIALIZED;
1692 }
1693
1694 static const IDirectDraw7Vtbl Uninit_DirectDraw_VTable =
1695 {
1696     Main_DirectDraw_QueryInterface,
1697     Main_DirectDraw_AddRef,
1698     Main_DirectDraw_Release,
1699     Uninit_DirectDraw_Compact,
1700     Uninit_DirectDraw_CreateClipper,
1701     Uninit_DirectDraw_CreatePalette,
1702     Uninit_DirectDraw_CreateSurface,
1703     Uninit_DirectDraw_DuplicateSurface,
1704     Uninit_DirectDraw_EnumDisplayModes,
1705     Uninit_DirectDraw_EnumSurfaces,
1706     Uninit_DirectDraw_FlipToGDISurface,
1707     Uninit_DirectDraw_GetCaps,
1708     Uninit_DirectDraw_GetDisplayMode,
1709     Uninit_DirectDraw_GetFourCCCodes,
1710     Uninit_DirectDraw_GetGDISurface,
1711     Uninit_DirectDraw_GetMonitorFrequency,
1712     Uninit_DirectDraw_GetScanLine,
1713     Uninit_DirectDraw_GetVerticalBlankStatus,
1714     Uninit_DirectDraw_Initialize,
1715     Uninit_DirectDraw_RestoreDisplayMode,
1716     Uninit_DirectDraw_SetCooperativeLevel,
1717     Uninit_DirectDraw_SetDisplayMode,
1718     Uninit_DirectDraw_WaitForVerticalBlank,
1719     Uninit_DirectDraw_GetAvailableVidMem,
1720     Uninit_DirectDraw_GetSurfaceFromDC,
1721     Uninit_DirectDraw_RestoreAllSurfaces,
1722     Uninit_DirectDraw_TestCooperativeLevel,
1723     Uninit_DirectDraw_GetDeviceIdentifier,
1724     Uninit_DirectDraw_StartModeTest,
1725     Uninit_DirectDraw_EvaluateMode
1726 };