ddraw: Version 1 devices are aggregated by the surface that created them.
[wine] / dlls / ddrawex / ddraw.c
1 /*
2  * Copyright 2008 Stefan Dösinger for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #define COBJMACROS
20 #define NONAMELESSUNION
21
22 #include <stdarg.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wingdi.h"
26
27 #include "ddraw.h"
28 #include "d3d.h"
29
30 #include "ddrawex_private.h"
31 #include "wine/debug.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(ddrawex);
34
35 /******************************************************************************
36  * Helper functions for COM management
37  ******************************************************************************/
38 static IDirectDrawImpl *impl_from_IDirectDraw(IDirectDraw *iface)
39 {
40     return CONTAINING_RECORD(iface, IDirectDrawImpl, IDirectDraw_iface);
41 }
42
43 static IDirectDrawImpl *impl_from_IDirectDraw2(IDirectDraw2 *iface)
44 {
45     return CONTAINING_RECORD(iface, IDirectDrawImpl, IDirectDraw2_iface);
46 }
47
48 static IDirectDrawImpl *impl_from_IDirectDraw3(IDirectDraw3 *iface)
49 {
50     return CONTAINING_RECORD(iface, IDirectDrawImpl, IDirectDraw3_iface);
51 }
52
53 static IDirectDrawImpl *impl_from_IDirectDraw4(IDirectDraw4 *iface)
54 {
55     return CONTAINING_RECORD(iface, IDirectDrawImpl, IDirectDraw4_iface);
56 }
57
58 /******************************************************************************
59  * IDirectDraw4 -> ddraw.dll wrappers
60  ******************************************************************************/
61 static HRESULT WINAPI IDirectDraw4Impl_QueryInterface(IDirectDraw4 *iface, REFIID refiid,
62         void **obj)
63 {
64     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
65
66     TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(refiid), obj);
67     *obj = NULL;
68
69     if(!refiid)
70     {
71         return DDERR_INVALIDPARAMS;
72     }
73
74     if (IsEqualGUID( &IID_IDirectDraw7, refiid ) )
75     {
76         WARN("IDirectDraw7 not allowed in ddrawex.dll\n");
77         return E_NOINTERFACE;
78     }
79     else if ( IsEqualGUID( &IID_IUnknown, refiid ) ||
80               IsEqualGUID( &IID_IDirectDraw4, refiid ) )
81     {
82         *obj = &This->IDirectDraw4_iface;
83         TRACE("(%p) Returning IDirectDraw4 interface at %p\n", This, *obj);
84         IDirectDraw4_AddRef(&This->IDirectDraw4_iface);
85     }
86     else if ( IsEqualGUID( &IID_IDirectDraw3, refiid ) )
87     {
88         *obj = &This->IDirectDraw3_iface;
89         TRACE("(%p) Returning IDirectDraw3 interface at %p\n", This, *obj);
90         IDirectDraw3_AddRef(&This->IDirectDraw3_iface);
91     }
92     else if ( IsEqualGUID( &IID_IDirectDraw2, refiid ) )
93     {
94         *obj = &This->IDirectDraw2_iface;
95         TRACE("(%p) Returning IDirectDraw2 interface at %p\n", This, *obj);
96         IDirectDraw2_AddRef(&This->IDirectDraw2_iface);
97     }
98     else if ( IsEqualGUID( &IID_IDirectDraw, refiid ) )
99     {
100         *obj = &This->IDirectDraw_iface;
101         TRACE("(%p) Returning IDirectDraw interface at %p\n", This, *obj);
102         IDirectDraw_AddRef(&This->IDirectDraw_iface);
103     }
104     else if ( IsEqualGUID( &IID_IDirect3D  , refiid ) ||
105               IsEqualGUID( &IID_IDirect3D2 , refiid ) ||
106               IsEqualGUID( &IID_IDirect3D3 , refiid ) ||
107               IsEqualGUID( &IID_IDirect3D7 , refiid ) )
108     {
109         WARN("Direct3D not allowed in ddrawex.dll\n");
110         return E_NOINTERFACE;
111     }
112     /* Unknown interface */
113     else
114     {
115         ERR("(%p)->(%s, %p): No interface found\n", This, debugstr_guid(refiid), obj);
116         return E_NOINTERFACE;
117     }
118     TRACE("Returning S_OK\n");
119     return S_OK;
120 }
121
122 static HRESULT WINAPI IDirectDraw3Impl_QueryInterface(IDirectDraw3 *iface, REFIID refiid,
123         void **obj)
124 {
125     IDirectDrawImpl *This = impl_from_IDirectDraw3(iface);
126     TRACE("Thunking to IDirectDraw4\n");
127     return IDirectDraw4_QueryInterface(&This->IDirectDraw4_iface, refiid, obj);
128 }
129
130 static HRESULT WINAPI IDirectDraw2Impl_QueryInterface(IDirectDraw2 *iface, REFIID refiid,
131         void **obj)
132 {
133     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
134     TRACE("Thunking to IDirectDraw4\n");
135     return IDirectDraw4_QueryInterface(&This->IDirectDraw4_iface, refiid, obj);
136 }
137
138 static HRESULT WINAPI IDirectDrawImpl_QueryInterface(IDirectDraw *iface, REFIID refiid, void **obj)
139 {
140     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
141     TRACE("Thunking to IDirectDraw4\n");
142     return IDirectDraw4_QueryInterface(&This->IDirectDraw4_iface, refiid, obj);
143 }
144
145 static ULONG WINAPI IDirectDraw4Impl_AddRef(IDirectDraw4 *iface)
146 {
147     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
148     ULONG ref = InterlockedIncrement(&This->ref);
149
150     TRACE("(%p) : incrementing refcount from %u.\n", This, ref - 1);
151
152     return ref;
153 }
154
155 static ULONG WINAPI IDirectDraw3Impl_AddRef(IDirectDraw3 *iface)
156 {
157     IDirectDrawImpl *This = impl_from_IDirectDraw3(iface);
158     TRACE("Thunking to IDirectDraw4\n");
159     return IDirectDraw4_AddRef(&This->IDirectDraw4_iface);
160 }
161
162 static ULONG WINAPI IDirectDraw2Impl_AddRef(IDirectDraw2 *iface)
163 {
164     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
165     TRACE("Thunking to IDirectDraw4\n");
166     return IDirectDraw4_AddRef(&This->IDirectDraw4_iface);
167 }
168
169 static ULONG WINAPI IDirectDrawImpl_AddRef(IDirectDraw *iface)
170 {
171     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
172     TRACE("Thunking to IDirectDraw4\n");
173     return IDirectDraw4_AddRef(&This->IDirectDraw4_iface);
174 }
175
176 static ULONG WINAPI IDirectDraw4Impl_Release(IDirectDraw4 *iface)
177 {
178     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
179     ULONG ref = InterlockedDecrement(&This->ref);
180
181     TRACE("(%p) : decrementing refcount to %u.\n", This, ref);
182
183     if(ref == 0)
184     {
185         TRACE("Destroying object\n");
186         IDirectDraw4_Release(This->parent);
187         HeapFree(GetProcessHeap(), 0, This);
188     }
189     return ref;
190 }
191
192 static ULONG WINAPI IDirectDraw3Impl_Release(IDirectDraw3 *iface)
193 {
194     IDirectDrawImpl *This = impl_from_IDirectDraw3(iface);
195     TRACE("Thunking to IDirectDraw4\n");
196     return IDirectDraw4_Release(&This->IDirectDraw4_iface);
197 }
198
199 static ULONG WINAPI IDirectDraw2Impl_Release(IDirectDraw2 *iface)
200 {
201     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
202     TRACE("Thunking to IDirectDraw4\n");
203     return IDirectDraw4_Release(&This->IDirectDraw4_iface);
204 }
205
206 static ULONG WINAPI IDirectDrawImpl_Release(IDirectDraw *iface)
207 {
208     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
209     TRACE("Thunking to IDirectDraw4\n");
210     return IDirectDraw4_Release(&This->IDirectDraw4_iface);
211 }
212
213 static HRESULT WINAPI IDirectDraw4Impl_Compact(IDirectDraw4 *iface)
214 {
215     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
216     TRACE("(%p)\n", This);
217
218     return IDirectDraw4_Compact(This->parent);
219 }
220
221 static HRESULT WINAPI IDirectDraw3Impl_Compact(IDirectDraw3 *iface)
222 {
223     IDirectDrawImpl *This = impl_from_IDirectDraw3(iface);
224     TRACE("Thunking to IDirectDraw4\n");
225     return IDirectDraw4_Compact(&This->IDirectDraw4_iface);
226 }
227
228 static HRESULT WINAPI IDirectDraw2Impl_Compact(IDirectDraw2 *iface)
229 {
230     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
231     TRACE("Thunking to IDirectDraw4\n");
232     return IDirectDraw4_Compact(&This->IDirectDraw4_iface);
233 }
234
235 static HRESULT WINAPI IDirectDrawImpl_Compact(IDirectDraw *iface)
236 {
237     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
238     TRACE("Thunking to IDirectDraw4\n");
239     return IDirectDraw4_Compact(&This->IDirectDraw4_iface);
240 }
241
242 static HRESULT WINAPI IDirectDraw4Impl_CreateClipper(IDirectDraw4 *iface, DWORD Flags,
243         IDirectDrawClipper **clipper, IUnknown *UnkOuter)
244 {
245     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
246     TRACE("(%p)->(0x%08x, %p, %p)\n", This, Flags, clipper, UnkOuter);
247
248     if(UnkOuter != NULL)
249     {
250         /* This may require a wrapper interface for clippers too which handles this */
251         FIXME("Test and implement Aggregation for ddrawex clippers\n");
252     }
253
254     return IDirectDraw4_CreateClipper(This->parent, Flags, clipper, UnkOuter);
255 }
256
257 static HRESULT WINAPI IDirectDraw3Impl_CreateClipper(IDirectDraw3 *iface, DWORD Flags,
258         IDirectDrawClipper **clipper, IUnknown *UnkOuter)
259 {
260     IDirectDrawImpl *This = impl_from_IDirectDraw3(iface);
261     TRACE("Thunking to IDirectDraw4\n");
262     return IDirectDraw4_CreateClipper(&This->IDirectDraw4_iface, Flags, clipper, UnkOuter);
263 }
264
265 static HRESULT WINAPI IDirectDraw2Impl_CreateClipper(IDirectDraw2 *iface, DWORD Flags,
266         IDirectDrawClipper **clipper, IUnknown *UnkOuter)
267 {
268     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
269     TRACE("Thunking to IDirectDraw4\n");
270     return IDirectDraw4_CreateClipper(&This->IDirectDraw4_iface, Flags, clipper, UnkOuter);
271 }
272
273 static HRESULT WINAPI IDirectDrawImpl_CreateClipper(IDirectDraw *iface, DWORD Flags,
274         IDirectDrawClipper **clipper, IUnknown *UnkOuter)
275 {
276     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
277     TRACE("Thunking to IDirectDraw4\n");
278     return IDirectDraw4_CreateClipper(&This->IDirectDraw4_iface, Flags, clipper, UnkOuter);
279 }
280
281 static HRESULT WINAPI IDirectDraw4Impl_CreatePalette(IDirectDraw4 *iface, DWORD Flags,
282         PALETTEENTRY *ColorTable, IDirectDrawPalette **Palette, IUnknown *UnkOuter)
283 {
284     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
285     TRACE("(%p)(0x%08x,%p,%p,%p)\n", This, Flags, ColorTable, Palette, UnkOuter);
286
287     if(UnkOuter != NULL)
288     {
289         /* This may require a wrapper interface for palettes too which handles this */
290         FIXME("Test and implement Aggregation for ddrawex palettes\n");
291     }
292
293     return IDirectDraw4_CreatePalette(This->parent, Flags, ColorTable, Palette, UnkOuter);
294 }
295
296 static HRESULT WINAPI IDirectDraw3Impl_CreatePalette(IDirectDraw3 *iface, DWORD Flags,
297         PALETTEENTRY *ColorTable, IDirectDrawPalette **Palette, IUnknown *UnkOuter)
298 {
299     IDirectDrawImpl *This = impl_from_IDirectDraw3(iface);
300     TRACE("Thunking to IDirectDraw4\n");
301     return IDirectDraw4_CreatePalette(&This->IDirectDraw4_iface, Flags, ColorTable, Palette,
302             UnkOuter);
303 }
304
305 static HRESULT WINAPI IDirectDraw2Impl_CreatePalette(IDirectDraw2 *iface, DWORD Flags,
306         PALETTEENTRY *ColorTable, IDirectDrawPalette **Palette, IUnknown *UnkOuter)
307 {
308     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
309     TRACE("Thunking to IDirectDraw4\n");
310     return IDirectDraw4_CreatePalette(&This->IDirectDraw4_iface, Flags, ColorTable, Palette,
311             UnkOuter);
312 }
313
314 static HRESULT WINAPI IDirectDrawImpl_CreatePalette(IDirectDraw *iface, DWORD Flags,
315         PALETTEENTRY *ColorTable, IDirectDrawPalette **Palette, IUnknown *UnkOuter)
316 {
317     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
318     TRACE("Thunking to IDirectDraw4\n");
319     return IDirectDraw4_CreatePalette(&This->IDirectDraw4_iface, Flags, ColorTable, Palette,
320             UnkOuter);
321 }
322
323 static HRESULT WINAPI IDirectDraw4Impl_CreateSurface(IDirectDraw4 *iface, DDSURFACEDESC2 *DDSD,
324         IDirectDrawSurface4 **Surf, IUnknown *UnkOuter)
325 {
326     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
327     HRESULT hr;
328     const DWORD perm_dc_flags = DDSCAPS_VIDEOMEMORY | DDSCAPS_SYSTEMMEMORY;
329     BOOL permanent_dc;
330     TRACE("(%p)(%p, %p, %p)\n", This, DDSD, Surf, UnkOuter);
331
332     if(UnkOuter != NULL)
333     {
334         /* Handle this in this dll. Don't forward the UnkOuter to ddraw.dll */
335         FIXME("Implement aggregation for ddrawex surfaces\n");
336     }
337
338     /* plain ddraw.dll refuses to create a surface that has both VIDMEM and SYSMEM flags
339      * set. In ddrawex this succeeds, and the GetDC() call changes the behavior. The DC
340      * is permanently valid, and the surface can be locked between GetDC() and ReleaseDC()
341      * calls. GetDC() can be called more than once too
342      */
343     if((DDSD->ddsCaps.dwCaps & perm_dc_flags) == perm_dc_flags)
344     {
345         permanent_dc = TRUE;
346         DDSD->ddsCaps.dwCaps &= ~DDSCAPS_VIDEOMEMORY;
347         DDSD->ddsCaps.dwCaps |= DDSCAPS_OWNDC;
348     }
349     else
350     {
351         permanent_dc = FALSE;
352     }
353
354     hr = IDirectDraw4_CreateSurface(This->parent, DDSD, Surf, UnkOuter);
355     *Surf = dds_get_outer(*Surf);
356     if(permanent_dc) prepare_permanent_dc(*Surf);
357     return hr;
358 }
359
360 void DDSD_to_DDSD2(const DDSURFACEDESC *in, DDSURFACEDESC2 *out)
361 {
362     memset(out, 0, sizeof(*out));
363     out->dwSize = sizeof(*out);
364     out->dwFlags = in->dwFlags;
365     if(in->dwFlags & DDSD_WIDTH) out->dwWidth = in->dwWidth;
366     if(in->dwFlags & DDSD_HEIGHT) out->dwHeight = in->dwHeight;
367     if(in->dwFlags & DDSD_PIXELFORMAT) out->u4.ddpfPixelFormat = in->ddpfPixelFormat;
368     if(in->dwFlags & DDSD_CAPS) out->ddsCaps.dwCaps = in->ddsCaps.dwCaps;
369     if(in->dwFlags & DDSD_PITCH) out->u1.lPitch = in->u1.lPitch;
370     if(in->dwFlags & DDSD_BACKBUFFERCOUNT) out->dwBackBufferCount = in->dwBackBufferCount;
371     if(in->dwFlags & DDSD_ZBUFFERBITDEPTH) out->u2.dwMipMapCount = in->u2.dwZBufferBitDepth; /* same union */
372     if(in->dwFlags & DDSD_ALPHABITDEPTH) out->dwAlphaBitDepth = in->dwAlphaBitDepth;
373     /* DDraw(native, and wine) does not set the DDSD_LPSURFACE, so always copy */
374     out->lpSurface = in->lpSurface;
375     if(in->dwFlags & DDSD_CKDESTOVERLAY) out->u3.ddckCKDestOverlay = in->ddckCKDestOverlay;
376     if(in->dwFlags & DDSD_CKDESTBLT) out->ddckCKDestBlt = in->ddckCKDestBlt;
377     if(in->dwFlags & DDSD_CKSRCOVERLAY) out->ddckCKSrcOverlay = in->ddckCKSrcOverlay;
378     if(in->dwFlags & DDSD_CKSRCBLT) out->ddckCKSrcBlt = in->ddckCKSrcBlt;
379     if(in->dwFlags & DDSD_MIPMAPCOUNT) out->u2.dwMipMapCount = in->u2.dwMipMapCount;
380     if(in->dwFlags & DDSD_REFRESHRATE) out->u2.dwRefreshRate = in->u2.dwRefreshRate;
381     if(in->dwFlags & DDSD_LINEARSIZE) out->u1.dwLinearSize = in->u1.dwLinearSize;
382     /* Does not exist in DDSURFACEDESC:
383      * DDSD_TEXTURESTAGE, DDSD_FVF, DDSD_SRCVBHANDLE,
384      */
385 }
386
387 void DDSD2_to_DDSD(const DDSURFACEDESC2 *in, DDSURFACEDESC *out)
388 {
389     memset(out, 0, sizeof(*out));
390     out->dwSize = sizeof(*out);
391     out->dwFlags = in->dwFlags;
392     if(in->dwFlags & DDSD_WIDTH) out->dwWidth = in->dwWidth;
393     if(in->dwFlags & DDSD_HEIGHT) out->dwHeight = in->dwHeight;
394     if(in->dwFlags & DDSD_PIXELFORMAT) out->ddpfPixelFormat = in->u4.ddpfPixelFormat;
395     if(in->dwFlags & DDSD_CAPS) out->ddsCaps.dwCaps = in->ddsCaps.dwCaps;
396     if(in->dwFlags & DDSD_PITCH) out->u1.lPitch = in->u1.lPitch;
397     if(in->dwFlags & DDSD_BACKBUFFERCOUNT) out->dwBackBufferCount = in->dwBackBufferCount;
398     if(in->dwFlags & DDSD_ZBUFFERBITDEPTH) out->u2.dwZBufferBitDepth = in->u2.dwMipMapCount; /* same union */
399     if(in->dwFlags & DDSD_ALPHABITDEPTH) out->dwAlphaBitDepth = in->dwAlphaBitDepth;
400     /* DDraw(native, and wine) does not set the DDSD_LPSURFACE, so always copy */
401     out->lpSurface = in->lpSurface;
402     if(in->dwFlags & DDSD_CKDESTOVERLAY) out->ddckCKDestOverlay = in->u3.ddckCKDestOverlay;
403     if(in->dwFlags & DDSD_CKDESTBLT) out->ddckCKDestBlt = in->ddckCKDestBlt;
404     if(in->dwFlags & DDSD_CKSRCOVERLAY) out->ddckCKSrcOverlay = in->ddckCKSrcOverlay;
405     if(in->dwFlags & DDSD_CKSRCBLT) out->ddckCKSrcBlt = in->ddckCKSrcBlt;
406     if(in->dwFlags & DDSD_MIPMAPCOUNT) out->u2.dwMipMapCount = in->u2.dwMipMapCount;
407     if(in->dwFlags & DDSD_REFRESHRATE) out->u2.dwRefreshRate = in->u2.dwRefreshRate;
408     if(in->dwFlags & DDSD_LINEARSIZE) out->u1.dwLinearSize = in->u1.dwLinearSize;
409     /* Does not exist in DDSURFACEDESC:
410      * DDSD_TEXTURESTAGE, DDSD_FVF, DDSD_SRCVBHANDLE,
411      */
412     if(in->dwFlags & DDSD_TEXTURESTAGE) WARN("Does not exist in DDSURFACEDESC: DDSD_TEXTURESTAGE\n");
413     if(in->dwFlags & DDSD_FVF) WARN("Does not exist in DDSURFACEDESC: DDSD_FVF\n");
414     if(in->dwFlags & DDSD_SRCVBHANDLE) WARN("Does not exist in DDSURFACEDESC: DDSD_SRCVBHANDLE\n");
415     out->dwFlags &= ~(DDSD_TEXTURESTAGE | DDSD_FVF | DDSD_SRCVBHANDLE);
416 }
417
418 static HRESULT WINAPI IDirectDraw3Impl_CreateSurface(IDirectDraw3 *iface, DDSURFACEDESC *DDSD,
419         IDirectDrawSurface **Surf, IUnknown *UnkOuter)
420 {
421     IDirectDrawImpl *This = impl_from_IDirectDraw3(iface);
422     DDSURFACEDESC2 ddsd2;
423     IDirectDrawSurface4 *surf4 = NULL;
424     HRESULT hr;
425     TRACE("Thunking to IDirectDraw4\n");
426
427     DDSD_to_DDSD2(DDSD, &ddsd2);
428
429     hr = IDirectDraw4_CreateSurface(&This->IDirectDraw4_iface, &ddsd2, &surf4, UnkOuter);
430     if(FAILED(hr))
431     {
432         *Surf = NULL;
433         return hr;
434     }
435
436     TRACE("Got surface %p\n", surf4);
437     IDirectDrawSurface4_QueryInterface(surf4, &IID_IDirectDrawSurface, (void **) Surf);
438     IDirectDrawSurface4_Release(surf4);
439     return hr;
440 }
441
442 static HRESULT WINAPI IDirectDraw2Impl_CreateSurface(IDirectDraw2 *iface, DDSURFACEDESC *DDSD,
443         IDirectDrawSurface **Surf, IUnknown *UnkOuter)
444 {
445     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
446     TRACE("Thunking to IDirectDraw3\n");
447     return IDirectDraw3_CreateSurface(&This->IDirectDraw3_iface, DDSD, Surf, UnkOuter);
448 }
449
450 static HRESULT WINAPI IDirectDrawImpl_CreateSurface(IDirectDraw *iface, DDSURFACEDESC *DDSD,
451         IDirectDrawSurface **Surf, IUnknown *UnkOuter)
452 {
453     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
454     TRACE("Thunking to IDirectDraw3\n");
455     return IDirectDraw3_CreateSurface(&This->IDirectDraw3_iface, DDSD, Surf, UnkOuter);
456 }
457
458 static HRESULT WINAPI IDirectDraw4Impl_DuplicateSurface(IDirectDraw4 *iface,
459         IDirectDrawSurface4 *src, IDirectDrawSurface4 **dst)
460 {
461     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
462     FIXME("(%p)->(%p,%p). Create a wrapper surface\n", This, src, dst);
463
464     return IDirectDraw4_DuplicateSurface(This->parent, dds_get_inner(src), dst);
465 }
466
467 static HRESULT WINAPI IDirectDraw3Impl_DuplicateSurface(IDirectDraw3 *iface,
468         IDirectDrawSurface *src, IDirectDrawSurface **dst)
469 {
470     IDirectDrawImpl *This = impl_from_IDirectDraw3(iface);
471     IDirectDrawSurface4 *src_4;
472     IDirectDrawSurface4 *dst_4;
473     HRESULT hr;
474
475     TRACE("Thunking to IDirectDraw4\n");
476     IDirectDrawSurface_QueryInterface(src, &IID_IDirectDrawSurface4, (void **) &src_4);
477     hr = IDirectDraw4_DuplicateSurface(&This->IDirectDraw4_iface, src_4, &dst_4);
478     IDirectDrawSurface4_Release(src_4);
479
480     if(FAILED(hr))
481     {
482         *dst = NULL;
483         return hr;
484     }
485     IDirectDrawSurface4_QueryInterface(dst_4, &IID_IDirectDrawSurface, (void **) dst);
486     IDirectDrawSurface4_Release(dst_4);
487     return hr;
488 }
489
490 static HRESULT WINAPI IDirectDraw2Impl_DuplicateSurface(IDirectDraw2 *iface,
491         IDirectDrawSurface *src, IDirectDrawSurface **dst)
492 {
493     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
494     TRACE("Thunking to IDirectDraw3\n");
495     return IDirectDraw3_DuplicateSurface(&This->IDirectDraw3_iface, src, dst);
496 }
497
498 static HRESULT WINAPI IDirectDrawImpl_DuplicateSurface(IDirectDraw *iface, IDirectDrawSurface *src,
499         IDirectDrawSurface **dst)
500 {
501     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
502     TRACE("Thunking to IDirectDraw3\n");
503     return IDirectDraw3_DuplicateSurface(&This->IDirectDraw3_iface, src, dst);
504 }
505
506 static HRESULT WINAPI IDirectDraw4Impl_EnumDisplayModes(IDirectDraw4 *iface, DWORD Flags,
507         DDSURFACEDESC2 *DDSD, void *Context, LPDDENUMMODESCALLBACK2 cb)
508 {
509     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
510     TRACE("(%p)->(0x%08x,%p,%p,%p)\n", This, Flags, DDSD, Context, cb);
511
512     return IDirectDraw4_EnumDisplayModes(This->parent, Flags, DDSD, Context, cb);
513 }
514
515 struct enummodes_ctx
516 {
517     LPDDENUMMODESCALLBACK orig_cb;
518     void *orig_ctx;
519 };
520
521 static HRESULT WINAPI
522 enum_modes_cb2(DDSURFACEDESC2 *ddsd2, void *vctx)
523 {
524     struct enummodes_ctx *ctx = vctx;
525     DDSURFACEDESC ddsd;
526
527     DDSD2_to_DDSD(ddsd2, &ddsd);
528     return ctx->orig_cb(&ddsd, ctx->orig_ctx);
529 }
530
531 static HRESULT WINAPI IDirectDraw3Impl_EnumDisplayModes(IDirectDraw3 *iface, DWORD Flags,
532         DDSURFACEDESC *DDSD, void *Context, LPDDENUMMODESCALLBACK cb)
533 {
534     IDirectDrawImpl *This = impl_from_IDirectDraw3(iface);
535     DDSURFACEDESC2 ddsd2;
536     struct enummodes_ctx ctx;
537     TRACE("(%p)->(0x%08x,%p,%p,%p): Thunking to IDirectDraw4\n", This, Flags, DDSD, Context, cb);
538
539     DDSD_to_DDSD2(DDSD, &ddsd2);
540     ctx.orig_cb = cb;
541     ctx.orig_ctx = Context;
542     return IDirectDraw4_EnumDisplayModes(&This->IDirectDraw4_iface, Flags, &ddsd2, &ctx,
543             enum_modes_cb2);
544 }
545
546 static HRESULT WINAPI IDirectDraw2Impl_EnumDisplayModes(IDirectDraw2 *iface, DWORD Flags,
547         DDSURFACEDESC *DDSD, void *Context, LPDDENUMMODESCALLBACK cb)
548 {
549     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
550     TRACE("(%p)->(0x%08x,%p,%p,%p): Thunking to IDirectDraw3\n", This, Flags, DDSD, Context, cb);
551     return IDirectDraw3_EnumDisplayModes(&This->IDirectDraw3_iface, Flags, DDSD, Context, cb);
552 }
553
554 static HRESULT WINAPI IDirectDrawImpl_EnumDisplayModes(IDirectDraw *iface, DWORD Flags,
555         DDSURFACEDESC *DDSD, void *Context, LPDDENUMMODESCALLBACK cb)
556 {
557     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
558     TRACE("(%p)->(0x%08x,%p,%p,%p): Thunking to IDirectDraw3\n", This, Flags, DDSD, Context, cb);
559     return IDirectDraw3_EnumDisplayModes(&This->IDirectDraw3_iface, Flags, DDSD, Context, cb);
560 }
561
562 struct enumsurfaces4_ctx
563 {
564     LPDDENUMSURFACESCALLBACK2 orig_cb;
565     void *orig_ctx;
566 };
567
568 static HRESULT WINAPI
569 enum_surfaces_wrapper(IDirectDrawSurface4 *surf4, DDSURFACEDESC2 *ddsd2, void *vctx)
570 {
571     struct enumsurfaces4_ctx *ctx = vctx;
572     IDirectDrawSurface4 *outer = dds_get_outer(surf4);
573     IDirectDrawSurface4_AddRef(outer);
574     IDirectDrawSurface4_Release(surf4);
575     TRACE("Returning wrapper surface %p for enumerated inner surface %p\n", outer, surf4);
576     return ctx->orig_cb(outer, ddsd2, ctx->orig_ctx);
577 }
578
579 static HRESULT WINAPI IDirectDraw4Impl_EnumSurfaces(IDirectDraw4 *iface, DWORD Flags,
580         DDSURFACEDESC2 *DDSD, void *Context, LPDDENUMSURFACESCALLBACK2 Callback)
581 {
582     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
583     struct enumsurfaces4_ctx ctx;
584     TRACE("(%p)->(0x%08x,%p,%p,%p)\n", This, Flags, DDSD, Context, Callback);
585
586     ctx.orig_cb = Callback;
587     ctx.orig_ctx = Context;
588     return IDirectDraw4Impl_EnumSurfaces(This->parent, Flags, DDSD, &ctx, enum_surfaces_wrapper);
589 }
590
591 struct enumsurfaces_ctx
592 {
593     LPDDENUMSURFACESCALLBACK orig_cb;
594     void *orig_ctx;
595 };
596
597 static HRESULT WINAPI
598 enum_surfaces_cb2(IDirectDrawSurface4 *surf4, DDSURFACEDESC2 *ddsd2, void *vctx)
599 {
600     struct enumsurfaces_ctx *ctx = vctx;
601     IDirectDrawSurface *surf1;
602     DDSURFACEDESC ddsd;
603
604     /* Keep the reference, it goes to the application */
605     IDirectDrawSurface4_QueryInterface(surf4, &IID_IDirectDrawSurface, (void **) &surf1);
606     /* Release the reference this function got */
607     IDirectDrawSurface4_Release(surf4);
608
609     DDSD2_to_DDSD(ddsd2, &ddsd);
610     return ctx->orig_cb(surf1, &ddsd, ctx->orig_ctx);
611 }
612
613 static HRESULT WINAPI IDirectDraw3Impl_EnumSurfaces(IDirectDraw3 *iface, DWORD Flags,
614         DDSURFACEDESC *DDSD, void *Context, LPDDENUMSURFACESCALLBACK Callback)
615 {
616     IDirectDrawImpl *This = impl_from_IDirectDraw3(iface);
617     DDSURFACEDESC2 ddsd2;
618     struct enumsurfaces_ctx ctx;
619     TRACE("(%p)->(0x%08x,%p,%p,%p): Thunking to IDirectDraw4\n", This, Flags, DDSD, Context, Callback);
620
621     DDSD_to_DDSD2(DDSD, &ddsd2);
622     ctx.orig_cb = Callback;
623     ctx.orig_ctx = Context;
624     return IDirectDraw4_EnumSurfaces(&This->IDirectDraw4_iface, Flags, &ddsd2, &ctx,
625             enum_surfaces_cb2);
626 }
627
628 static HRESULT WINAPI IDirectDraw2Impl_EnumSurfaces(IDirectDraw2 *iface, DWORD Flags,
629         DDSURFACEDESC *DDSD, void *Context, LPDDENUMSURFACESCALLBACK Callback)
630 {
631     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
632     TRACE("(%p)->(0x%08x,%p,%p,%p): Thunking to IDirectDraw3\n", This, Flags, DDSD, Context, Callback);
633     return IDirectDraw3_EnumSurfaces(&This->IDirectDraw3_iface, Flags, DDSD, Context, Callback);
634 }
635
636 static HRESULT WINAPI IDirectDrawImpl_EnumSurfaces(IDirectDraw *iface, DWORD Flags,
637         DDSURFACEDESC *DDSD, void *Context, LPDDENUMSURFACESCALLBACK Callback)
638 {
639     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
640     TRACE("(%p)->(0x%08x,%p,%p,%p): Thunking to IDirectDraw3\n", This, Flags, DDSD, Context, Callback);
641     return IDirectDraw3_EnumSurfaces(&This->IDirectDraw3_iface, Flags, DDSD, Context, Callback);
642 }
643
644 static HRESULT WINAPI IDirectDraw4Impl_FlipToGDISurface(IDirectDraw4 *iface)
645 {
646     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
647     TRACE("(%p)\n", This);
648
649     return IDirectDraw4_FlipToGDISurface(This->parent);
650 }
651
652 static HRESULT WINAPI IDirectDraw3Impl_FlipToGDISurface(IDirectDraw3 *iface)
653 {
654     IDirectDrawImpl *This = impl_from_IDirectDraw3(iface);
655     TRACE("(%p). Thunking to IDirectDraw4\n", This);
656     return IDirectDraw4_FlipToGDISurface(&This->IDirectDraw4_iface);
657 }
658
659 static HRESULT WINAPI IDirectDraw2Impl_FlipToGDISurface(IDirectDraw2 *iface)
660 {
661     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
662     TRACE("(%p). Thunking to IDirectDraw4\n", This);
663     return IDirectDraw4_FlipToGDISurface(&This->IDirectDraw4_iface);
664 }
665
666 static HRESULT WINAPI IDirectDrawImpl_FlipToGDISurface(IDirectDraw *iface)
667 {
668     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
669     TRACE("(%p). Thunking to IDirectDraw4\n", This);
670     return IDirectDraw4_FlipToGDISurface(&This->IDirectDraw4_iface);
671 }
672
673 static HRESULT WINAPI IDirectDraw4Impl_GetCaps(IDirectDraw4 *iface, DDCAPS *DriverCaps,
674         DDCAPS *HELCaps)
675 {
676     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
677     TRACE("(%p)->(%p,%p)\n", This, DriverCaps, HELCaps);
678     return IDirectDraw4_GetCaps(This->parent, DriverCaps, HELCaps);
679 }
680
681 static HRESULT WINAPI IDirectDraw3Impl_GetCaps(IDirectDraw3 *iface, DDCAPS *DriverCaps,
682         DDCAPS *HELCaps)
683 {
684     IDirectDrawImpl *This = impl_from_IDirectDraw3(iface);
685     TRACE("(%p)->(%p,%p). Thunking to IDirectDraw4\n", This, DriverCaps, HELCaps);
686     return IDirectDraw4_GetCaps(&This->IDirectDraw4_iface, DriverCaps, HELCaps);
687 }
688
689 static HRESULT WINAPI IDirectDraw2Impl_GetCaps(IDirectDraw2 *iface, DDCAPS *DriverCaps,
690         DDCAPS *HELCaps)
691 {
692     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
693     TRACE("(%p)->(%p,%p). Thunking to IDirectDraw4\n", This, DriverCaps, HELCaps);
694     return IDirectDraw4_GetCaps(&This->IDirectDraw4_iface, DriverCaps, HELCaps);
695 }
696
697 static HRESULT WINAPI IDirectDrawImpl_GetCaps(IDirectDraw *iface, DDCAPS *DriverCaps,
698         DDCAPS *HELCaps)
699 {
700     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
701     TRACE("(%p)->(%p,%p). Thunking to IDirectDraw4\n", This, DriverCaps, HELCaps);
702     return IDirectDraw4_GetCaps(&This->IDirectDraw4_iface, DriverCaps, HELCaps);
703 }
704
705 static HRESULT WINAPI IDirectDraw4Impl_GetDisplayMode(IDirectDraw4 *iface, DDSURFACEDESC2 *DDSD)
706 {
707     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
708     TRACE("(%p)->(%p)\n", This, DDSD);
709     return IDirectDraw4_GetDisplayMode(This->parent, DDSD);
710 }
711
712 static HRESULT WINAPI IDirectDraw3Impl_GetDisplayMode(IDirectDraw3 *iface, DDSURFACEDESC *DDSD)
713 {
714     IDirectDrawImpl *This = impl_from_IDirectDraw3(iface);
715     DDSURFACEDESC2 ddsd2;
716     HRESULT hr;
717
718     TRACE("(%p)->(%p): Thunking to IDirectDraw4\n", This, DDSD);
719     hr = IDirectDraw4_GetDisplayMode(&This->IDirectDraw4_iface, &ddsd2);
720     DDSD2_to_DDSD(&ddsd2, DDSD);
721     return hr;
722 }
723
724 static HRESULT WINAPI IDirectDraw2Impl_GetDisplayMode(IDirectDraw2 *iface, DDSURFACEDESC *DDSD)
725 {
726     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
727     TRACE("(%p)->(%p): Thunking to IDirectDraw3\n", This, DDSD);
728     return IDirectDraw3_GetDisplayMode(&This->IDirectDraw3_iface, DDSD);
729 }
730
731 static HRESULT WINAPI IDirectDrawImpl_GetDisplayMode(IDirectDraw *iface, DDSURFACEDESC *DDSD)
732 {
733     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
734     TRACE("(%p)->(%p): Thunking to IDirectDraw3\n", This, DDSD);
735     return IDirectDraw3_GetDisplayMode(&This->IDirectDraw3_iface, DDSD);
736 }
737
738 static HRESULT WINAPI IDirectDraw4Impl_GetFourCCCodes(IDirectDraw4 *iface, DWORD *NumCodes,
739         DWORD *Codes)
740 {
741     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
742     TRACE("(%p)->(%p, %p):\n", This, NumCodes, Codes);
743     return IDirectDraw4_GetFourCCCodes(This->parent, NumCodes, Codes);
744 }
745
746 static HRESULT WINAPI IDirectDraw3Impl_GetFourCCCodes(IDirectDraw3 *iface, DWORD *NumCodes,
747         DWORD *Codes)
748 {
749     IDirectDrawImpl *This = impl_from_IDirectDraw3(iface);
750     TRACE("(%p)->(%p, %p): Thunking to IDirectDraw4\n", This, NumCodes, Codes);
751     return IDirectDraw4_GetFourCCCodes(&This->IDirectDraw4_iface, NumCodes, Codes);
752 }
753
754 static HRESULT WINAPI IDirectDraw2Impl_GetFourCCCodes(IDirectDraw2 *iface, DWORD *NumCodes,
755         DWORD *Codes)
756 {
757     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
758     TRACE("(%p)->(%p, %p): Thunking to IDirectDraw4\n", This, NumCodes, Codes);
759     return IDirectDraw4_GetFourCCCodes(&This->IDirectDraw4_iface, NumCodes, Codes);
760 }
761
762 static HRESULT WINAPI IDirectDrawImpl_GetFourCCCodes(IDirectDraw *iface, DWORD *NumCodes,
763         DWORD *Codes)
764 {
765     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
766     TRACE("(%p)->(%p, %p): Thunking to IDirectDraw4\n", This, NumCodes, Codes);
767     return IDirectDraw4_GetFourCCCodes(&This->IDirectDraw4_iface, NumCodes, Codes);
768 }
769
770 static HRESULT WINAPI IDirectDraw4Impl_GetGDISurface(IDirectDraw4 *iface,
771         IDirectDrawSurface4 **GDISurface)
772 {
773     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
774     IDirectDrawSurface4 *inner = NULL;
775     HRESULT hr;
776     TRACE("(%p)->(%p)\n", This, GDISurface);
777
778     hr = IDirectDraw4_GetGDISurface(This->parent, &inner);
779     if(SUCCEEDED(hr))
780     {
781         *GDISurface = dds_get_outer(inner);
782         IDirectDrawSurface4_AddRef(*GDISurface);
783         IDirectDrawSurface4_Release(inner);
784     }
785     else
786     {
787         *GDISurface = NULL;
788     }
789     return hr;
790 }
791
792 static HRESULT WINAPI IDirectDraw3Impl_GetGDISurface(IDirectDraw3 *iface,
793         IDirectDrawSurface **GDISurface)
794 {
795     IDirectDrawImpl *This = impl_from_IDirectDraw3(iface);
796     IDirectDrawSurface4 *surf4;
797     HRESULT hr;
798     TRACE("(%p)->(%p): Thunking to IDirectDraw4\n", This, GDISurface);
799
800     hr = IDirectDraw4_GetGDISurface(&This->IDirectDraw4_iface, &surf4);
801     if(FAILED(hr)) {
802         *GDISurface = NULL;
803         return hr;
804     }
805
806     /* Release the reference we got from the DDraw4 call, and pass a reference to the caller */
807     IDirectDrawSurface4_QueryInterface(surf4, &IID_IDirectDrawSurface, (void **) GDISurface);
808     IDirectDrawSurface4_Release(surf4);
809     return hr;
810 }
811
812 static HRESULT WINAPI IDirectDraw2Impl_GetGDISurface(IDirectDraw2 *iface,
813         IDirectDrawSurface **GDISurface)
814 {
815     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
816     TRACE("(%p)->(%p): Thunking to IDirectDraw3\n", This, GDISurface);
817     return IDirectDraw3_GetGDISurface(&This->IDirectDraw3_iface, GDISurface);
818 }
819
820 static HRESULT WINAPI IDirectDrawImpl_GetGDISurface(IDirectDraw *iface,
821         IDirectDrawSurface **GDISurface)
822 {
823     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
824     TRACE("(%p)->(%p): Thunking to IDirectDraw3\n", This, GDISurface);
825     return IDirectDraw3_GetGDISurface(&This->IDirectDraw3_iface, GDISurface);
826 }
827
828 static HRESULT WINAPI IDirectDraw4Impl_GetMonitorFrequency(IDirectDraw4 *iface, DWORD *Freq)
829 {
830     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
831     TRACE("(%p)->(%p)\n", This, Freq);
832     return IDirectDraw4_GetMonitorFrequency(This->parent, Freq);
833 }
834
835 static HRESULT WINAPI IDirectDraw3Impl_GetMonitorFrequency(IDirectDraw3 *iface, DWORD *Freq)
836 {
837     IDirectDrawImpl *This = impl_from_IDirectDraw3(iface);
838     TRACE("(%p)->(%p): Thunking to IDirectDraw4\n", This, Freq);
839     return IDirectDraw4_GetMonitorFrequency(&This->IDirectDraw4_iface, Freq);
840 }
841
842 static HRESULT WINAPI IDirectDraw2Impl_GetMonitorFrequency(IDirectDraw2 *iface, DWORD *Freq)
843 {
844     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
845     TRACE("(%p)->(%p): Thunking to IDirectDraw4\n", This, Freq);
846     return IDirectDraw4_GetMonitorFrequency(&This->IDirectDraw4_iface, Freq);
847 }
848
849 static HRESULT WINAPI IDirectDrawImpl_GetMonitorFrequency(IDirectDraw *iface, DWORD *Freq)
850 {
851     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
852     TRACE("(%p)->(%p): Thunking to IDirectDraw4\n", This, Freq);
853     return IDirectDraw4_GetMonitorFrequency(&This->IDirectDraw4_iface, Freq);
854 }
855
856 static HRESULT WINAPI IDirectDraw4Impl_GetScanLine(IDirectDraw4 *iface, DWORD *Scanline)
857 {
858     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
859     TRACE("(%p)->(%p)\n", This, Scanline);
860     return IDirectDraw4_GetScanLine(This->parent, Scanline);
861 }
862
863 static HRESULT WINAPI IDirectDraw3Impl_GetScanLine(IDirectDraw3 *iface, DWORD *Scanline)
864 {
865     IDirectDrawImpl *This = impl_from_IDirectDraw3(iface);
866     TRACE("(%p)->(%p): Thunking to IDirectDraw4\n", This, Scanline);
867     return IDirectDraw4_GetScanLine(&This->IDirectDraw4_iface, Scanline);
868 }
869
870 static HRESULT WINAPI IDirectDraw2Impl_GetScanLine(IDirectDraw2 *iface, DWORD *Scanline)
871 {
872     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
873     TRACE("(%p)->(%p): Thunking to IDirectDraw4\n", This, Scanline);
874     return IDirectDraw4_GetScanLine(&This->IDirectDraw4_iface, Scanline);
875 }
876
877 static HRESULT WINAPI IDirectDrawImpl_GetScanLine(IDirectDraw *iface, DWORD *Scanline)
878 {
879     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
880     TRACE("(%p)->(%p): Thunking to IDirectDraw4\n", This, Scanline);
881     return IDirectDraw4_GetScanLine(&This->IDirectDraw4_iface, Scanline);
882 }
883
884 static HRESULT WINAPI IDirectDraw4Impl_GetVerticalBlankStatus(IDirectDraw4 *iface, BOOL *status)
885 {
886     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
887     TRACE("(%p)->(%p)\n", This, status);
888     return IDirectDraw4_GetVerticalBlankStatus(This->parent, status);
889 }
890
891 static HRESULT WINAPI IDirectDraw3Impl_GetVerticalBlankStatus(IDirectDraw3 *iface, BOOL *status)
892 {
893     IDirectDrawImpl *This = impl_from_IDirectDraw3(iface);
894     TRACE("(%p)->(%p): Thunking to IDirectDraw4\n", This, status);
895     return IDirectDraw4_GetVerticalBlankStatus(&This->IDirectDraw4_iface, status);
896 }
897
898 static HRESULT WINAPI IDirectDraw2Impl_GetVerticalBlankStatus(IDirectDraw2 *iface, BOOL *status)
899 {
900     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
901     TRACE("(%p)->(%p): Thunking to IDirectDraw4\n", This, status);
902     return IDirectDraw4_GetVerticalBlankStatus(&This->IDirectDraw4_iface, status);
903 }
904
905 static HRESULT WINAPI IDirectDrawImpl_GetVerticalBlankStatus(IDirectDraw *iface, BOOL *status)
906 {
907     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
908     TRACE("(%p)->(%p): Thunking to IDirectDraw4\n", This, status);
909     return IDirectDraw4_GetVerticalBlankStatus(&This->IDirectDraw4_iface, status);
910 }
911
912 static HRESULT WINAPI IDirectDraw4Impl_Initialize(IDirectDraw4 *iface, GUID *Guid)
913 {
914     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
915     TRACE("(%p)->(%s)\n", This, debugstr_guid(Guid));
916     return IDirectDraw4_Initialize(This->parent, Guid);
917 }
918
919 static HRESULT WINAPI IDirectDraw3Impl_Initialize(IDirectDraw3 *iface, GUID *Guid)
920 {
921     IDirectDrawImpl *This = impl_from_IDirectDraw3(iface);
922     TRACE("(%p)->(%s): Thunking to IDirectDraw4\n", This, debugstr_guid(Guid));
923     return IDirectDraw4_Initialize(&This->IDirectDraw4_iface, Guid);
924 }
925
926 static HRESULT WINAPI IDirectDraw2Impl_Initialize(IDirectDraw2 *iface, GUID *Guid)
927 {
928     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
929     TRACE("(%p)->(%s): Thunking to IDirectDraw4\n", This, debugstr_guid(Guid));
930     return IDirectDraw4_Initialize(&This->IDirectDraw4_iface, Guid);
931 }
932
933 static HRESULT WINAPI IDirectDrawImpl_Initialize(IDirectDraw *iface, GUID *Guid)
934 {
935     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
936     TRACE("(%p)->(%s): Thunking to IDirectDraw4\n", This, debugstr_guid(Guid));
937     return IDirectDraw4_Initialize(&This->IDirectDraw4_iface, Guid);
938 }
939
940 static HRESULT WINAPI IDirectDraw4Impl_RestoreDisplayMode(IDirectDraw4 *iface)
941 {
942     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
943     TRACE("(%p)\n", This);
944     return IDirectDraw4_RestoreDisplayMode(This->parent);
945 }
946
947 static HRESULT WINAPI IDirectDraw3Impl_RestoreDisplayMode(IDirectDraw3 *iface)
948 {
949     IDirectDrawImpl *This = impl_from_IDirectDraw3(iface);
950     TRACE("(%p): Thunking to IDirectDraw4\n", This);
951     return IDirectDraw4_RestoreDisplayMode(&This->IDirectDraw4_iface);
952 }
953
954 static HRESULT WINAPI IDirectDraw2Impl_RestoreDisplayMode(IDirectDraw2 *iface)
955 {
956     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
957     TRACE("(%p): Thunking to IDirectDraw4\n", This);
958     return IDirectDraw4_RestoreDisplayMode(&This->IDirectDraw4_iface);
959 }
960
961 static HRESULT WINAPI IDirectDrawImpl_RestoreDisplayMode(IDirectDraw *iface)
962 {
963     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
964     TRACE("(%p): Thunking to IDirectDraw4\n", This);
965     return IDirectDraw4_RestoreDisplayMode(&This->IDirectDraw4_iface);
966 }
967
968 static HRESULT WINAPI IDirectDraw4Impl_SetCooperativeLevel(IDirectDraw4 *iface, HWND hwnd,
969         DWORD cooplevel)
970 {
971     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
972     TRACE("(%p)->(%p, 0x%08x)\n", This, hwnd, cooplevel);
973     return IDirectDraw4_SetCooperativeLevel(This->parent, hwnd, cooplevel);
974 }
975
976 static HRESULT WINAPI IDirectDraw3Impl_SetCooperativeLevel(IDirectDraw3 *iface, HWND hwnd,
977         DWORD cooplevel)
978 {
979     IDirectDrawImpl *This = impl_from_IDirectDraw3(iface);
980     TRACE("(%p)->(%p, 0x%08x): Thunking to IDirectDraw4\n", This, hwnd, cooplevel);
981     return IDirectDraw4_SetCooperativeLevel(&This->IDirectDraw4_iface, hwnd, cooplevel);
982 }
983
984 static HRESULT WINAPI IDirectDraw2Impl_SetCooperativeLevel(IDirectDraw2 *iface, HWND hwnd,
985         DWORD cooplevel)
986 {
987     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
988     TRACE("(%p)->(%p, 0x%08x): Thunking to IDirectDraw4\n", This, hwnd, cooplevel);
989     return IDirectDraw4_SetCooperativeLevel(&This->IDirectDraw4_iface, hwnd, cooplevel);
990 }
991
992 static HRESULT WINAPI IDirectDrawImpl_SetCooperativeLevel(IDirectDraw *iface, HWND hwnd,
993         DWORD cooplevel)
994 {
995     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
996     TRACE("(%p)->(%p, 0x%08x): Thunking to IDirectDraw4\n", This, hwnd, cooplevel);
997     return IDirectDraw4_SetCooperativeLevel(&This->IDirectDraw4_iface, hwnd, cooplevel);
998 }
999
1000 static HRESULT WINAPI IDirectDraw4Impl_SetDisplayMode(IDirectDraw4 *iface, DWORD Width,
1001         DWORD Height, DWORD BPP, DWORD RefreshRate, DWORD Flags)
1002 {
1003     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
1004     TRACE("(%p)->(%u, %u, %u, %u, 0x%08x)\n", This, Width, Height, BPP, RefreshRate, Flags);
1005     return IDirectDraw4_SetDisplayMode(This->parent, Width, Height, BPP, RefreshRate, Flags);
1006 }
1007
1008 static HRESULT WINAPI IDirectDraw3Impl_SetDisplayMode(IDirectDraw3 *iface, DWORD Width,
1009         DWORD Height, DWORD BPP, DWORD RefreshRate, DWORD Flags)
1010 {
1011     IDirectDrawImpl *This = impl_from_IDirectDraw3(iface);
1012     TRACE("(%p)->(%u, %u, %u, %u, 0x%08x): Thunking to IDirectDraw4\n", This, Width, Height, BPP, RefreshRate, Flags);
1013     return IDirectDraw3_SetDisplayMode(&This->IDirectDraw4_iface, Width, Height, BPP, RefreshRate,
1014             Flags);
1015 }
1016
1017 static HRESULT WINAPI IDirectDraw2Impl_SetDisplayMode(IDirectDraw2 *iface, DWORD Width,
1018         DWORD Height, DWORD BPP, DWORD RefreshRate, DWORD Flags)
1019 {
1020     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
1021     TRACE("(%p)->(%u, %u, %u, %u, 0x%08x): Thunking to IDirectDraw4\n", This, Width, Height, BPP, RefreshRate, Flags);
1022     return IDirectDraw3_SetDisplayMode(&This->IDirectDraw4_iface, Width, Height, BPP, RefreshRate,
1023             Flags);
1024 }
1025
1026 static HRESULT WINAPI IDirectDrawImpl_SetDisplayMode(IDirectDraw *iface, DWORD Width, DWORD Height,
1027         DWORD BPP)
1028 {
1029     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
1030     TRACE("(%p)->(%u, %u, %u): Thunking to IDirectDraw4\n", This, Width, Height, BPP);
1031     return IDirectDraw3_SetDisplayMode(&This->IDirectDraw4_iface, Width, Height, BPP, 0, 0);
1032 }
1033
1034 static HRESULT WINAPI IDirectDraw4Impl_WaitForVerticalBlank(IDirectDraw4 *iface, DWORD Flags,
1035         HANDLE h)
1036 {
1037     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
1038     TRACE("(%p)->(0x%08x, %p)\n", This, Flags, h);
1039     return IDirectDraw4_WaitForVerticalBlank(This->parent, Flags, h);
1040 }
1041
1042 static HRESULT WINAPI IDirectDraw3Impl_WaitForVerticalBlank(IDirectDraw3 *iface, DWORD Flags,
1043         HANDLE h)
1044 {
1045     IDirectDrawImpl *This = impl_from_IDirectDraw3(iface);
1046     TRACE("(%p)->(0x%08x, %p): Thunking to IDirectDraw4\n", This, Flags, h);
1047     return IDirectDraw4_WaitForVerticalBlank(&This->IDirectDraw4_iface, Flags, h);
1048 }
1049
1050 static HRESULT WINAPI IDirectDraw2Impl_WaitForVerticalBlank(IDirectDraw2 *iface, DWORD Flags,
1051         HANDLE h)
1052 {
1053     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
1054     TRACE("(%p)->(0x%08x, %p): Thunking to IDirectDraw4\n", This, Flags, h);
1055     return IDirectDraw4_WaitForVerticalBlank(&This->IDirectDraw4_iface, Flags, h);
1056 }
1057
1058 static HRESULT WINAPI IDirectDrawImpl_WaitForVerticalBlank(IDirectDraw *iface, DWORD Flags,
1059         HANDLE h)
1060 {
1061     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
1062     TRACE("(%p)->(0x%08x, %p): Thunking to IDirectDraw4\n", This, Flags, h);
1063     return IDirectDraw4_WaitForVerticalBlank(&This->IDirectDraw4_iface, Flags, h);
1064 }
1065
1066 static HRESULT WINAPI IDirectDraw4Impl_GetAvailableVidMem(IDirectDraw4 *iface, DDSCAPS2 *Caps,
1067         DWORD *total, DWORD *free)
1068 {
1069     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
1070     TRACE("(%p)->(%p, %p, %p)\n", This, Caps, total, free);
1071     return IDirectDraw4_GetAvailableVidMem(This->parent, Caps, total, free);
1072 }
1073
1074 static HRESULT WINAPI IDirectDraw3Impl_GetAvailableVidMem(IDirectDraw3 *iface, DDSCAPS *Caps,
1075         DWORD *total, DWORD *free)
1076 {
1077     IDirectDrawImpl *This = impl_from_IDirectDraw3(iface);
1078     DDSCAPS2 caps2;
1079     TRACE("(%p)->(%p, %p, %p): Thunking to IDirectDraw4\n", This, Caps, total, free);
1080     memset(&caps2, 0, sizeof(caps2));
1081     caps2.dwCaps = Caps->dwCaps;
1082     return IDirectDraw4_GetAvailableVidMem(&This->IDirectDraw4_iface, &caps2, total, free);
1083 }
1084
1085 static HRESULT WINAPI IDirectDraw2Impl_GetAvailableVidMem(IDirectDraw2 *iface, DDSCAPS *Caps,
1086         DWORD *total, DWORD *free)
1087 {
1088     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
1089     DDSCAPS2 caps2;
1090     TRACE("(%p)->(%p, %p, %p): Thunking to IDirectDraw4\n", This, Caps, total, free);
1091     memset(&caps2, 0, sizeof(caps2));
1092     caps2.dwCaps = Caps->dwCaps;
1093     return IDirectDraw4_GetAvailableVidMem(&This->IDirectDraw4_iface, &caps2, total, free);
1094 }
1095
1096 static HRESULT WINAPI IDirectDraw4Impl_GetSurfaceFromDC(IDirectDraw4 *iface, HDC hdc,
1097         IDirectDrawSurface4 **Surface)
1098 {
1099     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
1100     HRESULT hr;
1101     TRACE("(%p)->(%p, %p)\n", This, hdc, Surface);
1102     hr = IDirectDraw4_GetSurfaceFromDC(This->parent,hdc, Surface);
1103
1104     return hr;
1105 }
1106
1107 static HRESULT WINAPI IDirectDraw3Impl_GetSurfaceFromDC(IDirectDraw3 *iface, HDC hdc,
1108         IDirectDrawSurface **Surface)
1109 {
1110     IDirectDrawImpl *This = impl_from_IDirectDraw3(iface);
1111     IDirectDrawSurface4 *surf4, *outer;
1112     IDirectDrawSurface *inner;
1113     HRESULT hr;
1114     TRACE("(%p)->(%p, %p): Thunking to IDirectDraw4\n", This, hdc, Surface);
1115
1116     if (!Surface) return E_POINTER;
1117
1118     hr = IDirectDraw4_GetSurfaceFromDC(This->parent, hdc, (IDirectDrawSurface4 **)&inner);
1119     if(FAILED(hr))
1120     {
1121         *Surface = NULL;
1122         return hr;
1123     }
1124
1125     hr = IDirectDrawSurface_QueryInterface(inner, &IID_IDirectDrawSurface4, (void **)&surf4);
1126     IDirectDrawSurface_Release(inner);
1127     if (FAILED(hr))
1128     {
1129         *Surface = NULL;
1130         return hr;
1131     }
1132
1133     outer = dds_get_outer(surf4);
1134     hr = IDirectDrawSurface4_QueryInterface(outer, &IID_IDirectDrawSurface, (void **)Surface);
1135     IDirectDrawSurface4_Release(surf4);
1136     return hr;
1137 }
1138
1139 static HRESULT WINAPI IDirectDraw4Impl_RestoreAllSurfaces(IDirectDraw4 *iface)
1140 {
1141     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
1142     TRACE("(%p)\n", This);
1143     return IDirectDraw4_RestoreAllSurfaces(This->parent);
1144 }
1145
1146 static HRESULT WINAPI IDirectDraw4Impl_TestCooperativeLevel(IDirectDraw4 *iface)
1147 {
1148     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
1149     TRACE("(%p)\n", This);
1150     return IDirectDraw4_TestCooperativeLevel(This->parent);
1151 }
1152
1153 static HRESULT WINAPI IDirectDraw4Impl_GetDeviceIdentifier(IDirectDraw4 *iface,
1154         DDDEVICEIDENTIFIER *DDDI, DWORD Flags)
1155 {
1156     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
1157     TRACE("(%p)->(%p,0x%08x)\n", This, DDDI, Flags);
1158     return IDirectDraw4_GetDeviceIdentifier(This->parent, DDDI, Flags);
1159 }
1160
1161 static const IDirectDrawVtbl IDirectDraw1_Vtbl =
1162 {
1163     IDirectDrawImpl_QueryInterface,
1164     IDirectDrawImpl_AddRef,
1165     IDirectDrawImpl_Release,
1166     IDirectDrawImpl_Compact,
1167     IDirectDrawImpl_CreateClipper,
1168     IDirectDrawImpl_CreatePalette,
1169     IDirectDrawImpl_CreateSurface,
1170     IDirectDrawImpl_DuplicateSurface,
1171     IDirectDrawImpl_EnumDisplayModes,
1172     IDirectDrawImpl_EnumSurfaces,
1173     IDirectDrawImpl_FlipToGDISurface,
1174     IDirectDrawImpl_GetCaps,
1175     IDirectDrawImpl_GetDisplayMode,
1176     IDirectDrawImpl_GetFourCCCodes,
1177     IDirectDrawImpl_GetGDISurface,
1178     IDirectDrawImpl_GetMonitorFrequency,
1179     IDirectDrawImpl_GetScanLine,
1180     IDirectDrawImpl_GetVerticalBlankStatus,
1181     IDirectDrawImpl_Initialize,
1182     IDirectDrawImpl_RestoreDisplayMode,
1183     IDirectDrawImpl_SetCooperativeLevel,
1184     IDirectDrawImpl_SetDisplayMode,
1185     IDirectDrawImpl_WaitForVerticalBlank,
1186 };
1187
1188 static const IDirectDraw2Vtbl IDirectDraw2_Vtbl =
1189 {
1190     IDirectDraw2Impl_QueryInterface,
1191     IDirectDraw2Impl_AddRef,
1192     IDirectDraw2Impl_Release,
1193     IDirectDraw2Impl_Compact,
1194     IDirectDraw2Impl_CreateClipper,
1195     IDirectDraw2Impl_CreatePalette,
1196     IDirectDraw2Impl_CreateSurface,
1197     IDirectDraw2Impl_DuplicateSurface,
1198     IDirectDraw2Impl_EnumDisplayModes,
1199     IDirectDraw2Impl_EnumSurfaces,
1200     IDirectDraw2Impl_FlipToGDISurface,
1201     IDirectDraw2Impl_GetCaps,
1202     IDirectDraw2Impl_GetDisplayMode,
1203     IDirectDraw2Impl_GetFourCCCodes,
1204     IDirectDraw2Impl_GetGDISurface,
1205     IDirectDraw2Impl_GetMonitorFrequency,
1206     IDirectDraw2Impl_GetScanLine,
1207     IDirectDraw2Impl_GetVerticalBlankStatus,
1208     IDirectDraw2Impl_Initialize,
1209     IDirectDraw2Impl_RestoreDisplayMode,
1210     IDirectDraw2Impl_SetCooperativeLevel,
1211     IDirectDraw2Impl_SetDisplayMode,
1212     IDirectDraw2Impl_WaitForVerticalBlank,
1213     IDirectDraw2Impl_GetAvailableVidMem
1214 };
1215
1216 static const IDirectDraw3Vtbl IDirectDraw3_Vtbl =
1217 {
1218     IDirectDraw3Impl_QueryInterface,
1219     IDirectDraw3Impl_AddRef,
1220     IDirectDraw3Impl_Release,
1221     IDirectDraw3Impl_Compact,
1222     IDirectDraw3Impl_CreateClipper,
1223     IDirectDraw3Impl_CreatePalette,
1224     IDirectDraw3Impl_CreateSurface,
1225     IDirectDraw3Impl_DuplicateSurface,
1226     IDirectDraw3Impl_EnumDisplayModes,
1227     IDirectDraw3Impl_EnumSurfaces,
1228     IDirectDraw3Impl_FlipToGDISurface,
1229     IDirectDraw3Impl_GetCaps,
1230     IDirectDraw3Impl_GetDisplayMode,
1231     IDirectDraw3Impl_GetFourCCCodes,
1232     IDirectDraw3Impl_GetGDISurface,
1233     IDirectDraw3Impl_GetMonitorFrequency,
1234     IDirectDraw3Impl_GetScanLine,
1235     IDirectDraw3Impl_GetVerticalBlankStatus,
1236     IDirectDraw3Impl_Initialize,
1237     IDirectDraw3Impl_RestoreDisplayMode,
1238     IDirectDraw3Impl_SetCooperativeLevel,
1239     IDirectDraw3Impl_SetDisplayMode,
1240     IDirectDraw3Impl_WaitForVerticalBlank,
1241     IDirectDraw3Impl_GetAvailableVidMem,
1242     IDirectDraw3Impl_GetSurfaceFromDC,
1243 };
1244
1245 static const IDirectDraw4Vtbl IDirectDraw4_Vtbl =
1246 {
1247     IDirectDraw4Impl_QueryInterface,
1248     IDirectDraw4Impl_AddRef,
1249     IDirectDraw4Impl_Release,
1250     IDirectDraw4Impl_Compact,
1251     IDirectDraw4Impl_CreateClipper,
1252     IDirectDraw4Impl_CreatePalette,
1253     IDirectDraw4Impl_CreateSurface,
1254     IDirectDraw4Impl_DuplicateSurface,
1255     IDirectDraw4Impl_EnumDisplayModes,
1256     IDirectDraw4Impl_EnumSurfaces,
1257     IDirectDraw4Impl_FlipToGDISurface,
1258     IDirectDraw4Impl_GetCaps,
1259     IDirectDraw4Impl_GetDisplayMode,
1260     IDirectDraw4Impl_GetFourCCCodes,
1261     IDirectDraw4Impl_GetGDISurface,
1262     IDirectDraw4Impl_GetMonitorFrequency,
1263     IDirectDraw4Impl_GetScanLine,
1264     IDirectDraw4Impl_GetVerticalBlankStatus,
1265     IDirectDraw4Impl_Initialize,
1266     IDirectDraw4Impl_RestoreDisplayMode,
1267     IDirectDraw4Impl_SetCooperativeLevel,
1268     IDirectDraw4Impl_SetDisplayMode,
1269     IDirectDraw4Impl_WaitForVerticalBlank,
1270     IDirectDraw4Impl_GetAvailableVidMem,
1271     IDirectDraw4Impl_GetSurfaceFromDC,
1272     IDirectDraw4Impl_RestoreAllSurfaces,
1273     IDirectDraw4Impl_TestCooperativeLevel,
1274     IDirectDraw4Impl_GetDeviceIdentifier
1275 };
1276
1277 /*******************************************************************************
1278  * IDirectDrawFactoryImpl_CreateDirectDraw
1279  *******************************************************************************/
1280 HRESULT WINAPI
1281 IDirectDrawFactoryImpl_CreateDirectDraw(IDirectDrawFactory* iface,
1282                                         GUID * pGUID,
1283                                         HWND hWnd,
1284                                         DWORD dwCoopLevelFlags,
1285                                         DWORD dwReserved,
1286                                         IUnknown *pUnkOuter,
1287                                         IDirectDraw **ppDirectDraw)
1288 {
1289     HRESULT hr;
1290     IDirectDrawImpl *object = NULL;
1291     IDirectDraw *parent = NULL;
1292
1293     TRACE("(%p)->(%s,%p,0x%08x,0x%08x,%p,%p)\n", iface, debugstr_guid(pGUID), hWnd, dwCoopLevelFlags,
1294           dwReserved, pUnkOuter, ppDirectDraw);
1295
1296     if(pUnkOuter)
1297     {
1298         FIXME("Implement aggregation in ddrawex's IDirectDraw interface\n");
1299     }
1300
1301     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1302     if(!object)
1303     {
1304         ERR("Out of memory\n");
1305         hr = E_OUTOFMEMORY;
1306         goto err;
1307     }
1308     object->ref = 1;
1309     object->IDirectDraw_iface.lpVtbl = &IDirectDraw1_Vtbl;
1310     object->IDirectDraw2_iface.lpVtbl = &IDirectDraw2_Vtbl;
1311     object->IDirectDraw3_iface.lpVtbl = &IDirectDraw3_Vtbl;
1312     object->IDirectDraw4_iface.lpVtbl = &IDirectDraw4_Vtbl;
1313
1314     hr = DirectDrawCreate(pGUID, &parent, NULL);
1315     if (FAILED(hr)) goto err;
1316
1317     hr = IDirectDraw_QueryInterface(parent, &IID_IDirectDraw4, (void **) &object->parent);
1318     if(FAILED(hr)) goto err;
1319
1320     hr = IDirectDraw_SetCooperativeLevel(&object->IDirectDraw_iface, hWnd, dwCoopLevelFlags);
1321     if (FAILED(hr)) goto err;
1322
1323     *ppDirectDraw = &object->IDirectDraw_iface;
1324     IDirectDraw_Release(parent);
1325     return DD_OK;
1326
1327 err:
1328     if(object && object->parent) IDirectDraw4_Release(object->parent);
1329     if(parent) IDirectDraw_Release(parent);
1330     HeapFree(GetProcessHeap(), 0, object);
1331     *ppDirectDraw = NULL;
1332     return hr;
1333 }
1334
1335 IDirectDraw4 *dd_get_inner(IDirectDraw4 *outer)
1336 {
1337     IDirectDrawImpl *This = impl_from_IDirectDraw4(outer);
1338
1339     if (outer->lpVtbl != &IDirectDraw4_Vtbl) return NULL;
1340     return This->parent;
1341 }