Question Error: Bitmap Region Is Already Locked

bigfoot3d

Well-known member
Joined
Mar 11, 2007
Messages
56
Location
New Orleans, LA
Programming Experience
3-5
So I have tested this over and over again trying to add a mutex and synclocks to see if maybe I had a multithreading issue going on, and I am still stuck. After exhausting all my other options I am posting here to see if anyone is familiar with this problem or anyone has an idea on how I could solve it.

When this errors out, the error does not specify which line of code, it just shows the error and while in debug mode the debugging stops after clicking continue.

The code is comparing the old image to the new image and updating the new image changes over the old image.

The error only seems to come about if I move the form that I am displaying the changed image on, or if another window covers the form and when that window is moved or minimized to show the form again, that is when it crashes.

I am not sure if it is a drawing issue or what.

VB.NET:
Sub getdataHFHRecScreen(ByVal mem As IO.MemoryStream)
        Try
            Me.myMutex.WaitOne()
            SyncLock Me.picboxClientScreen.Image
                SyncLock Me.oldscreen
                    Dim gs As New System.IO.Compression.GZipStream(mem, IO.Compression.CompressionMode.Decompress, False)
                    Dim collector As New IO.MemoryStream
                    mem.Position = 0
                    Dim Data(4) As Byte
                    Dim nread As Integer
                    Do
                        nread = gs.Read(Data, 0, Data.Length)
                        If 1 > nread Then
                            Exit Do
                        End If
                        collector.Write(Data, 0, nread)
                    Loop
                    Dim newscreen As Bitmap = Image.FromStream(collector)
                    gs.Close()
                    collector.Close()
                    Dim rct As New Rectangle(0, 0, Me.ClientScreenResolution.X, Me.ClientScreenResolution.Y)
                    Dim bmdata1 As Imaging.BitmapData = oldscreen.LockBits(rct, Imaging.ImageLockMode.ReadWrite, Imaging.PixelFormat.Format32bppArgb)
                    Dim bmdata2 As Imaging.BitmapData = newscreen.LockBits(rct, Imaging.ImageLockMode.ReadWrite, Imaging.PixelFormat.Format32bppArgb)
                    For x As Integer = 0 To rct.Width - 1
                        For y As Integer = 0 To rct.Height - 1
                            Dim pos As Integer = (x * 4) + (y * bmdata1.Stride)
                            Dim px1 As Integer = Runtime.InteropServices.Marshal.ReadInt32(bmdata1.Scan0, pos)
                            Dim px2 As Integer = Runtime.InteropServices.Marshal.ReadInt32(bmdata2.Scan0, pos)
                            If px2 <> 0 Then
                                Runtime.InteropServices.Marshal.WriteInt32(bmdata1.Scan0, pos, px2)
                            End If
                        Next
                    Next
                    oldscreen.UnlockBits(bmdata1)
                    newscreen.UnlockBits(bmdata2)
                    Me.picboxClientScreen.Image = oldscreen
                    newscreen.Dispose()
                    rct = Nothing
                    bmdata1 = Nothing
                    bmdata2 = Nothing
                    mem.Dispose()
                End SyncLock
            End SyncLock
        Catch e As Exception
            MsgBox("Processing Image Failed: " + e.GetBaseException.ToString)
        Finally
            Me.myMutex.ReleaseMutex()
        End Try
        Me.sendMessage("<HFH><Action>SendScreen</Action></HFH>")
    End Sub

and this is the error I get:
VB.NET:
System.InvalidOperationException was unhandled
  Message="Bitmap region is already locked."
  Source="System.Drawing"
  StackTrace:
       at System.Drawing.Graphics.CheckErrorStatus(Int32 status)
       at System.Drawing.Graphics.DrawImage(Image image, Int32 x, Int32 y, Int32 width, Int32 height)
       at System.Drawing.Graphics.DrawImage(Image image, Rectangle rect)
       at System.Windows.Forms.PictureBox.OnPaint(PaintEventArgs pe)
       at System.Windows.Forms.Control.PaintWithErrorHandling(PaintEventArgs e, Int16 layer, Boolean disposeEventArgs)
       at System.Windows.Forms.Control.WmPaint(Message& m)
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.UnsafeNativeMethods.CallWindowProc(IntPtr wndProc, IntPtr hWnd, Int32 msg, IntPtr wParam, IntPtr lParam)
       at System.Windows.Forms.NativeWindow.DefWndProc(Message& m)
       at System.Windows.Forms.Form.DefWndProc(Message& m)
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
       at System.Windows.Forms.ContainerControl.WndProc(Message& m)
       at System.Windows.Forms.Form.WmSysCommand(Message& m)
       at System.Windows.Forms.Form.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.UnsafeNativeMethods.CallWindowProc(IntPtr wndProc, IntPtr hWnd, Int32 msg, IntPtr wParam, IntPtr lParam)
       at System.Windows.Forms.NativeWindow.DefWndProc(Message& m)
       at System.Windows.Forms.Form.DefWndProc(Message& m)
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
       at System.Windows.Forms.ContainerControl.WndProc(Message& m)
       at System.Windows.Forms.Form.WmNcButtonDown(Message& m)
       at System.Windows.Forms.Form.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
       at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager
.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.Run(ApplicationContext context)
       at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun()
       at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoApplicationModel()
       at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.Run(String[] commandLine)
       at HFHRemoteHandTech.My.MyApplication.Main(String[] Args) in 17d14f5c-a337-4978-8281-53493378c1071.vb:line 81
       at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()

Any insight or ideas would be greatly appreciated.

Thanks in Advance!
 
From what I see you only use one resource external to the method, and that is "oldscreen", you should pass this as parameter. Also If you're using this image elsewhere like displaying it in a picturebox (which you do later in method I see) you should create a clone in order to have exclusive usage when processing it.

If you run your method in UI thread you should run it in a Threadpool thread, if you already are you should invoke a method on UI thread to update the Picturebox image.
 
Fabulous!! That did it! Thanks!

:D FABULOUS!!!!! :D

Yep, that sure did the trick of cloning the resource. I was tempting to do that earlier, but I was only cloning attempting to clone it to display it, and gave up on that when my results didn't change. You gave me the insight to create a complete clone of resource before even working with it.

If only hindsight was foresight...

GENIUS! THANKS!
 
Back
Top