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