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