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