quartz: Silence requests for ipin on filters.
[wine] / dlls / ddraw / surface.c
1 /* DirectDraw Surface Implementation
2  *
3  * Copyright (c) 1997-2000 Marcus Meissner
4  * Copyright (c) 1998-2000 Lionel Ulmer
5  * Copyright (c) 2000-2001 TransGaming Technologies Inc.
6  * Copyright (c) 2006 Stefan Dösinger
7  *
8  * This file contains the (internal) driver registration functions,
9  * driver enumeration APIs and DirectDraw creation functions.
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25
26 #include "config.h"
27 #include "wine/port.h"
28
29 #include <assert.h>
30 #include <stdarg.h>
31 #include <string.h>
32 #include <stdlib.h>
33
34 #define COBJMACROS
35 #define NONAMELESSUNION
36
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winerror.h"
40 #include "wingdi.h"
41 #include "wine/exception.h"
42
43 #include "ddraw.h"
44 #include "d3d.h"
45
46 #include "ddraw_private.h"
47 #include "wine/debug.h"
48
49 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
50
51 /*****************************************************************************
52  * IUnknown parts follow
53  *****************************************************************************/
54
55 /*****************************************************************************
56  * IDirectDrawSurface7::QueryInterface
57  *
58  * A normal QueryInterface implementation. For QueryInterface rules
59  * see ddraw.c, IDirectDraw7::QueryInterface. This method
60  * can Query IDirectDrawSurface interfaces in all version, IDirect3DTexture
61  * in all versions, the IDirectDrawGammaControl interface and it can
62  * create an IDirect3DDevice. (Uses IDirect3D7::CreateDevice)
63  *
64  * Params:
65  *  riid: The interface id queried for
66  *  obj: Address to write the pointer to
67  *
68  * Returns:
69  *  S_OK on success
70  *  E_NOINTERFACE if the requested interface wasn't found
71  *
72  *****************************************************************************/
73 static HRESULT WINAPI
74 IDirectDrawSurfaceImpl_QueryInterface(IDirectDrawSurface7 *iface,
75                                       REFIID riid,
76                                       void **obj)
77 {
78     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
79
80     /* According to COM docs, if the QueryInterface fails, obj should be set to NULL */
81     *obj = NULL;
82
83     if(!riid)
84         return DDERR_INVALIDPARAMS;
85
86     TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),obj);
87     if (IsEqualGUID(riid, &IID_IUnknown)
88      || IsEqualGUID(riid, &IID_IDirectDrawSurface7)
89      || IsEqualGUID(riid, &IID_IDirectDrawSurface4) )
90     {
91         IUnknown_AddRef(iface);
92         *obj = ICOM_INTERFACE(This, IDirectDrawSurface7);
93         TRACE("(%p) returning IDirectDrawSurface7 interface at %p\n", This, *obj);
94         return S_OK;
95     }
96     else if( IsEqualGUID(riid, &IID_IDirectDrawSurface3)
97           || IsEqualGUID(riid, &IID_IDirectDrawSurface2)
98           || IsEqualGUID(riid, &IID_IDirectDrawSurface) )
99     {
100         IUnknown_AddRef(iface);
101         *obj = ICOM_INTERFACE(This, IDirectDrawSurface3);
102         TRACE("(%p) returning IDirectDrawSurface3 interface at %p\n", This, *obj);
103         return S_OK;
104     }
105     else if( IsEqualGUID(riid, &IID_IDirectDrawGammaControl) )
106     {
107         IUnknown_AddRef(iface);
108         *obj = ICOM_INTERFACE(This, IDirectDrawGammaControl);
109         TRACE("(%p) returning IDirectDrawGammaControl interface at %p\n", This, *obj);
110         return S_OK;
111     }
112     else if( IsEqualGUID(riid, &IID_D3DDEVICE_WineD3D) ||
113              IsEqualGUID(riid, &IID_IDirect3DHALDevice)||
114              IsEqualGUID(riid, &IID_IDirect3DRGBDevice) )
115     {
116         IDirect3DDevice7 *d3d;
117
118         /* Call into IDirect3D7 for creation */
119         IDirect3D7_CreateDevice(ICOM_INTERFACE(This->ddraw, IDirect3D7),
120                                 riid,
121                                 ICOM_INTERFACE(This, IDirectDrawSurface7),
122                                 &d3d);
123
124         *obj = COM_INTERFACE_CAST(IDirect3DDeviceImpl, IDirect3DDevice7, IDirect3DDevice, d3d);
125         TRACE("(%p) Returning IDirect3DDevice interface at %p\n", This, *obj);
126
127         return S_OK;
128     }
129     else if (IsEqualGUID( &IID_IDirect3DTexture, riid ) ||
130              IsEqualGUID( &IID_IDirect3DTexture2, riid ))
131     {
132         if (IsEqualGUID( &IID_IDirect3DTexture, riid ))
133         {
134             *obj = ICOM_INTERFACE(This, IDirect3DTexture);
135             TRACE(" returning Direct3DTexture interface at %p.\n", *obj);
136         }
137         else
138         {
139             *obj = ICOM_INTERFACE(This, IDirect3DTexture2);
140             TRACE(" returning Direct3DTexture2 interface at %p.\n", *obj);
141         }
142         IUnknown_AddRef( (IUnknown *) *obj);
143         return S_OK;
144     }
145
146     ERR("No interface\n");
147     return E_NOINTERFACE;
148 }
149
150 /*****************************************************************************
151  * IDirectDrawSurface7::AddRef
152  *
153  * A normal addref implementation
154  *
155  * Returns:
156  *  The new refcount
157  *
158  *****************************************************************************/
159 static ULONG WINAPI
160 IDirectDrawSurfaceImpl_AddRef(IDirectDrawSurface7 *iface)
161 {
162     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
163     ULONG refCount = InterlockedIncrement(&This->ref);
164
165     TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
166     return refCount;
167 }
168
169 /*****************************************************************************
170  * IDirectDrawSurfaceImpl_Destroy
171  *
172  * A helper function for IDirectDrawSurface7::Release
173  *
174  * Frees the surface, regardless of its refcount.
175  *  See IDirectDrawSurface7::Release for more information
176  *
177  * Params:
178  *  This: Surface to free
179  *
180  *****************************************************************************/
181 void IDirectDrawSurfaceImpl_Destroy(IDirectDrawSurfaceImpl *This)
182 {
183     TRACE("(%p)\n", This);
184
185     /* Check the refcount and give a warning */
186     if(This->ref > 1)
187     {
188         /* This can happen when a complex surface is destroyed,
189          * because the 2nd surface was addref()ed when the app
190          * called GetAttachedSurface
191          */
192         WARN("(%p): Destroying surface with refount %d\n", This, This->ref);
193     }
194
195     /* Check for attached surfaces and detach them */
196     if(This->first_attached != This)
197     {
198         /* Well, this shouldn't happen: The surface being attached is addref()ed
199           * in AddAttachedSurface, so it shouldn't be released until DeleteAttachedSurface
200           * is called, because the refcount is held. It looks like the app released()
201           * it often enough to force this
202           */
203         IDirectDrawSurface7 *root = ICOM_INTERFACE(This->first_attached, IDirectDrawSurface7);
204         IDirectDrawSurface7 *detach = ICOM_INTERFACE(This, IDirectDrawSurface7);
205
206         FIXME("(%p) Freeing a surface that is attached to surface %p\n", This, This->first_attached);
207
208         /* The refcount will drop to -1 here */
209         if(IDirectDrawSurface7_DeleteAttachedSurface(root, 0, detach) != DD_OK)
210         {
211             ERR("(%p) DeleteAttachedSurface failed!\n", This);
212         }
213     }
214
215     while(This->next_attached != NULL)
216     {
217         IDirectDrawSurface7 *root = ICOM_INTERFACE(This, IDirectDrawSurface7);
218         IDirectDrawSurface7 *detach = ICOM_INTERFACE(This->next_attached, IDirectDrawSurface7);
219
220         if(IDirectDrawSurface7_DeleteAttachedSurface(root, 0, detach) != DD_OK)
221         {
222             ERR("(%p) DeleteAttachedSurface failed!\n", This);
223             assert(0);
224         }
225     }
226
227     /* Now destroy the surface. Wait: It could have been released if we are a texture */
228     if(This->WineD3DSurface)
229         IWineD3DSurface_Release(This->WineD3DSurface);
230
231     /* Having a texture handle set implies that the device still exists */
232     if(This->Handle)
233     {
234         This->ddraw->d3ddevice->Handles[This->Handle - 1].ptr = NULL;
235         This->ddraw->d3ddevice->Handles[This->Handle - 1].type = DDrawHandle_Unknown;
236     }
237
238     /* Reduce the ddraw surface count */
239     InterlockedDecrement(&This->ddraw->surfaces);
240     list_remove(&This->surface_list_entry);
241
242     HeapFree(GetProcessHeap(), 0, This);
243 }
244
245 /*****************************************************************************
246  * IDirectDrawSurface7::Release
247  *
248  * Reduces the surface's refcount by 1. If the refcount falls to 0, the
249  * surface is destroyed.
250  *
251  * Destroying the surface is a bit tricky. For the connection between
252  * WineD3DSurfaces and DirectDrawSurfaces see IDirectDraw7::CreateSurface
253  * It has a nice graph explaining the connection.
254  *
255  * What happens here is basically this:
256  * When a surface is destroyed, its WineD3DSurface is released,
257  * and the refcount of the DirectDraw interface is reduced by 1. If it has
258  * complex surfaces attached to it, then these surfaces are destroyed too,
259  * regardless of their refcount. If any surface being destroyed has another
260  * surface attached to it (with a "soft" attachment, not complex), then
261  * this surface is detached with DeleteAttachedSurface.
262  *
263  * When the surface is a texture, the WineD3DTexture is released.
264  * If the surface is the Direct3D render target, then the D3D
265  * capabilities of the WineD3DDevice are uninitialized, which causes the
266  * swapchain to be released.
267  *
268  * When a complex sublevel falls to ref zero, then this is ignored.
269  *
270  * Returns:
271  *  The new refcount
272  *
273  *****************************************************************************/
274 static ULONG WINAPI
275 IDirectDrawSurfaceImpl_Release(IDirectDrawSurface7 *iface)
276 {
277     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
278     ULONG ref;
279     TRACE("(%p) : Releasing from %d\n", This, This->ref);
280     ref = InterlockedDecrement(&This->ref);
281
282     if (ref == 0)
283     {
284
285         IDirectDrawSurfaceImpl *surf;
286         IDirectDrawImpl *ddraw;
287         IUnknown *ifaceToRelease = This->ifaceToRelease;
288         int i;
289
290         /* Complex attached surfaces are destroyed implicitely when the root is released */
291         EnterCriticalSection(&ddraw_cs);
292         if(!This->is_complex_root)
293         {
294             WARN("(%p) Attempt to destroy a surface that is not a complex root\n", This);
295             LeaveCriticalSection(&ddraw_cs);
296             return ref;
297         }
298         ddraw = This->ddraw;
299
300         /* If it's a texture, destroy the WineD3DTexture.
301          * WineD3D will destroy the IParent interfaces
302          * of the sublevels, which destroys the WineD3DSurfaces.
303          * Set the surfaces to NULL to avoid destroying them again later
304          */
305         if(This->wineD3DTexture)
306         {
307             IWineD3DBaseTexture_Release(This->wineD3DTexture);
308         }
309         /* If it's the RenderTarget, destroy the d3ddevice */
310         else if( (ddraw->d3d_initialized) && (This == ddraw->d3d_target))
311         {
312             TRACE("(%p) Destroying the render target, uninitializing D3D\n", This);
313
314             /* Unset any index buffer, just to be sure */
315             IWineD3DDevice_SetIndices(ddraw->wineD3DDevice, NULL);
316             IWineD3DDevice_SetDepthStencilSurface(ddraw->wineD3DDevice, NULL);
317             IWineD3DDevice_SetVertexDeclaration(ddraw->wineD3DDevice, NULL);
318             for(i = 0; i < ddraw->numConvertedDecls; i++)
319             {
320                 IWineD3DVertexDeclaration_Release(ddraw->decls[i].decl);
321             }
322             HeapFree(GetProcessHeap(), 0, ddraw->decls);
323             ddraw->numConvertedDecls = 0;
324
325             if(IWineD3DDevice_Uninit3D(ddraw->wineD3DDevice, D3D7CB_DestroyDepthStencilSurface, D3D7CB_DestroySwapChain) != D3D_OK)
326             {
327                 /* Not good */
328                 ERR("(%p) Failed to uninit 3D\n", This);
329             }
330             else
331             {
332                 /* Free the d3d window if one was created */
333                 if(ddraw->d3d_window != 0)
334                 {
335                     TRACE(" (%p) Destroying the hidden render window %p\n", This, ddraw->d3d_window);
336                     DestroyWindow(ddraw->d3d_window);
337                     ddraw->d3d_window = 0;
338                 }
339                 /* Unset the pointers */
340             }
341
342             ddraw->d3d_initialized = FALSE;
343             ddraw->d3d_target = NULL;
344
345             /* Reset to the default surface implementation type. This is needed if apps use
346              * non render target surfaces and expect blits to work after destroying the render
347              * target.
348              *
349              * TODO: Recreate existing offscreen surfaces
350              */
351             ddraw->ImplType = DefaultSurfaceType;
352
353             /* Write a trace because D3D unloading was the reason for many
354              * crashes during development.
355              */
356             TRACE("(%p) D3D unloaded\n", This);
357         }
358         else if(This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE |
359                                                      DDSCAPS_3DDEVICE       |
360                                                      DDSCAPS_TEXTURE        ) )
361         {
362             /* It's a render target, but no swapchain was created.
363              * The IParent interfaces have to be released manually.
364              * The same applies for textures without an
365              * IWineD3DTexture object attached
366              */
367             IParent *Parent;
368
369             for(i = 0; i < MAX_COMPLEX_ATTACHED; i++)
370             {
371                 if(This->complex_array[i])
372                 {
373                     /* Only the topmost level can have more than 1 surfaces in the complex
374                      * attachment array(Cube texture roots), for all others there is only
375                      * one
376                      */
377                     surf = This->complex_array[i];
378                     while(surf)
379                     {
380                         IWineD3DSurface_GetParent(surf->WineD3DSurface,
381                                                   (IUnknown **) &Parent);
382                         IParent_Release(Parent);  /* For the getParent */
383                         IParent_Release(Parent);  /* To release it */
384                         surf = surf->complex_array[0];
385                     }
386                 }
387             }
388
389             /* Now the top-level surface */
390             IWineD3DSurface_GetParent(This->WineD3DSurface,
391                                       (IUnknown **) &Parent);
392             IParent_Release(Parent);  /* For the getParent */
393             IParent_Release(Parent);  /* To release it */
394         }
395
396         /* The refcount test shows that the palette is detached when the surface is destroyed */
397         IDirectDrawSurface7_SetPalette(ICOM_INTERFACE(This, IDirectDrawSurface7),
398                                                       NULL);
399
400         /* Loop through all complex attached surfaces,
401          * and destroy them.
402          *
403          * Yet again, only the root can have more than one complexly attached surface, all the others
404          * have a total of one;
405          */
406         for(i = 0; i < MAX_COMPLEX_ATTACHED; i++)
407         {
408             if(!This->complex_array[i]) break;
409
410             surf = This->complex_array[i];
411             This->complex_array[i] = NULL;
412             while(surf)
413             {
414                 IDirectDrawSurfaceImpl *destroy = surf;
415                 surf = surf->complex_array[0];              /* Iterate through the "tree" */
416                 IDirectDrawSurfaceImpl_Destroy(destroy);    /* Destroy it */
417             }
418         }
419
420         /* Destroy the root surface.
421          */
422         IDirectDrawSurfaceImpl_Destroy(This);
423
424         /* Reduce the ddraw refcount */
425         if(ifaceToRelease) IUnknown_Release(ifaceToRelease);
426         LeaveCriticalSection(&ddraw_cs);
427     }
428
429     return ref;
430 }
431
432 /*****************************************************************************
433  * IDirectDrawSurface7::GetAttachedSurface
434  *
435  * Returns an attached surface with the requested caps. Surface attachment
436  * and complex surfaces are not clearly described by the MSDN or sdk,
437  * so this method is tricky and likely to contain problems.
438  * This implementation searches the complex list first, then the
439  * attachment chain.
440  *
441  * The chains are searched from This down to the last surface in the chain,
442  * not from the first element in the chain. The first surface found is
443  * returned. The MSDN says that this method fails if more than one surface
444  * matches the caps, but it is not sure if that is right. The attachment
445  * structure may not even allow two matching surfaces.
446  *
447  * The found surface is AddRef-ed before it is returned.
448  *
449  * Params:
450  *  Caps: Pointer to a DDCAPS2 structure describing the caps asked for
451  *  Surface: Address to store the found surface
452  *
453  * Returns:
454  *  DD_OK on success
455  *  DDERR_INVALIDPARAMS if Caps or Surface is NULL
456  *  DDERR_NOTFOUND if no surface was found
457  *
458  *****************************************************************************/
459 static HRESULT WINAPI
460 IDirectDrawSurfaceImpl_GetAttachedSurface(IDirectDrawSurface7 *iface,
461                                           DDSCAPS2 *Caps,
462                                           IDirectDrawSurface7 **Surface)
463 {
464     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
465     IDirectDrawSurfaceImpl *surf;
466     DDSCAPS2 our_caps;
467     int i;
468
469     TRACE("(%p)->(%p,%p)\n", This, Caps, Surface);
470     EnterCriticalSection(&ddraw_cs);
471
472     our_caps = *Caps;
473
474     if(This->version < 7)
475     {
476         /* Earlier dx apps put garbage into these members, clear them */
477         our_caps.dwCaps2 = 0;
478         our_caps.dwCaps3 = 0;
479         our_caps.dwCaps4 = 0;
480     }
481
482     TRACE("(%p): Looking for caps: %x,%x,%x,%x\n", This, our_caps.dwCaps, our_caps.dwCaps2, our_caps.dwCaps3, our_caps.dwCaps4); /* FIXME: Better debugging */
483
484     for(i = 0; i < MAX_COMPLEX_ATTACHED; i++)
485     {
486         surf = This->complex_array[i];
487         if(!surf) break;
488
489         if (TRACE_ON(ddraw))
490         {
491             TRACE("Surface: (%p) caps: %x,%x,%x,%x\n", surf,
492                    surf->surface_desc.ddsCaps.dwCaps,
493                    surf->surface_desc.ddsCaps.dwCaps2,
494                    surf->surface_desc.ddsCaps.dwCaps3,
495                    surf->surface_desc.ddsCaps.dwCaps4);
496         }
497
498         if (((surf->surface_desc.ddsCaps.dwCaps & our_caps.dwCaps) == our_caps.dwCaps) &&
499             ((surf->surface_desc.ddsCaps.dwCaps2 & our_caps.dwCaps2) == our_caps.dwCaps2)) {
500
501             /* MSDN: "This method fails if more than one surface is attached
502              * that matches the capabilities requested."
503              *
504              * Not sure how to test this.
505              */
506
507             TRACE("(%p): Returning surface %p\n", This, surf);
508             TRACE("(%p): mipmapcount=%d\n", This, surf->mipmap_level);
509             *Surface = ICOM_INTERFACE(surf, IDirectDrawSurface7);
510             IDirectDrawSurface7_AddRef(*Surface);
511             LeaveCriticalSection(&ddraw_cs);
512             return DD_OK;
513         }
514     }
515
516     /* Next, look at the attachment chain */
517     surf = This;
518
519     while( (surf = surf->next_attached) )
520     {
521         if (TRACE_ON(ddraw))
522         {
523             TRACE("Surface: (%p) caps: %x,%x,%x,%x\n", surf,
524                    surf->surface_desc.ddsCaps.dwCaps,
525                    surf->surface_desc.ddsCaps.dwCaps2,
526                    surf->surface_desc.ddsCaps.dwCaps3,
527                    surf->surface_desc.ddsCaps.dwCaps4);
528         }
529
530         if (((surf->surface_desc.ddsCaps.dwCaps & our_caps.dwCaps) == our_caps.dwCaps) &&
531             ((surf->surface_desc.ddsCaps.dwCaps2 & our_caps.dwCaps2) == our_caps.dwCaps2)) {
532
533             TRACE("(%p): Returning surface %p\n", This, surf);
534             *Surface = ICOM_INTERFACE(surf, IDirectDrawSurface7);
535             IDirectDrawSurface7_AddRef(*Surface);
536             LeaveCriticalSection(&ddraw_cs);
537             return DD_OK;
538         }
539     }
540
541     TRACE("(%p) Didn't find a valid surface\n", This);
542     LeaveCriticalSection(&ddraw_cs);
543     return DDERR_NOTFOUND;
544 }
545
546 /*****************************************************************************
547  * IDirectDrawSurface7::Lock
548  *
549  * Locks the surface and returns a pointer to the surface's memory
550  *
551  * Params:
552  *  Rect: Rectangle to lock. If NULL, the whole surface is locked
553  *  DDSD: Pointer to a DDSURFACEDESC2 which shall receive the surface's desc.
554  *  Flags: Locking flags, e.g Read only or write only
555  *  h: An event handle that's not used and must be NULL
556  *
557  * Returns:
558  *  DD_OK on success
559  *  DDERR_INVALIDPARAMS if DDSD is NULL
560  *  For more details, see IWineD3DSurface::LockRect
561  *
562  *****************************************************************************/
563 static HRESULT WINAPI
564 IDirectDrawSurfaceImpl_Lock(IDirectDrawSurface7 *iface,
565                             RECT *Rect,
566                             DDSURFACEDESC2 *DDSD,
567                             DWORD Flags,
568                             HANDLE h)
569 {
570     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
571     WINED3DLOCKED_RECT LockedRect;
572     HRESULT hr;
573     TRACE("(%p)->(%p,%p,%x,%p)\n", This, Rect, DDSD, Flags, h);
574
575     if(!DDSD)
576         return DDERR_INVALIDPARAMS;
577
578     /* This->surface_desc.dwWidth and dwHeight are changeable, thus lock */
579     EnterCriticalSection(&ddraw_cs);
580
581     /* Should I check for the handle to be NULL?
582      *
583      * The DDLOCK flags and the D3DLOCK flags are equal
584      * for the supported values. The others are ignored by WineD3D
585      */
586
587     if(DDSD->dwSize != sizeof(DDSURFACEDESC) &&
588        DDSD->dwSize != sizeof(DDSURFACEDESC2))
589     {
590         WARN("Invalid structure size %d, returning DDERR_INVALIDPARAMS\n", DDERR_INVALIDPARAMS);
591         LeaveCriticalSection(&ddraw_cs);
592         return DDERR_INVALIDPARAMS;
593     }
594
595     /* Windows zeroes this if the rect is invalid */
596     DDSD->lpSurface = 0;
597
598     if (Rect)
599     {
600         if ((Rect->left < 0)
601                 || (Rect->top < 0)
602                 || (Rect->left > Rect->right)
603                 || (Rect->top > Rect->bottom)
604                 || (Rect->right > This->surface_desc.dwWidth)
605                 || (Rect->bottom > This->surface_desc.dwHeight))
606         {
607             WARN("Trying to lock an invalid rectangle, returning DDERR_INVALIDPARAMS\n");
608             LeaveCriticalSection(&ddraw_cs);
609             return DDERR_INVALIDPARAMS;
610         }
611     }
612
613     hr = IWineD3DSurface_LockRect(This->WineD3DSurface,
614                                   &LockedRect,
615                                   Rect,
616                                   Flags);
617     if(hr != D3D_OK)
618     {
619         LeaveCriticalSection(&ddraw_cs);
620         switch(hr)
621         {
622             /* D3D8 and D3D9 return the general D3DERR_INVALIDCALL error, but ddraw has a more
623              * specific error. But since IWineD3DSurface::LockRect returns that error in this
624              * only occasion, keep d3d8 and d3d9 free from the return value override. There are
625              * many different places where d3d8/9 would have to catch the DDERR_SURFACEBUSY, it
626              * is much easier to do it in one place in ddraw
627              */
628             case WINED3DERR_INVALIDCALL:    return DDERR_SURFACEBUSY;
629             default:                        return hr;
630         }
631     }
632
633     /* Override the memory area. The pitch should be set already. Strangely windows
634      * does not set the LPSURFACE flag on locked surfaces !?!.
635      * DDSD->dwFlags |= DDSD_LPSURFACE;
636      */
637     This->surface_desc.lpSurface = LockedRect.pBits;
638     DD_STRUCT_COPY_BYSIZE(DDSD,&(This->surface_desc));
639
640     TRACE("locked surface returning description :\n");
641     if (TRACE_ON(ddraw)) DDRAW_dump_surface_desc(DDSD);
642
643     LeaveCriticalSection(&ddraw_cs);
644     return DD_OK;
645 }
646
647 /*****************************************************************************
648  * IDirectDrawSurface7::Unlock
649  *
650  * Unlocks an locked surface
651  *
652  * Params:
653  *  Rect: Not used by this implementation
654  *
655  * Returns:
656  *  D3D_OK on success
657  *  For more details, see IWineD3DSurface::UnlockRect
658  *
659  *****************************************************************************/
660 static HRESULT WINAPI
661 IDirectDrawSurfaceImpl_Unlock(IDirectDrawSurface7 *iface,
662                               RECT *pRect)
663 {
664     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
665     HRESULT hr;
666     TRACE("(%p)->(%p)\n", This, pRect);
667
668     EnterCriticalSection(&ddraw_cs);
669     hr = IWineD3DSurface_UnlockRect(This->WineD3DSurface);
670     if(SUCCEEDED(hr))
671     {
672         This->surface_desc.lpSurface = NULL;
673     }
674     LeaveCriticalSection(&ddraw_cs);
675     return hr;
676 }
677
678 /*****************************************************************************
679  * IDirectDrawSurface7::Flip
680  *
681  * Flips a surface with the DDSCAPS_FLIP flag. The flip is relayed to
682  * IWineD3DSurface::Flip. Because WineD3D doesn't handle attached surfaces,
683  * the flip target is passed to WineD3D, even if the app didn't specify one
684  *
685  * Params:
686  *  DestOverride: Specifies the surface that will become the new front
687  *                buffer. If NULL, the current back buffer is used
688  *  Flags: some DirectDraw flags, see include/ddraw.h
689  *
690  * Returns:
691  *  DD_OK on success
692  *  DDERR_NOTFLIPPABLE if no flip target could be found
693  *  DDERR_INVALIDOBJECT if the surface isn't a front buffer
694  *  For more details, see IWineD3DSurface::Flip
695  *
696  *****************************************************************************/
697 static HRESULT WINAPI
698 IDirectDrawSurfaceImpl_Flip(IDirectDrawSurface7 *iface,
699                             IDirectDrawSurface7 *DestOverride,
700                             DWORD Flags)
701 {
702     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
703     IDirectDrawSurfaceImpl *Override = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, DestOverride);
704     IDirectDrawSurface7 *Override7;
705     HRESULT hr;
706     TRACE("(%p)->(%p,%x)\n", This, DestOverride, Flags);
707
708     /* Flip has to be called from a front buffer
709      * What about overlay surfaces, AFAIK they can flip too?
710      */
711     if( !(This->surface_desc.ddsCaps.dwCaps & DDSCAPS_FRONTBUFFER) )
712         return DDERR_INVALIDOBJECT; /* Unckecked */
713
714     EnterCriticalSection(&ddraw_cs);
715
716     /* WineD3D doesn't keep track of attached surface, so find the target */
717     if(!Override)
718     {
719         DDSCAPS2 Caps;
720
721         memset(&Caps, 0, sizeof(Caps));
722         Caps.dwCaps |= DDSCAPS_BACKBUFFER;
723         hr = IDirectDrawSurface7_GetAttachedSurface(iface, &Caps, &Override7);
724         if(hr != DD_OK)
725         {
726             ERR("Can't find a flip target\n");
727             LeaveCriticalSection(&ddraw_cs);
728             return DDERR_NOTFLIPPABLE; /* Unchecked */
729         }
730         Override = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, Override7);
731
732         /* For the GetAttachedSurface */
733         IDirectDrawSurface7_Release(Override7);
734     }
735
736     hr = IWineD3DSurface_Flip(This->WineD3DSurface,
737                               Override->WineD3DSurface,
738                               Flags);
739     LeaveCriticalSection(&ddraw_cs);
740     return hr;
741 }
742
743 /*****************************************************************************
744  * IDirectDrawSurface7::Blt
745  *
746  * Performs a blit on the surface
747  *
748  * Params:
749  *  DestRect: Destination rectangle, can be NULL
750  *  SrcSurface: Source surface, can be NULL
751  *  SrcRect: Source rectangle, can be NULL
752  *  Flags: Blt flags
753  *  DDBltFx: Some extended blt parameters, connected to the flags
754  *
755  * Returns:
756  *  D3D_OK on success
757  *  See IWineD3DSurface::Blt for more details
758  *
759  *****************************************************************************/
760 static HRESULT WINAPI
761 IDirectDrawSurfaceImpl_Blt(IDirectDrawSurface7 *iface,
762                            RECT *DestRect,
763                            IDirectDrawSurface7 *SrcSurface,
764                            RECT *SrcRect,
765                            DWORD Flags,
766                            DDBLTFX *DDBltFx)
767 {
768     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
769     HRESULT hr;
770     IDirectDrawSurfaceImpl *Src = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, SrcSurface);
771     TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, Src, SrcRect, Flags, DDBltFx);
772
773     /* Check for validity of the flags here. WineD3D Has the software-opengl selection path and would have
774      * to check at 2 places, and sometimes do double checks. This also saves the call to wined3d :-)
775      */
776     if((Flags & DDBLT_KEYSRCOVERRIDE) && (!DDBltFx || Flags & DDBLT_KEYSRC)) {
777         WARN("Invalid source color key parameters, returning DDERR_INVALIDPARAMS\n");
778         return DDERR_INVALIDPARAMS;
779     }
780
781     if((Flags & DDBLT_KEYDESTOVERRIDE) && (!DDBltFx || Flags & DDBLT_KEYDEST)) {
782         WARN("Invalid destination color key parameters, returning DDERR_INVALIDPARAMS\n");
783         return DDERR_INVALIDPARAMS;
784     }
785
786     /* Sizes can change, therefore hold the lock when testing the rectangles */
787     EnterCriticalSection(&ddraw_cs);
788     if(DestRect)
789     {
790         if(DestRect->top >= DestRect->bottom || DestRect->left >= DestRect->right ||
791            DestRect->right > This->surface_desc.dwWidth ||
792            DestRect->bottom > This->surface_desc.dwHeight)
793         {
794             WARN("Destination rectangle is invalid, returning DDERR_INVALIDRECT\n");
795             LeaveCriticalSection(&ddraw_cs);
796             return DDERR_INVALIDRECT;
797         }
798     }
799     if(Src && SrcRect)
800     {
801         if(SrcRect->top >= SrcRect->bottom || SrcRect->left >=SrcRect->right ||
802            SrcRect->right > Src->surface_desc.dwWidth ||
803            SrcRect->bottom > Src->surface_desc.dwHeight)
804         {
805             WARN("Source rectangle is invalid, returning DDERR_INVALIDRECT\n");
806             LeaveCriticalSection(&ddraw_cs);
807             return DDERR_INVALIDRECT;
808         }
809     }
810
811     if(Flags & DDBLT_KEYSRC && (!Src || !(Src->surface_desc.dwFlags & DDSD_CKSRCBLT))) {
812         WARN("DDBLT_KEYDEST blit without color key in surface, returning DDERR_INVALIDPARAMS\n");
813         LeaveCriticalSection(&ddraw_cs);
814         return DDERR_INVALIDPARAMS;
815     }
816
817     /* TODO: Check if the DDBltFx contains any ddraw surface pointers. If it does, copy the struct,
818      * and replace the ddraw surfaces with the wined3d surfaces
819      * So far no blitting operations using surfaces in the bltfx struct are supported anyway.
820      */
821     hr = IWineD3DSurface_Blt(This->WineD3DSurface,
822                              DestRect,
823                              Src ? Src->WineD3DSurface : NULL,
824                              SrcRect,
825                              Flags,
826                              (WINEDDBLTFX *) DDBltFx,
827                              WINED3DTEXF_POINT);
828
829     LeaveCriticalSection(&ddraw_cs);
830     switch(hr)
831     {
832         case WINED3DERR_NOTAVAILABLE:       return DDERR_UNSUPPORTED;
833         case WINED3DERR_WRONGTEXTUREFORMAT: return DDERR_INVALIDPIXELFORMAT;
834         default:                            return hr;
835     }
836 }
837
838 /*****************************************************************************
839  * IDirectDrawSurface7::AddAttachedSurface
840  *
841  * Attaches a surface to another surface. How the surface attachments work
842  * is not totally understood yet, and this method is prone to problems.
843  * he surface that is attached is AddRef-ed.
844  *
845  * Tests with complex surfaces suggest that the surface attachments form a
846  * tree, but no method to test this has been found yet.
847  *
848  * The attachment list consists of a first surface (first_attached) and
849  * for each surface a pointer to the next attached surface (next_attached).
850  * For the first surface, and a surface that has no attachments
851  * first_attached points to the surface itself. A surface that has
852  * no successors in the chain has next_attached set to NULL.
853  *
854  * Newly attached surfaces are attached right after the root surface.
855  * If a surface is attached to a complex surface compound, it's attached to
856  * the surface that the app requested, not the complex root. See
857  * GetAttachedSurface for a description how surfaces are found.
858  *
859  * This is how the current implementation works, and it was coded by looking
860  * at the needs of the applications.
861  *
862  * So far only Z-Buffer attachments are tested, and they are activated in
863  * WineD3D. Mipmaps could be tricky to activate in WineD3D.
864  * Back buffers should work in 2D mode, but they are not tested(They can be
865  * attached in older iface versions). Rendering to the front buffer and
866  * switching between that and double buffering is not yet implemented in
867  * WineD3D, so for 3D it might have unexpected results.
868  *
869  * IDirectDrawSurfaceImpl_AddAttachedSurface is the real thing,
870  * IDirectDrawSurface7Impl_AddAttachedSurface is a wrapper around it that
871  * performs additional checks. Version 7 of this interface is much more restrictive
872  * than its predecessors.
873  *
874  * Params:
875  *  Attach: Surface to attach to iface
876  *
877  * Returns:
878  *  DD_OK on success
879  *  DDERR_CANNOTATTACHSURFACE if the surface can't be attached for some reason
880  *
881  *****************************************************************************/
882 HRESULT WINAPI
883 IDirectDrawSurfaceImpl_AddAttachedSurface(IDirectDrawSurfaceImpl *This,
884                                           IDirectDrawSurfaceImpl *Surf)
885 {
886     TRACE("(%p)->(%p)\n", This, Surf);
887
888     if(Surf == This)
889         return DDERR_CANNOTATTACHSURFACE; /* unchecked */
890
891     EnterCriticalSection(&ddraw_cs);
892
893     /* Check if the surface is already attached somewhere */
894     if( (Surf->next_attached != NULL) ||
895         (Surf->first_attached != Surf) )
896     {
897         /* TODO: Test for the structure of the manual attachment. Is it a chain or a list?
898          * What happens if one surface is attached to 2 different surfaces?
899          */
900         FIXME("(%p) The Surface %p is already attached somewhere else: next_attached = %p, first_attached = %p, can't handle by now\n", This, Surf, Surf->next_attached, Surf->first_attached);
901         LeaveCriticalSection(&ddraw_cs);
902         return DDERR_SURFACEALREADYATTACHED;
903     }
904
905     /* This inserts the new surface at the 2nd position in the chain, right after the root surface */
906     Surf->next_attached = This->next_attached;
907     Surf->first_attached = This->first_attached;
908     This->next_attached = Surf;
909
910     /* Check if the WineD3D depth stencil needs updating */
911     if(This->ddraw->d3ddevice)
912     {
913         IDirect3DDeviceImpl_UpdateDepthStencil(This->ddraw->d3ddevice);
914     }
915
916     /* MSDN: 
917      * "This method increments the reference count of the surface being attached."
918      */
919     IDirectDrawSurface7_AddRef(ICOM_INTERFACE(Surf, IDirectDrawSurface7));
920     LeaveCriticalSection(&ddraw_cs);
921     return DD_OK;
922 }
923
924 static HRESULT WINAPI
925 IDirectDrawSurface7Impl_AddAttachedSurface(IDirectDrawSurface7 *iface,
926                                            IDirectDrawSurface7 *Attach)
927 {
928     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
929     IDirectDrawSurfaceImpl *Surf = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, Attach);
930
931     /* Version 7 of this interface seems to refuse everything except z buffers, as per msdn */
932     if(!(Surf->surface_desc.ddsCaps.dwCaps & DDSCAPS_ZBUFFER))
933     {
934
935         WARN("Application tries to attach a non Z buffer surface. caps %08x\n",
936               Surf->surface_desc.ddsCaps.dwCaps);
937         return DDERR_CANNOTATTACHSURFACE;
938     }
939
940     return IDirectDrawSurfaceImpl_AddAttachedSurface(This,
941                                                      Surf);
942 }
943 /*****************************************************************************
944  * IDirectDrawSurface7::DeleteAttachedSurface
945  *
946  * Removes a surface from the attachment chain. The surface's refcount
947  * is decreased by one after it has been removed
948  *
949  * Params:
950  *  Flags: Some flags, not used by this implementation
951  *  Attach: Surface to detach
952  *
953  * Returns:
954  *  DD_OK on success
955  *  DDERR_SURFACENOTATTACHED if the surface isn't attached to
956  *
957  *****************************************************************************/
958 static HRESULT WINAPI
959 IDirectDrawSurfaceImpl_DeleteAttachedSurface(IDirectDrawSurface7 *iface,
960                                              DWORD Flags,
961                                              IDirectDrawSurface7 *Attach)
962 {
963     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
964     IDirectDrawSurfaceImpl *Surf = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, Attach);
965     IDirectDrawSurfaceImpl *Prev = This;
966     TRACE("(%p)->(%08x,%p)\n", This, Flags, Surf);
967
968     EnterCriticalSection(&ddraw_cs);
969     if (!Surf || (Surf->first_attached != This) || (Surf == This) )
970     {
971         LeaveCriticalSection(&ddraw_cs);
972         return DDERR_CANNOTDETACHSURFACE;
973     }
974
975     /* Remove MIPMAPSUBLEVEL if this seemed to be one */
976     if (This->surface_desc.ddsCaps.dwCaps &
977         Surf->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP)
978     {
979         Surf->surface_desc.ddsCaps.dwCaps2 &= ~DDSCAPS2_MIPMAPSUBLEVEL;
980         /* FIXME: we should probably also subtract from dwMipMapCount of this
981          * and all parent surfaces */
982     }
983
984     /* Find the predecessor of the detached surface */
985     while(Prev)
986     {
987         if(Prev->next_attached == Surf) break;
988         Prev = Prev->next_attached;
989     }
990
991     /* There must be a surface, otherwise there's a bug */
992     assert(Prev != NULL);
993
994     /* Unchain the surface */
995     Prev->next_attached = Surf->next_attached;
996     Surf->next_attached = NULL;
997     Surf->first_attached = Surf;
998
999     /* Check if the WineD3D depth stencil needs updating */
1000     if(This->ddraw->d3ddevice)
1001     {
1002         IDirect3DDeviceImpl_UpdateDepthStencil(This->ddraw->d3ddevice);
1003     }
1004
1005     IDirectDrawSurface7_Release(Attach);
1006     LeaveCriticalSection(&ddraw_cs);
1007     return DD_OK;
1008 }
1009
1010 /*****************************************************************************
1011  * IDirectDrawSurface7::AddOverlayDirtyRect
1012  *
1013  * "This method is not currently implemented"
1014  *
1015  * Params:
1016  *  Rect: ?
1017  *
1018  * Returns:
1019  *  DDERR_UNSUPPORTED
1020  *
1021  *****************************************************************************/
1022 static HRESULT WINAPI
1023 IDirectDrawSurfaceImpl_AddOverlayDirtyRect(IDirectDrawSurface7 *iface,
1024                                            LPRECT Rect)
1025 {
1026     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1027     TRACE("(%p)->(%p)\n",This,Rect);
1028
1029     /* MSDN says it's not implemented. I could forward it to WineD3D, 
1030      * then we'd implement it, but I don't think that's a good idea
1031      * (Stefan Dösinger)
1032      */
1033 #if 0
1034     return IWineD3DSurface_AddOverlayDirtyRect(This->WineD3DSurface, pRect);
1035 #endif
1036     return DDERR_UNSUPPORTED; /* unchecked */
1037 }
1038
1039 /*****************************************************************************
1040  * IDirectDrawSurface7::GetDC
1041  *
1042  * Returns a GDI device context for the surface
1043  *
1044  * Params:
1045  *  hdc: Address of a HDC variable to store the dc to
1046  *
1047  * Returns:
1048  *  DD_OK on success
1049  *  DDERR_INVALIDPARAMS if hdc is NULL
1050  *  For details, see IWineD3DSurface::GetDC
1051  *
1052  *****************************************************************************/
1053 static HRESULT WINAPI
1054 IDirectDrawSurfaceImpl_GetDC(IDirectDrawSurface7 *iface,
1055                              HDC *hdc)
1056 {
1057     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1058     HRESULT hr;
1059     TRACE("(%p)->(%p): Relay\n", This, hdc);
1060
1061     if(!hdc)
1062         return DDERR_INVALIDPARAMS;
1063
1064     EnterCriticalSection(&ddraw_cs);
1065     hr = IWineD3DSurface_GetDC(This->WineD3DSurface,
1066                                hdc);
1067     LeaveCriticalSection(&ddraw_cs);
1068     return hr;
1069 }
1070
1071 /*****************************************************************************
1072  * IDirectDrawSurface7::ReleaseDC
1073  *
1074  * Releases the DC that was constructed with GetDC
1075  *
1076  * Params:
1077  *  hdc: HDC to release
1078  *
1079  * Returns:
1080  *  DD_OK on success
1081  *  For more details, see IWineD3DSurface::ReleaseDC
1082  *
1083  *****************************************************************************/
1084 static HRESULT WINAPI
1085 IDirectDrawSurfaceImpl_ReleaseDC(IDirectDrawSurface7 *iface,
1086                                  HDC hdc)
1087 {
1088     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1089     HRESULT hr;
1090     TRACE("(%p)->(%p): Relay\n", This, hdc);
1091
1092     EnterCriticalSection(&ddraw_cs);
1093     hr = IWineD3DSurface_ReleaseDC(This->WineD3DSurface, hdc);
1094     LeaveCriticalSection(&ddraw_cs);
1095     return hr;
1096 }
1097
1098 /*****************************************************************************
1099  * IDirectDrawSurface7::GetCaps
1100  *
1101  * Returns the surface's caps
1102  *
1103  * Params:
1104  *  Caps: Address to write the caps to
1105  *
1106  * Returns:
1107  *  DD_OK on success
1108  *  DDERR_INVALIDPARAMS if Caps is NULL
1109  *
1110  *****************************************************************************/
1111 static HRESULT WINAPI
1112 IDirectDrawSurfaceImpl_GetCaps(IDirectDrawSurface7 *iface,
1113                                DDSCAPS2 *Caps)
1114 {
1115     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1116     TRACE("(%p)->(%p)\n",This,Caps);
1117
1118     if(!Caps)
1119         return DDERR_INVALIDPARAMS;
1120
1121     *Caps = This->surface_desc.ddsCaps;
1122     return DD_OK;
1123 }
1124
1125 /*****************************************************************************
1126  * IDirectDrawSurface7::SetPriority
1127  *
1128  * Sets a texture priority for managed textures.
1129  *
1130  * Params:
1131  *  Priority: The new priority
1132  *
1133  * Returns:
1134  *  DD_OK on success
1135  *  For more details, see IWineD3DSurface::SetPriority
1136  *
1137  *****************************************************************************/
1138 static HRESULT WINAPI
1139 IDirectDrawSurfaceImpl_SetPriority(IDirectDrawSurface7 *iface, DWORD Priority)
1140 {
1141     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1142     HRESULT hr;
1143     TRACE("(%p)->(%d): Relay!\n",This,Priority);
1144
1145     EnterCriticalSection(&ddraw_cs);
1146     hr = IWineD3DSurface_SetPriority(This->WineD3DSurface, Priority);
1147     LeaveCriticalSection(&ddraw_cs);
1148     return hr;
1149 }
1150
1151 /*****************************************************************************
1152  * IDirectDrawSurface7::GetPriority
1153  *
1154  * Returns the surface's priority
1155  *
1156  * Params:
1157  *  Priority: Address of a variable to write the priority to
1158  *
1159  * Returns:
1160  *  D3D_OK on success
1161  *  DDERR_INVALIDPARAMS if Priority == NULL
1162  *  For more details, see IWineD3DSurface::GetPriority
1163  *
1164  *****************************************************************************/
1165 static HRESULT WINAPI
1166 IDirectDrawSurfaceImpl_GetPriority(IDirectDrawSurface7 *iface,
1167                                    DWORD *Priority)
1168 {
1169     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1170     TRACE("(%p)->(%p): Relay\n",This,Priority);
1171
1172     if(!Priority)
1173     {
1174         return DDERR_INVALIDPARAMS;
1175     }
1176
1177     EnterCriticalSection(&ddraw_cs);
1178     *Priority = IWineD3DSurface_GetPriority(This->WineD3DSurface);
1179     LeaveCriticalSection(&ddraw_cs);
1180     return DD_OK;
1181 }
1182
1183 /*****************************************************************************
1184  * IDirectDrawSurface7::SetPrivateData
1185  *
1186  * Stores some data in the surface that is intended for the application's
1187  * use.
1188  *
1189  * Params:
1190  *  tag: GUID that identifies the data
1191  *  Data: Pointer to the private data
1192  *  Size: Size of the private data
1193  *  Flags: Some flags
1194  *
1195  * Returns:
1196  *  D3D_OK on success
1197  *  For more details, see IWineD3DSurface::SetPrivateData
1198  *
1199  *****************************************************************************/
1200 static HRESULT WINAPI
1201 IDirectDrawSurfaceImpl_SetPrivateData(IDirectDrawSurface7 *iface,
1202                                       REFGUID tag,
1203                                       void *Data,
1204                                       DWORD Size,
1205                                       DWORD Flags)
1206 {
1207     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1208     HRESULT hr;
1209     TRACE("(%p)->(%s,%p,%d,%x): Relay\n", This, debugstr_guid(tag), Data, Size, Flags);
1210
1211     EnterCriticalSection(&ddraw_cs);
1212     hr = IWineD3DSurface_SetPrivateData(This->WineD3DSurface,
1213                                         tag,
1214                                         Data,
1215                                         Size,
1216                                         Flags);
1217     LeaveCriticalSection(&ddraw_cs);
1218     switch(hr)
1219     {
1220         case WINED3DERR_INVALIDCALL:        return DDERR_INVALIDPARAMS;
1221         default:                            return hr;
1222     }
1223 }
1224
1225 /*****************************************************************************
1226  * IDirectDrawSurface7::GetPrivateData
1227  *
1228  * Returns the private data set with IDirectDrawSurface7::SetPrivateData
1229  *
1230  * Params:
1231  *  tag: GUID of the data to return
1232  *  Data: Address where to write the data to
1233  *  Size: Size of the buffer at Data
1234  *
1235  * Returns:
1236  *  DD_OK on success
1237  *  DDERR_INVALIDPARAMS if Data is NULL
1238  *  For more details, see IWineD3DSurface::GetPrivateData
1239  *
1240  *****************************************************************************/
1241 static HRESULT WINAPI
1242 IDirectDrawSurfaceImpl_GetPrivateData(IDirectDrawSurface7 *iface,
1243                                       REFGUID tag,
1244                                       void *Data,
1245                                       DWORD *Size)
1246 {
1247     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1248     HRESULT hr;
1249     TRACE("(%p)->(%s,%p,%p): Relay\n", This, debugstr_guid(tag), Data, Size);
1250
1251     if(!Data)
1252         return DDERR_INVALIDPARAMS;
1253
1254     EnterCriticalSection(&ddraw_cs);
1255     hr = IWineD3DSurface_GetPrivateData(This->WineD3DSurface,
1256                                         tag,
1257                                         Data,
1258                                         Size);
1259     LeaveCriticalSection(&ddraw_cs);
1260     return hr;
1261 }
1262
1263 /*****************************************************************************
1264  * IDirectDrawSurface7::FreePrivateData
1265  *
1266  * Frees private data stored in the surface
1267  *
1268  * Params:
1269  *  tag: Tag of the data to free
1270  *
1271  * Returns:
1272  *  D3D_OK on success
1273  *  For more details, see IWineD3DSurface::FreePrivateData
1274  *
1275  *****************************************************************************/
1276 static HRESULT WINAPI
1277 IDirectDrawSurfaceImpl_FreePrivateData(IDirectDrawSurface7 *iface,
1278                                        REFGUID tag)
1279 {
1280     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1281     HRESULT hr;
1282     TRACE("(%p)->(%s): Relay\n", This, debugstr_guid(tag));
1283
1284     EnterCriticalSection(&ddraw_cs);
1285     hr = IWineD3DSurface_FreePrivateData(This->WineD3DSurface, tag);
1286     LeaveCriticalSection(&ddraw_cs);
1287     return hr;
1288 }
1289
1290 /*****************************************************************************
1291  * IDirectDrawSurface7::PageLock
1292  *
1293  * Prevents a sysmem surface from being paged out
1294  *
1295  * Params:
1296  *  Flags: Not used, must be 0(unchecked)
1297  *
1298  * Returns:
1299  *  DD_OK, because it's a stub
1300  *
1301  *****************************************************************************/
1302 static HRESULT WINAPI
1303 IDirectDrawSurfaceImpl_PageLock(IDirectDrawSurface7 *iface,
1304                                 DWORD Flags)
1305 {
1306     TRACE("(%p)->(%x)\n", iface, Flags);
1307
1308     /* This is Windows memory management related - we don't need this */
1309     return DD_OK;
1310 }
1311
1312 /*****************************************************************************
1313  * IDirectDrawSurface7::PageUnlock
1314  *
1315  * Allows a sysmem surface to be paged out
1316  *
1317  * Params:
1318  *  Flags: Not used, must be 0(unckeched)
1319  *
1320  * Returns:
1321  *  DD_OK, because it's a stub
1322  *
1323  *****************************************************************************/
1324 static HRESULT WINAPI
1325 IDirectDrawSurfaceImpl_PageUnlock(IDirectDrawSurface7 *iface,
1326                                   DWORD Flags)
1327 {
1328     TRACE("(%p)->(%x)\n", iface, Flags);
1329
1330     return DD_OK;
1331 }
1332
1333 /*****************************************************************************
1334  * IDirectDrawSurface7::BltBatch
1335  *
1336  * An unimplemented function
1337  *
1338  * Params:
1339  *  ?
1340  *
1341  * Returns:
1342  *  DDERR_UNSUPPORTED
1343  *
1344  *****************************************************************************/
1345 static HRESULT WINAPI IDirectDrawSurfaceImpl_BltBatch(IDirectDrawSurface7 *iface, DDBLTBATCH *Batch, DWORD Count, DWORD Flags)
1346 {
1347     TRACE("(%p)->(%p,%d,%08x)\n",iface,Batch,Count,Flags);
1348
1349     /* MSDN: "not currently implemented" */
1350     return DDERR_UNSUPPORTED;
1351 }
1352
1353 /*****************************************************************************
1354  * IDirectDrawSurface7::EnumAttachedSurfaces
1355  *
1356  * Enumerates all surfaces attached to this surface
1357  *
1358  * Params:
1359  *  context: Pointer to pass unmodified to the callback
1360  *  cb: Callback function to call for each surface
1361  *
1362  * Returns:
1363  *  DD_OK on success
1364  *  DDERR_INVALIDPARAMS if cb is NULL
1365  *
1366  *****************************************************************************/
1367 static HRESULT WINAPI
1368 IDirectDrawSurfaceImpl_EnumAttachedSurfaces(IDirectDrawSurface7 *iface,
1369                                             void *context,
1370                                             LPDDENUMSURFACESCALLBACK7 cb)
1371 {
1372     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1373     IDirectDrawSurfaceImpl *surf;
1374     DDSURFACEDESC2 desc;
1375     int i;
1376
1377     /* Attached surfaces aren't handled in WineD3D */
1378     TRACE("(%p)->(%p,%p)\n",This,context,cb);
1379
1380     if(!cb)
1381         return DDERR_INVALIDPARAMS;
1382
1383     EnterCriticalSection(&ddraw_cs);
1384     for(i = 0; i < MAX_COMPLEX_ATTACHED; i++)
1385     {
1386         surf = This->complex_array[i];
1387         if(!surf) break;
1388
1389         IDirectDrawSurface7_AddRef(ICOM_INTERFACE(surf, IDirectDrawSurface7));
1390         desc = surf->surface_desc;
1391         /* check: != DDENUMRET_OK or == DDENUMRET_CANCEL? */
1392         if (cb(ICOM_INTERFACE(surf, IDirectDrawSurface7), &desc, context) == DDENUMRET_CANCEL)
1393         {
1394             LeaveCriticalSection(&ddraw_cs);
1395             return DD_OK;
1396         }
1397     }
1398
1399     for (surf = This->next_attached; surf != NULL; surf = surf->next_attached)
1400     {
1401         IDirectDrawSurface7_AddRef(ICOM_INTERFACE(surf, IDirectDrawSurface7));
1402         desc = surf->surface_desc;
1403         /* check: != DDENUMRET_OK or == DDENUMRET_CANCEL? */
1404         if (cb( ICOM_INTERFACE(surf, IDirectDrawSurface7), &desc, context) == DDENUMRET_CANCEL)
1405         {
1406             LeaveCriticalSection(&ddraw_cs);
1407             return DD_OK;
1408         }
1409     }
1410
1411     TRACE(" end of enumeration.\n");
1412
1413     LeaveCriticalSection(&ddraw_cs);
1414     return DD_OK;
1415 }
1416
1417 /*****************************************************************************
1418  * IDirectDrawSurface7::EnumOverlayZOrders
1419  *
1420  * "Enumerates the overlay surfaces on the specified destination"
1421  *
1422  * Params:
1423  *  Flags: DDENUMOVERLAYZ_BACKTOFRONT  or DDENUMOVERLAYZ_FRONTTOBACK
1424  *  context: context to pass back to the callback
1425  *  cb: callback function to call for each enumerated surface
1426  *
1427  * Returns:
1428  *  DD_OK, because it's a stub
1429  *
1430  *****************************************************************************/
1431 static HRESULT WINAPI
1432 IDirectDrawSurfaceImpl_EnumOverlayZOrders(IDirectDrawSurface7 *iface,
1433                                           DWORD Flags,
1434                                           void *context,
1435                                           LPDDENUMSURFACESCALLBACK7 cb)
1436 {
1437      FIXME("(%p)->(%x,%p,%p): Stub!\n", iface, Flags, context, cb);
1438
1439     return DD_OK;
1440 }
1441
1442 /*****************************************************************************
1443  * IDirectDrawSurface7::GetBltStatus
1444  *
1445  * Returns the blitting status
1446  *
1447  * Params:
1448  *  Flags: DDGBS_CANBLT or DDGBS_ISBLTDONE
1449  *
1450  * Returns:
1451  *  See IWineD3DSurface::Blt
1452  *
1453  *****************************************************************************/
1454 static HRESULT WINAPI
1455 IDirectDrawSurfaceImpl_GetBltStatus(IDirectDrawSurface7 *iface,
1456                                     DWORD Flags)
1457 {
1458     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1459     HRESULT hr;
1460     TRACE("(%p)->(%x): Relay\n", This, Flags);
1461
1462     EnterCriticalSection(&ddraw_cs);
1463     hr = IWineD3DSurface_GetBltStatus(This->WineD3DSurface, Flags);
1464     LeaveCriticalSection(&ddraw_cs);
1465     switch(hr)
1466     {
1467         case WINED3DERR_INVALIDCALL:        return DDERR_INVALIDPARAMS;
1468         default:                            return hr;
1469     }
1470 }
1471
1472 /*****************************************************************************
1473  * IDirectDrawSurface7::GetColorKey
1474  *
1475  * Returns the color key assigned to the surface
1476  *
1477  * Params:
1478  *  Flags: Some flags
1479  *  CKey: Address to store the key to
1480  *
1481  * Returns:
1482  *  DD_OK on success
1483  *  DDERR_INVALIDPARAMS if CKey is NULL
1484  *
1485  *****************************************************************************/
1486 static HRESULT WINAPI
1487 IDirectDrawSurfaceImpl_GetColorKey(IDirectDrawSurface7 *iface,
1488                                    DWORD Flags,
1489                                    DDCOLORKEY *CKey)
1490 {
1491     /* There is a DDERR_NOCOLORKEY error, but how do we know if a color key
1492      * isn't there? That's like saying that an int isn't there. (Which MS
1493      * has done in other docs.) */
1494     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1495     TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey);
1496
1497     if(!CKey)
1498         return DDERR_INVALIDPARAMS;
1499
1500     EnterCriticalSection(&ddraw_cs);
1501     switch (Flags)
1502     {
1503     case DDCKEY_DESTBLT:
1504         *CKey = This->surface_desc.ddckCKDestBlt;
1505         break;
1506
1507     case DDCKEY_DESTOVERLAY:
1508         *CKey = This->surface_desc.u3.ddckCKDestOverlay;
1509         break;
1510
1511     case DDCKEY_SRCBLT:
1512         *CKey = This->surface_desc.ddckCKSrcBlt;
1513         break;
1514
1515     case DDCKEY_SRCOVERLAY:
1516         *CKey = This->surface_desc.ddckCKSrcOverlay;
1517         break;
1518
1519     default:
1520         LeaveCriticalSection(&ddraw_cs);
1521         return DDERR_INVALIDPARAMS;
1522     }
1523
1524     LeaveCriticalSection(&ddraw_cs);
1525     return DD_OK;
1526 }
1527
1528 /*****************************************************************************
1529  * IDirectDrawSurface7::GetFlipStatus
1530  *
1531  * Returns the flipping status of the surface
1532  *
1533  * Params:
1534  *  Flags: DDGFS_CANFLIP of DDGFS_ISFLIPDONE
1535  *
1536  * Returns:
1537  *  See IWineD3DSurface::GetFlipStatus
1538  *
1539  *****************************************************************************/
1540 static HRESULT WINAPI
1541 IDirectDrawSurfaceImpl_GetFlipStatus(IDirectDrawSurface7 *iface,
1542                                      DWORD Flags)
1543 {
1544     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1545     HRESULT hr;
1546     TRACE("(%p)->(%x): Relay\n", This, Flags);
1547
1548     EnterCriticalSection(&ddraw_cs);
1549     hr = IWineD3DSurface_GetFlipStatus(This->WineD3DSurface, Flags);
1550     LeaveCriticalSection(&ddraw_cs);
1551     switch(hr)
1552     {
1553         case WINED3DERR_INVALIDCALL:        return DDERR_INVALIDPARAMS;
1554         default:                            return hr;
1555     }
1556 }
1557
1558 /*****************************************************************************
1559  * IDirectDrawSurface7::GetOverlayPosition
1560  *
1561  * Returns the display coordinates of a visible and active overlay surface
1562  *
1563  * Params:
1564  *  X
1565  *  Y
1566  *
1567  * Returns:
1568  *  DDERR_NOTAOVERLAYSURFACE, because it's a stub
1569  *****************************************************************************/
1570 static HRESULT WINAPI
1571 IDirectDrawSurfaceImpl_GetOverlayPosition(IDirectDrawSurface7 *iface,
1572                                           LONG *X,
1573                                           LONG *Y) {
1574     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1575     HRESULT hr;
1576     TRACE("(%p)->(%p,%p): Relay\n", This, X, Y);
1577
1578     EnterCriticalSection(&ddraw_cs);
1579     hr = IWineD3DSurface_GetOverlayPosition(This->WineD3DSurface,
1580                                             X,
1581                                             Y);
1582     LeaveCriticalSection(&ddraw_cs);
1583     return hr;
1584 }
1585
1586 /*****************************************************************************
1587  * IDirectDrawSurface7::GetPixelFormat
1588  *
1589  * Returns the pixel format of the Surface
1590  *
1591  * Params:
1592  *  PixelFormat: Pointer to a DDPIXELFORMAT structure to which the pixel
1593  *               format should be written
1594  *
1595  * Returns:
1596  *  DD_OK on success
1597  *  DDERR_INVALIDPARAMS if PixelFormat is NULL
1598  *
1599  *****************************************************************************/
1600 static HRESULT WINAPI
1601 IDirectDrawSurfaceImpl_GetPixelFormat(IDirectDrawSurface7 *iface,
1602                                       DDPIXELFORMAT *PixelFormat)
1603 {
1604     /* What is DDERR_INVALIDSURFACETYPE for here? */
1605     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1606     TRACE("(%p)->(%p)\n",This,PixelFormat);
1607
1608     if(!PixelFormat)
1609         return DDERR_INVALIDPARAMS;
1610
1611     EnterCriticalSection(&ddraw_cs);
1612     DD_STRUCT_COPY_BYSIZE(PixelFormat,&This->surface_desc.u4.ddpfPixelFormat);
1613     LeaveCriticalSection(&ddraw_cs);
1614
1615     return DD_OK;
1616 }
1617
1618
1619 /*****************************************************************************
1620  * IDirectDrawSurface7::GetSurfaceDesc
1621  *
1622  * Returns the description of this surface
1623  *
1624  * Params:
1625  *  DDSD: Address of a DDSURFACEDESC2 structure that is to be filled with the
1626  *        surface desc
1627  *
1628  * Returns:
1629  *  DD_OK on success
1630  *  DDERR_INVALIDPARAMS if DDSD is NULL
1631  *
1632  *****************************************************************************/
1633 static HRESULT WINAPI
1634 IDirectDrawSurfaceImpl_GetSurfaceDesc(IDirectDrawSurface7 *iface,
1635                                       DDSURFACEDESC2 *DDSD)
1636 {
1637     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1638
1639     TRACE("(%p)->(%p)\n",This,DDSD);
1640
1641     if(!DDSD)
1642         return DDERR_INVALIDPARAMS;
1643
1644     if (DDSD->dwSize != sizeof(DDSURFACEDESC2))
1645     {
1646         WARN("Incorrect struct size %d, returning DDERR_INVALIDPARAMS\n",DDSD->dwSize);
1647         return DDERR_INVALIDPARAMS;
1648     }
1649
1650     EnterCriticalSection(&ddraw_cs);
1651     DD_STRUCT_COPY_BYSIZE(DDSD,&This->surface_desc);
1652     TRACE("Returning surface desc:\n");
1653     if (TRACE_ON(ddraw)) DDRAW_dump_surface_desc(DDSD);
1654
1655     LeaveCriticalSection(&ddraw_cs);
1656     return DD_OK;
1657 }
1658
1659 /*****************************************************************************
1660  * IDirectDrawSurface7::Initialize
1661  *
1662  * Initializes the surface. This is a no-op in Wine
1663  *
1664  * Params:
1665  *  DD: Pointer to an DirectDraw interface
1666  *  DDSD: Surface description for initialization
1667  *
1668  * Returns:
1669  *  DDERR_ALREADYINITIALIZED
1670  *
1671  *****************************************************************************/
1672 static HRESULT WINAPI
1673 IDirectDrawSurfaceImpl_Initialize(IDirectDrawSurface7 *iface,
1674                                   IDirectDraw *DD,
1675                                   DDSURFACEDESC2 *DDSD)
1676 {
1677     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1678     IDirectDrawImpl *ddimpl = ICOM_OBJECT(IDirectDrawImpl, IDirectDraw, DD);
1679     TRACE("(%p)->(%p,%p)\n",This,ddimpl,DDSD);
1680
1681     return DDERR_ALREADYINITIALIZED;
1682 }
1683
1684 /*****************************************************************************
1685  * IDirectDrawSurface7::IsLost
1686  *
1687  * Checks if the surface is lost
1688  *
1689  * Returns:
1690  *  DD_OK, if the surface is useable
1691  *  DDERR_ISLOST if the surface is lost
1692  *  See IWineD3DSurface::IsLost for more details
1693  *
1694  *****************************************************************************/
1695 static HRESULT WINAPI
1696 IDirectDrawSurfaceImpl_IsLost(IDirectDrawSurface7 *iface)
1697 {
1698     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1699     HRESULT hr;
1700     TRACE("(%p)\n", This);
1701
1702     EnterCriticalSection(&ddraw_cs);
1703     /* We lose the surface if the implementation was changed */
1704     if(This->ImplType != This->ddraw->ImplType)
1705     {
1706         /* But this shouldn't happen. When we change the implementation,
1707          * all surfaces are re-created automatically, and their content
1708          * is copied
1709          */
1710         ERR(" (%p) Implementation was changed from %d to %d\n", This, This->ImplType, This->ddraw->ImplType);
1711         LeaveCriticalSection(&ddraw_cs);
1712         return DDERR_SURFACELOST;
1713     }
1714
1715     hr = IWineD3DSurface_IsLost(This->WineD3DSurface);
1716     LeaveCriticalSection(&ddraw_cs);
1717     switch(hr)
1718     {
1719         /* D3D8 and 9 loose full devices, thus there's only a DEVICELOST error.
1720          * WineD3D uses the same error for surfaces
1721          */
1722         case WINED3DERR_DEVICELOST:         return DDERR_SURFACELOST;
1723         default:                            return hr;
1724     }
1725 }
1726
1727 /*****************************************************************************
1728  * IDirectDrawSurface7::Restore
1729  *
1730  * Restores a lost surface. This makes the surface usable again, but
1731  * doesn't reload its old contents
1732  *
1733  * Returns:
1734  *  DD_OK on success
1735  *  See IWineD3DSurface::Restore for more details
1736  *
1737  *****************************************************************************/
1738 static HRESULT WINAPI
1739 IDirectDrawSurfaceImpl_Restore(IDirectDrawSurface7 *iface)
1740 {
1741     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1742     HRESULT hr;
1743     TRACE("(%p)\n", This);
1744
1745     EnterCriticalSection(&ddraw_cs);
1746     if(This->ImplType != This->ddraw->ImplType)
1747     {
1748         /* Call the recreation callback. Make sure to AddRef first */
1749         IDirectDrawSurface_AddRef(iface);
1750         IDirectDrawImpl_RecreateSurfacesCallback(iface,
1751                                                  &This->surface_desc,
1752                                                  NULL /* Not needed */);
1753     }
1754     hr = IWineD3DSurface_Restore(This->WineD3DSurface);
1755     LeaveCriticalSection(&ddraw_cs);
1756     return hr;
1757 }
1758
1759 /*****************************************************************************
1760  * IDirectDrawSurface7::SetOverlayPosition
1761  *
1762  * Changes the display coordinates of an overlay surface
1763  *
1764  * Params:
1765  *  X:
1766  *  Y:
1767  *
1768  * Returns:
1769  *   DDERR_NOTAOVERLAYSURFACE, because we don't support overlays right now
1770  *****************************************************************************/
1771 static HRESULT WINAPI
1772 IDirectDrawSurfaceImpl_SetOverlayPosition(IDirectDrawSurface7 *iface,
1773                                           LONG X,
1774                                           LONG Y)
1775 {
1776     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1777     HRESULT hr;
1778     TRACE("(%p)->(%d,%d): Relay\n", This, X, Y);
1779
1780     EnterCriticalSection(&ddraw_cs);
1781     hr = IWineD3DSurface_SetOverlayPosition(This->WineD3DSurface,
1782                                             X,
1783                                             Y);
1784     LeaveCriticalSection(&ddraw_cs);
1785     return hr;
1786 }
1787
1788 /*****************************************************************************
1789  * IDirectDrawSurface7::UpdateOverlay
1790  *
1791  * Modifies the attributes of an overlay surface.
1792  *
1793  * Params:
1794  *  SrcRect: The section of the source being used for the overlay
1795  *  DstSurface: Address of the surface that is overlaid
1796  *  DstRect: Place of the overlay
1797  *  Flags: some DDOVER_* flags
1798  *
1799  * Returns:
1800  *  DDERR_UNSUPPORTED, because we don't support overlays
1801  *
1802  *****************************************************************************/
1803 static HRESULT WINAPI
1804 IDirectDrawSurfaceImpl_UpdateOverlay(IDirectDrawSurface7 *iface,
1805                                      LPRECT SrcRect,
1806                                      IDirectDrawSurface7 *DstSurface,
1807                                      LPRECT DstRect,
1808                                      DWORD Flags,
1809                                      LPDDOVERLAYFX FX)
1810 {
1811     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1812     IDirectDrawSurfaceImpl *Dst = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, DstSurface);
1813     HRESULT hr;
1814     TRACE("(%p)->(%p,%p,%p,%x,%p): Relay\n", This, SrcRect, Dst, DstRect, Flags, FX);
1815
1816     EnterCriticalSection(&ddraw_cs);
1817     hr = IWineD3DSurface_UpdateOverlay(This->WineD3DSurface,
1818                                        SrcRect,
1819                                        Dst ? Dst->WineD3DSurface : NULL,
1820                                        DstRect,
1821                                        Flags,
1822                                        (WINEDDOVERLAYFX *) FX);
1823     LeaveCriticalSection(&ddraw_cs);
1824     return hr;
1825 }
1826
1827 /*****************************************************************************
1828  * IDirectDrawSurface7::UpdateOverlayDisplay
1829  *
1830  * The DX7 sdk says that it's not implemented
1831  *
1832  * Params:
1833  *  Flags: ?
1834  *
1835  * Returns: DDERR_UNSUPPORTED, because we don't support overlays
1836  *
1837  *****************************************************************************/
1838 static HRESULT WINAPI
1839 IDirectDrawSurfaceImpl_UpdateOverlayDisplay(IDirectDrawSurface7 *iface,
1840                                             DWORD Flags)
1841 {
1842     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1843     TRACE("(%p)->(%x)\n", This, Flags);
1844     return DDERR_UNSUPPORTED;
1845 }
1846
1847 /*****************************************************************************
1848  * IDirectDrawSurface7::UpdateOverlayZOrder
1849  *
1850  * Sets an overlay's Z order
1851  *
1852  * Params:
1853  *  Flags: DDOVERZ_* flags
1854  *  DDSRef: Defines the relative position in the overlay chain
1855  *
1856  * Returns:
1857  *  DDERR_NOTOVERLAYSURFACE, because we don't support overlays
1858  *
1859  *****************************************************************************/
1860 static HRESULT WINAPI
1861 IDirectDrawSurfaceImpl_UpdateOverlayZOrder(IDirectDrawSurface7 *iface,
1862                                            DWORD Flags,
1863                                            IDirectDrawSurface7 *DDSRef)
1864 {
1865     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1866     HRESULT hr;
1867     IDirectDrawSurfaceImpl *Ref = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, DDSRef);
1868
1869     TRACE("(%p)->(%x,%p): Relay\n", This, Flags, Ref);
1870     EnterCriticalSection(&ddraw_cs);
1871     hr =  IWineD3DSurface_UpdateOverlayZOrder(This->WineD3DSurface,
1872                                               Flags,
1873                                               Ref ? Ref->WineD3DSurface : NULL);
1874     LeaveCriticalSection(&ddraw_cs);
1875     return hr;
1876 }
1877
1878 /*****************************************************************************
1879  * IDirectDrawSurface7::GetDDInterface
1880  *
1881  * Returns the IDirectDraw7 interface pointer of the DirectDraw object this
1882  * surface belongs to
1883  *
1884  * Params:
1885  *  DD: Address to write the interface pointer to
1886  *
1887  * Returns:
1888  *  DD_OK on success
1889  *  DDERR_INVALIDPARAMS if DD is NULL
1890  *
1891  *****************************************************************************/
1892 static HRESULT WINAPI
1893 IDirectDrawSurfaceImpl_GetDDInterface(IDirectDrawSurface7 *iface,
1894                                       void **DD)
1895 {
1896     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1897
1898     TRACE("(%p)->(%p)\n",This,DD);
1899
1900     if(!DD)
1901         return DDERR_INVALIDPARAMS;
1902
1903     switch(This->version)
1904     {
1905         case 7:
1906             *((IDirectDraw7 **) DD) = ICOM_INTERFACE(This->ddraw, IDirectDraw7);
1907             IDirectDraw7_AddRef(*(IDirectDraw7 **) DD);
1908             break;
1909
1910         case 4:
1911             *((IDirectDraw4 **) DD) = ICOM_INTERFACE(This->ddraw, IDirectDraw4);
1912             IDirectDraw4_AddRef(*(IDirectDraw4 **) DD);
1913             break;
1914
1915         case 2:
1916             *((IDirectDraw2 **) DD) = ICOM_INTERFACE(This->ddraw, IDirectDraw2);
1917             IDirectDraw_AddRef( *(IDirectDraw2 **) DD);
1918             break;
1919
1920         case 1:
1921             *((IDirectDraw **) DD) = ICOM_INTERFACE(This->ddraw, IDirectDraw);
1922             IDirectDraw_AddRef( *(IDirectDraw **) DD);
1923             break;
1924
1925     }
1926
1927     return DD_OK;
1928 }
1929
1930 /* This seems also windows implementation specific - I don't think WineD3D needs this */
1931 static HRESULT WINAPI IDirectDrawSurfaceImpl_ChangeUniquenessValue(IDirectDrawSurface7 *iface)
1932 {
1933     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1934     volatile IDirectDrawSurfaceImpl* vThis = This;
1935
1936     TRACE("(%p)\n",This);
1937     EnterCriticalSection(&ddraw_cs);
1938     /* A uniqueness value of 0 is apparently special.
1939      * This needs to be checked.
1940      * TODO: Write tests for this code and check if the volatile, interlocked stuff is really needed
1941      */
1942     while (1) {
1943         DWORD old_uniqueness_value = vThis->uniqueness_value;
1944         DWORD new_uniqueness_value = old_uniqueness_value+1;
1945
1946         if (old_uniqueness_value == 0) break;
1947         if (new_uniqueness_value == 0) new_uniqueness_value = 1;
1948
1949         if (InterlockedCompareExchange((LONG*)&vThis->uniqueness_value,
1950                                       old_uniqueness_value,
1951                                       new_uniqueness_value)
1952             == old_uniqueness_value)
1953             break;
1954     }
1955
1956     LeaveCriticalSection(&ddraw_cs);
1957     return DD_OK;
1958 }
1959
1960 static HRESULT WINAPI IDirectDrawSurfaceImpl_GetUniquenessValue(IDirectDrawSurface7 *iface, LPDWORD pValue)
1961 {
1962     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1963
1964     TRACE("(%p)->(%p)\n",This,pValue);
1965     EnterCriticalSection(&ddraw_cs);
1966     *pValue = This->uniqueness_value;
1967     LeaveCriticalSection(&ddraw_cs);
1968     return DD_OK;
1969 }
1970
1971 /*****************************************************************************
1972  * IDirectDrawSurface7::SetLOD
1973  *
1974  * Sets the level of detail of a texture
1975  *
1976  * Params:
1977  *  MaxLOD: LOD to set
1978  *
1979  * Returns:
1980  *  DD_OK on success
1981  *  DDERR_INVALIDOBJECT if the surface is invalid for this method
1982  *
1983  *****************************************************************************/
1984 static HRESULT WINAPI
1985 IDirectDrawSurfaceImpl_SetLOD(IDirectDrawSurface7 *iface,
1986                               DWORD MaxLOD)
1987 {
1988     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1989     HRESULT hr;
1990     TRACE("(%p)->(%d)\n", This, MaxLOD);
1991
1992     EnterCriticalSection(&ddraw_cs);
1993     if (!(This->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_TEXTUREMANAGE))
1994     {
1995         LeaveCriticalSection(&ddraw_cs);
1996         return DDERR_INVALIDOBJECT;
1997     }
1998
1999     if(!This->wineD3DTexture)
2000     {
2001         ERR("(%p) The DirectDraw texture has no WineD3DTexture!\n", This);
2002         LeaveCriticalSection(&ddraw_cs);
2003         return DDERR_INVALIDOBJECT;
2004     }
2005
2006     hr = IWineD3DBaseTexture_SetLOD(This->wineD3DTexture,
2007                                     MaxLOD);
2008     LeaveCriticalSection(&ddraw_cs);
2009     return hr;
2010 }
2011
2012 /*****************************************************************************
2013  * IDirectDrawSurface7::GetLOD
2014  *
2015  * Returns the level of detail of a Direct3D texture
2016  *
2017  * Params:
2018  *  MaxLOD: Address to write the LOD to
2019  *
2020  * Returns:
2021  *  DD_OK on success
2022  *  DDERR_INVALIDPARAMS if MaxLOD is NULL
2023  *  DDERR_INVALIDOBJECT if the surface is invalid for this method
2024  *
2025  *****************************************************************************/
2026 static HRESULT WINAPI
2027 IDirectDrawSurfaceImpl_GetLOD(IDirectDrawSurface7 *iface,
2028                               DWORD *MaxLOD)
2029 {
2030     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
2031     TRACE("(%p)->(%p)\n", This, MaxLOD);
2032
2033     if(!MaxLOD)
2034         return DDERR_INVALIDPARAMS;
2035
2036     EnterCriticalSection(&ddraw_cs);
2037     if (!(This->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_TEXTUREMANAGE))
2038     {
2039         LeaveCriticalSection(&ddraw_cs);
2040         return DDERR_INVALIDOBJECT;
2041     }
2042
2043     *MaxLOD = IWineD3DBaseTexture_GetLOD(This->wineD3DTexture);
2044     LeaveCriticalSection(&ddraw_cs);
2045     return DD_OK;
2046 }
2047
2048 /*****************************************************************************
2049  * IDirectDrawSurface7::BltFast
2050  *
2051  * Performs a fast Blit.
2052  *
2053  * Params:
2054  *  dstx: The x coordinate to blit to on the destination
2055  *  dsty: The y coordinate to blit to on the destination
2056  *  Source: The source surface
2057  *  rsrc: The source rectangle
2058  *  trans: Type of transfer. Some DDBLTFAST_* flags
2059  *
2060  * Returns:
2061  *  DD_OK on success
2062  *  For more details, see IWineD3DSurface::BltFast
2063  *
2064  *****************************************************************************/
2065 static HRESULT WINAPI
2066 IDirectDrawSurfaceImpl_BltFast(IDirectDrawSurface7 *iface,
2067                                DWORD dstx,
2068                                DWORD dsty,
2069                                IDirectDrawSurface7 *Source,
2070                                RECT *rsrc,
2071                                DWORD trans)
2072 {
2073     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
2074     HRESULT hr;
2075     IDirectDrawSurfaceImpl *src = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, Source);
2076     TRACE("(%p)->(%d,%d,%p,%p,%d): Relay\n", This, dstx, dsty, Source, rsrc, trans);
2077
2078     /* Source must be != NULL, This is not checked by windows. Windows happily throws a 0xc0000005
2079      * in that case
2080      */
2081     if(rsrc)
2082     {
2083         if(rsrc->top > rsrc->bottom || rsrc->left > rsrc->right ||
2084            rsrc->right > src->surface_desc.dwWidth ||
2085            rsrc->bottom > src->surface_desc.dwHeight)
2086         {
2087             WARN("Source rectangle is invalid, returning DDERR_INVALIDRECT\n");
2088             return DDERR_INVALIDRECT;
2089         }
2090         if(dstx + rsrc->right - rsrc->left > This->surface_desc.dwWidth ||
2091            dsty + rsrc->bottom - rsrc->top > This->surface_desc.dwHeight)
2092         {
2093             WARN("Destination area out of bounds, returning DDERR_INVALIDRECT\n");
2094             return DDERR_INVALIDRECT;
2095         }
2096     }
2097     else
2098     {
2099         if(dstx + src->surface_desc.dwWidth > This->surface_desc.dwWidth ||
2100            dsty + src->surface_desc.dwHeight > This->surface_desc.dwHeight)
2101         {
2102             WARN("Destination area out of bounds, returning DDERR_INVALIDRECT\n");
2103             return DDERR_INVALIDRECT;
2104         }
2105     }
2106
2107     EnterCriticalSection(&ddraw_cs);
2108     hr = IWineD3DSurface_BltFast(This->WineD3DSurface,
2109                                  dstx, dsty,
2110                                  src ? src->WineD3DSurface : NULL,
2111                                  rsrc,
2112                                  trans);
2113     LeaveCriticalSection(&ddraw_cs);
2114     switch(hr)
2115     {
2116         case WINED3DERR_NOTAVAILABLE:           return DDERR_UNSUPPORTED;
2117         case WINED3DERR_WRONGTEXTUREFORMAT:     return DDERR_INVALIDPIXELFORMAT;
2118         default:                                return hr;
2119     }
2120 }
2121
2122 /*****************************************************************************
2123  * IDirectDrawSurface7::GetClipper
2124  *
2125  * Returns the IDirectDrawClipper interface of the clipper assigned to this
2126  * surface
2127  *
2128  * Params:
2129  *  Clipper: Address to store the interface pointer at
2130  *
2131  * Returns:
2132  *  DD_OK on success
2133  *  DDERR_INVALIDPARAMS if Clipper is NULL
2134  *  DDERR_NOCLIPPERATTACHED if there's no clipper attached
2135  *
2136  *****************************************************************************/
2137 static HRESULT WINAPI
2138 IDirectDrawSurfaceImpl_GetClipper(IDirectDrawSurface7 *iface,
2139                                   IDirectDrawClipper **Clipper)
2140 {
2141     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
2142     TRACE("(%p)->(%p)\n", This, Clipper);
2143
2144     if(!Clipper)
2145     {
2146         LeaveCriticalSection(&ddraw_cs);
2147         return DDERR_INVALIDPARAMS;
2148     }
2149
2150     EnterCriticalSection(&ddraw_cs);
2151     if(This->clipper == NULL)
2152     {
2153         LeaveCriticalSection(&ddraw_cs);
2154         return DDERR_NOCLIPPERATTACHED;
2155     }
2156
2157     *Clipper = ICOM_INTERFACE(This->clipper, IDirectDrawClipper);
2158     IDirectDrawClipper_AddRef(*Clipper);
2159     LeaveCriticalSection(&ddraw_cs);
2160     return DD_OK;
2161 }
2162
2163 /*****************************************************************************
2164  * IDirectDrawSurface7::SetClipper
2165  *
2166  * Sets a clipper for the surface
2167  *
2168  * Params:
2169  *  Clipper: IDirectDrawClipper interface of the clipper to set
2170  *
2171  * Returns:
2172  *  DD_OK on success
2173  *
2174  *****************************************************************************/
2175 static HRESULT WINAPI
2176 IDirectDrawSurfaceImpl_SetClipper(IDirectDrawSurface7 *iface,
2177                                   IDirectDrawClipper *Clipper)
2178 {
2179     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
2180     IDirectDrawClipperImpl *oldClipper = This->clipper;
2181     HRESULT hr;
2182     TRACE("(%p)->(%p)\n",This,Clipper);
2183
2184     EnterCriticalSection(&ddraw_cs);
2185     if (ICOM_OBJECT(IDirectDrawClipperImpl, IDirectDrawClipper, Clipper) == This->clipper)
2186     {
2187         LeaveCriticalSection(&ddraw_cs);
2188         return DD_OK;
2189     }
2190
2191     This->clipper = ICOM_OBJECT(IDirectDrawClipperImpl, IDirectDrawClipper, Clipper);
2192
2193     if (Clipper != NULL)
2194         IDirectDrawClipper_AddRef(Clipper);
2195     if(oldClipper)
2196         IDirectDrawClipper_Release(ICOM_INTERFACE(oldClipper, IDirectDrawClipper));
2197
2198     hr = IWineD3DSurface_SetClipper(This->WineD3DSurface, This->clipper ? This->clipper->wineD3DClipper : NULL);
2199     LeaveCriticalSection(&ddraw_cs);
2200     return hr;
2201 }
2202
2203 /*****************************************************************************
2204  * IDirectDrawSurface7::SetSurfaceDesc
2205  *
2206  * Sets the surface description. It can override the pixel format, the surface
2207  * memory, ...
2208  * It's not really tested.
2209  *
2210  * Params:
2211  * DDSD: Pointer to the new surface description to set
2212  * Flags: Some flags
2213  *
2214  * Returns:
2215  *  DD_OK on success
2216  *  DDERR_INVALIDPARAMS if DDSD is NULL
2217  *
2218  *****************************************************************************/
2219 static HRESULT WINAPI
2220 IDirectDrawSurfaceImpl_SetSurfaceDesc(IDirectDrawSurface7 *iface,
2221                                       DDSURFACEDESC2 *DDSD,
2222                                       DWORD Flags)
2223 {
2224     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
2225     WINED3DFORMAT newFormat = WINED3DFMT_UNKNOWN;
2226     HRESULT hr;
2227     TRACE("(%p)->(%p,%x)\n", This, DDSD, Flags);
2228
2229     if(!DDSD)
2230         return DDERR_INVALIDPARAMS;
2231
2232     EnterCriticalSection(&ddraw_cs);
2233     if (DDSD->dwFlags & DDSD_PIXELFORMAT)
2234     {
2235         newFormat = PixelFormat_DD2WineD3D(&DDSD->u4.ddpfPixelFormat);
2236
2237         if(newFormat == WINED3DFMT_UNKNOWN)
2238         {
2239             ERR("Requested to set an unknown pixelformat\n");
2240             LeaveCriticalSection(&ddraw_cs);
2241             return DDERR_INVALIDPARAMS;
2242         }
2243         if(newFormat != PixelFormat_DD2WineD3D(&This->surface_desc.u4.ddpfPixelFormat) )
2244         {
2245             hr = IWineD3DSurface_SetFormat(This->WineD3DSurface,
2246                                            newFormat);
2247             if(hr != DD_OK)
2248             {
2249                 LeaveCriticalSection(&ddraw_cs);
2250                 return hr;
2251             }
2252         }
2253     }
2254     if (DDSD->dwFlags & DDSD_CKDESTOVERLAY)
2255     {
2256         IWineD3DSurface_SetColorKey(This->WineD3DSurface,
2257                                     DDCKEY_DESTOVERLAY,
2258                                     (WINEDDCOLORKEY *) &DDSD->u3.ddckCKDestOverlay);
2259     }
2260     if (DDSD->dwFlags & DDSD_CKDESTBLT)
2261     {
2262         IWineD3DSurface_SetColorKey(This->WineD3DSurface,
2263                                     DDCKEY_DESTBLT,
2264                                     (WINEDDCOLORKEY *) &DDSD->ddckCKDestBlt);
2265     }
2266     if (DDSD->dwFlags & DDSD_CKSRCOVERLAY)
2267     {
2268         IWineD3DSurface_SetColorKey(This->WineD3DSurface,
2269                                     DDCKEY_SRCOVERLAY,
2270                                     (WINEDDCOLORKEY *) &DDSD->ddckCKSrcOverlay);
2271     }
2272     if (DDSD->dwFlags & DDSD_CKSRCBLT)
2273     {
2274         IWineD3DSurface_SetColorKey(This->WineD3DSurface,
2275                                     DDCKEY_SRCBLT,
2276                                     (WINEDDCOLORKEY *) &DDSD->ddckCKSrcBlt);
2277     }
2278     if (DDSD->dwFlags & DDSD_LPSURFACE && DDSD->lpSurface)
2279     {
2280         hr = IWineD3DSurface_SetMem(This->WineD3DSurface, DDSD->lpSurface);
2281         if(hr != WINED3D_OK)
2282         {
2283             /* No need for a trace here, wined3d does that for us */
2284             LeaveCriticalSection(&ddraw_cs);
2285             switch(hr)
2286             {
2287                 case WINED3DERR_INVALIDCALL:        return DDERR_INVALIDPARAMS;
2288                 default:                            break; /* Go on */
2289             }
2290         }
2291
2292     }
2293
2294     This->surface_desc = *DDSD;
2295
2296     LeaveCriticalSection(&ddraw_cs);
2297     return DD_OK;
2298 }
2299
2300 /*****************************************************************************
2301  * IDirectDrawSurface7::GetPalette
2302  *
2303  * Returns the IDirectDrawPalette interface of the palette currently assigned
2304  * to the surface
2305  *
2306  * Params:
2307  *  Pal: Address to write the interface pointer to
2308  *
2309  * Returns:
2310  *  DD_OK on success
2311  *  DDERR_INVALIDPARAMS if Pal is NULL
2312  *
2313  *****************************************************************************/
2314 static HRESULT WINAPI
2315 IDirectDrawSurfaceImpl_GetPalette(IDirectDrawSurface7 *iface,
2316                                   IDirectDrawPalette **Pal)
2317 {
2318     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
2319     IWineD3DPalette *wPal;
2320     HRESULT hr;
2321     TRACE("(%p)->(%p): Relay\n", This, Pal);
2322
2323     if(!Pal)
2324         return DDERR_INVALIDPARAMS;
2325
2326     EnterCriticalSection(&ddraw_cs);
2327     hr = IWineD3DSurface_GetPalette(This->WineD3DSurface, &wPal);
2328     if(hr != DD_OK)
2329     {
2330         LeaveCriticalSection(&ddraw_cs);
2331         return hr;
2332     }
2333
2334     if(wPal)
2335     {
2336         hr = IWineD3DPalette_GetParent(wPal, (IUnknown **) Pal);
2337     }
2338     else
2339     {
2340         *Pal = NULL;
2341         hr = DDERR_NOPALETTEATTACHED;
2342     }
2343
2344     LeaveCriticalSection(&ddraw_cs);
2345     return hr;
2346 }
2347
2348 /*****************************************************************************
2349  * SetColorKeyEnum
2350  *
2351  * EnumAttachedSurface callback for SetColorKey. Used to set color keys
2352  * recursively in the surface tree
2353  *
2354  *****************************************************************************/
2355 struct SCKContext
2356 {
2357     HRESULT ret;
2358     WINEDDCOLORKEY *CKey;
2359     DWORD Flags;
2360 };
2361
2362 static HRESULT WINAPI
2363 SetColorKeyEnum(IDirectDrawSurface7 *surface,
2364                 DDSURFACEDESC2 *desc,
2365                 void *context)
2366 {
2367     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, surface);
2368     struct SCKContext *ctx = context;
2369     HRESULT hr;
2370
2371     hr = IWineD3DSurface_SetColorKey(This->WineD3DSurface,
2372                                      ctx->Flags,
2373                                      ctx->CKey);
2374     if(hr != DD_OK)
2375     {
2376         WARN("IWineD3DSurface_SetColorKey failed, hr = %08x\n", hr);
2377         ctx->ret = hr;
2378     }
2379
2380     IDirectDrawSurface7_EnumAttachedSurfaces(surface,
2381                                              context,
2382                                              SetColorKeyEnum);
2383     IDirectDrawSurface7_Release(surface);
2384     return DDENUMRET_OK;
2385 }
2386
2387 /*****************************************************************************
2388  * IDirectDrawSurface7::SetColorKey
2389  *
2390  * Sets the color keying options for the surface. Observations showed that
2391  * in case of complex surfaces the color key has to be assigned to all
2392  * sublevels.
2393  *
2394  * Params:
2395  *  Flags: DDCKEY_*
2396  *  CKey: The new color key
2397  *
2398  * Returns:
2399  *  DD_OK on success
2400  *  See IWineD3DSurface::SetColorKey for details
2401  *
2402  *****************************************************************************/
2403 static HRESULT WINAPI
2404 IDirectDrawSurfaceImpl_SetColorKey(IDirectDrawSurface7 *iface,
2405                                    DWORD Flags,
2406                                    DDCOLORKEY *CKey)
2407 {
2408     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
2409     struct SCKContext ctx = { DD_OK, (WINEDDCOLORKEY *) CKey, Flags };
2410     TRACE("(%p)->(%x,%p)\n", This, Flags, CKey);
2411
2412     EnterCriticalSection(&ddraw_cs);
2413     if (CKey)
2414     {
2415         switch (Flags & ~DDCKEY_COLORSPACE)
2416         {
2417         case DDCKEY_DESTBLT:
2418             This->surface_desc.ddckCKDestBlt = *CKey;
2419             This->surface_desc.dwFlags |= DDSD_CKDESTBLT;
2420             break;
2421
2422         case DDCKEY_DESTOVERLAY:
2423             This->surface_desc.u3.ddckCKDestOverlay = *CKey;
2424             This->surface_desc.dwFlags |= DDSD_CKDESTOVERLAY;
2425             break;
2426
2427         case DDCKEY_SRCOVERLAY:
2428             This->surface_desc.ddckCKSrcOverlay = *CKey;
2429             This->surface_desc.dwFlags |= DDSD_CKSRCOVERLAY;
2430             break;
2431
2432         case DDCKEY_SRCBLT:
2433             This->surface_desc.ddckCKSrcBlt = *CKey;
2434             This->surface_desc.dwFlags |= DDSD_CKSRCBLT;
2435             break;
2436
2437         default:
2438             LeaveCriticalSection(&ddraw_cs);
2439             return DDERR_INVALIDPARAMS;
2440         }
2441     }
2442     else
2443     {
2444         switch (Flags & ~DDCKEY_COLORSPACE)
2445         {
2446         case DDCKEY_DESTBLT:
2447             This->surface_desc.dwFlags &= ~DDSD_CKDESTBLT;
2448             break;
2449
2450         case DDCKEY_DESTOVERLAY:
2451             This->surface_desc.dwFlags &= ~DDSD_CKDESTOVERLAY;
2452             break;
2453
2454         case DDCKEY_SRCOVERLAY:
2455             This->surface_desc.dwFlags &= ~DDSD_CKSRCOVERLAY;
2456             break;
2457
2458         case DDCKEY_SRCBLT:
2459             This->surface_desc.dwFlags &= ~DDSD_CKSRCBLT;
2460             break;
2461
2462         default:
2463             LeaveCriticalSection(&ddraw_cs);
2464             return DDERR_INVALIDPARAMS;
2465         }
2466     }
2467     ctx.ret = IWineD3DSurface_SetColorKey(This->WineD3DSurface,
2468                                           Flags,
2469                                           ctx.CKey);
2470     IDirectDrawSurface7_EnumAttachedSurfaces(iface,
2471                                              (void *) &ctx,
2472                                              SetColorKeyEnum);
2473     LeaveCriticalSection(&ddraw_cs);
2474     switch(ctx.ret)
2475     {
2476         case WINED3DERR_INVALIDCALL:        return DDERR_INVALIDPARAMS;
2477         default:                            return ctx.ret;
2478     }
2479 }
2480
2481 /*****************************************************************************
2482  * IDirectDrawSurface7::SetPalette
2483  *
2484  * Assigns a DirectDrawPalette object to the surface
2485  *
2486  * Params:
2487  *  Pal: Interface to the palette to set
2488  *
2489  * Returns:
2490  *  DD_OK on success
2491  *
2492  *****************************************************************************/
2493 static HRESULT WINAPI
2494 IDirectDrawSurfaceImpl_SetPalette(IDirectDrawSurface7 *iface,
2495                                   IDirectDrawPalette *Pal)
2496 {
2497     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
2498     IDirectDrawPalette *oldPal;
2499     IDirectDrawSurfaceImpl *surf;
2500     IDirectDrawPaletteImpl *PalImpl = ICOM_OBJECT(IDirectDrawPaletteImpl, IDirectDrawPalette, Pal);
2501     HRESULT hr;
2502     TRACE("(%p)->(%p)\n", This, Pal);
2503
2504     /* Find the old palette */
2505     EnterCriticalSection(&ddraw_cs);
2506     hr = IDirectDrawSurface_GetPalette(iface, &oldPal);
2507     if(hr != DD_OK && hr != DDERR_NOPALETTEATTACHED)
2508     {
2509         LeaveCriticalSection(&ddraw_cs);
2510         return hr;
2511     }
2512     if(oldPal) IDirectDrawPalette_Release(oldPal);  /* For the GetPalette */
2513
2514     /* Set the new Palette */
2515     IWineD3DSurface_SetPalette(This->WineD3DSurface,
2516                                PalImpl ? PalImpl->wineD3DPalette : NULL);
2517     /* AddRef the Palette */
2518     if(Pal) IDirectDrawPalette_AddRef(Pal);
2519
2520     /* Release the old palette */
2521     if(oldPal) IDirectDrawPalette_Release(oldPal);
2522
2523     /* If this is a front buffer, also update the back buffers
2524      * TODO: How do things work for palettized cube textures?
2525      */
2526     if(This->surface_desc.ddsCaps.dwCaps & DDSCAPS_FRONTBUFFER)
2527     {
2528         /* For primary surfaces the tree is just a list, so the simpler scheme fits too */
2529         DDSCAPS2 caps2 = { DDSCAPS_PRIMARYSURFACE, 0, 0, 0 };
2530
2531         surf = This;
2532         while(1)
2533         {
2534             IDirectDrawSurface7 *attach;
2535             HRESULT hr;
2536             hr = IDirectDrawSurface7_GetAttachedSurface(ICOM_INTERFACE(surf, IDirectDrawSurface7),
2537                                                         &caps2, &attach);
2538             if(hr != DD_OK)
2539             {
2540                 break;
2541             }
2542
2543             TRACE("Setting palette on %p\n", attach);
2544             IDirectDrawSurface7_SetPalette(attach,
2545                                            Pal);
2546             surf = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, attach);
2547             IDirectDrawSurface7_Release(attach);
2548         }
2549     }
2550
2551     LeaveCriticalSection(&ddraw_cs);
2552     return DD_OK;
2553 }
2554
2555 /*****************************************************************************
2556  * The VTable
2557  *****************************************************************************/
2558
2559 const IDirectDrawSurface7Vtbl IDirectDrawSurface7_Vtbl =
2560 {
2561     /*** IUnknown ***/
2562     IDirectDrawSurfaceImpl_QueryInterface,
2563     IDirectDrawSurfaceImpl_AddRef,
2564     IDirectDrawSurfaceImpl_Release,
2565     /*** IDirectDrawSurface ***/
2566     IDirectDrawSurface7Impl_AddAttachedSurface,
2567     IDirectDrawSurfaceImpl_AddOverlayDirtyRect,
2568     IDirectDrawSurfaceImpl_Blt,
2569     IDirectDrawSurfaceImpl_BltBatch,
2570     IDirectDrawSurfaceImpl_BltFast,
2571     IDirectDrawSurfaceImpl_DeleteAttachedSurface,
2572     IDirectDrawSurfaceImpl_EnumAttachedSurfaces,
2573     IDirectDrawSurfaceImpl_EnumOverlayZOrders,
2574     IDirectDrawSurfaceImpl_Flip,
2575     IDirectDrawSurfaceImpl_GetAttachedSurface,
2576     IDirectDrawSurfaceImpl_GetBltStatus,
2577     IDirectDrawSurfaceImpl_GetCaps,
2578     IDirectDrawSurfaceImpl_GetClipper,
2579     IDirectDrawSurfaceImpl_GetColorKey,
2580     IDirectDrawSurfaceImpl_GetDC,
2581     IDirectDrawSurfaceImpl_GetFlipStatus,
2582     IDirectDrawSurfaceImpl_GetOverlayPosition,
2583     IDirectDrawSurfaceImpl_GetPalette,
2584     IDirectDrawSurfaceImpl_GetPixelFormat,
2585     IDirectDrawSurfaceImpl_GetSurfaceDesc,
2586     IDirectDrawSurfaceImpl_Initialize,
2587     IDirectDrawSurfaceImpl_IsLost,
2588     IDirectDrawSurfaceImpl_Lock,
2589     IDirectDrawSurfaceImpl_ReleaseDC,
2590     IDirectDrawSurfaceImpl_Restore,
2591     IDirectDrawSurfaceImpl_SetClipper,
2592     IDirectDrawSurfaceImpl_SetColorKey,
2593     IDirectDrawSurfaceImpl_SetOverlayPosition,
2594     IDirectDrawSurfaceImpl_SetPalette,
2595     IDirectDrawSurfaceImpl_Unlock,
2596     IDirectDrawSurfaceImpl_UpdateOverlay,
2597     IDirectDrawSurfaceImpl_UpdateOverlayDisplay,
2598     IDirectDrawSurfaceImpl_UpdateOverlayZOrder,
2599     /*** IDirectDrawSurface2 ***/
2600     IDirectDrawSurfaceImpl_GetDDInterface,
2601     IDirectDrawSurfaceImpl_PageLock,
2602     IDirectDrawSurfaceImpl_PageUnlock,
2603     /*** IDirectDrawSurface3 ***/
2604     IDirectDrawSurfaceImpl_SetSurfaceDesc,
2605     /*** IDirectDrawSurface4 ***/
2606     IDirectDrawSurfaceImpl_SetPrivateData,
2607     IDirectDrawSurfaceImpl_GetPrivateData,
2608     IDirectDrawSurfaceImpl_FreePrivateData,
2609     IDirectDrawSurfaceImpl_GetUniquenessValue,
2610     IDirectDrawSurfaceImpl_ChangeUniquenessValue,
2611     /*** IDirectDrawSurface7 ***/
2612     IDirectDrawSurfaceImpl_SetPriority,
2613     IDirectDrawSurfaceImpl_GetPriority,
2614     IDirectDrawSurfaceImpl_SetLOD,
2615     IDirectDrawSurfaceImpl_GetLOD
2616 };