none
AccessViolationException When Using CopyMemory on Bitmap->WriteableBitmap

    Question

  • Hello all.

    I'm attempting to copy the contents of a Bitmap to a WriteableBitmap.  Unfortunately, I am getting a AccessViolationException when attempting to make the call.  Does anyone have any clues as to what I might be doing wrong?

    Here is my code:

    WriteableBitmap _writeableBitmap1 = new WriteableBitmap(1920, 1200, 96, 96, PixelFormats.Rgb24, null);
    
    private void OnIdeaNotificationReceived(IdeaNotificationMessage m)
    {
      if (m.Notification == Notifications.IdeaFG1OnSnap)
      {
        Bitmap bmp = Bitmap.FromHbitmap(m.Bitmap); // m.Bitmap = hBitmap to memory Bitmap
        BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, 1920, 1200), ImageLockMode.ReadOnly, bmp.PixelFormat);
    
        _writeableBitmap1.Lock();
    
        CopyMemory(_writeableBitmap1.BackBuffer, bmpData.Scan0, (_writeableBitmap1.BackBufferStride * 1200));
    
        _writeableBitmap1.AddDirtyRect(new Int32Rect(0, 0, 1920, 1200));
        _writeableBitmap1.Unlock();
    
        bmp.UnlockBits(bmpData);
        bmp.Dispose();
      }
    }
    
    [DllImport("kernel32.dll", EntryPoint="RtlMoveMemory")]
    public static extern void CopyMemory(IntPtr dest, IntPtr source, int length);
    
    

    My first guess is that I'm not sure how to calculate the "length" parameter for CopyMemory -- I've tried several variations of heights, widths and strides, but to no avail.

    Any help in getting this figured out is greatly appreciated!

    Wednesday, November 03, 2010 11:41 PM

Answers

  • Hi Evil,

    It is a native method to check the memory block. Use Windbg to access and check the data segment of the image in memory. But I know, it is not easy to do it. About the exception - AccessViolationException: http://msdn.microsoft.com/en-us/library/system.accessviolationexception.aspx So I think you'd better to try to read memory the by unsafe code first, the m.Bitmap may use a protected memory.

    As we knoe, Bitmap.FromHbitmap(IntPtr) creates a Bitmap from the handle, and I reflect the code of FromHbitmap(), find it use the GdipCreateBitmapFromHBITMAP method to create the bitmap, could you please try to this API instead of  Bitmap.FromHbitmap:

    [DllImport("gdiplus.dll", CharSet=CharSet.Unicode, ExactSpelling=true)]
    static extern int GdipCreateBitmapFromHBITMAP(HandleRef hbitmap,
      HandleRef hpalette, out IntPtr bitmap);
    

    The code from reflector of FromHbitmap method:

    public static Bitmap FromHbitmap(IntPtr hbitmap, IntPtr hpalette)
    {
     IntSecurity.ObjectFromWin32Handle.Demand();
     IntPtr zero = IntPtr.Zero;
     int status = SafeNativeMethods.Gdip.GdipCreateBitmapFromHBITMAP(new HandleRef(null, hbitmap), new HandleRef(null, hpalette), out zero);
     if (status != 0)
     {
      throw SafeNativeMethods.Gdip.StatusException(status);
     }
     return Bitmap.FromGDIplus(zero);
    }
    
     
    
    

     

    Sincerely,
    Bob Bao 
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Are you looking for a typical code sample? Please download all in one code framework !
    Friday, November 05, 2010 8:16 AM
    Moderator

