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