Added mappings for a few messages.
[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     /* Set MIPMAPSUBLEVEL if this seems to be one */
257     if (This->surface_desc.ddsCaps.dwCaps &
258         surf->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) {
259         surf->surface_desc.ddsCaps.dwCaps2 |= DDSCAPS2_MIPMAPSUBLEVEL;
260         /* FIXME: we should probably also add to dwMipMapCount of this
261          * and all parent surfaces (update create_texture if you do) */
262     }
263
264     /* Callback to allow the surface to do something special now that it is
265      * attached. (e.g. maybe the Z-buffer tells the renderer to use it.) */
266     if (!surf->attach(surf, This))
267         return DDERR_CANNOTATTACHSURFACE;
268
269     /* check: Where should it go in the chain? This puts it on the head. */
270     if (This->attached)
271         This->attached->prev_attached = surf;
272     surf->next_attached = This->attached;
273     surf->prev_attached = NULL;
274     This->attached = surf;
275     surf->surface_owner = This;
276
277     IDirectDrawSurface7_AddRef(pAttach);
278
279     return DD_OK;
280 }
281
282 /* MSDN: "not currently implemented." */
283 HRESULT WINAPI
284 Main_DirectDrawSurface_AddOverlayDirtyRect(LPDIRECTDRAWSURFACE7 iface,
285                                            LPRECT pRect)
286 {
287     TRACE("(%p)->(%p)\n",iface,pRect);
288     return DDERR_UNSUPPORTED; /* unchecked */
289 }
290
291 /* MSDN: "not currently implemented." */
292 HRESULT WINAPI
293 Main_DirectDrawSurface_BltBatch(LPDIRECTDRAWSURFACE7 iface,
294                                 LPDDBLTBATCH pBatch, DWORD dwCount,
295                                 DWORD dwFlags)
296 {
297     TRACE("(%p)->(%p,%ld,%08lx)\n",iface,pBatch,dwCount,dwFlags);
298     return DDERR_UNSUPPORTED; /* unchecked */
299 }
300
301 HRESULT WINAPI
302 Main_DirectDrawSurface_ChangeUniquenessValue(LPDIRECTDRAWSURFACE7 iface)
303 {
304     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
305     volatile IDirectDrawSurfaceImpl* vThis = This;
306
307     TRACE("(%p)\n",This);
308     /* A uniquness value of 0 is apparently special.
309      * This needs to be checked. */
310     while (1)
311     {
312         DWORD old_uniqueness_value = vThis->uniqueness_value;
313         DWORD new_uniqueness_value = old_uniqueness_value+1;
314
315         if (old_uniqueness_value == 0) break;
316         if (new_uniqueness_value == 0) new_uniqueness_value = 1;
317
318         if (InterlockedCompareExchange((LONG*)&vThis->uniqueness_value,
319                                        old_uniqueness_value,
320                                        new_uniqueness_value)
321             == old_uniqueness_value)
322             break;
323     }
324
325     return DD_OK;
326 }
327
328 HRESULT WINAPI
329 Main_DirectDrawSurface_DeleteAttachedSurface(LPDIRECTDRAWSURFACE7 iface,
330                                              DWORD dwFlags,
331                                              LPDIRECTDRAWSURFACE7 pAttach)
332 {
333     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
334     IDirectDrawSurfaceImpl* surf = ICOM_OBJECT(IDirectDrawSurfaceImpl,
335                                                IDirectDrawSurface7, pAttach);
336
337     TRACE("(%p)->(%08lx,%p)\n",This,dwFlags,pAttach);
338
339     if (!surf || (surf->surface_owner != This))
340         return DDERR_SURFACENOTATTACHED; /* unchecked */
341
342     surf->detach(surf);
343
344     /* Remove MIPMAPSUBLEVEL if this seemed to be one */
345     if (This->surface_desc.ddsCaps.dwCaps &
346         surf->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) {
347         surf->surface_desc.ddsCaps.dwCaps2 &= ~DDSCAPS2_MIPMAPSUBLEVEL;
348         /* FIXME: we should probably also subtract from dwMipMapCount of this
349          * and all parent surfaces */
350     }
351
352     if (surf->next_attached)
353         surf->next_attached->prev_attached = surf->prev_attached;
354     if (surf->prev_attached)
355         surf->prev_attached->next_attached = surf->next_attached;
356     if (This->attached == surf)
357         This->attached = surf->next_attached;
358
359     IDirectDrawSurface7_Release(pAttach);
360
361     return DD_OK;
362 }
363
364 HRESULT WINAPI
365 Main_DirectDrawSurface_EnumAttachedSurfaces(LPDIRECTDRAWSURFACE7 iface,
366                                             LPVOID context,
367                                             LPDDENUMSURFACESCALLBACK7 cb)
368 {
369     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
370     IDirectDrawSurfaceImpl* surf;
371
372     TRACE("(%p)->(%p,%p)\n",This,context,cb);
373
374     for (surf = This->attached; surf != NULL; surf = surf->next_attached)
375     {
376         /* check: != DDENUMRET_OK or == DDENUMRET_CANCEL? */
377         if (cb(ICOM_INTERFACE(surf, IDirectDrawSurface7), &surf->surface_desc,
378                context) == DDENUMRET_CANCEL)
379             break;
380     }
381
382     return DD_OK;
383 }
384
385 HRESULT WINAPI
386 Main_DirectDrawSurface_EnumOverlayZOrders(LPDIRECTDRAWSURFACE7 iface,
387                                           DWORD dwFlags, LPVOID context,
388                                           LPDDENUMSURFACESCALLBACK7 cb)
389 {
390     TRACE("(%p)->(%08lx,%p,%p)\n",iface,dwFlags,context,cb);
391     return DD_OK;
392 }
393
394 BOOL Main_DirectDrawSurface_flip_data(IDirectDrawSurfaceImpl* front,
395                                       IDirectDrawSurfaceImpl* back,
396                                       DWORD dwFlags)
397 {
398     /* uniqueness_value? */
399     /* This is necessary. But is it safe? */
400     {
401         HDC tmp = front->hDC;
402         front->hDC = back->hDC;
403         back->hDC = tmp;
404     }
405
406     {
407         BOOL tmp = front->dc_in_use;
408         front->dc_in_use = back->dc_in_use;
409         back->dc_in_use = tmp;
410     }
411
412     {
413         FLATPTR tmp = front->global.fpVidMem;
414         front->global.fpVidMem = back->global.fpVidMem;
415         back->global.fpVidMem = tmp;
416     }
417
418     {
419         ULONG_PTR tmp = front->global_more.hKernelSurface;
420         front->global_more.hKernelSurface = back->global_more.hKernelSurface;
421         back->global_more.hKernelSurface = tmp;
422     }
423
424     return TRUE;
425 }
426
427 HRESULT WINAPI
428 Main_DirectDrawSurface_Flip(LPDIRECTDRAWSURFACE7 iface,
429                             LPDIRECTDRAWSURFACE7 override, DWORD dwFlags)
430 {
431     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
432     IDirectDrawSurfaceImpl* target;
433     HRESULT hr;
434
435     TRACE("(%p)->(%p,%08lx)\n",This,override,dwFlags);
436
437     /* MSDN: "This method can be called only for a surface that has the
438      * DDSCAPS_FLIP and DDSCAPS_FRONTBUFFER capabilities." */
439     if ((This->surface_desc.ddsCaps.dwCaps&(DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER))
440         != (DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER))
441         return DDERR_NOTFLIPPABLE;
442
443     if (This->aux_flip)
444         if (This->aux_flip(This->aux_ctx, This->aux_data))
445             return DD_OK;
446
447     /* 1. find the flip target */
448     /* XXX I don't think this algorithm works for more than 1 backbuffer. */
449     if (override == NULL)
450     {
451         static DDSCAPS2 back_caps = { DDSCAPS_BACKBUFFER };
452         LPDIRECTDRAWSURFACE7 tgt;
453
454         hr = IDirectDrawSurface7_GetAttachedSurface(iface, &back_caps, &tgt);
455         if (FAILED(hr)) return DDERR_NOTFLIPPABLE; /* unchecked */
456
457         target = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7,
458                              tgt);
459         IDirectDrawSurface7_Release(tgt);
460     }
461     else
462     {
463         BOOL on_chain = FALSE;
464         IDirectDrawSurfaceImpl* surf;
465
466         /* MSDN: "The method fails if the specified [override] surface is not
467          * a member of the flipping chain." */
468         
469         /* Verify that override is on this flip chain. We assume that
470          * surf is the head of the flipping chain, because it's the front
471          * buffer. */
472         target = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7,
473                              override);
474
475         /* Either target is (indirectly) attached to This or This is
476          * (indirectly) attached to target. */
477         for (surf = target; surf != NULL; surf = surf->surface_owner)
478         {
479             if (surf == This)
480             {
481                 on_chain = TRUE;
482                 break;
483             }
484         }
485
486         if (!on_chain)
487             return DDERR_INVALIDPARAMS; /* unchecked */
488     }
489
490     TRACE("flip to backbuffer: %p\n",target);
491     if (This->flip_data(This, target, dwFlags))
492         This->flip_update(This, dwFlags);
493
494     return DD_OK;
495 }
496
497 static PrivateData* find_private_data(IDirectDrawSurfaceImpl *This,
498                                       REFGUID tag)
499 {
500     PrivateData* data;
501     for (data = This->private_data; data != NULL; data = data->next)
502     {
503         if (IsEqualGUID(&data->tag, tag)) break;
504     }
505
506     return data;
507 }
508
509 HRESULT WINAPI
510 Main_DirectDrawSurface_FreePrivateData(LPDIRECTDRAWSURFACE7 iface, REFGUID tag)
511 {
512     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
513     PrivateData *data;
514
515     data = find_private_data(This, tag);
516     if (data == NULL) return DDERR_NOTFOUND;
517
518     if (data->prev)
519         data->prev->next = data->next;
520     if (data->next)
521         data->next->prev = data->prev;
522
523     if (data->flags & DDSPD_IUNKNOWNPTR)
524     {
525         if (data->ptr.object != NULL)
526             IUnknown_Release(data->ptr.object);
527     }
528     else
529         HeapFree(GetProcessHeap(), 0, data->ptr.data);
530
531     HeapFree(GetProcessHeap(), 0, data);
532
533     return DD_OK;
534 }
535
536 HRESULT WINAPI
537 Main_DirectDrawSurface_GetAttachedSurface(LPDIRECTDRAWSURFACE7 iface,
538                                           LPDDSCAPS2 pCaps,
539                                           LPDIRECTDRAWSURFACE7* ppSurface)
540 {
541     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
542     IDirectDrawSurfaceImpl* surf;
543     IDirectDrawSurfaceImpl* found = NULL;
544
545     TRACE("(%p)->Looking for caps: %lx,%lx,%lx,%lx output: %p\n",This,pCaps->dwCaps, pCaps->dwCaps2,
546           pCaps->dwCaps3, pCaps->dwCaps4, ppSurface);
547
548     for (surf = This->attached; surf != NULL; surf = surf->next_attached)
549     {
550         TRACE("Surface: (%p) caps: %lx,%lx,%lx,%lx \n",surf ,
551                surf->surface_desc.ddsCaps.dwCaps,
552                surf->surface_desc.ddsCaps.dwCaps2,
553                surf->surface_desc.ddsCaps.dwCaps3,
554                surf->surface_desc.ddsCaps.dwCaps4);
555         if (((surf->surface_desc.ddsCaps.dwCaps & pCaps->dwCaps) == pCaps->dwCaps)
556            && ((surf->surface_desc.ddsCaps.dwCaps2 & pCaps->dwCaps2) == pCaps->dwCaps2))
557         {
558             /* MSDN: "This method fails if more than one surface is attached
559              * that matches the capabilities requested." */
560             if (found != NULL)
561             {
562                 FIXME("More than one attached surface matches requested caps.  What should we do here?\n");
563                 /* Previous code returned 'DDERR_NOTFOUND'.  That appears not 
564                    to be correct, given what 3DMark expects from MipMapped surfaces. 
565                    We shall just continue instead. */
566             }
567
568             found = surf;
569         }
570     }
571
572     if (found == NULL)
573         return DDERR_NOTFOUND;
574
575     *ppSurface = ICOM_INTERFACE(found, IDirectDrawSurface7);
576
577     /* XXX d3dframe.cpp sometimes AddRefs things that it gets from us. */
578     IDirectDrawSurface7_AddRef(ICOM_INTERFACE(found, IDirectDrawSurface7));
579     return DD_OK;
580 }
581
582 HRESULT WINAPI
583 Main_DirectDrawSurface_GetBltStatus(LPDIRECTDRAWSURFACE7 iface, DWORD dwFlags)
584 {
585     TRACE("(%p)->(%08lx)\n",iface,dwFlags);
586
587     switch (dwFlags)
588     {
589     case DDGBS_CANBLT:
590     case DDGBS_ISBLTDONE:
591         return DD_OK;
592
593     default:
594         return DDERR_INVALIDPARAMS;
595     }
596 }
597
598 HRESULT WINAPI
599 Main_DirectDrawSurface_GetCaps(LPDIRECTDRAWSURFACE7 iface, LPDDSCAPS2 pCaps)
600 {
601     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
602
603     TRACE("(%p)->(%p)\n",This,pCaps);
604     *pCaps = This->surface_desc.ddsCaps;
605     return DD_OK;
606 }
607
608 HRESULT WINAPI
609 Main_DirectDrawSurface_GetClipper(LPDIRECTDRAWSURFACE7 iface,
610                                   LPDIRECTDRAWCLIPPER* ppClipper)
611 {
612     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
613
614     TRACE("(%p)->(%p)\n",This,ppClipper);
615     if (This->clipper == NULL)
616         return DDERR_NOCLIPPERATTACHED;
617
618     *ppClipper = ICOM_INTERFACE(This->clipper, IDirectDrawClipper);
619     IDirectDrawClipper_AddRef(ICOM_INTERFACE(This->clipper,
620                                              IDirectDrawClipper));
621     return DD_OK;
622 }
623
624 HRESULT WINAPI
625 Main_DirectDrawSurface_GetColorKey(LPDIRECTDRAWSURFACE7 iface, DWORD dwFlags,
626                                    LPDDCOLORKEY pCKey)
627 {
628     /* There is a DDERR_NOCOLORKEY error, but how do we know if a color key
629      * isn't there? That's like saying that an int isn't there. (Which MS
630      * has done in other docs.) */
631
632     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
633
634     TRACE("(%p)->(%08lx,%p)\n",This,dwFlags,pCKey);
635     switch (dwFlags)
636     {
637     case DDCKEY_DESTBLT:
638         *pCKey = This->surface_desc.ddckCKDestBlt;
639         break;
640
641     case DDCKEY_DESTOVERLAY:
642         *pCKey = This->surface_desc.u3.ddckCKDestOverlay;
643         break;
644
645     case DDCKEY_SRCBLT:
646         *pCKey = This->surface_desc.ddckCKSrcBlt;
647         break;
648
649     case DDCKEY_SRCOVERLAY:
650         *pCKey = This->surface_desc.ddckCKSrcOverlay;
651         break;
652
653     default:
654         return DDERR_INVALIDPARAMS;
655     }
656
657     return DD_OK;
658 }
659
660 /* XXX We need to do something with the DC if the surface gets lost. */
661 HRESULT WINAPI
662 Main_DirectDrawSurface_GetDC(LPDIRECTDRAWSURFACE7 iface, HDC *phDC)
663 {
664     DDSURFACEDESC2 ddsd;
665     HRESULT hr;
666     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
667
668     TRACE("(%p)->(%p)\n",This,phDC);
669     CHECK_LOST(This);
670
671     LOCK_OBJECT(This);
672
673     if (This->dc_in_use)
674     {
675         UNLOCK_OBJECT(This);
676         return DDERR_DCALREADYCREATED;
677     }
678
679     /* Lock as per MSDN.
680      * Strange: Lock lists DDERR_SURFACEBUSY as an error, meaning that another
681      * thread has it locked, but GetDC does not. */
682     ddsd.dwSize = sizeof(ddsd);
683     hr = IDirectDrawSurface7_Lock(iface, NULL, &ddsd, 0, 0);
684     if (FAILED(hr))
685     {
686         UNLOCK_OBJECT(This);
687         return hr;
688     }
689
690     hr = This->get_dc(This, &This->hDC);
691     if (SUCCEEDED(hr))
692     {
693         TRACE("returning %08x\n",This->hDC);
694
695         *phDC = This->hDC;
696         This->dc_in_use = TRUE;
697     }
698     else WARN("No DC! Prepare for trouble\n");
699
700     UNLOCK_OBJECT(This);
701     return hr;
702 }
703
704 HRESULT WINAPI
705 Main_DirectDrawSurface_GetDDInterface(LPDIRECTDRAWSURFACE7 iface, LPVOID* pDD)
706 {
707     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
708
709     TRACE("(%p)->(%p)\n",This,pDD);
710     *pDD = ICOM_INTERFACE(This->ddraw_owner, IDirectDraw7);
711     IDirectDraw7_AddRef(ICOM_INTERFACE(This->ddraw_owner, IDirectDraw7));
712     return DD_OK;
713 }
714
715 HRESULT WINAPI
716 Main_DirectDrawSurface_GetFlipStatus(LPDIRECTDRAWSURFACE7 iface, DWORD dwFlags)
717 {
718     /* XXX: DDERR_INVALIDSURFACETYPE */
719
720     TRACE("(%p)->(%08lx)\n",iface,dwFlags);
721     switch (dwFlags)
722     {
723     case DDGFS_CANFLIP:
724     case DDGFS_ISFLIPDONE:
725         return DD_OK;
726
727     default:
728         return DDERR_INVALIDPARAMS;
729     }
730 }
731
732 HRESULT WINAPI
733 Main_DirectDrawSurface_GetLOD(LPDIRECTDRAWSURFACE7 iface, LPDWORD pdwMaxLOD)
734 {
735     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
736
737     TRACE("(%p)->(%p)\n",This,pdwMaxLOD);
738     CHECK_TEXTURE(This);
739
740     *pdwMaxLOD = This->max_lod;
741     return DD_OK;
742 }
743
744 HRESULT WINAPI
745 Main_DirectDrawSurface_GetOverlayPosition(LPDIRECTDRAWSURFACE7 iface,
746                                           LPLONG pX, LPLONG pY)
747 {
748     return DDERR_NOTAOVERLAYSURFACE;
749 }
750
751 HRESULT WINAPI
752 Main_DirectDrawSurface_GetPalette(LPDIRECTDRAWSURFACE7 iface,
753                                   LPDIRECTDRAWPALETTE* ppPalette)
754 {
755     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
756
757     TRACE("(%p)->(%p)\n",This,ppPalette);
758     if (This->palette == NULL)
759         return DDERR_NOPALETTEATTACHED;
760
761     *ppPalette = ICOM_INTERFACE(This->palette, IDirectDrawPalette);
762     IDirectDrawPalette_AddRef(ICOM_INTERFACE(This->palette,
763                                              IDirectDrawPalette));
764     return DD_OK;
765 }
766
767 HRESULT WINAPI
768 Main_DirectDrawSurface_GetPixelFormat(LPDIRECTDRAWSURFACE7 iface,
769                                       LPDDPIXELFORMAT pDDPixelFormat)
770 {
771     /* What is DDERR_INVALIDSURFACETYPE for here? */
772     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
773
774     TRACE("(%p)->(%p)\n",This,pDDPixelFormat);
775     DD_STRUCT_COPY_BYSIZE(pDDPixelFormat,&This->surface_desc.u4.ddpfPixelFormat);
776     return DD_OK;
777 }
778
779 HRESULT WINAPI
780 Main_DirectDrawSurface_GetPriority(LPDIRECTDRAWSURFACE7 iface,
781                                    LPDWORD pdwPriority)
782 {
783     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
784
785     TRACE("(%p)->(%p)\n",This,pdwPriority);
786     CHECK_TEXTURE(This);
787
788     *pdwPriority = This->priority;
789     return DD_OK;
790 }
791
792 HRESULT WINAPI
793 Main_DirectDrawSurface_GetPrivateData(LPDIRECTDRAWSURFACE7 iface,
794                                       REFGUID tag, LPVOID pBuffer,
795                                       LPDWORD pcbBufferSize)
796 {
797     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
798     PrivateData* data;
799
800     data = find_private_data(This, tag);
801     if (data == NULL) return DDERR_NOTFOUND;
802
803     /* This may not be right. */
804     if ((data->flags & DDSPD_VOLATILE)
805         && data->uniqueness_value != This->uniqueness_value)
806         return DDERR_EXPIRED;
807
808     if (*pcbBufferSize < data->size)
809     {
810         *pcbBufferSize = data->size;
811         return DDERR_MOREDATA;
812     }
813
814     if (data->flags & DDSPD_IUNKNOWNPTR)
815     {
816         *(LPUNKNOWN *)pBuffer = data->ptr.object;
817         IUnknown_AddRef(data->ptr.object);
818     }
819     else
820     {
821         memcpy(pBuffer, data->ptr.data, data->size);
822     }
823
824     return DD_OK;
825 }
826
827 HRESULT WINAPI
828 Main_DirectDrawSurface_GetSurfaceDesc(LPDIRECTDRAWSURFACE7 iface,
829                                       LPDDSURFACEDESC2 pDDSD)
830 {
831     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
832
833     TRACE("(%p)->(%p)\n",This,pDDSD);
834     if ((pDDSD->dwSize < sizeof(DDSURFACEDESC)) || 
835         (pDDSD->dwSize > sizeof(DDSURFACEDESC2))) {
836         ERR("Impossible/Strange struct size %ld.\n",pDDSD->dwSize);
837         return DDERR_GENERIC;
838     }
839         
840     DD_STRUCT_COPY_BYSIZE(pDDSD,&This->surface_desc);
841     return DD_OK;
842 }
843
844 HRESULT WINAPI
845 Main_DirectDrawSurface_GetUniquenessValue(LPDIRECTDRAWSURFACE7 iface,
846                                           LPDWORD pValue)
847 {
848     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
849
850     TRACE("(%p)->(%p)\n",This,pValue);
851     *pValue = This->uniqueness_value;
852     return DD_OK;
853 }
854
855 HRESULT WINAPI
856 Main_DirectDrawSurface_Initialize(LPDIRECTDRAWSURFACE7 iface,
857                                   LPDIRECTDRAW pDD, LPDDSURFACEDESC2 pDDSD)
858 {
859     TRACE("(%p)->(%p,%p)\n",iface,pDD,pDDSD);
860     return DDERR_ALREADYINITIALIZED;
861 }
862
863 HRESULT WINAPI
864 Main_DirectDrawSurface_IsLost(LPDIRECTDRAWSURFACE7 iface)
865 {
866     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
867
868     TRACE("(%p) is%s lost\n",This, (This->lost ? "" : " not"));
869     return This->lost ? DDERR_SURFACELOST : DD_OK;
870 }
871
872
873 /* XXX This doesn't actually do any locking or keep track of the locked
874  * rectangles. The behaviour is poorly documented. */
875 HRESULT WINAPI
876 Main_DirectDrawSurface_Lock(LPDIRECTDRAWSURFACE7 iface, LPRECT prect,
877                             LPDDSURFACEDESC2 pDDSD, DWORD flags, HANDLE h)
878 {
879     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
880
881     TRACE("(%p)->Lock(%p,%p,%08lx,%08lx)\n",This,prect,pDDSD,flags,(DWORD)h);
882
883     if (flags & ~(DDLOCK_WAIT|DDLOCK_READONLY|DDLOCK_WRITEONLY))
884         WARN("(%p)->Lock(%p,%p,%08lx,%08lx)\n",
885                  This,prect,pDDSD,flags,(DWORD)h);
886
887     /* First, copy the Surface description */
888     DD_STRUCT_COPY_BYSIZE(pDDSD,&(This->surface_desc));
889
890     TRACE("locked surface: height=%ld, width=%ld, pitch=%ld\n",
891           pDDSD->dwHeight,pDDSD->dwWidth,pDDSD->u1.lPitch);
892
893     /* If asked only for a part, change the surface pointer.
894      * (Not documented.) */
895     if (prect != NULL) {
896         TRACE(" lprect: %dx%d-%dx%d\n",
897                 prect->top,prect->left,prect->bottom,prect->right
898         );
899         if ((prect->top < 0) ||
900             (prect->left < 0) ||
901             (prect->bottom < 0) ||
902             (prect->right < 0)) {
903           ERR(" Negative values in LPRECT !!!\n");
904           return DDERR_INVALIDPARAMS;
905        }
906
907         This->lock_update(This, prect);
908        
909         pDDSD->lpSurface = (char *)This->surface_desc.lpSurface
910             + prect->top * This->surface_desc.u1.lPitch
911             + prect->left * GET_BPP(This->surface_desc);
912     }
913
914     return DD_OK;
915 }
916
917 HRESULT WINAPI
918 Main_DirectDrawSurface_PageLock(LPDIRECTDRAWSURFACE7 iface, DWORD dwFlags)
919 {
920     /* Some surface types should return DDERR_CANTPAGELOCK. */
921     return DD_OK;
922 }
923
924 HRESULT WINAPI
925 Main_DirectDrawSurface_PageUnlock(LPDIRECTDRAWSURFACE7 iface, DWORD dwFlags)
926 {
927     /* Some surface types should return DDERR_CANTPAGEUNLOCK, and we should
928      * keep track so we can return DDERR_NOTPAGELOCKED as appropriate. */
929     return DD_OK;
930 }
931
932 HRESULT WINAPI
933 Main_DirectDrawSurface_ReleaseDC(LPDIRECTDRAWSURFACE7 iface, HDC hDC)
934 {
935     HRESULT hr;
936     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
937
938     TRACE("(%p)->(%08x)\n",This,hDC);
939
940     if (!This->dc_in_use || This->hDC != hDC)
941         return DDERR_INVALIDPARAMS;
942
943     This->release_dc(This, hDC);
944
945     hr = IDirectDrawSurface7_Unlock(iface, NULL);
946     if (FAILED(hr)) return hr;
947
948     This->dc_in_use = FALSE;
949     This->hDC = 0;
950
951     return DD_OK;
952 }
953
954 /* Restore */
955
956 HRESULT WINAPI
957 Main_DirectDrawSurface_SetClipper(LPDIRECTDRAWSURFACE7 iface,
958                                   LPDIRECTDRAWCLIPPER pDDClipper)
959 {
960     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
961
962     TRACE("(%p)->(%p)\n",This,pDDClipper);
963     if (pDDClipper == ICOM_INTERFACE(This->clipper, IDirectDrawClipper))
964         return DD_OK;
965
966     if (This->clipper != NULL)
967         IDirectDrawClipper_Release(ICOM_INTERFACE(This->clipper,
968                                                   IDirectDrawClipper));
969
970     This->clipper = ICOM_OBJECT(IDirectDrawClipperImpl, IDirectDrawClipper,
971                                 pDDClipper);
972     if (pDDClipper != NULL)
973         IDirectDrawClipper_AddRef(pDDClipper);
974
975     return DD_OK;
976 }
977
978 HRESULT WINAPI
979 Main_DirectDrawSurface_SetColorKey(LPDIRECTDRAWSURFACE7 iface,
980                                    DWORD dwFlags, LPDDCOLORKEY pCKey)
981 {
982     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
983
984     TRACE("(%p)->(%08lx,%p)\n",This,dwFlags,pCKey);
985     if (pCKey == NULL)
986     {
987         FIXME("supposedly removing color key %lu\n",
988               dwFlags & ~DDCKEY_COLORSPACE);
989         return DD_OK;
990     }
991
992     switch (dwFlags & ~DDCKEY_COLORSPACE)
993     {
994     case DDCKEY_DESTBLT:
995         This->surface_desc.ddckCKDestBlt = *pCKey;
996         break;
997
998     case DDCKEY_DESTOVERLAY:
999         This->surface_desc.u3.ddckCKDestOverlay = *pCKey;
1000         break;
1001
1002     case DDCKEY_SRCOVERLAY:
1003         This->surface_desc.ddckCKSrcOverlay = *pCKey;
1004         break;
1005
1006     case DDCKEY_SRCBLT:
1007         This->surface_desc.ddckCKSrcBlt = *pCKey;
1008         break;
1009
1010     default:
1011         return DDERR_INVALIDPARAMS;
1012     }
1013
1014     return DD_OK;
1015 }
1016
1017 HRESULT WINAPI
1018 Main_DirectDrawSurface_SetLOD(LPDIRECTDRAWSURFACE7 iface, DWORD dwMaxLOD)
1019 {
1020     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
1021
1022     TRACE("(%p)->(%08lx)\n",This,dwMaxLOD);
1023     CHECK_TEXTURE(This);
1024
1025     This->max_lod = dwMaxLOD;
1026     return DD_OK;
1027 }
1028
1029 HRESULT WINAPI
1030 Main_DirectDrawSurface_SetOverlayPosition(LPDIRECTDRAWSURFACE7 iface,
1031                                           LONG X, LONG Y)
1032 {
1033     return DDERR_NOTAOVERLAYSURFACE;
1034 }
1035
1036 HRESULT WINAPI
1037 Main_DirectDrawSurface_SetPalette(LPDIRECTDRAWSURFACE7 iface,
1038                                   LPDIRECTDRAWPALETTE pPalette)
1039 {
1040     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
1041
1042     TRACE("(%p)->(%p)\n",This,pPalette);
1043     if (pPalette == ICOM_INTERFACE(This->palette, IDirectDrawPalette))
1044         return DD_OK;
1045
1046     if (This->palette != NULL) {
1047         if (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
1048             This->palette->flags &= ~DDPCAPS_PRIMARYSURFACE;
1049         IDirectDrawPalette_Release(ICOM_INTERFACE(This->palette,
1050                                                   IDirectDrawPalette));
1051     }
1052
1053     This->palette = ICOM_OBJECT(IDirectDrawPaletteImpl, IDirectDrawPalette,
1054                                 pPalette);
1055     if (pPalette != NULL) {
1056         IDirectDrawPalette_AddRef(pPalette);
1057         if (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
1058             This->palette->flags |= DDPCAPS_PRIMARYSURFACE;
1059     }
1060
1061     This->set_palette(This, This->palette);
1062
1063     return DD_OK;
1064 }
1065
1066 HRESULT WINAPI
1067 Main_DirectDrawSurface_SetPriority(LPDIRECTDRAWSURFACE7 iface,
1068                                    DWORD dwPriority)
1069 {
1070     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
1071
1072     TRACE("(%p)->(%08lx)\n",This,dwPriority);
1073     CHECK_TEXTURE(This);
1074
1075     This->priority = dwPriority;
1076     return DD_OK;
1077 }
1078
1079 /* Be careful when locking this: it is risky to call the object's AddRef
1080  * or Release holding a lock. */
1081 HRESULT WINAPI
1082 Main_DirectDrawSurface_SetPrivateData(LPDIRECTDRAWSURFACE7 iface,
1083                                       REFGUID tag, LPVOID pData,
1084                                       DWORD cbSize, DWORD dwFlags)
1085 {
1086     PrivateData* data;
1087     ICOM_THIS(IDirectDrawSurfaceImpl, iface);
1088
1089     data = find_private_data(This, tag);
1090     if (data == NULL)
1091     {
1092         data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data));
1093         if (data == NULL) return DDERR_OUTOFMEMORY;
1094
1095         data->tag = *tag;
1096         data->flags = dwFlags;
1097         data->uniqueness_value = This->uniqueness_value;
1098
1099         if (dwFlags & DDSPD_IUNKNOWNPTR)
1100         {
1101             data->ptr.object = (LPUNKNOWN)pData;
1102             data->size = sizeof(LPUNKNOWN);
1103             IUnknown_AddRef(data->ptr.object);
1104         }
1105         else
1106         {
1107             data->ptr.data = HeapAlloc(GetProcessHeap(), 0, cbSize);
1108             if (data->ptr.data == NULL)
1109             {
1110                 HeapFree(GetProcessHeap(), 0, data);
1111                 return DDERR_OUTOFMEMORY;
1112             }
1113         }
1114
1115         /* link it in */
1116         data->next = This->private_data;
1117         data->prev = NULL;
1118         if (This->private_data)
1119             This->private_data->prev = data;
1120         This->private_data = data;
1121
1122         return DD_OK;
1123     }
1124     else
1125     {
1126         /* I don't actually know how windows handles this case. The only
1127          * reason I don't just call FreePrivateData is because I want to
1128          * guarantee SetPrivateData working when using LPUNKNOWN or data
1129          * that is no larger than the old data. */
1130
1131         return E_FAIL;
1132     }
1133 }
1134
1135 /* SetSurfaceDesc */
1136
1137 HRESULT WINAPI
1138 Main_DirectDrawSurface_Unlock(LPDIRECTDRAWSURFACE7 iface, LPRECT pRect)
1139 {
1140     ICOM_THIS(IDirectDrawSurfaceImpl,iface);
1141
1142     TRACE("(%p)->Unlock(%p)\n",This,pRect);
1143
1144     This->unlock_update(This, pRect);
1145     if (This->aux_unlock)
1146         This->aux_unlock(This->aux_ctx, This->aux_data, pRect);
1147
1148     return DD_OK;
1149 }
1150
1151 HRESULT WINAPI
1152 Main_DirectDrawSurface_UpdateOverlay(LPDIRECTDRAWSURFACE7 iface,
1153                                      LPRECT pSrcRect,
1154                                      LPDIRECTDRAWSURFACE7 pDstSurface,
1155                                      LPRECT pDstRect, DWORD dwFlags,
1156                                      LPDDOVERLAYFX pFX)
1157 {
1158     return DDERR_UNSUPPORTED;
1159 }
1160
1161 /* MSDN: "not currently implemented." */
1162 HRESULT WINAPI
1163 Main_DirectDrawSurface_UpdateOverlayDisplay(LPDIRECTDRAWSURFACE7 iface,
1164                                             DWORD dwFlags)
1165 {
1166     return DDERR_UNSUPPORTED;
1167 }
1168
1169 HRESULT WINAPI
1170 Main_DirectDrawSurface_UpdateOverlayZOrder(LPDIRECTDRAWSURFACE7 iface,
1171                                            DWORD dwFlags,
1172                                            LPDIRECTDRAWSURFACE7 pDDSRef)
1173 {
1174     return DDERR_NOTAOVERLAYSURFACE;
1175 }