Prevent crash when no URL is specified.
[wine] / dlls / ddraw / dsurface / main.c
1 /*              DirectDrawSurface base implementation
2  *
3  * Copyright 1997-2000 Marcus Meissner
4  * Copyright 1998-2000 Lionel Ulmer (most of Direct3D stuff)
5  * Copyright 2000-2001 TransGaming Technologies Inc.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21 #include "config.h"
22
23 #include <assert.h>
24 #include <string.h>
25
26 #define COBJMACROS
27 #define NONAMELESSUNION
28 #define NONAMELESSSTRUCT
29
30 #include "winerror.h"
31 #include "mesa_private.h"
32 #include "wine/debug.h"
33 #include "ddraw_private.h"
34 #include "dsurface/main.h"
35 #include "ddraw/main.h"
36 #include "dsurface/thunks.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
39 WINE_DECLARE_DEBUG_CHANNEL(ddraw_flip);
40 WINE_DECLARE_DEBUG_CHANNEL(ddraw_fps);
41
42 /** Creation/Destruction functions */
43
44 HRESULT
45 Main_DirectDrawSurface_Construct(IDirectDrawSurfaceImpl *This,
46                                  IDirectDrawImpl *pDD,
47                                  const DDSURFACEDESC2 *pDDSD)
48 {
49     TRACE("(%p)->(%p,%p)\n", This, pDD, pDDSD);
50
51     if (pDDSD != &This->surface_desc) {
52         This->surface_desc.dwSize = sizeof(This->surface_desc);
53         DD_STRUCT_COPY_BYSIZE(&(This->surface_desc),pDDSD);
54     }
55     This->uniqueness_value = 1; /* unchecked */
56     This->ref = 1;
57
58     This->local.lpSurfMore = &This->more;
59     This->local.lpGbl = &This->global;
60     This->local.dwProcessId = GetCurrentProcessId();
61     This->local.dwFlags = 0; /* FIXME */
62     This->local.ddsCaps.dwCaps = This->surface_desc.ddsCaps.dwCaps;
63     /* FIXME: more local stuff */
64     This->more.lpDD_lcl = &pDD->local;
65     This->more.ddsCapsEx.dwCaps2 = This->surface_desc.ddsCaps.dwCaps2;
66     This->more.ddsCapsEx.dwCaps3 = This->surface_desc.ddsCaps.dwCaps3;
67     This->more.ddsCapsEx.dwCaps4 = This->surface_desc.ddsCaps.dwCaps4;
68     /* FIXME: more more stuff */
69     This->gmore = &This->global_more;
70     This->global.u3.lpDD = pDD->local.lpGbl;
71     /* FIXME: more global stuff */
72
73     This->final_release = Main_DirectDrawSurface_final_release;
74     This->late_allocate = Main_DirectDrawSurface_late_allocate;
75     This->attach = Main_DirectDrawSurface_attach;
76     This->detach = Main_DirectDrawSurface_detach;
77     This->lock_update = Main_DirectDrawSurface_lock_update;
78     This->unlock_update = Main_DirectDrawSurface_unlock_update;
79     This->lose_surface = Main_DirectDrawSurface_lose_surface;
80     This->set_palette    = Main_DirectDrawSurface_set_palette;
81     This->update_palette = Main_DirectDrawSurface_update_palette;
82     This->get_display_window = Main_DirectDrawSurface_get_display_window;
83     This->get_gamma_ramp = Main_DirectDrawSurface_get_gamma_ramp;
84     This->set_gamma_ramp = Main_DirectDrawSurface_set_gamma_ramp;
85
86     ICOM_INIT_INTERFACE(This, IDirectDrawSurface3,
87                         DDRAW_IDDS3_Thunk_VTable);
88     ICOM_INIT_INTERFACE(This, IDirectDrawGammaControl,
89                         DDRAW_IDDGC_VTable);
90
91     /* There is no generic implementation of IDDS7 or texture */
92
93     Main_DirectDraw_AddSurface(pDD, This);
94     return DD_OK;
95 }
96
97 void Main_DirectDrawSurface_final_release(IDirectDrawSurfaceImpl* This)
98 {
99     Main_DirectDraw_RemoveSurface(This->ddraw_owner, This);
100 }
101
102 HRESULT Main_DirectDrawSurface_late_allocate(IDirectDrawSurfaceImpl* This)
103 {
104     return DD_OK;
105 }
106
107 static void Main_DirectDrawSurface_Destroy(IDirectDrawSurfaceImpl* This)
108 {
109     if (This->palette) {
110         IDirectDrawPalette_Release(ICOM_INTERFACE(This->palette, IDirectDrawPalette));
111         This->palette = NULL;
112     }
113     This->final_release(This);
114     if (This->private != This+1) HeapFree(GetProcessHeap(), 0, This->private);
115     if (This->tex_private) HeapFree(GetProcessHeap(), 0, This->tex_private);
116     HeapFree(GetProcessHeap(), 0, This);
117 }
118
119 void Main_DirectDrawSurface_ForceDestroy(IDirectDrawSurfaceImpl* This)
120 {
121     WARN("destroying surface %p with refcnt %lu\n", This, This->ref);
122     Main_DirectDrawSurface_Destroy(This);
123 }
124
125 ULONG WINAPI Main_DirectDrawSurface_Release(LPDIRECTDRAWSURFACE7 iface)
126 {
127     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
128     ULONG ref = InterlockedDecrement(&This->ref);
129
130     TRACE("(%p)->(): decreasing from %ld\n", This, ref + 1);
131     
132     if (ref == 0)
133     {
134         if (This->aux_release)
135             This->aux_release(This->aux_ctx, This->aux_data);
136         Main_DirectDrawSurface_Destroy(This);
137
138         TRACE("released surface %p\n", This);
139         
140         return 0;
141     }
142
143     return ref;
144 }
145
146 ULONG WINAPI Main_DirectDrawSurface_AddRef(LPDIRECTDRAWSURFACE7 iface)
147 {
148     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
149     ULONG ref = InterlockedIncrement(&This->ref);
150
151     TRACE("(%p)->(): increasing from %ld\n", This, ref - 1);
152     
153     return ref;
154 }
155
156 HRESULT WINAPI
157 Main_DirectDrawSurface_QueryInterface(LPDIRECTDRAWSURFACE7 iface, REFIID riid,
158                                       LPVOID* ppObj)
159 {
160     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
161     TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppObj);
162
163     *ppObj = NULL;
164
165     if (IsEqualGUID(&IID_IUnknown, riid)
166         || IsEqualGUID(&IID_IDirectDrawSurface7, riid)
167         || IsEqualGUID(&IID_IDirectDrawSurface4, riid))
168     {
169         InterlockedIncrement(&This->ref);
170         *ppObj = ICOM_INTERFACE(This, IDirectDrawSurface7);
171         return S_OK;
172     }
173     else if (IsEqualGUID(&IID_IDirectDrawSurface, riid)
174              || IsEqualGUID(&IID_IDirectDrawSurface2, riid)
175              || IsEqualGUID(&IID_IDirectDrawSurface3, riid))
176     {
177         InterlockedIncrement(&This->ref);
178         *ppObj = ICOM_INTERFACE(This, IDirectDrawSurface3);
179         return S_OK;
180     }
181     else if (IsEqualGUID(&IID_IDirectDrawGammaControl, riid))
182     {
183         InterlockedIncrement(&This->ref);
184         *ppObj = ICOM_INTERFACE(This, IDirectDrawGammaControl);
185         return S_OK;
186     }
187 #ifdef HAVE_OPENGL
188     /* interfaces following here require OpenGL */
189     if( !opengl_initialized )
190         return E_NOINTERFACE;
191
192     if ( IsEqualGUID( &IID_D3DDEVICE_OpenGL, riid ) ||
193           IsEqualGUID( &IID_IDirect3DHALDevice, riid) )
194     {
195         IDirect3DDeviceImpl *d3ddevimpl;
196         HRESULT ret_value;
197
198         ret_value = d3ddevice_create(&d3ddevimpl, This->ddraw_owner, This, 1);
199         if (FAILED(ret_value)) return ret_value;
200
201         *ppObj = ICOM_INTERFACE(d3ddevimpl, IDirect3DDevice);
202         TRACE(" returning Direct3DDevice interface at %p.\n", *ppObj);
203         
204         InterlockedIncrement(&This->ref); /* No idea if this is correct.. Need to check using real Windows */
205         return ret_value;
206     }
207     else if (IsEqualGUID( &IID_IDirect3DTexture, riid ) ||
208              IsEqualGUID( &IID_IDirect3DTexture2, riid ))
209     {
210         HRESULT ret_value = S_OK;
211
212         /* Note: this is not exactly how Windows does it... But this seems not to hurt the only
213                  application I know creating a texture without this flag set and it will prevent
214                  bugs in other parts of Wine.
215         */
216         This->surface_desc.ddsCaps.dwCaps |= DDSCAPS_TEXTURE;
217
218         /* In case the texture surface was created before the D3D creation */
219         if (This->tex_private == NULL) {
220             if (This->ddraw_owner->d3d_private == NULL) {
221                 ERR("Texture created with no D3D object yet.. Not supported !\n");
222                 return E_NOINTERFACE;
223             }
224
225             ret_value = This->ddraw_owner->d3d_create_texture(This->ddraw_owner, This, FALSE, This->mip_main);
226             if (FAILED(ret_value)) return ret_value;
227         }
228         if (IsEqualGUID( &IID_IDirect3DTexture, riid )) {
229             *ppObj = ICOM_INTERFACE(This, IDirect3DTexture);
230             TRACE(" returning Direct3DTexture interface at %p.\n", *ppObj);
231         } else {
232             *ppObj = ICOM_INTERFACE(This, IDirect3DTexture2);
233             TRACE(" returning Direct3DTexture2 interface at %p.\n", *ppObj);
234         }
235         InterlockedIncrement(&This->ref);
236         return ret_value;
237     }
238 #endif
239
240     return E_NOINTERFACE;
241 }
242
243 /*** Callbacks */
244
245 BOOL
246 Main_DirectDrawSurface_attach(IDirectDrawSurfaceImpl *This,
247                               IDirectDrawSurfaceImpl *to)
248 {
249     return TRUE;
250 }
251
252 BOOL Main_DirectDrawSurface_detach(IDirectDrawSurfaceImpl *This)
253 {
254     return TRUE;
255 }
256
257 void
258 Main_DirectDrawSurface_lock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect,
259         DWORD dwFlags)
260 {
261 }
262
263 void
264 Main_DirectDrawSurface_unlock_update(IDirectDrawSurfaceImpl* This,
265                                      LPCRECT pRect)
266 {
267 }
268
269 void
270 Main_DirectDrawSurface_lose_surface(IDirectDrawSurfaceImpl* This)
271 {
272 }
273
274 void
275 Main_DirectDrawSurface_set_palette(IDirectDrawSurfaceImpl* This,
276                                    IDirectDrawPaletteImpl* pal)
277 {
278 }
279
280 void
281 Main_DirectDrawSurface_update_palette(IDirectDrawSurfaceImpl* This,
282                                       IDirectDrawPaletteImpl* pal,
283                                       DWORD dwStart, DWORD dwCount,
284                                       LPPALETTEENTRY palent)
285 {
286 }
287
288 HWND
289 Main_DirectDrawSurface_get_display_window(IDirectDrawSurfaceImpl* This)
290 {
291     return 0;
292 }
293
294 HRESULT
295 Main_DirectDrawSurface_get_gamma_ramp(IDirectDrawSurfaceImpl* This,
296                                       DWORD dwFlags,
297                                       LPDDGAMMARAMP lpGammaRamp)
298 {
299     HDC hDC;
300     HRESULT hr;
301     hr = This->get_dc(This, &hDC);
302     if (FAILED(hr)) return hr;
303     hr = GetDeviceGammaRamp(hDC, lpGammaRamp) ? DD_OK : DDERR_UNSUPPORTED;
304     This->release_dc(This, hDC);
305     return hr;
306 }
307
308 HRESULT
309 Main_DirectDrawSurface_set_gamma_ramp(IDirectDrawSurfaceImpl* This,
310                                       DWORD dwFlags,
311                                       LPDDGAMMARAMP lpGammaRamp)
312 {
313     HDC hDC;
314     HRESULT hr;
315     hr = This->get_dc(This, &hDC);
316     if (FAILED(hr)) return hr;
317     hr = SetDeviceGammaRamp(hDC, lpGammaRamp) ? DD_OK : DDERR_UNSUPPORTED;
318     This->release_dc(This, hDC);
319     return hr;
320 }
321
322
323 /*** Interface functions */
324
325 HRESULT WINAPI
326 Main_DirectDrawSurface_AddAttachedSurface(LPDIRECTDRAWSURFACE7 iface,
327                                           LPDIRECTDRAWSURFACE7 pAttach)
328 {
329     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
330     IDirectDrawSurfaceImpl* surf = ICOM_OBJECT(IDirectDrawSurfaceImpl,
331                                                IDirectDrawSurface7, pAttach);
332
333     TRACE("(%p)->(%p)\n",This,pAttach);
334
335     /* Does windows check this? */
336     if (surf == This)
337         return DDERR_CANNOTATTACHSURFACE; /* unchecked */
338
339     /* Does windows check this? */
340     if (surf->ddraw_owner != This->ddraw_owner)
341         return DDERR_CANNOTATTACHSURFACE; /* unchecked */
342
343     if (surf->surface_owner != NULL)
344         return DDERR_SURFACEALREADYATTACHED; /* unchecked */
345
346     /* TODO MSDN: "You can attach only z-buffer surfaces with this method."
347      * But apparently backbuffers and mipmaps can be attached too. */
348
349     /* Set MIPMAPSUBLEVEL if this seems to be one */
350     if (This->surface_desc.ddsCaps.dwCaps &
351         surf->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) {
352         surf->surface_desc.ddsCaps.dwCaps2 |= DDSCAPS2_MIPMAPSUBLEVEL;
353         /* FIXME: we should probably also add to dwMipMapCount of this
354          * and all parent surfaces (update create_texture if you do) */
355     }
356
357     /* Callback to allow the surface to do something special now that it is
358      * attached. (e.g. maybe the Z-buffer tells the renderer to use it.) */
359     if (!surf->attach(surf, This))
360         return DDERR_CANNOTATTACHSURFACE;
361
362     /* check: Where should it go in the chain? This puts it on the head. */
363     if (This->attached)
364         This->attached->prev_attached = surf;
365     surf->next_attached = This->attached;
366     surf->prev_attached = NULL;
367     This->attached = surf;
368     surf->surface_owner = This;
369
370     IDirectDrawSurface7_AddRef(pAttach);
371
372     return DD_OK;
373 }
374
375 /* MSDN: "not currently implemented." */
376 HRESULT WINAPI
377 Main_DirectDrawSurface_AddOverlayDirtyRect(LPDIRECTDRAWSURFACE7 iface,
378                                            LPRECT pRect)
379 {
380     TRACE("(%p)->(%p)\n",iface,pRect);
381     return DDERR_UNSUPPORTED; /* unchecked */
382 }
383
384 /* MSDN: "not currently implemented." */
385 HRESULT WINAPI
386 Main_DirectDrawSurface_BltBatch(LPDIRECTDRAWSURFACE7 iface,
387                                 LPDDBLTBATCH pBatch, DWORD dwCount,
388                                 DWORD dwFlags)
389 {
390     TRACE("(%p)->(%p,%ld,%08lx)\n",iface,pBatch,dwCount,dwFlags);
391     return DDERR_UNSUPPORTED; /* unchecked */
392 }
393
394 HRESULT WINAPI
395 Main_DirectDrawSurface_ChangeUniquenessValue(LPDIRECTDRAWSURFACE7 iface)
396 {
397     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
398     volatile IDirectDrawSurfaceImpl* vThis = This;
399
400     TRACE("(%p)\n",This);
401     /* A uniquness value of 0 is apparently special.
402      * This needs to be checked. */
403     while (1)
404     {
405         DWORD old_uniqueness_value = vThis->uniqueness_value;
406         DWORD new_uniqueness_value = old_uniqueness_value+1;
407
408         if (old_uniqueness_value == 0) break;
409         if (new_uniqueness_value == 0) new_uniqueness_value = 1;
410
411         if (InterlockedCompareExchange((LONG*)&vThis->uniqueness_value,
412                                        old_uniqueness_value,
413                                        new_uniqueness_value)
414             == old_uniqueness_value)
415             break;
416     }
417
418     return DD_OK;
419 }
420
421 HRESULT WINAPI
422 Main_DirectDrawSurface_DeleteAttachedSurface(LPDIRECTDRAWSURFACE7 iface,
423                                              DWORD dwFlags,
424                                              LPDIRECTDRAWSURFACE7 pAttach)
425 {
426     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
427     IDirectDrawSurfaceImpl* surf = ICOM_OBJECT(IDirectDrawSurfaceImpl,
428                                                IDirectDrawSurface7, pAttach);
429
430     TRACE("(%p)->(%08lx,%p)\n",This,dwFlags,pAttach);
431
432     if (!surf || (surf->surface_owner != This))
433         return DDERR_SURFACENOTATTACHED; /* unchecked */
434
435     surf->detach(surf);
436
437     /* Remove MIPMAPSUBLEVEL if this seemed to be one */
438     if (This->surface_desc.ddsCaps.dwCaps &
439         surf->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) {
440         surf->surface_desc.ddsCaps.dwCaps2 &= ~DDSCAPS2_MIPMAPSUBLEVEL;
441         /* FIXME: we should probably also subtract from dwMipMapCount of this
442          * and all parent surfaces */
443     }
444
445     if (surf->next_attached)
446         surf->next_attached->prev_attached = surf->prev_attached;
447     if (surf->prev_attached)
448         surf->prev_attached->next_attached = surf->next_attached;
449     if (This->attached == surf)
450         This->attached = surf->next_attached;
451
452     IDirectDrawSurface7_Release(pAttach);
453
454     return DD_OK;
455 }
456
457 HRESULT WINAPI
458 Main_DirectDrawSurface_EnumAttachedSurfaces(LPDIRECTDRAWSURFACE7 iface,
459                                             LPVOID context,
460                                             LPDDENUMSURFACESCALLBACK7 cb)
461 {
462     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
463     IDirectDrawSurfaceImpl* surf;
464
465     TRACE("(%p)->(%p,%p)\n",This,context,cb);
466
467     for (surf = This->attached; surf != NULL; surf = surf->next_attached)
468     {
469         /* check: != DDENUMRET_OK or == DDENUMRET_CANCEL? */
470         if (cb(ICOM_INTERFACE(surf, IDirectDrawSurface7), &surf->surface_desc,
471                context) == DDENUMRET_CANCEL)
472             break;
473     }
474
475     return DD_OK;
476 }
477
478 HRESULT WINAPI
479 Main_DirectDrawSurface_EnumOverlayZOrders(LPDIRECTDRAWSURFACE7 iface,
480                                           DWORD dwFlags, LPVOID context,
481                                           LPDDENUMSURFACESCALLBACK7 cb)
482 {
483     TRACE("(%p)->(%08lx,%p,%p)\n",iface,dwFlags,context,cb);
484     return DD_OK;
485 }
486
487 BOOL Main_DirectDrawSurface_flip_data(IDirectDrawSurfaceImpl* front,
488                                       IDirectDrawSurfaceImpl* back,
489                                       DWORD dwFlags)
490 {
491     /* uniqueness_value? */
492     /* This is necessary. But is it safe? */
493     {
494         HDC tmp = front->hDC;
495         front->hDC = back->hDC;
496         back->hDC = tmp;
497     }
498
499     {
500         BOOL tmp = front->dc_in_use;
501         front->dc_in_use = back->dc_in_use;
502         back->dc_in_use = tmp;
503     }
504
505     {
506         FLATPTR tmp = front->global.fpVidMem;
507         front->global.fpVidMem = back->global.fpVidMem;
508         back->global.fpVidMem = tmp;
509     }
510
511     {
512         ULONG_PTR tmp = front->global_more.hKernelSurface;
513         front->global_more.hKernelSurface = back->global_more.hKernelSurface;
514         back->global_more.hKernelSurface = tmp;
515     }
516
517     return TRUE;
518 }
519
520 /* This is unnecessarely complicated :-) */
521 #define MEASUREMENT_WINDOW 5
522 #define NUMBER_OF_WINDOWS 10
523
524 static LONGLONG perf_freq;
525 static LONGLONG perf_storage[NUMBER_OF_WINDOWS];
526 static LONGLONG prev_time = 0;
527 static unsigned int current_window;
528 static unsigned int measurements_in_window;
529 static unsigned int valid_windows;
530
531 HRESULT WINAPI
532 Main_DirectDrawSurface_Flip(LPDIRECTDRAWSURFACE7 iface,
533                             LPDIRECTDRAWSURFACE7 override, DWORD dwFlags)
534 {
535     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
536     IDirectDrawSurfaceImpl* target;
537     HRESULT hr;
538
539     TRACE("(%p)->(%p,%08lx)\n",This,override,dwFlags);
540
541     if (TRACE_ON(ddraw_fps)) {
542         LONGLONG current_time;
543         LONGLONG frame_duration;
544         QueryPerformanceCounter((LARGE_INTEGER *) &current_time);
545
546         if (prev_time != 0) {
547             LONGLONG total_time = 0;
548             int tot_meas;
549             
550             frame_duration = current_time - prev_time;
551             prev_time = current_time;
552             
553             perf_storage[current_window] += frame_duration;
554             measurements_in_window++;
555             
556             if (measurements_in_window >= MEASUREMENT_WINDOW) {
557                 current_window++;
558                 valid_windows++;
559
560                 if (valid_windows < NUMBER_OF_WINDOWS) {
561                     unsigned int i;
562                     tot_meas = valid_windows * MEASUREMENT_WINDOW;
563                     for (i = 0; i < valid_windows; i++) {
564                         total_time += perf_storage[i];
565                     }
566                 } else {
567                     int i;
568                     tot_meas = NUMBER_OF_WINDOWS * MEASUREMENT_WINDOW;
569                     for (i = 0; i < NUMBER_OF_WINDOWS; i++) {
570                         total_time += perf_storage[i];
571                     }
572                 }
573
574                 TRACE_(ddraw_fps)(" %9.5f\n", (double) (perf_freq * tot_meas) / (double) total_time);
575                 
576                 if (current_window >= NUMBER_OF_WINDOWS) {
577                     current_window = 0;
578                 }
579                 perf_storage[current_window] = 0;
580                 measurements_in_window = 0;
581             }
582         } else {
583             prev_time = current_time;
584             memset(perf_storage, 0, sizeof(perf_storage));
585             current_window = 0;
586             valid_windows = 0;
587             measurements_in_window = 0;
588             QueryPerformanceFrequency((LARGE_INTEGER *) &perf_freq);
589         }
590     }
591     
592     /* MSDN: "This method can be called only for a surface that has the
593      * DDSCAPS_FLIP and DDSCAPS_FRONTBUFFER capabilities." */
594     if ((This->surface_desc.ddsCaps.dwCaps&(DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER))
595         != (DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER))
596         return DDERR_NOTFLIPPABLE;
597
598     if (This->aux_flip)
599         if (This->aux_flip(This->aux_ctx, This->aux_data))
600             return DD_OK;
601
602     /* 1. find the flip target */
603     /* XXX I don't think this algorithm works for more than 1 backbuffer. */
604     if (override == NULL)
605     {
606         static DDSCAPS2 back_caps = { DDSCAPS_BACKBUFFER };
607         LPDIRECTDRAWSURFACE7 tgt;
608
609         hr = IDirectDrawSurface7_GetAttachedSurface(iface, &back_caps, &tgt);
610         if (FAILED(hr)) return DDERR_NOTFLIPPABLE; /* unchecked */
611
612         target = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7,
613                              tgt);
614         IDirectDrawSurface7_Release(tgt);
615     }
616     else
617     {
618         BOOL on_chain = FALSE;
619         IDirectDrawSurfaceImpl* surf;
620
621         /* MSDN: "The method fails if the specified [override] surface is not
622          * a member of the flipping chain." */
623
624         /* Verify that override is on this flip chain. We assume that
625          * surf is the head of the flipping chain, because it's the front
626          * buffer. */
627         target = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7,
628                              override);
629
630         /* Either target is (indirectly) attached to This or This is
631          * (indirectly) attached to target. */
632         for (surf = target; surf != NULL; surf = surf->surface_owner)
633         {
634             if (surf == This)
635             {
636                 on_chain = TRUE;
637                 break;
638             }
639         }
640
641         if (!on_chain)
642             return DDERR_INVALIDPARAMS; /* unchecked */
643     }
644
645     TRACE("flip to backbuffer: %p\n",target);
646     if (TRACE_ON(ddraw_flip)) {
647         static unsigned int flip_count = 0;
648         IDirectDrawPaletteImpl *palette;
649         char buf[32];
650         FILE *f;
651
652         /* Hack for paletted games... */
653         palette = target->palette;
654         target->palette = This->palette;
655         
656         sprintf(buf, "flip_%08d.ppm", flip_count++);
657         TRACE_(ddraw_flip)("Dumping file %s to disk.\n", buf);
658         f = fopen(buf, "wb");
659         DDRAW_dump_surface_to_disk(target, f, 8);
660         target->palette = palette;
661     }
662
663     if (This->flip_data(This, target, dwFlags))
664         This->flip_update(This, dwFlags);
665     
666     return DD_OK;
667 }
668
669 static PrivateData* find_private_data(IDirectDrawSurfaceImpl *This,
670                                       REFGUID tag)
671 {
672     PrivateData* data;
673     for (data = This->private_data; data != NULL; data = data->next)
674     {
675         if (IsEqualGUID(&data->tag, tag)) break;
676     }
677
678     return data;
679 }
680
681 HRESULT WINAPI
682 Main_DirectDrawSurface_FreePrivateData(LPDIRECTDRAWSURFACE7 iface, REFGUID tag)
683 {
684     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
685     PrivateData *data;
686
687     data = find_private_data(This, tag);
688     if (data == NULL) return DDERR_NOTFOUND;
689
690     if (data->prev)
691         data->prev->next = data->next;
692     if (data->next)
693         data->next->prev = data->prev;
694
695     if (data->flags & DDSPD_IUNKNOWNPTR)
696     {
697         if (data->ptr.object != NULL)
698             IUnknown_Release(data->ptr.object);
699     }
700     else
701         HeapFree(GetProcessHeap(), 0, data->ptr.data);
702
703     HeapFree(GetProcessHeap(), 0, data);
704
705     return DD_OK;
706 }
707
708 HRESULT WINAPI
709 Main_DirectDrawSurface_GetAttachedSurface(LPDIRECTDRAWSURFACE7 iface,
710                                           LPDDSCAPS2 pCaps,
711                                           LPDIRECTDRAWSURFACE7* ppSurface)
712 {
713     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
714     IDirectDrawSurfaceImpl* surf;
715     IDirectDrawSurfaceImpl* found = NULL;
716     DDSCAPS2 our_caps;
717     
718     if (TRACE_ON(ddraw)) {
719         TRACE("(%p)->Looking for caps: %lx,%lx,%lx,%lx output: %p\n",This,pCaps->dwCaps, pCaps->dwCaps2,
720               pCaps->dwCaps3, pCaps->dwCaps4, ppSurface);
721         TRACE("   Caps are : "); DDRAW_dump_DDSCAPS2(pCaps); TRACE("\n");
722     }
723
724     our_caps = *pCaps;
725     if ((This->ddraw_owner->local.dwLocalFlags & DDRAWILCL_DIRECTDRAW7) == 0) {
726         /* As this is not a DirectDraw7 application, remove the garbage that some games
727            put in the new fields of the DDSCAPS2 structure. */
728         our_caps.dwCaps2 = 0;
729         our_caps.dwCaps3 = 0;
730         our_caps.dwCaps4 = 0;
731         if (TRACE_ON(ddraw)) {
732             TRACE("   Real caps are : "); DDRAW_dump_DDSCAPS2(&our_caps); TRACE("\n");
733         }
734     }
735     
736     for (surf = This->attached; surf != NULL; surf = surf->next_attached)
737     {
738         if (TRACE_ON(ddraw)) {
739             TRACE("Surface: (%p) caps: %lx,%lx,%lx,%lx \n",surf ,
740                   surf->surface_desc.ddsCaps.dwCaps,
741                   surf->surface_desc.ddsCaps.dwCaps2,
742                   surf->surface_desc.ddsCaps.dwCaps3,
743                   surf->surface_desc.ddsCaps.dwCaps4);
744             TRACE("   Surface caps are : "); DDRAW_dump_DDSCAPS2(&(surf->surface_desc.ddsCaps)); TRACE("\n");
745         }
746         if (((surf->surface_desc.ddsCaps.dwCaps & our_caps.dwCaps) == our_caps.dwCaps) &&
747             ((surf->surface_desc.ddsCaps.dwCaps2 & our_caps.dwCaps2) == our_caps.dwCaps2))
748         {
749             /* MSDN: "This method fails if more than one surface is attached
750              * that matches the capabilities requested." */
751             if (found != NULL)
752             {
753                 FIXME("More than one attached surface matches requested caps.  What should we do here?\n");
754                 /* Previous code returned 'DDERR_NOTFOUND'.  That appears not
755                    to be correct, given what 3DMark expects from MipMapped surfaces.
756                    We shall just continue instead. */
757             }
758
759             found = surf;
760         }
761     }
762
763     if (found == NULL) {
764         TRACE("Did not find any valid surface\n");
765         return DDERR_NOTFOUND;
766     }
767
768     *ppSurface = ICOM_INTERFACE(found, IDirectDrawSurface7);
769
770     if (TRACE_ON(ddraw)) {
771         TRACE("Returning surface %p with description : \n", *ppSurface);
772         DDRAW_dump_surface_desc(&(found->surface_desc));
773     }
774     
775     /* XXX d3dframe.cpp sometimes AddRefs things that it gets from us. */
776     IDirectDrawSurface7_AddRef(ICOM_INTERFACE(found, IDirectDrawSurface7));
777     return DD_OK;
778 }
779
780 HRESULT WINAPI
781 Main_DirectDrawSurface_GetBltStatus(LPDIRECTDRAWSURFACE7 iface, DWORD dwFlags)
782 {
783     TRACE("(%p)->(%08lx)\n",iface,dwFlags);
784
785     switch (dwFlags)
786     {
787     case DDGBS_CANBLT:
788     case DDGBS_ISBLTDONE:
789         return DD_OK;
790
791     default:
792         return DDERR_INVALIDPARAMS;
793     }
794 }
795
796 HRESULT WINAPI
797 Main_DirectDrawSurface_GetCaps(LPDIRECTDRAWSURFACE7 iface, LPDDSCAPS2 pCaps)
798 {
799     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
800
801     TRACE("(%p)->(%p)\n",This,pCaps);
802     *pCaps = This->surface_desc.ddsCaps;
803     return DD_OK;
804 }
805
806 HRESULT WINAPI
807 Main_DirectDrawSurface_GetClipper(LPDIRECTDRAWSURFACE7 iface,
808                                   LPDIRECTDRAWCLIPPER* ppClipper)
809 {
810     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
811
812     TRACE("(%p)->(%p)\n",This,ppClipper);
813     if (This->clipper == NULL)
814         return DDERR_NOCLIPPERATTACHED;
815
816     *ppClipper = ICOM_INTERFACE(This->clipper, IDirectDrawClipper);
817     IDirectDrawClipper_AddRef(ICOM_INTERFACE(This->clipper,
818                                              IDirectDrawClipper));
819     return DD_OK;
820 }
821
822 HRESULT WINAPI
823 Main_DirectDrawSurface_GetColorKey(LPDIRECTDRAWSURFACE7 iface, DWORD dwFlags,
824                                    LPDDCOLORKEY pCKey)
825 {
826     /* There is a DDERR_NOCOLORKEY error, but how do we know if a color key
827      * isn't there? That's like saying that an int isn't there. (Which MS
828      * has done in other docs.) */
829
830     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
831
832     TRACE("(%p)->(%08lx,%p)\n",This,dwFlags,pCKey);
833     if (TRACE_ON(ddraw)) {
834         TRACE(" - colorkey flags : ");
835         DDRAW_dump_colorkeyflag(dwFlags);
836     }
837
838     switch (dwFlags)
839     {
840     case DDCKEY_DESTBLT:
841         *pCKey = This->surface_desc.ddckCKDestBlt;
842         break;
843
844     case DDCKEY_DESTOVERLAY:
845         *pCKey = This->surface_desc.u3.ddckCKDestOverlay;
846         break;
847
848     case DDCKEY_SRCBLT:
849         *pCKey = This->surface_desc.ddckCKSrcBlt;
850         break;
851
852     case DDCKEY_SRCOVERLAY:
853         *pCKey = This->surface_desc.ddckCKSrcOverlay;
854         break;
855
856     default:
857         return DDERR_INVALIDPARAMS;
858     }
859
860     return DD_OK;
861 }
862
863 /* XXX We need to do something with the DC if the surface gets lost. */
864 HRESULT WINAPI
865 Main_DirectDrawSurface_GetDC(LPDIRECTDRAWSURFACE7 iface, HDC *phDC)
866 {
867     DDSURFACEDESC2 ddsd;
868     HRESULT hr;
869     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
870
871     TRACE("(%p)->(%p)\n",This,phDC);
872     CHECK_LOST(This);
873
874     LOCK_OBJECT(This);
875
876     if (This->dc_in_use)
877     {
878         UNLOCK_OBJECT(This);
879         return DDERR_DCALREADYCREATED;
880     }
881
882     /* Lock as per MSDN.
883      * Strange: Lock lists DDERR_SURFACEBUSY as an error, meaning that another
884      * thread has it locked, but GetDC does not. */
885     ddsd.dwSize = sizeof(ddsd);
886     hr = IDirectDrawSurface7_Lock(iface, NULL, &ddsd, 0, 0);
887     if (FAILED(hr))
888     {
889         UNLOCK_OBJECT(This);
890         return hr;
891     }
892
893     hr = This->get_dc(This, &This->hDC);
894     if (SUCCEEDED(hr))
895     {
896         TRACE("returning %p\n",This->hDC);
897
898         *phDC = This->hDC;
899         This->dc_in_use = TRUE;
900     }
901     else WARN("No DC! Prepare for trouble\n");
902
903     UNLOCK_OBJECT(This);
904     return hr;
905 }
906
907 HRESULT WINAPI
908 Main_DirectDrawSurface_GetDDInterface(LPDIRECTDRAWSURFACE7 iface, LPVOID* pDD)
909 {
910     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
911
912     TRACE("(%p)->(%p)\n",This,pDD);
913     *pDD = ICOM_INTERFACE(This->ddraw_owner, IDirectDraw7);
914     IDirectDraw7_AddRef(ICOM_INTERFACE(This->ddraw_owner, IDirectDraw7));
915     return DD_OK;
916 }
917
918 HRESULT WINAPI
919 Main_DirectDrawSurface_GetFlipStatus(LPDIRECTDRAWSURFACE7 iface, DWORD dwFlags)
920 {
921     /* XXX: DDERR_INVALIDSURFACETYPE */
922
923     TRACE("(%p)->(%08lx)\n",iface,dwFlags);
924     switch (dwFlags)
925     {
926     case DDGFS_CANFLIP:
927     case DDGFS_ISFLIPDONE:
928         return DD_OK;
929
930     default:
931         return DDERR_INVALIDPARAMS;
932     }
933 }
934
935 HRESULT WINAPI
936 Main_DirectDrawSurface_GetLOD(LPDIRECTDRAWSURFACE7 iface, LPDWORD pdwMaxLOD)
937 {
938     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
939
940     TRACE("(%p)->(%p)\n",This,pdwMaxLOD);
941     CHECK_TEXTURE(This);
942
943     *pdwMaxLOD = This->max_lod;
944     return DD_OK;
945 }
946
947 HRESULT WINAPI
948 Main_DirectDrawSurface_GetOverlayPosition(LPDIRECTDRAWSURFACE7 iface,
949                                           LPLONG pX, LPLONG pY)
950 {
951     return DDERR_NOTAOVERLAYSURFACE;
952 }
953
954 HRESULT WINAPI
955 Main_DirectDrawSurface_GetPalette(LPDIRECTDRAWSURFACE7 iface,
956                                   LPDIRECTDRAWPALETTE* ppPalette)
957 {
958     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
959
960     TRACE("(%p)->(%p)\n",This,ppPalette);
961     if (This->palette == NULL)
962         return DDERR_NOPALETTEATTACHED;
963
964     *ppPalette = ICOM_INTERFACE(This->palette, IDirectDrawPalette);
965     IDirectDrawPalette_AddRef(ICOM_INTERFACE(This->palette,
966                                              IDirectDrawPalette));
967     return DD_OK;
968 }
969
970 HRESULT WINAPI
971 Main_DirectDrawSurface_GetPixelFormat(LPDIRECTDRAWSURFACE7 iface,
972                                       LPDDPIXELFORMAT pDDPixelFormat)
973 {
974     /* What is DDERR_INVALIDSURFACETYPE for here? */
975     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
976
977     TRACE("(%p)->(%p)\n",This,pDDPixelFormat);
978     DD_STRUCT_COPY_BYSIZE(pDDPixelFormat,&This->surface_desc.u4.ddpfPixelFormat);
979     return DD_OK;
980 }
981
982 HRESULT WINAPI
983 Main_DirectDrawSurface_GetPriority(LPDIRECTDRAWSURFACE7 iface,
984                                    LPDWORD pdwPriority)
985 {
986     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
987
988     TRACE("(%p)->(%p)\n",This,pdwPriority);
989     CHECK_TEXTURE(This);
990
991     *pdwPriority = This->priority;
992     return DD_OK;
993 }
994
995 HRESULT WINAPI
996 Main_DirectDrawSurface_GetPrivateData(LPDIRECTDRAWSURFACE7 iface,
997                                       REFGUID tag, LPVOID pBuffer,
998                                       LPDWORD pcbBufferSize)
999 {
1000     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1001     PrivateData* data;
1002
1003     data = find_private_data(This, tag);
1004     if (data == NULL) return DDERR_NOTFOUND;
1005
1006     /* This may not be right. */
1007     if ((data->flags & DDSPD_VOLATILE)
1008         && data->uniqueness_value != This->uniqueness_value)
1009         return DDERR_EXPIRED;
1010
1011     if (*pcbBufferSize < data->size)
1012     {
1013         *pcbBufferSize = data->size;
1014         return DDERR_MOREDATA;
1015     }
1016
1017     if (data->flags & DDSPD_IUNKNOWNPTR)
1018     {
1019         *(LPUNKNOWN *)pBuffer = data->ptr.object;
1020         IUnknown_AddRef(data->ptr.object);
1021     }
1022     else
1023     {
1024         memcpy(pBuffer, data->ptr.data, data->size);
1025     }
1026
1027     return DD_OK;
1028 }
1029
1030 HRESULT WINAPI
1031 Main_DirectDrawSurface_GetSurfaceDesc(LPDIRECTDRAWSURFACE7 iface,
1032                                       LPDDSURFACEDESC2 pDDSD)
1033 {
1034     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1035
1036     TRACE("(%p)->(%p)\n",This,pDDSD);
1037     if ((pDDSD->dwSize < sizeof(DDSURFACEDESC)) ||
1038         (pDDSD->dwSize > sizeof(DDSURFACEDESC2))) {
1039         ERR("Impossible/Strange struct size %ld.\n",pDDSD->dwSize);
1040         return DDERR_GENERIC;
1041     }
1042
1043     DD_STRUCT_COPY_BYSIZE(pDDSD,&This->surface_desc);
1044     if (TRACE_ON(ddraw)) {
1045       DDRAW_dump_surface_desc(pDDSD);
1046     }
1047     return DD_OK;
1048 }
1049
1050 HRESULT WINAPI
1051 Main_DirectDrawSurface_GetUniquenessValue(LPDIRECTDRAWSURFACE7 iface,
1052                                           LPDWORD pValue)
1053 {
1054     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1055
1056     TRACE("(%p)->(%p)\n",This,pValue);
1057     *pValue = This->uniqueness_value;
1058     return DD_OK;
1059 }
1060
1061 HRESULT WINAPI
1062 Main_DirectDrawSurface_Initialize(LPDIRECTDRAWSURFACE7 iface,
1063                                   LPDIRECTDRAW pDD, LPDDSURFACEDESC2 pDDSD)
1064 {
1065     TRACE("(%p)->(%p,%p)\n",iface,pDD,pDDSD);
1066     return DDERR_ALREADYINITIALIZED;
1067 }
1068
1069 HRESULT WINAPI
1070 Main_DirectDrawSurface_IsLost(LPDIRECTDRAWSURFACE7 iface)
1071 {
1072     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1073
1074     TRACE("(%p) is%s lost\n",This, (This->lost ? "" : " not"));
1075     return This->lost ? DDERR_SURFACELOST : DD_OK;
1076 }
1077
1078
1079 /* XXX This doesn't actually do any locking or keep track of the locked
1080  * rectangles. The behaviour is poorly documented. */
1081 HRESULT WINAPI
1082 Main_DirectDrawSurface_Lock(LPDIRECTDRAWSURFACE7 iface, LPRECT prect,
1083                             LPDDSURFACEDESC2 pDDSD, DWORD flags, HANDLE h)
1084 {
1085     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1086
1087     if (TRACE_ON(ddraw)) {
1088         TRACE("(%p)->Lock(%p,%p,%08lx,%08lx)\n",This,prect,pDDSD,flags,(DWORD)h);
1089         TRACE(" - locking flags : "); DDRAW_dump_lockflag(flags);
1090     }
1091     if (WARN_ON(ddraw)) {
1092         if (flags & ~(DDLOCK_WAIT|DDLOCK_READONLY|DDLOCK_WRITEONLY)) {
1093             WARN(" - unsupported locking flag : "); DDRAW_dump_lockflag(flags & ~(DDLOCK_WAIT|DDLOCK_READONLY|DDLOCK_WRITEONLY));
1094         }
1095     }
1096
1097     /* If the surface is already locked, return busy */
1098     if (This->locked) {
1099         WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
1100         return DDERR_SURFACEBUSY;
1101     }
1102
1103     /* First, copy the Surface description */
1104     DD_STRUCT_COPY_BYSIZE(pDDSD,&(This->surface_desc));
1105
1106     /* Used to optimize the D3D Device locking */
1107     This->lastlocktype = flags & (DDLOCK_READONLY|DDLOCK_WRITEONLY);
1108     
1109     /* If asked only for a part, change the surface pointer.
1110      * (Not documented.) */
1111     if (prect != NULL) {
1112         TRACE(" lprect: %ldx%ld-%ldx%ld\n",
1113                 prect->left,prect->top,prect->right,prect->bottom);
1114         /* First do some sanity checkings on the rectangle we receive.
1115            DungeonSiege seems to gives us once a very bad rectangle for example */
1116         if ((prect->top < 0) ||
1117             (prect->left < 0) ||
1118             (prect->bottom < 0) ||
1119             (prect->right < 0) ||
1120             (prect->left >= prect->right) ||
1121             (prect->top >= prect->bottom) ||
1122             (prect->left >= This->surface_desc.dwWidth) ||
1123             (prect->right > This->surface_desc.dwWidth) ||
1124             (prect->top >= This->surface_desc.dwHeight) ||
1125             (prect->bottom > This->surface_desc.dwHeight)) {
1126             ERR(" Invalid values in LPRECT !!!\n");
1127             return DDERR_INVALIDPARAMS;
1128         }
1129
1130         This->lock_update(This, prect, flags);
1131
1132         if (pDDSD->u4.ddpfPixelFormat.dwFlags & DDPF_FOURCC) {
1133             int blksize;
1134             switch(pDDSD->u4.ddpfPixelFormat.dwFourCC) {
1135                 case MAKE_FOURCC('D','X','T','1') : blksize = 8; break;
1136                 case MAKE_FOURCC('D','X','T','3') : blksize = 16; break;
1137                 case MAKE_FOURCC('D','X','T','5') : blksize = 16; break;
1138                 default: return DDERR_INVALIDPIXELFORMAT;
1139             }
1140             pDDSD->lpSurface = (char *)This->surface_desc.lpSurface
1141                 + prect->top/4 * (pDDSD->dwWidth+3)/4 * blksize
1142                 + prect->left/4 * blksize;
1143         } else
1144             pDDSD->lpSurface = (char *)This->surface_desc.lpSurface
1145                 + prect->top * This->surface_desc.u1.lPitch
1146                 + prect->left * GET_BPP(This->surface_desc);
1147     } else {
1148         This->lock_update(This, NULL, flags);
1149     }
1150
1151     This->locked = TRUE;
1152
1153     TRACE("locked surface returning description : \n");
1154     if (TRACE_ON(ddraw)) DDRAW_dump_surface_desc(pDDSD);
1155     
1156     return DD_OK;
1157 }
1158
1159 HRESULT WINAPI
1160 Main_DirectDrawSurface_PageLock(LPDIRECTDRAWSURFACE7 iface, DWORD dwFlags)
1161 {
1162     /* Some surface types should return DDERR_CANTPAGELOCK. */
1163     return DD_OK;
1164 }
1165
1166 HRESULT WINAPI
1167 Main_DirectDrawSurface_PageUnlock(LPDIRECTDRAWSURFACE7 iface, DWORD dwFlags)
1168 {
1169     /* Some surface types should return DDERR_CANTPAGEUNLOCK, and we should
1170      * keep track so we can return DDERR_NOTPAGELOCKED as appropriate. */
1171     return DD_OK;
1172 }
1173
1174 HRESULT WINAPI
1175 Main_DirectDrawSurface_ReleaseDC(LPDIRECTDRAWSURFACE7 iface, HDC hDC)
1176 {
1177     HRESULT hr;
1178     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1179
1180     TRACE("(%p)->(%p)\n",This,hDC);
1181
1182     if (!This->dc_in_use || This->hDC != hDC)
1183         return DDERR_INVALIDPARAMS;
1184
1185     This->release_dc(This, hDC);
1186
1187     hr = IDirectDrawSurface7_Unlock(iface, NULL);
1188     if (FAILED(hr)) return hr;
1189
1190     This->dc_in_use = FALSE;
1191     This->hDC = 0;
1192
1193     return DD_OK;
1194 }
1195
1196 /* Restore */
1197
1198 HRESULT WINAPI
1199 Main_DirectDrawSurface_SetClipper(LPDIRECTDRAWSURFACE7 iface,
1200                                   LPDIRECTDRAWCLIPPER pDDClipper)
1201 {
1202     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1203
1204     TRACE("(%p)->(%p)\n",This,pDDClipper);
1205     if (pDDClipper == ICOM_INTERFACE(This->clipper, IDirectDrawClipper))
1206         return DD_OK;
1207
1208     if (This->clipper != NULL)
1209         IDirectDrawClipper_Release(ICOM_INTERFACE(This->clipper,
1210                                                   IDirectDrawClipper));
1211
1212     This->clipper = ICOM_OBJECT(IDirectDrawClipperImpl, IDirectDrawClipper,
1213                                 pDDClipper);
1214     if (pDDClipper != NULL)
1215         IDirectDrawClipper_AddRef(pDDClipper);
1216
1217     return DD_OK;
1218 }
1219
1220 HRESULT WINAPI
1221 Main_DirectDrawSurface_SetColorKey(LPDIRECTDRAWSURFACE7 iface,
1222                                    DWORD dwFlags, LPDDCOLORKEY pCKey)
1223 {
1224     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1225     
1226     TRACE("(%p)->(%08lx,%p)\n",This,dwFlags,pCKey);
1227
1228     if (TRACE_ON(ddraw)) {
1229         TRACE(" - colorkey flags : ");
1230         DDRAW_dump_colorkeyflag(dwFlags);
1231     }
1232
1233     if ((dwFlags & DDCKEY_COLORSPACE) != 0) {
1234         FIXME(" colorkey value not supported (%08lx) !\n", dwFlags);
1235         return DDERR_INVALIDPARAMS;
1236     }
1237     
1238     /* TODO: investigate if this function can take multiple bits set at the same
1239              time (ie setting multiple colorkey values at the same time with only
1240              one API call).
1241     */
1242     if (pCKey) {
1243         switch (dwFlags & ~DDCKEY_COLORSPACE) {
1244             case DDCKEY_DESTBLT:
1245                 This->surface_desc.ddckCKDestBlt = *pCKey;
1246                 This->surface_desc.dwFlags |= DDSD_CKDESTBLT;
1247                 break;
1248
1249             case DDCKEY_DESTOVERLAY:
1250                 This->surface_desc.u3.ddckCKDestOverlay = *pCKey;
1251                 This->surface_desc.dwFlags |= DDSD_CKDESTOVERLAY;
1252                 break;
1253
1254             case DDCKEY_SRCOVERLAY:
1255                 This->surface_desc.ddckCKSrcOverlay = *pCKey;
1256                 This->surface_desc.dwFlags |= DDSD_CKSRCOVERLAY;
1257                 break;
1258
1259             case DDCKEY_SRCBLT:
1260                 This->surface_desc.ddckCKSrcBlt = *pCKey;
1261                 This->surface_desc.dwFlags |= DDSD_CKSRCBLT;
1262                 break;
1263
1264             default:
1265                 return DDERR_INVALIDPARAMS;
1266         }
1267     } else {
1268         switch (dwFlags & ~DDCKEY_COLORSPACE) {
1269             case DDCKEY_DESTBLT:
1270                 This->surface_desc.dwFlags &= ~DDSD_CKDESTBLT;
1271                 break;
1272
1273             case DDCKEY_DESTOVERLAY:
1274                 This->surface_desc.dwFlags &= ~DDSD_CKDESTOVERLAY;
1275                 break;
1276
1277             case DDCKEY_SRCOVERLAY:
1278                 This->surface_desc.dwFlags &= ~DDSD_CKSRCOVERLAY;
1279                 break;
1280
1281             case DDCKEY_SRCBLT:
1282                 This->surface_desc.dwFlags &= ~DDSD_CKSRCBLT;
1283                 break;
1284
1285             default:
1286                 return DDERR_INVALIDPARAMS;
1287         }
1288     }
1289
1290     if (This->aux_setcolorkey_cb) This->aux_setcolorkey_cb(This, dwFlags, pCKey);
1291
1292     return DD_OK;
1293 }
1294
1295 HRESULT WINAPI
1296 Main_DirectDrawSurface_SetLOD(LPDIRECTDRAWSURFACE7 iface, DWORD dwMaxLOD)
1297 {
1298     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1299
1300     TRACE("(%p)->(%08lx)\n",This,dwMaxLOD);
1301     CHECK_TEXTURE(This);
1302
1303     This->max_lod = dwMaxLOD;
1304     return DD_OK;
1305 }
1306
1307 HRESULT WINAPI
1308 Main_DirectDrawSurface_SetOverlayPosition(LPDIRECTDRAWSURFACE7 iface,
1309                                           LONG X, LONG Y)
1310 {
1311     return DDERR_NOTAOVERLAYSURFACE;
1312 }
1313
1314 HRESULT WINAPI
1315 Main_DirectDrawSurface_SetPalette(LPDIRECTDRAWSURFACE7 iface,
1316                                   LPDIRECTDRAWPALETTE pPalette)
1317 {
1318     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1319     IDirectDrawPalette *pal_to_rel = NULL;
1320
1321     TRACE("(%p)->(%p)\n",This,pPalette);
1322     if (pPalette == ICOM_INTERFACE(This->palette, IDirectDrawPalette))
1323         return DD_OK;
1324
1325     if (This->palette != NULL) {
1326         if (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
1327             This->palette->global.dwFlags &= ~DDPCAPS_PRIMARYSURFACE;
1328         pal_to_rel = ICOM_INTERFACE(This->palette, IDirectDrawPalette);
1329     }
1330
1331     This->palette = ICOM_OBJECT(IDirectDrawPaletteImpl, IDirectDrawPalette,
1332                                 pPalette);
1333     if (pPalette != NULL) {
1334         IDirectDrawPalette_AddRef(pPalette);
1335         if (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
1336             This->palette->global.dwFlags |= DDPCAPS_PRIMARYSURFACE;
1337     }
1338
1339     This->set_palette(This, This->palette);
1340
1341     /* Do the palette release at the end to prevent doing some 'loop' when removing
1342      * the surface maintaining the last reference on a palette.
1343      */
1344     if (pal_to_rel != NULL)
1345         IDirectDrawPalette_Release(pal_to_rel);
1346
1347     return DD_OK;
1348 }
1349
1350 HRESULT WINAPI
1351 Main_DirectDrawSurface_SetPriority(LPDIRECTDRAWSURFACE7 iface,
1352                                    DWORD dwPriority)
1353 {
1354     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1355
1356     TRACE("(%p)->(%08lx)\n",This,dwPriority);
1357     CHECK_TEXTURE(This);
1358
1359     This->priority = dwPriority;
1360     return DD_OK;
1361 }
1362
1363 /* Be careful when locking this: it is risky to call the object's AddRef
1364  * or Release holding a lock. */
1365 HRESULT WINAPI
1366 Main_DirectDrawSurface_SetPrivateData(LPDIRECTDRAWSURFACE7 iface,
1367                                       REFGUID tag, LPVOID pData,
1368                                       DWORD cbSize, DWORD dwFlags)
1369 {
1370     PrivateData* data;
1371     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1372
1373     data = find_private_data(This, tag);
1374     if (data == NULL)
1375     {
1376         data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data));
1377         if (data == NULL) return DDERR_OUTOFMEMORY;
1378
1379         data->tag = *tag;
1380         data->flags = dwFlags;
1381         data->uniqueness_value = This->uniqueness_value;
1382
1383         if (dwFlags & DDSPD_IUNKNOWNPTR)
1384         {
1385             data->ptr.object = (LPUNKNOWN)pData;
1386             data->size = sizeof(LPUNKNOWN);
1387             IUnknown_AddRef(data->ptr.object);
1388         }
1389         else
1390         {
1391             data->ptr.data = HeapAlloc(GetProcessHeap(), 0, cbSize);
1392             if (data->ptr.data == NULL)
1393             {
1394                 HeapFree(GetProcessHeap(), 0, data);
1395                 return DDERR_OUTOFMEMORY;
1396             }
1397         }
1398
1399         /* link it in */
1400         data->next = This->private_data;
1401         data->prev = NULL;
1402         if (This->private_data)
1403             This->private_data->prev = data;
1404         This->private_data = data;
1405
1406         return DD_OK;
1407     }
1408     else
1409     {
1410         /* I don't actually know how windows handles this case. The only
1411          * reason I don't just call FreePrivateData is because I want to
1412          * guarantee SetPrivateData working when using LPUNKNOWN or data
1413          * that is no larger than the old data. */
1414
1415         return E_FAIL;
1416     }
1417 }
1418
1419 /* SetSurfaceDesc */
1420
1421 HRESULT WINAPI
1422 Main_DirectDrawSurface_Unlock(LPDIRECTDRAWSURFACE7 iface, LPRECT pRect)
1423 {
1424     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1425
1426     TRACE("(%p)->Unlock(%p)\n",This,pRect);
1427
1428     if (!This->locked) {
1429         WARN("Surface not locked - returing DDERR_NOTLOCKED\n");
1430         return DDERR_NOTLOCKED;
1431     }
1432
1433     This->locked = FALSE;
1434     This->unlock_update(This, pRect);
1435     if (This->aux_unlock)
1436         This->aux_unlock(This->aux_ctx, This->aux_data, pRect);
1437
1438     return DD_OK;
1439 }
1440
1441 HRESULT WINAPI
1442 Main_DirectDrawSurface_UpdateOverlay(LPDIRECTDRAWSURFACE7 iface,
1443                                      LPRECT pSrcRect,
1444                                      LPDIRECTDRAWSURFACE7 pDstSurface,
1445                                      LPRECT pDstRect, DWORD dwFlags,
1446                                      LPDDOVERLAYFX pFX)
1447 {
1448     return DDERR_UNSUPPORTED;
1449 }
1450
1451 /* MSDN: "not currently implemented." */
1452 HRESULT WINAPI
1453 Main_DirectDrawSurface_UpdateOverlayDisplay(LPDIRECTDRAWSURFACE7 iface,
1454                                             DWORD dwFlags)
1455 {
1456     return DDERR_UNSUPPORTED;
1457 }
1458
1459 HRESULT WINAPI
1460 Main_DirectDrawSurface_UpdateOverlayZOrder(LPDIRECTDRAWSURFACE7 iface,
1461                                            DWORD dwFlags,
1462                                            LPDIRECTDRAWSURFACE7 pDDSRef)
1463 {
1464     return DDERR_NOTAOVERLAYSURFACE;
1465 }