DDraw: Make IDirectDrawImpl thread safe

Stefan Dösinger stefandoesinger at gmx.at
Sun Aug 27 04:00:31 CDT 2006


This patch is the patch from last week, with two modificiations:

* The ddraw object list is protected by a global critical section(Previous 
patch)
* The ddraw object isn't locked in the destroy function because it is not 
neccessary

I have patches for all other ddraw objects too, but I'll wait for feedback or 
until this patch is comitted before flooding wine-patches again :-)
-------------- next part --------------
From nobody Mon Sep 17 00:00:00 2001
From: Stefan Dösinger <stefan at codeweavers.com>
Date: Sun Aug 27 10:33:21 2006 +0200
Subject: [PATCH] DDraw: Make IDirectDrawImpl thread safe

---

 dlls/ddraw/ddraw.c         |  105 ++++++++++++++++++++++++++++++++++++++++----
 dlls/ddraw/ddraw_private.h |    8 +++
 dlls/ddraw/direct3d.c      |   15 ++++++
 dlls/ddraw/main.c          |    2 +
 dlls/ddraw/surface.c       |    2 +
 5 files changed, 122 insertions(+), 10 deletions(-)

83d1d1b7e79f03d84843c242ff490706f5ddaca9
diff --git a/dlls/ddraw/ddraw.c b/dlls/ddraw/ddraw.c
index f33f5f1..a93f8b2 100644
--- a/dlls/ddraw/ddraw.c
+++ b/dlls/ddraw/ddraw.c
@@ -109,6 +109,11 @@ IDirectDrawImpl_QueryInterface(IDirectDr
     if(!refiid)
         return DDERR_INVALIDPARAMS;
 
+    /* Lock the object, we access and change private members when querying
+     * IDirect3D interfaces
+     */
+    DDOBJ_LOCK(This);
+
     /* Check DirectDraw Interfaces */
     if ( IsEqualGUID( &IID_IUnknown, refiid ) ||
          IsEqualGUID( &IID_IDirectDraw7, refiid ) )
@@ -194,10 +199,12 @@ IDirectDrawImpl_QueryInterface(IDirectDr
     else
     {
         ERR("(%p)->(%s, %p): No interface found\n", This, debugstr_guid(refiid), obj);
+        DDOBJ_UNLOCK(This);
         return E_NOINTERFACE;
     }
 
     IUnknown_AddRef( (IUnknown *) *obj );
+    DDOBJ_UNLOCK(This);
     return S_OK;
 }
 
@@ -246,11 +253,14 @@ void
 IDirectDrawImpl_Destroy(IDirectDrawImpl *This)
 {
     IDirectDrawImpl *prev;
+    /* No need to lock the object here, after the refcount falls to 0
+     * it shouldn't be in use anywere else
+     */
 
     /* Clear the cooplevel to restore window and display mode */
     IDirectDraw7_SetCooperativeLevel(ICOM_INTERFACE(This, IDirectDraw7),
-                                        NULL,
-                                        DDSCL_NORMAL);
+                                     NULL,
+                                     DDSCL_NORMAL);
 
     /* Destroy the device window if we created one */
     if(This->devicewindow != 0)
@@ -273,10 +283,17 @@ IDirectDrawImpl_Destroy(IDirectDrawImpl 
     else
     {
         for(prev = ddraw_list; prev; prev = prev->next)
+        {
             if(prev->next == This) break;
+        }
 
         if(prev)
+        {
+            /* No need to hold the lock on prev, the members related to the list
+             * are only modified / read when the whole list lock is held
+             */
             prev->next = This->next;
+        }
         else
             ERR("Didn't find the previous ddraw element in the list\n");
     }
@@ -286,6 +303,9 @@ IDirectDrawImpl_Destroy(IDirectDrawImpl 
     IWineD3DDevice_Release(This->wineD3DDevice);
     IWineD3D_Release(This->wineD3D);
 
+    if(This->hasCrit) DeleteCriticalSection(&This->crit);
+    This->hasCrit = FALSE;
+
     /* Now free the object */
     HeapFree(GetProcessHeap(), 0, This);
 }
@@ -324,6 +344,8 @@ IDirectDrawImpl_Release(IDirectDraw7 *if
  * Helper function that modifies a HWND's Style and ExStyle for proper
  * fullscreen use.
  *
+ * Assumes that the critical section is properly held
+ *
  * Params:
  *  This: Pointer to the DirectDraw implementation
  *  HWND: Window to setup
@@ -379,6 +401,8 @@ IDirectDrawImpl_SetupFullscreenWindow(ID
  * Helper function that restores a windows' properties when taking it out
  * of fullscreen mode
  *
+ * Assumes that the critical section is properly held
+ *
  * Params:
  *  This: Pointer to the DirectDraw implementation
  *  HWND: Window to setup
@@ -484,6 +508,7 @@ IDirectDrawImpl_SetCooperativeLevel(IDir
         return DDERR_INVALIDPARAMS;
     }
 
+    DDOBJ_LOCK(This);
     /* Handle those levels first which set various hwnds */
     if(cooplevel & DDSCL_SETFOCUSWINDOW)
     {
@@ -498,11 +523,13 @@ IDirectDrawImpl_SetCooperativeLevel(IDir
                          DDSCL_EXCLUSIVE       |
                          DDSCL_FULLSCREEN      ) )
         {
+            DDOBJ_UNLOCK(This);
             TRACE("Called with incompatible flags, returning DDERR_INVALIDPARAMS\n");
             return DDERR_INVALIDPARAMS;
         }
         else if( (This->cooperative_level & DDSCL_FULLSCREEN) && window)
         {
+            DDOBJ_UNLOCK(This);
             TRACE("Setting DDSCL_SETFOCUSWINDOW with an already set window, returning DDERR_HWNDALREADYSET\n");
             return DDERR_HWNDALREADYSET;
         }
@@ -527,6 +554,7 @@ IDirectDrawImpl_SetCooperativeLevel(IDir
         /* Can't coexist with fullscreen or exclusive */
         if(cooplevel & (DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE) )
         {
+            DDOBJ_UNLOCK(This);
             TRACE("(%p) DDSCL_NORMAL is not compative with DDSCL_FULLSCREEN or DDSCL_EXCLUSIVE\n", This);
             return DDERR_INVALIDPARAMS;
         }
@@ -559,6 +587,7 @@ IDirectDrawImpl_SetCooperativeLevel(IDir
         /* Needs DDSCL_EXCLUSIVE */
         if(!(cooplevel & DDSCL_EXCLUSIVE) )
         {
+            DDOBJ_UNLOCK(This);
             TRACE("(%p) DDSCL_FULLSCREEN needs DDSCL_EXCLUSIVE\n", This);
             return DDERR_INVALIDPARAMS;
         }
@@ -594,6 +623,7 @@ IDirectDrawImpl_SetCooperativeLevel(IDir
     }
     else if(cooplevel & DDSCL_EXCLUSIVE)
     {
+        DDOBJ_UNLOCK(This);
         TRACE("(%p) DDSCL_EXCLUSIVE needs DDSCL_FULLSCREEN\n", This);
         return DDERR_INVALIDPARAMS;
     }
@@ -617,13 +647,24 @@ IDirectDrawImpl_SetCooperativeLevel(IDir
         }
     }
 
+    if(cooplevel & DDSCL_MULTITHREADED && !(This->cooperative_level & DDSCL_MULTITHREADED))
+    {
+        if(This->surfaces != 0)
+        {
+            ERR("Setting DDSCL_MULTITHREADED, but surfaces exist already\n");
+        }
+
+        TRACE("(%p): Creating a critical section for the IDirectDrawImpl object\n", This);
+        InitializeCriticalSection(&This->crit);
+        This->hasCrit = TRUE;
+        DDOBJ_LOCK(This); /* Lock to allow the unlock later to work */
+    }
+
     /* Unhandled flags */
     if(cooplevel & DDSCL_ALLOWREBOOT)
         WARN("(%p) Unhandled flag DDSCL_ALLOWREBOOT, harmless\n", This);
     if(cooplevel & DDSCL_ALLOWMODEX)
         WARN("(%p) Unhandled flag DDSCL_ALLOWMODEX, harmless\n", This);
-    if(cooplevel & DDSCL_MULTITHREADED)
-        FIXME("(%p) Unhandled flag DDSCL_MULTITHREADED, Uh Oh...\n", This);
     if(cooplevel & DDSCL_FPUSETUP)
         WARN("(%p) Unhandled flag DDSCL_FPUSETUP, harmless\n", This);
     if(cooplevel & DDSCL_FPUPRESERVE)
@@ -631,6 +672,7 @@ IDirectDrawImpl_SetCooperativeLevel(IDir
 
     /* Store the cooperative_level */
     This->cooperative_level |= cooplevel;
+    DDOBJ_UNLOCK(This);
     TRACE("SetCooperativeLevel retuning DD_OK\n");
     return DD_OK;
 }
@@ -766,6 +808,7 @@ IDirectDrawImpl_GetCaps(IDirectDraw7 *if
 {
     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
     TRACE("(%p)->(%p,%p)\n", This, DriverCaps, HELCaps);
+    /* The caps are only set at startup and not changed, no need to lock */
 
     /* One structure must be != NULL */
     if( (!DriverCaps) && (!HELCaps) )
@@ -838,6 +881,7 @@ IDirectDrawImpl_GetDisplayMode(IDirectDr
     WINED3DDISPLAYMODE Mode;
     DWORD Size;
     TRACE("(%p)->(%p): Relay\n", This, DDSD);
+    /* Does not use structure members, no need to lock */
 
     /* This seems sane */
     if(!DDSD) 
@@ -960,8 +1004,10 @@ IDirectDrawImpl_GetVerticalBlankStatus(I
     /* This looks sane, the MSDN suggests it too */
     if(!status) return DDERR_INVALIDPARAMS;
 
+    DDOBJ_LOCK(This);
     *status = This->fake_vblank;
     This->fake_vblank = !This->fake_vblank;
+    DDOBJ_UNLOCK(This);
     return DD_OK;
 }
 
@@ -985,6 +1031,7 @@ IDirectDrawImpl_GetAvailableVidMem(IDire
 {
     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
     TRACE("(%p)->(%p, %p, %p)\n", This, Caps, total, free);
+    /* Total vidmem is const, free comes from wineD3D, no need to lock */
 
     if(TRACE_ON(ddraw))
     {
@@ -1121,11 +1168,13 @@ static HRESULT WINAPI IDirectDrawImpl_Ge
                                   &Mode);
 
     /* Fake the line sweeping of the monitor */
-    /* FIXME: We should synchronize with a source to keep the refresh rate */ 
+    /* FIXME: We should synchronize with a source to keep the refresh rate */
+    DDOBJ_LOCK(This);
     *Scanline = This->cur_scanline++;
     /* Assume 20 scan lines in the vertical blank */
     if (This->cur_scanline >= Mode.Height + 20)
         This->cur_scanline = 0;
+    DDOBJ_UNLOCK(This);
 
     return DD_OK;
 }
@@ -1148,6 +1197,7 @@ IDirectDrawImpl_TestCooperativeLevel(IDi
     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
     HRESULT hr;
     TRACE("(%p)\n", This);
+    /* Only data from wineD3D is used, no need to lock */
 
     /* Description from MSDN:
      * For fullscreen apps return DDERR_NOEXCLUSIVEMODE if the user switched
@@ -1213,6 +1263,7 @@ IDirectDrawImpl_GetGDISurface(IDirectDra
     HRESULT hr;
     DDSCAPS2 ddsCaps;
     TRACE("(%p)->(%p)\n", This, GDISurface);
+    /* No need to lock, only data from wineD3D is used */
 
     /* Get the back buffer from the wineD3DDevice and search its
      * attached surfaces for the front buffer
@@ -1408,6 +1459,8 @@ IDirectDrawImpl_GetDeviceIdentifier(IDir
     /* The DDGDI_GETHOSTIDENTIFIER returns the information about the 2D
      * host adapter, if there's a secondary 3D adapter. This doesn't apply
      * to any modern hardware, nor is it interesting for Wine, so ignore it
+     *
+     * The device identifier is global and const, no need to lock anything
      */
 
     *DDDI = deviceidentifier;
@@ -1425,7 +1478,7 @@ IDirectDrawImpl_GetDeviceIdentifier(IDir
  *  Surface: Address to write the surface pointer to
  *
  * Returns:
- *  Always returns DD_OK because it's a stub
+ *  Always returns DDERR_NOTFOUND because it's a stub
  *
  *****************************************************************************/
 static HRESULT WINAPI
@@ -1517,6 +1570,8 @@ IDirectDrawImpl_StartModeTest(IDirectDra
  * Enumeration callback for IDirectDrawImpl_RecreateAllSurfaces.
  * It re-recreates the WineD3DSurface. It's pretty straightforward
  *
+ * Assumes that the lock is held properly by the caller
+ *
  *****************************************************************************/
 HRESULT WINAPI
 IDirectDrawImpl_RecreateSurfacesCallback(IDirectDrawSurface7 *surf,
@@ -1625,7 +1680,9 @@ IDirectDrawImpl_RecreateSurfacesCallback
  *
  * A function, that converts all wineD3DSurfaces to the new implementation type
  * It enumerates all surfaces with IWineD3DDevice::EnumSurfaces, creates a
- * new WineD3DSurface, copies the content and releases the old surface
+ * new WineD3DSurface, copies the content and releases the old surface.
+ *
+ * Assumes that the lock is held properly by the caller
  *
  *****************************************************************************/
 static HRESULT
@@ -1660,6 +1717,8 @@ IDirectDrawImpl_RecreateAllSurfaces(IDir
  * correct mipmap sublevel, and returns it to WineD3D.
  * The surfaces are created already by IDirectDraw7::CreateSurface
  *
+ * Assumes that the lock is held properly by IDirectDraw7::CreateSurface
+ *
  * Params:
  *  With, Height: With and height of the surface
  *  Format: The requested format
@@ -1702,6 +1761,10 @@ D3D7CB_CreateSurface(IUnknown *device,
  * A helper function for IDirectDraw7::CreateSurface. It creates a new surface
  * with the passed parameters.
  *
+ * Assumes that the lock on the IDirectDrawImpl object is held by
+ * IDirectDraw7::CreateSurface. No need to hold the lock on the surface,
+ * because it is beeing created
+ *
  * Params:
  *  DDSD: Description of the surface to create
  *  Surf: Address to store the interface pointer at
@@ -2154,6 +2217,7 @@ IDirectDrawImpl_CreateSurface(IDirectDra
                                        &Mode);
     if(FAILED(hr))
     {
+        /* This->orig_bpp is never changed, no need to lock */
         ERR("Failed to read display mode from wined3d\n");
         switch(This->orig_bpp)
         {
@@ -2296,7 +2360,9 @@ IDirectDrawImpl_CreateSurface(IDirectDra
     }
 
     /* Create the first surface */
+    DDOBJ_LOCK(This);
     hr = IDirectDrawImpl_CreateNewSurface(This, &desc2, &object, 0);
+    DDOBJ_UNLOCK(This);
     if( hr != DD_OK)
     {
         ERR("IDirectDrawImpl_CreateNewSurface failed with %08lx\n", hr);
@@ -2332,10 +2398,12 @@ IDirectDrawImpl_CreateSurface(IDirectDra
             desc2.dwHeight /= 2;
         }
 
+        DDOBJ_LOCK(This);
         hr = IDirectDrawImpl_CreateNewSurface(This,
                                               &desc2,
                                               &object2,
                                               level);
+        DDOBJ_UNLOCK(This);
         if(hr != DD_OK)
         {
             /* This destroys and possibly created surfaces too */
@@ -2344,11 +2412,13 @@ IDirectDrawImpl_CreateSurface(IDirectDra
         }
 
         /* Add the new surface to the complex attachment list */
+        DDOBJ_LOCK(This);
         object2->first_complex = object;
         object2->next_complex = NULL;
         iterator = object;
         while(iterator->next_complex) iterator = iterator->next_complex;
         iterator->next_complex = object2;
+        DDOBJ_UNLOCK(This);
 
         /* Remove the (possible) back buffer cap from the new surface description,
          * because only one surface in the flipping chain is a back buffer, one
@@ -2406,6 +2476,7 @@ IDirectDrawImpl_CreateSurface(IDirectDra
         WINED3DFORMAT Format;
         WINED3DPOOL Pool = WINED3DPOOL_DEFAULT;
 
+        DDOBJ_LOCK(This);
         This->tex_root = object;
 
         if(desc2.ddsCaps.dwCaps & DDSCAPS_MIPMAP)
@@ -2443,6 +2514,7 @@ IDirectDrawImpl_CreateSurface(IDirectDra
                                            (IUnknown *) ICOM_INTERFACE(object, IDirectDrawSurface7),
                                            D3D7CB_CreateSurface );
         This->tex_root = NULL;
+        DDOBJ_UNLOCK(This);
     }
 
     return hr;
@@ -2607,6 +2679,7 @@ IDirectDrawImpl_EnumSurfaces(IDirectDraw
     if(!Callback)
         return DDERR_INVALIDPARAMS;
 
+    DDOBJ_LOCK(This);
     for(surf = This->surface_list; surf; surf = surf->next)
     {
         if (all || (nomatch != IDirectDrawImpl_DDSD_Match(DDSD, &surf->surface_desc)))
@@ -2614,9 +2687,13 @@ IDirectDrawImpl_EnumSurfaces(IDirectDraw
             desc = surf->surface_desc;
             IDirectDrawSurface7_AddRef(ICOM_INTERFACE(surf, IDirectDrawSurface7));
             if(Callback( ICOM_INTERFACE(surf, IDirectDrawSurface7), &desc, Context) != DDENUMRET_OK)
+            {
+                DDOBJ_UNLOCK(This);
                 return DD_OK;
+            }
         }
     }
+    DDOBJ_UNLOCK(This);
     return DD_OK;
 }
 
@@ -2626,7 +2703,9 @@ IDirectDrawImpl_EnumSurfaces(IDirectDraw
  * Callback called by WineD3D to create Surfaces for render target usage
  * This function takes the D3D target from the IDirectDrawImpl structure,
  * and returns the WineD3DSurface. To avoid double usage, the surface
- * is marked as render target afterwards
+ * is marked as render target afterwards.
+ *
+ * Assumes that the lock is properly held by IDirectDraw7::CreateSurface
  *
  * Params
  *  device: The WineD3DDevice's parent
@@ -2732,7 +2811,10 @@ D3D7CB_CreateDepthStencilSurface(IUnknow
  * Callback function for WineD3D which creates a new WineD3DSwapchain
  * interface. It also creates an IParent interface to store that pointer,
  * so the WineD3DSwapchain has a parent and can be released when the D3D
- * device is destroyed
+ * device is destroyed.
+ *
+ * Assumes that the lock is properly held by IDirectDraw7::CreateSurface
+ *
  *****************************************************************************/
 static HRESULT WINAPI
 D3D7CB_CreateAdditionalSwapChain(IUnknown *device,
@@ -2821,6 +2903,7 @@ IDirectDrawImpl_AttachD3DDevice(IDirectD
     /* If there's no window, create a hidden window. WineD3D needs it */
     if(window == 0)
     {
+        DDOBJ_LOCK(This);
         window = CreateWindowExA(0, This->classname, "Hidden D3D Window",
                                  WS_DISABLED, 0, 0,
                                  GetSystemMetrics(SM_CXSCREEN),
@@ -2830,6 +2913,7 @@ IDirectDrawImpl_AttachD3DDevice(IDirectD
         ShowWindow(window, SW_HIDE);   /* Just to be sure */
         WARN("(%p) No window for the Direct3DDevice, created a hidden window. HWND=%p\n", This, window);
         This->d3d_window = window;
+        DDOBJ_UNLOCK(This);
     }
     else
     {
@@ -2881,6 +2965,7 @@ IDirectDrawImpl_AttachD3DDevice(IDirectD
     /* Set this NOW, otherwise creating the depth stencil surface will cause a
      * recursive loop until ram or emulated video memory is full
      */
+    DDOBJ_LOCK(This);
     This->d3d_initialized = TRUE;
 
     hr = IWineD3DDevice_Init3D(This->wineD3DDevice,
@@ -2889,8 +2974,10 @@ IDirectDrawImpl_AttachD3DDevice(IDirectD
     if(FAILED(hr))
     {
         This->wineD3DDevice = NULL;
+        DDOBJ_UNLOCK(This);
         return hr;
     }
+    DDOBJ_UNLOCK(This);
 
     /* Create an Index Buffer parent */
     TRACE("(%p) Successfully initialized 3D\n", This);
diff --git a/dlls/ddraw/ddraw_private.h b/dlls/ddraw/ddraw_private.h
index abb6e36..ce269b3 100644
--- a/dlls/ddraw/ddraw_private.h
+++ b/dlls/ddraw/ddraw_private.h
@@ -145,6 +145,10 @@ struct IDirectDrawImpl
     /* For the dll unload cleanup code */
     IDirectDrawImpl *next;
     LONG surfaces;
+
+    /* Multithreading synchronisation */
+    CRITICAL_SECTION        crit;
+    BOOL                    hasCrit;
 };
 
 /* Declare the VTables. They can be found ddraw.c */
@@ -189,6 +193,10 @@ extern CRITICAL_SECTION listCrit;
 /* The default surface type */
 extern WINED3DSURFTYPE DefaultSurfaceType;
 
+/* Helper macro for multithreading, for all objects */
+#define DDOBJ_LOCK(obj) if(obj->hasCrit) EnterCriticalSection(&obj->crit)
+#define DDOBJ_UNLOCK(obj) if(obj->hasCrit) LeaveCriticalSection(&obj->crit)
+
 /*****************************************************************************
  * IDirectDrawSurface implementation structure
  *****************************************************************************/
diff --git a/dlls/ddraw/direct3d.c b/dlls/ddraw/direct3d.c
index ab59340..468f700 100644
--- a/dlls/ddraw/direct3d.c
+++ b/dlls/ddraw/direct3d.c
@@ -741,12 +741,16 @@ IDirect3DImpl_7_CreateDevice(IDirect3D7 
 
     *Device = NULL;
 
+    /* Lock to be sure */
+    DDOBJ_LOCK(This);
     /* Fail device creation if non-opengl surfaces are used */
     if(This->ImplType != SURFACE_OPENGL)
     {
+        DDOBJ_UNLOCK(This);
         ERR("The application wants to create a Direct3D device, but non-opengl surfaces are set in the registry. Please set the surface implementation to opengl or autodetection to allow 3D rendering\n");
 
-        /* We only hit this path if a default surface is set in the registry. Incorrect autodetection
+        /* We only hit this path if a default s    DDOBJ_LOCK(This);
+        urface is set in the registry. Incorrect autodetection
          * is caught in CreateSurface or QueryInterface
          */
         return DDERR_NO3D;
@@ -755,6 +759,7 @@ IDirect3DImpl_7_CreateDevice(IDirect3D7 
     /* So far we can only create one device per ddraw object */
     if(This->d3ddevice)
     {
+        DDOBJ_UNLOCK(This);
         FIXME("(%p): Only one Direct3D device per DirectDraw object supported\n", This);
         return DDERR_INVALIDPARAMS;
     }
@@ -762,6 +767,7 @@ IDirect3DImpl_7_CreateDevice(IDirect3D7 
     object = HeapAlloc(GetProcessHeap(), 0, sizeof(IDirect3DDeviceImpl));
     if(!object)
     {
+        DDOBJ_UNLOCK(This);
         ERR("Out of memory when allocating a IDirect3DDevice implementation\n");
         return DDERR_OUTOFMEMORY;
     }
@@ -788,6 +794,7 @@ IDirect3DImpl_7_CreateDevice(IDirect3D7 
     IndexBufferParent = HeapAlloc(GetProcessHeap(), 0, sizeof(IParentImpl *));
     if(!IndexBufferParent)
     {
+        DDOBJ_UNLOCK(This);
         ERR("Allocating memory for an index buffer parent failed\n");
         HeapFree(GetProcessHeap(), 0, object);
         return DDERR_OUTOFMEMORY;
@@ -811,6 +818,7 @@ IDirect3DImpl_7_CreateDevice(IDirect3D7 
 
     if(FAILED(hr))
     {
+        DDOBJ_UNLOCK(This);
         ERR("Failed to create an index buffer\n");
         HeapFree(GetProcessHeap(), 0, object);
         return hr;
@@ -851,7 +859,11 @@ IDirect3DImpl_7_CreateDevice(IDirect3D7 
                                                 This->d3d_target->WineD3DSurface,
                                                 target->WineD3DSurface);
         if(hr != D3D_OK)
+        {
+            DDOBJ_UNLOCK(This);
             ERR("(%p) Error %08lx setting the front and back buffer\n", This, hr);
+            return hr;
+        }
 
         object->OffScreenTarget = TRUE;
     }
@@ -872,6 +884,7 @@ IDirect3DImpl_7_CreateDevice(IDirect3D7 
 
     This->d3ddevice = object;
 
+    DDOBJ_UNLOCK(This);
     return D3D_OK;
 }
 
diff --git a/dlls/ddraw/main.c b/dlls/ddraw/main.c
index 1084c01..f322b2e 100644
--- a/dlls/ddraw/main.c
+++ b/dlls/ddraw/main.c
@@ -737,6 +737,8 @@ HRESULT WINAPI DllCanUnloadNow(void)
  * Callback function for the EnumSurfaces call in DllMain.
  * Dumps some surface info and releases the surface
  *
+ * No need to hold the lock because this is called when the last thread detaches
+ *
  * Params:
  *  surf: The enumerated surface
  *  desc: it's description
diff --git a/dlls/ddraw/surface.c b/dlls/ddraw/surface.c
index 587a3e9..a55347f 100644
--- a/dlls/ddraw/surface.c
+++ b/dlls/ddraw/surface.c
@@ -238,6 +238,7 @@ static void IDirectDrawSurfaceImpl_Destr
 
     /* Reduce the ddraw surface count */
     InterlockedDecrement(&This->ddraw->surfaces);
+    DDOBJ_LOCK(This->ddraw);
     if(This->prev)
         This->prev->next = This->next;
     else
@@ -247,6 +248,7 @@ static void IDirectDrawSurfaceImpl_Destr
     }
     if(This->next)
         This->next->prev = This->prev;
+    DDOBJ_UNLOCK(This->ddraw);
 
     HeapFree(GetProcessHeap(), 0, This);
 }
-- 
1.2.4



More information about the wine-patches mailing list