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