From 14ca56ed97c4cde388fa3938bf72fb74d3d606b4 Mon Sep 17 00:00:00 2001 From: Henri Verbeet Date: Mon, 17 Oct 2011 21:06:22 +0200 Subject: [PATCH] ddraw: Destroy the swapchain in ddraw_destroy() if it still exists. --- dlls/ddraw/ddraw.c | 55 +++++++++++++++++++++++++++++++++++++- dlls/ddraw/ddraw_private.h | 1 + dlls/ddraw/surface.c | 41 +--------------------------- 3 files changed, 56 insertions(+), 41 deletions(-) diff --git a/dlls/ddraw/ddraw.c b/dlls/ddraw/ddraw.c index 17f1900eb44..080197614ff 100644 --- a/dlls/ddraw/ddraw.c +++ b/dlls/ddraw/ddraw.c @@ -410,6 +410,50 @@ static ULONG WINAPI d3d1_AddRef(IDirect3D *iface) return ddraw1_AddRef(&This->IDirectDraw_iface); } +void ddraw_destroy_swapchain(IDirectDrawImpl *ddraw) +{ + TRACE("Destroying the swapchain.\n"); + + wined3d_swapchain_decref(ddraw->wined3d_swapchain); + ddraw->wined3d_swapchain = NULL; + + if (DefaultSurfaceType == SURFACE_OPENGL) + { + UINT i; + + for (i = 0; i < ddraw->numConvertedDecls; ++i) + { + wined3d_vertex_declaration_decref(ddraw->decls[i].decl); + } + HeapFree(GetProcessHeap(), 0, ddraw->decls); + ddraw->numConvertedDecls = 0; + + if (FAILED(wined3d_device_uninit_3d(ddraw->wined3d_device))) + { + ERR("Failed to uninit 3D.\n"); + } + else + { + /* Free the d3d window if one was created. */ + if (ddraw->d3d_window && ddraw->d3d_window != ddraw->dest_window) + { + TRACE("Destroying the hidden render window %p.\n", ddraw->d3d_window); + DestroyWindow(ddraw->d3d_window); + ddraw->d3d_window = 0; + } + } + + ddraw->d3d_initialized = FALSE; + ddraw->d3d_target = NULL; + } + else + { + wined3d_device_uninit_gdi(ddraw->wined3d_device); + } + + TRACE("Swapchain destroyed.\n"); +} + /***************************************************************************** * ddraw_destroy * @@ -437,7 +481,16 @@ static void ddraw_destroy(IDirectDrawImpl *This) list_remove(&This->ddraw_list_entry); LeaveCriticalSection(&ddraw_cs); - /* Release the attached WineD3D stuff */ + /* This can happen more or less legitimately for ddraw 1 and 2, where + * surfaces don't keep a reference to the ddraw object. The surfaces + * will of course be broken after this, (and on native trying to do + * anything with them in that state results in an access violation), but + * the release of the ddraw object should succeed without crashing. */ + if (This->wined3d_swapchain) + { + WARN("DirectDraw object is being destroyed while the swapchain still exists.\n"); + ddraw_destroy_swapchain(This); + } wined3d_device_decref(This->wined3d_device); wined3d_decref(This->wineD3D); diff --git a/dlls/ddraw/ddraw_private.h b/dlls/ddraw/ddraw_private.h index 7b0d608425d..2f8b6098984 100644 --- a/dlls/ddraw/ddraw_private.h +++ b/dlls/ddraw/ddraw_private.h @@ -127,6 +127,7 @@ struct IDirectDrawImpl #define DDRAW_WINDOW_CLASS_NAME "ddraw_wc" HRESULT ddraw_init(IDirectDrawImpl *ddraw, WINED3DDEVTYPE device_type) DECLSPEC_HIDDEN; +void ddraw_destroy_swapchain(IDirectDrawImpl *ddraw) DECLSPEC_HIDDEN; /* Utility functions */ void DDRAW_Convert_DDSCAPS_1_To_2(const DDSCAPS *pIn, DDSCAPS2 *pOut) DECLSPEC_HIDDEN; diff --git a/dlls/ddraw/surface.c b/dlls/ddraw/surface.c index 976f557defe..561bca723ae 100644 --- a/dlls/ddraw/surface.c +++ b/dlls/ddraw/surface.c @@ -430,46 +430,7 @@ static void ddraw_surface_cleanup(IDirectDrawSurfaceImpl *surface) ddraw_surface_destroy(surface); if (ddraw->wined3d_swapchain && destroy_swapchain) - { - TRACE("Destroying the swapchain.\n"); - - wined3d_swapchain_decref(ddraw->wined3d_swapchain); - ddraw->wined3d_swapchain = NULL; - - if (DefaultSurfaceType == SURFACE_OPENGL) - { - for (i = 0; i < ddraw->numConvertedDecls; ++i) - { - wined3d_vertex_declaration_decref(ddraw->decls[i].decl); - } - HeapFree(GetProcessHeap(), 0, ddraw->decls); - ddraw->numConvertedDecls = 0; - - if (FAILED(wined3d_device_uninit_3d(ddraw->wined3d_device))) - { - ERR("Failed to uninit 3D.\n"); - } - else - { - /* Free the d3d window if one was created. */ - if (ddraw->d3d_window && ddraw->d3d_window != ddraw->dest_window) - { - TRACE("Destroying the hidden render window %p.\n", ddraw->d3d_window); - DestroyWindow(ddraw->d3d_window); - ddraw->d3d_window = 0; - } - } - - ddraw->d3d_initialized = FALSE; - ddraw->d3d_target = NULL; - } - else - { - wined3d_device_uninit_gdi(ddraw->wined3d_device); - } - - TRACE("Swapchain destroyed.\n"); - } + ddraw_destroy_swapchain(ddraw); /* Reduce the ddraw refcount */ if (ifaceToRelease)