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