ntdll: NtQueryInformationToken change parameters according to PSDK.
[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 = TRUE;
1071     return DD_OK;
1072 }
1073
1074 /* If we were not initialised then Uninit_Main_IDirectDraw7_Initialize would
1075  * have been called instead. */
1076 HRESULT WINAPI
1077 Main_DirectDraw_Initialize(LPDIRECTDRAW7 iface, LPGUID lpGuid)
1078 {
1079     TRACE("(%p)->(%s)\n", iface, debugstr_guid(lpGuid));
1080
1081     return DDERR_ALREADYINITIALIZED;
1082 }
1083
1084 HRESULT WINAPI
1085 Main_DirectDraw_RestoreAllSurfaces(LPDIRECTDRAW7 iface)
1086 {
1087     IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1088     IDirectDrawSurfaceImpl* surf;
1089
1090     TRACE("(%p)->()\n", This);
1091
1092     for (surf = This->surfaces; surf != NULL; surf = surf->next_ddraw)
1093         IDirectDrawSurface7_Restore(ICOM_INTERFACE(surf, IDirectDrawSurface7));
1094
1095     return DD_OK;
1096 }
1097
1098 static void DDRAW_SubclassWindow(IDirectDrawImpl* This)
1099 {
1100     /* Well we don't actually subclass the window yet. */
1101     SetPropA(This->window, ddProp, This);
1102 }
1103
1104 static void DDRAW_UnsubclassWindow(IDirectDrawImpl* This)
1105 {
1106     RemovePropA(This->window, ddProp);
1107 }
1108
1109 HRESULT WINAPI
1110 Main_DirectDraw_SetCooperativeLevel(LPDIRECTDRAW7 iface, HWND hwnd,
1111                                     DWORD cooplevel)
1112 {
1113     IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1114
1115     FIXME("(%p)->(%p,%08lx)\n",This,hwnd,cooplevel);
1116     DDRAW_dump_cooperativelevel(cooplevel);
1117
1118     /* Makes realMYST test happy. */
1119     if (This->cooperative_level == cooplevel
1120         && This->window == hwnd)
1121         return DD_OK;
1122
1123     /* XXX "It cannot be reset while the process has surfaces or palettes
1124      * created." Otherwise the window can be changed???
1125      *
1126      * This appears to be wrong - comment it out for now.
1127      * This seems to be true at least for DDSCL_SETFOCUSWINDOW
1128      * It looks like Windows doesn't store the HWND in all cases,
1129      * probably if DDSCL_NORMAL is specified, but that's not sure
1130     if (This->window)
1131         return DDERR_HWNDALREADYSET;
1132     */
1133
1134     /* DDSCL_EXCLUSIVE or DDSCL_NORMAL or DDSCL_SETFOCUSWINDOW must be given */
1135     if (!(cooplevel & (DDSCL_EXCLUSIVE|DDSCL_NORMAL|DDSCL_SETFOCUSWINDOW)))
1136     {
1137         ERR("(%p) : Call to SetCooperativeLevel failed: cooplevel  != DDSCL_EXCLUSIVE|DDSCL_NORMAL|DDSCL_SETFOCUSWINDOW, returning DDERR_INVALIDPARAMS\n", This);
1138         return DDERR_INVALIDPARAMS;
1139     }
1140     /* Device window and focus Window. They only really matter in a
1141      * Multi-Monitor application, but some games specify them and we
1142      * have to react correctly. */
1143     if(cooplevel & DDSCL_SETFOCUSWINDOW)
1144     {
1145         /* This flag is a biest: It is only valid when DDSCL_NORMAL has been set
1146          * or no hwnd is set and no other flags are allowed, except DDSCL_NOWINDOWCHANGES
1147          */
1148         if(This->window)
1149             if(!(This->cooperative_level & DDSCL_NORMAL))
1150             {
1151                 ERR("(%p) : Call to SetCooperativeLevel failed: DDSCL_SETFOCUSWINDOW may not be used in Cooplevel %08lx, returning DDERR_HWNDALREADYSET\n",
1152                             This, This->cooperative_level);
1153                 return DDERR_HWNDALREADYSET;
1154             }
1155         if((cooplevel != DDSCL_SETFOCUSWINDOW))
1156             if(cooplevel != (DDSCL_SETFOCUSWINDOW | DDSCL_NOWINDOWCHANGES) )
1157             {
1158                 ERR("(%p) : Call to SetCooperativeLevel failed: Invalid use of DDSCL_SETFOCUSWINDOW, returning DDERR_INVALIDPARAMS\n", This);
1159                 return DDERR_INVALIDPARAMS;
1160             }
1161
1162         /* Don't know what exactly to do, but it's perfectly valid
1163          * to pass DDSCL_SETFOCUSWINDOW only */
1164         FIXME("(%p) : Poorly handled flag DDSCL_SETFOCUSWINDOW\n", This);
1165
1166         /* Store the flag in the cooperative level. I don't think that all other
1167          * flags should be overwritten, so just add it 
1168          * (In the most cases this will be DDSCL_SETFOCUSWINDOW | DDSCL_NORMAL) */
1169         cooplevel |= DDSCL_SETFOCUSWINDOW;
1170
1171         return DD_OK;
1172     }
1173
1174     /* DDSCL_EXCLUSE mode requires  DDSCL_FULLSCREEN and vice versa */
1175     if((cooplevel & DDSCL_EXCLUSIVE) && !(cooplevel & DDSCL_FULLSCREEN))
1176         return DDERR_INVALIDPARAMS;
1177     /* The other case is checked above */
1178
1179     /* Unhandled flags. Give a warning */
1180     if(cooplevel & DDSCL_SETDEVICEWINDOW)
1181         FIXME("(%p) : Unhandled flag DDSCL_SETDEVICEWINDOW.\n", This);
1182     if(cooplevel & DDSCL_CREATEDEVICEWINDOW)
1183         FIXME("(%p) : Unhandled flag DDSCL_CREATEDEVICEWINDOW.\n", This);
1184
1185     /* Perhaps the hwnd is only set in DDSCL_EXLUSIVE and DDSCL_FULLSCREEN mode. Not sure */
1186     This->window = hwnd;
1187     This->cooperative_level = cooplevel;
1188
1189     This->local.hWnd = (ULONG_PTR)hwnd;
1190     This->local.dwLocalFlags |= DDRAWILCL_SETCOOPCALLED;
1191     /* not entirely sure about these */
1192     if (cooplevel & DDSCL_EXCLUSIVE)     This->local.dwLocalFlags |= DDRAWILCL_HASEXCLUSIVEMODE;
1193     if (cooplevel & DDSCL_FULLSCREEN)    This->local.dwLocalFlags |= DDRAWILCL_ISFULLSCREEN;
1194     if (cooplevel & DDSCL_ALLOWMODEX)    This->local.dwLocalFlags |= DDRAWILCL_ALLOWMODEX;
1195     if (cooplevel & DDSCL_MULTITHREADED) This->local.dwLocalFlags |= DDRAWILCL_MULTITHREADED;
1196     if (cooplevel & DDSCL_FPUSETUP)      This->local.dwLocalFlags |= DDRAWILCL_FPUSETUP;
1197     if (cooplevel & DDSCL_FPUPRESERVE)   This->local.dwLocalFlags |= DDRAWILCL_FPUPRESERVE;
1198
1199     if (This->local.lpGbl) {
1200         /* assume that this app is the active app (in wine, there's
1201          * probably only one app per global ddraw object anyway) */
1202         if (cooplevel & DDSCL_EXCLUSIVE) This->local.lpGbl->lpExclusiveOwner = &This->local;
1203         else if (This->local.lpGbl->lpExclusiveOwner == &This->local)
1204             This->local.lpGbl->lpExclusiveOwner = NULL;
1205         if (This->set_exclusive_mode)
1206             This->set_exclusive_mode(This, (cooplevel & DDSCL_EXCLUSIVE) != 0);
1207     }
1208
1209     ShowWindow(hwnd, SW_SHOW);
1210
1211     DDRAW_SubclassWindow(This);
1212
1213     /* TODO Does it also get resized to the current screen size? */
1214
1215     return DD_OK;
1216 }
1217
1218 HRESULT WINAPI
1219 Main_DirectDraw_SetDisplayMode(LPDIRECTDRAW7 iface, DWORD dwWidth,
1220                                DWORD dwHeight, LONG lPitch,
1221                                DWORD dwRefreshRate, DWORD dwFlags,
1222                                const DDPIXELFORMAT* pixelformat)
1223 {
1224     short screenX;
1225     short screenY;
1226
1227     IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1228
1229     TRACE("(%p)->SetDisplayMode(%ld,%ld)\n",This,dwWidth,dwHeight);
1230
1231     if (!(This->cooperative_level & DDSCL_EXCLUSIVE))
1232         return DDERR_NOEXCLUSIVEMODE;
1233
1234     if (!IsWindow(This->window))
1235         return DDERR_GENERIC; /* unchecked */
1236
1237     LosePrimarySurface(This);
1238
1239     screenX = GetSystemMetrics(SM_CXSCREEN);
1240     screenY = GetSystemMetrics(SM_CYSCREEN);
1241
1242     This->width = dwWidth;
1243     This->height = dwHeight;
1244     This->pitch = lPitch;
1245     This->pixelformat = *pixelformat;
1246
1247     /* Position the window in the center of the screen - don't center for now */
1248     /* MoveWindow(This->window, (screenX-dwWidth)/2, (screenY-dwHeight)/2,
1249                   dwWidth, dwHeight, TRUE);*/
1250     MoveWindow(This->window, 0, 0, dwWidth, dwHeight, TRUE);
1251
1252     SetFocus(This->window);
1253
1254     return DD_OK;
1255 }
1256
1257 HRESULT WINAPI
1258 Main_DirectDraw_RestoreDisplayMode(LPDIRECTDRAW7 iface)
1259 {
1260     IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1261
1262     TRACE("(%p)\n",This);
1263     if (!(This->cooperative_level & DDSCL_EXCLUSIVE))
1264         return DDERR_NOEXCLUSIVEMODE;
1265
1266     /* Lose the primary surface if the resolution changes. */
1267     if (This->orig_width != This->width || This->orig_height != This->height
1268         || This->orig_pitch != This->pitch
1269         || This->orig_pixelformat.dwFlags != This->pixelformat.dwFlags
1270         || !Main_DirectDraw_DDPIXELFORMAT_Match(&This->pixelformat,
1271                                                 &This->orig_pixelformat))
1272     {
1273         LosePrimarySurface(This);
1274     }
1275
1276     /* TODO Move the window back where it belongs. */
1277
1278     return DD_OK;
1279 }
1280
1281 HRESULT WINAPI
1282 Main_DirectDraw_WaitForVerticalBlank(LPDIRECTDRAW7 iface, DWORD dwFlags,
1283                                      HANDLE h)
1284 {
1285     IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1286     FIXME("(%p)->(flags=0x%08lx,handle=%p)\n",This,dwFlags,h);
1287     return DD_OK;
1288 }
1289
1290 HRESULT WINAPI
1291 Main_DirectDraw_GetDisplayMode(LPDIRECTDRAW7 iface, LPDDSURFACEDESC2 pDDSD)
1292 {
1293     IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1294     TRACE("(%p)->GetDisplayMode(%p)\n",This,pDDSD);
1295
1296     pDDSD->dwFlags = DDSD_HEIGHT|DDSD_WIDTH|DDSD_PITCH|DDSD_PIXELFORMAT|DDSD_REFRESHRATE;
1297     pDDSD->dwHeight = This->height;
1298     pDDSD->dwWidth = This->width;
1299     pDDSD->u1.lPitch = This->pitch;
1300     pDDSD->u2.dwRefreshRate = 60;
1301     pDDSD->u4.ddpfPixelFormat = This->pixelformat;
1302     pDDSD->ddsCaps.dwCaps = 0;
1303
1304     return DD_OK;
1305 }
1306
1307 static INT32 allocate_memory(IDirectDrawImpl *This, DWORD mem)
1308 {
1309     if (mem > This->available_vidmem) return -1;
1310     This->available_vidmem -= mem;
1311     return This->available_vidmem;
1312 }
1313
1314 static void free_memory(IDirectDrawImpl *This, DWORD mem)
1315 {
1316     This->available_vidmem += mem;
1317 }
1318
1319 HRESULT WINAPI
1320 Main_DirectDraw_GetAvailableVidMem(LPDIRECTDRAW7 iface, LPDDSCAPS2 ddscaps,
1321                                    LPDWORD total, LPDWORD free)
1322 {
1323     IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1324     TRACE("(%p)->(%p,%p,%p)\n", This,ddscaps,total,free);
1325
1326     if (TRACE_ON(ddraw)) {
1327         TRACE(" Asking for memory of type : ");
1328         DDRAW_dump_DDSCAPS2(ddscaps); TRACE("\n");
1329     }
1330
1331     /* We have 16 MB videomemory */
1332     if (total)  *total= This->total_vidmem;
1333     if (free)   *free = This->available_vidmem;
1334
1335     TRACE(" returning (total) %ld / (free) %ld\n", 
1336           total != NULL ? *total : 0, 
1337           free  != NULL ? *free  : 0);
1338     
1339     return DD_OK;
1340 }
1341
1342 HRESULT WINAPI Main_DirectDraw_TestCooperativeLevel(LPDIRECTDRAW7 iface) {
1343     IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1344     TRACE("(%p)->(): stub\n", This);
1345
1346     return DD_OK;
1347 }
1348
1349 HRESULT WINAPI
1350 Main_DirectDraw_StartModeTest(LPDIRECTDRAW7 iface, LPSIZE pModes,
1351                               DWORD dwNumModes, DWORD dwFlags)
1352 {
1353     IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1354     FIXME("(%p)->() stub\n", This);
1355
1356     return DD_OK;
1357 }
1358
1359 /*** Owned object management. */
1360
1361 void Main_DirectDraw_AddSurface(IDirectDrawImpl* This,
1362                                 IDirectDrawSurfaceImpl* surface)
1363 {
1364     assert(surface->ddraw_owner == NULL || surface->ddraw_owner == This);
1365
1366     surface->ddraw_owner = This;
1367
1368     /* where should it go? */
1369     surface->next_ddraw = This->surfaces;
1370     surface->prev_ddraw = NULL;
1371     if (This->surfaces)
1372         This->surfaces->prev_ddraw = surface;
1373     This->surfaces = surface;
1374 }
1375
1376 void Main_DirectDraw_RemoveSurface(IDirectDrawImpl* This,
1377                                    IDirectDrawSurfaceImpl* surface)
1378 {
1379     assert(surface->ddraw_owner == This);
1380
1381     if (This->surfaces == surface)
1382         This->surfaces = surface->next_ddraw;
1383
1384     if (This->primary_surface == surface)
1385         This->primary_surface = NULL;
1386
1387     if (surface->next_ddraw)
1388         surface->next_ddraw->prev_ddraw = surface->prev_ddraw;
1389     if (surface->prev_ddraw)
1390         surface->prev_ddraw->next_ddraw = surface->next_ddraw;
1391 }
1392
1393 static void Main_DirectDraw_DeleteSurfaces(IDirectDrawImpl* This)
1394 {
1395     while (This->surfaces != NULL)
1396         Main_DirectDrawSurface_ForceDestroy(This->surfaces);
1397 }
1398
1399 void Main_DirectDraw_AddClipper(IDirectDrawImpl* This,
1400                                 IDirectDrawClipperImpl* clipper)
1401 {
1402     assert(clipper->ddraw_owner == NULL || clipper->ddraw_owner == This);
1403
1404     clipper->ddraw_owner = This;
1405
1406     clipper->next_ddraw = This->clippers;
1407     clipper->prev_ddraw = NULL;
1408     if (This->clippers)
1409         This->clippers->prev_ddraw = clipper;
1410     This->clippers = clipper;
1411 }
1412
1413 void Main_DirectDraw_RemoveClipper(IDirectDrawImpl* This,
1414                                    IDirectDrawClipperImpl* clipper)
1415 {
1416     assert(clipper->ddraw_owner == This);
1417
1418     if (This->clippers == clipper)
1419         This->clippers = clipper->next_ddraw;
1420
1421     if (clipper->next_ddraw)
1422         clipper->next_ddraw->prev_ddraw = clipper->prev_ddraw;
1423     if (clipper->prev_ddraw)
1424         clipper->prev_ddraw->next_ddraw = clipper->next_ddraw;
1425 }
1426
1427 static void Main_DirectDraw_DeleteClippers(IDirectDrawImpl* This)
1428 {
1429     while (This->clippers != NULL)
1430         Main_DirectDrawClipper_ForceDestroy(This->clippers);
1431 }
1432
1433 void Main_DirectDraw_AddPalette(IDirectDrawImpl* This,
1434                                 IDirectDrawPaletteImpl* palette)
1435 {
1436     assert(palette->ddraw_owner == NULL || palette->ddraw_owner == This);
1437
1438     palette->ddraw_owner = This;
1439
1440     /* where should it go? */
1441     palette->next_ddraw = This->palettes;
1442     palette->prev_ddraw = NULL;
1443     if (This->palettes)
1444         This->palettes->prev_ddraw = palette;
1445     This->palettes = palette;
1446 }
1447
1448 void Main_DirectDraw_RemovePalette(IDirectDrawImpl* This,
1449                                    IDirectDrawPaletteImpl* palette)
1450 {
1451     IDirectDrawSurfaceImpl *surf;
1452
1453     assert(palette->ddraw_owner == This);
1454
1455     if (This->palettes == palette)
1456         This->palettes = palette->next_ddraw;
1457
1458     if (palette->next_ddraw)
1459         palette->next_ddraw->prev_ddraw = palette->prev_ddraw;
1460     if (palette->prev_ddraw)
1461         palette->prev_ddraw->next_ddraw = palette->next_ddraw;
1462
1463     /* Here we need also to remove tha palette from any surface which has it as the
1464      * current palette (checked on Windows)
1465      */
1466     for (surf = This->surfaces; surf != NULL; surf = surf->next_ddraw) {
1467         if (surf->palette == palette) {
1468             TRACE("Palette %p attached to surface %p.\n", palette, surf);
1469             surf->palette = NULL;
1470             surf->set_palette(surf, NULL);
1471         }
1472     }
1473 }
1474
1475 static void Main_DirectDraw_DeletePalettes(IDirectDrawImpl* This)
1476 {
1477     while (This->palettes != NULL)
1478         Main_DirectDrawPalette_ForceDestroy(This->palettes);
1479 }
1480
1481 /*** ??? */
1482
1483 static void
1484 LoseSurface(IDirectDrawSurfaceImpl *surface)
1485 {
1486     if (surface != NULL) surface->lose_surface(surface);
1487 }
1488
1489 static void
1490 LosePrimarySurface(IDirectDrawImpl *This)
1491 {
1492     /* MSDN: "If another application changes the display mode, the primary
1493      * surface is lost, and the method returns DDERR_SURFACELOST until the
1494      * primary surface is recreated to match the new display mode."
1495      *
1496      * We mark all the primary surfaces as lost as soon as the display
1497      * mode is changed (by any application). */
1498
1499     LoseSurface(This->primary_surface);
1500 }
1501
1502 /******************************************************************************
1503  * Uninitialised DirectDraw functions
1504  *
1505  * This vtable is used when a DirectDraw object is created with
1506  * CoCreateInstance. The only usable method is Initialize.
1507  */
1508
1509 void Uninit_DirectDraw_final_release(IDirectDrawImpl *This)
1510 {
1511     Main_DirectDraw_final_release(This);
1512 }
1513
1514 static const IDirectDraw7Vtbl Uninit_DirectDraw_VTable;
1515
1516 /* Not called from the vtable. */
1517 HRESULT Uninit_DirectDraw_Construct(IDirectDrawImpl *This, BOOL ex)
1518 {
1519     HRESULT hr;
1520
1521     hr = Main_DirectDraw_Construct(This, ex);
1522     if (FAILED(hr)) return hr;
1523
1524     This->final_release = Uninit_DirectDraw_final_release;
1525     ICOM_INIT_INTERFACE(This, IDirectDraw7, Uninit_DirectDraw_VTable);
1526
1527     return S_OK;
1528 }
1529
1530 HRESULT Uninit_DirectDraw_Create(const GUID* pGUID,
1531                                        LPDIRECTDRAW7* pIface,
1532                                        IUnknown* pUnkOuter, BOOL ex)
1533 {
1534     HRESULT hr;
1535     IDirectDrawImpl* This;
1536
1537     assert(pUnkOuter == NULL); /* XXX no: we must check this */
1538
1539     This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1540                      sizeof(IDirectDrawImpl));
1541     if (This == NULL) return E_OUTOFMEMORY;
1542
1543     hr = Uninit_DirectDraw_Construct(This, ex);
1544     if (FAILED(hr))
1545         HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY, This);
1546     else
1547         *pIface = ICOM_INTERFACE(This, IDirectDraw7);
1548
1549     return hr;
1550 }
1551
1552 static HRESULT WINAPI
1553 Uninit_DirectDraw_Initialize(LPDIRECTDRAW7 iface, LPGUID pDeviceGuid)
1554 {
1555     const ddraw_driver* driver;
1556     IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1557
1558     TRACE("(%p)->(%p)\n", iface, pDeviceGuid);
1559
1560     driver = DDRAW_FindDriver(pDeviceGuid);
1561     /* XXX This return value is not documented. (Not checked.) */
1562     if (driver == NULL) return DDERR_INVALIDDIRECTDRAWGUID;
1563
1564     return driver->init(This, pDeviceGuid);
1565 }
1566
1567 static HRESULT WINAPI
1568 Uninit_DirectDraw_Compact(LPDIRECTDRAW7 iface)
1569 {
1570     return DDERR_NOTINITIALIZED;
1571 }
1572
1573 static HRESULT WINAPI
1574 Uninit_DirectDraw_CreateClipper(LPDIRECTDRAW7 iface, DWORD dwFlags,
1575                                 LPDIRECTDRAWCLIPPER *lplpDDClipper,
1576                                 IUnknown *pUnkOuter)
1577
1578 {
1579     return DDERR_NOTINITIALIZED;
1580 }
1581
1582 static HRESULT WINAPI
1583 Uninit_DirectDraw_CreatePalette(LPDIRECTDRAW7 iface, DWORD dwFlags,
1584                                 LPPALETTEENTRY lpColorTable,
1585                                 LPDIRECTDRAWPALETTE *lplpDDPalette,
1586                                 IUnknown *pUnkOuter)
1587 {
1588     return DDERR_NOTINITIALIZED;
1589 }
1590
1591 static HRESULT WINAPI
1592 Uninit_DirectDraw_CreateSurface(LPDIRECTDRAW7 iface,
1593                                 LPDDSURFACEDESC2 lpDDSurfaceDesc,
1594                                 LPDIRECTDRAWSURFACE7 *lplpDDSurface,
1595                                 IUnknown *pUnkOuter)
1596 {
1597     return DDERR_NOTINITIALIZED;
1598 }
1599
1600 static HRESULT WINAPI
1601 Uninit_DirectDraw_DuplicateSurface(LPDIRECTDRAW7 iface,
1602                                    LPDIRECTDRAWSURFACE7 pSurf,
1603                                    LPDIRECTDRAWSURFACE7 *pDupSurf)
1604
1605 {
1606     return DDERR_NOTINITIALIZED;
1607 }
1608
1609 static HRESULT WINAPI
1610 Uninit_DirectDraw_EnumDisplayModes(LPDIRECTDRAW7 iface, DWORD dwFlags,
1611                                    LPDDSURFACEDESC2 lpDDSD,
1612                                    LPVOID context,
1613                                    LPDDENUMMODESCALLBACK2 cb)
1614 {
1615     return DDERR_NOTINITIALIZED;
1616 }
1617
1618 static HRESULT WINAPI
1619 Uninit_DirectDraw_EnumSurfaces(LPDIRECTDRAW7 iface, DWORD dwFlags,
1620                                LPDDSURFACEDESC2 pDDSD, LPVOID context,
1621                                LPDDENUMSURFACESCALLBACK7 cb)
1622 {
1623     return DDERR_NOTINITIALIZED;
1624 }
1625
1626 static HRESULT WINAPI
1627 Uninit_DirectDraw_FlipToGDISurface(LPDIRECTDRAW7 iface)
1628 {
1629     return DDERR_NOTINITIALIZED;
1630 }
1631
1632 static HRESULT WINAPI
1633 Uninit_DirectDraw_GetCaps(LPDIRECTDRAW7 iface, LPDDCAPS pDriverCaps,
1634                           LPDDCAPS pHELCaps)
1635 {
1636     return DDERR_NOTINITIALIZED;
1637 }
1638
1639 static HRESULT WINAPI
1640 Uninit_DirectDraw_GetDisplayMode(LPDIRECTDRAW7 iface,
1641                                  LPDDSURFACEDESC2 pDDSD)
1642 {
1643     return DDERR_NOTINITIALIZED;
1644 }
1645
1646 static HRESULT WINAPI
1647 Uninit_DirectDraw_GetFourCCCodes(LPDIRECTDRAW7 iface, LPDWORD pNumCodes,
1648                                  LPDWORD pCodes)
1649 {
1650     return DDERR_NOTINITIALIZED;
1651 }
1652
1653 static HRESULT WINAPI
1654 Uninit_DirectDraw_GetGDISurface(LPDIRECTDRAW7 iface,
1655                                 LPDIRECTDRAWSURFACE7 *pGDISurf)
1656 {
1657     return DDERR_NOTINITIALIZED;
1658 }
1659
1660 static HRESULT WINAPI
1661 Uninit_DirectDraw_GetMonitorFrequency(LPDIRECTDRAW7 iface, LPDWORD pdwFreq)
1662 {
1663     return DDERR_NOTINITIALIZED;
1664 }
1665
1666 static HRESULT WINAPI
1667 Uninit_DirectDraw_GetScanLine(LPDIRECTDRAW7 iface, LPDWORD pdwScanLine)
1668 {
1669     return DDERR_NOTINITIALIZED;
1670 }
1671
1672 static HRESULT WINAPI
1673 Uninit_DirectDraw_GetVerticalBlankStatus(LPDIRECTDRAW7 iface, PBOOL pbIsInVB)
1674 {
1675     return DDERR_NOTINITIALIZED;
1676 }
1677
1678 static HRESULT WINAPI
1679 Uninit_DirectDraw_RestoreDisplayMode(LPDIRECTDRAW7 iface)
1680 {
1681     return DDERR_NOTINITIALIZED;
1682 }
1683
1684 static HRESULT WINAPI
1685 Uninit_DirectDraw_SetCooperativeLevel(LPDIRECTDRAW7 iface, HWND hWnd,
1686                                       DWORD dwFlags)
1687 {
1688     return DDERR_NOTINITIALIZED;
1689 }
1690
1691 static HRESULT WINAPI
1692 Uninit_DirectDraw_SetDisplayMode(LPDIRECTDRAW7 iface, DWORD dwWidth,
1693                                  DWORD dwHeight, DWORD dwBPP,
1694                                  DWORD dwRefreshRate, DWORD dwFlags)
1695 {
1696     return DDERR_NOTINITIALIZED;
1697 }
1698
1699 static HRESULT WINAPI
1700 Uninit_DirectDraw_WaitForVerticalBlank(LPDIRECTDRAW7 iface, DWORD dwFlags,
1701                                        HANDLE hEvent)
1702 {
1703     return DDERR_NOTINITIALIZED;
1704 }
1705
1706 static HRESULT WINAPI
1707 Uninit_DirectDraw_GetAvailableVidMem(LPDIRECTDRAW7 iface, LPDDSCAPS2 pDDCaps,
1708                                      LPDWORD pdwTotal, LPDWORD pdwFree)
1709 {
1710     return DDERR_NOTINITIALIZED;
1711 }
1712
1713 static HRESULT WINAPI
1714 Uninit_DirectDraw_GetSurfaceFromDC(LPDIRECTDRAW7 iface, HDC hDC,
1715                                    LPDIRECTDRAWSURFACE7 *pSurf)
1716 {
1717     return DDERR_NOTINITIALIZED;
1718 }
1719
1720 static HRESULT WINAPI
1721 Uninit_DirectDraw_RestoreAllSurfaces(LPDIRECTDRAW7 iface)
1722 {
1723     return DDERR_NOTINITIALIZED;
1724 }
1725
1726 static HRESULT WINAPI
1727 Uninit_DirectDraw_TestCooperativeLevel(LPDIRECTDRAW7 iface)
1728 {
1729     return DDERR_NOTINITIALIZED;
1730 }
1731
1732 static HRESULT WINAPI
1733 Uninit_DirectDraw_GetDeviceIdentifier(LPDIRECTDRAW7 iface,
1734                                       LPDDDEVICEIDENTIFIER2 pDDDI,
1735                                       DWORD dwFlags)
1736 {
1737     return DDERR_NOTINITIALIZED;
1738 }
1739
1740 static HRESULT WINAPI
1741 Uninit_DirectDraw_StartModeTest(LPDIRECTDRAW7 iface, LPSIZE pszModes,
1742                                 DWORD cModes, DWORD dwFlags)
1743 {
1744     return DDERR_NOTINITIALIZED;
1745 }
1746
1747 static HRESULT WINAPI
1748 Uninit_DirectDraw_EvaluateMode(LPDIRECTDRAW7 iface, DWORD dwFlags,
1749                                LPDWORD pTimeout)
1750 {
1751     return DDERR_NOTINITIALIZED;
1752 }
1753
1754 static const IDirectDraw7Vtbl Uninit_DirectDraw_VTable =
1755 {
1756     Main_DirectDraw_QueryInterface,
1757     Main_DirectDraw_AddRef,
1758     Main_DirectDraw_Release,
1759     Uninit_DirectDraw_Compact,
1760     Uninit_DirectDraw_CreateClipper,
1761     Uninit_DirectDraw_CreatePalette,
1762     Uninit_DirectDraw_CreateSurface,
1763     Uninit_DirectDraw_DuplicateSurface,
1764     Uninit_DirectDraw_EnumDisplayModes,
1765     Uninit_DirectDraw_EnumSurfaces,
1766     Uninit_DirectDraw_FlipToGDISurface,
1767     Uninit_DirectDraw_GetCaps,
1768     Uninit_DirectDraw_GetDisplayMode,
1769     Uninit_DirectDraw_GetFourCCCodes,
1770     Uninit_DirectDraw_GetGDISurface,
1771     Uninit_DirectDraw_GetMonitorFrequency,
1772     Uninit_DirectDraw_GetScanLine,
1773     Uninit_DirectDraw_GetVerticalBlankStatus,
1774     Uninit_DirectDraw_Initialize,
1775     Uninit_DirectDraw_RestoreDisplayMode,
1776     Uninit_DirectDraw_SetCooperativeLevel,
1777     Uninit_DirectDraw_SetDisplayMode,
1778     Uninit_DirectDraw_WaitForVerticalBlank,
1779     Uninit_DirectDraw_GetAvailableVidMem,
1780     Uninit_DirectDraw_GetSurfaceFromDC,
1781     Uninit_DirectDraw_RestoreAllSurfaces,
1782     Uninit_DirectDraw_TestCooperativeLevel,
1783     Uninit_DirectDraw_GetDeviceIdentifier,
1784     Uninit_DirectDraw_StartModeTest,
1785     Uninit_DirectDraw_EvaluateMode
1786 };