All replies

  • Hi Evil,

    I performed a test based on your code, and I read a bitmap form the file directly. It works fine (I change the pixel format of the writeable bitmap to Bgr24, since the RGB  render order is opposite with the Bitmap):

       WriteableBitmap _writeableBitmap1 = new WriteableBitmap(width, height, 96, 96, PixelFormats.Bgr24, null);
       
       System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(@"my image file");
       System.Drawing.Imaging.BitmapData bmpData =
        bmp.LockBits(new System.Drawing.Rectangle(0, 0, width, height), System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp.PixelFormat);
    
       _writeableBitmap1.Lock();
    
       CopyMemory(_writeableBitmap1.BackBuffer, bmpData.Scan0, (_writeableBitmap1.BackBufferStride * height));
    
       _writeableBitmap1.AddDirtyRect(new Int32Rect(0, 0, width, height));
       _writeableBitmap1.Unlock();
    
       bmp.UnlockBits(bmpData);
       bmp.Dispose();
    
       img.Source = _writeableBitmap1;
    

    I donot think it is an issue of the "length" parameter, the BackBufferStride is 5760, it is correct. Could you please check the m.Bitmap if its data section in the memory can be read? Or you could try to test like me, use an image file dirctly.

    On the other hand, we could use Imaging.CreateBitmapSourceFromHBitmap method to convert the Drawing.Bitmap to BitmapSource in WPF.

    Hope this helps.

    Sincerely,
    Bob Bao

    MSDN Subscriber Support in Forum 

    If you have any feedback on our support, please contact msdnmg@microsoft.com


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Are you looking for a typical code sample? Please download all in one code framework !
    Thursday, November 04, 2010 3:28 AM
    Moderator
  • Thanks Bob.

    I will check out the code using a file off the disk tomorrow, when I'm back at my work computer.

    I have been using Imaging.CreateBitmapSourceFromHBitmap and that does work, using the same m.Bitmap reference (I'm using the same function to test my new code, so the m.Bitmap is the same as it was).  The problem I'm trying to get around comes from my previous question you answered to -- I'm updating this BitmapSource *very* often!  So, at the moment, I'm creating a new BitmapSource as quickly as I'm getting new image frames (they are from a video source) and assigning them to an Image.Source.  I do this so quickly that the garbage collector can not keep up, and I have to force it to collect or I run out of memory.  I'm hoping the WriteableBitmap will both improve the speed of the update and stop me from having to manually call the GC to run.

    Thursday, November 04, 2010 3:36 AM
  • Hi Bob,

    I just re-read your reply and noticed this question:

    "Could you please check the m.Bitmap if its data section in the memory can be read?"

    How do I test that?  I'm assuming there is a flag I can check, or an API call?

    Thanks!

    Thursday, November 04, 2010 2:45 PM
  • Hi Evil,

    It is a native method to check the memory block. Use Windbg to access and check the data segment of the image in memory. But I know, it is not easy to do it. About the exception - AccessViolationException: http://msdn.microsoft.com/en-us/library/system.accessviolationexception.aspx So I think you'd better to try to read memory the by unsafe code first, the m.Bitmap may use a protected memory.

    As we knoe, Bitmap.FromHbitmap(IntPtr) creates a Bitmap from the handle, and I reflect the code of FromHbitmap(), find it use the GdipCreateBitmapFromHBITMAP method to create the bitmap, could you please try to this API instead of  Bitmap.FromHbitmap:

    [DllImport("gdiplus.dll", CharSet=CharSet.Unicode, ExactSpelling=true)]
    static extern int GdipCreateBitmapFromHBITMAP(HandleRef hbitmap,
      HandleRef hpalette, out IntPtr bitmap);
    

    The code from reflector of FromHbitmap method:

    public static Bitmap FromHbitmap(IntPtr hbitmap, IntPtr hpalette)
    {
     IntSecurity.ObjectFromWin32Handle.Demand();
     IntPtr zero = IntPtr.Zero;
     int status = SafeNativeMethods.Gdip.GdipCreateBitmapFromHBITMAP(new HandleRef(null, hbitmap), new HandleRef(null, hpalette), out zero);
     if (status != 0)
     {
      throw SafeNativeMethods.Gdip.StatusException(status);
     }
     return Bitmap.FromGDIplus(zero);
    }
    
     
    
    

     

    Sincerely,
    Bob Bao 
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Are you looking for a typical code sample? Please download all in one code framework !
    Friday, November 05, 2010 8:16 AM
    Moderator
  • Thanks Bob.

    I'll give the code a try when they let me back into my lab on Monday.  Another group stole the space for today. =)

    Friday, November 05, 2010 4:58 PM