Display a bitmap from Win32, unmanaged code?

B

bsnguy

I'm trying to do something that seems simple, but I'm missing a key point, it
seems. I have a DLL that returns a bitmap handle (hBitmap) and I want to
display that bitmap in a picturebox control. I can do it with the following
code:

hBitmap = win32DrawImage();
theBitmap = Bitmap.FromHbitmap(hBitmap);
UpdateImageBitmapMethod(theBitmap);
this.theImage.Image = theBitmap;

This works fine to display my image. The problem is that I'm display a lot
of them, in real-time, from a data acquisition device so if I put this in a
loop I run out of memory after a while.

So I said "hey, dispose of the bitmap" and I added

theBitmap.Dispose();

This works, for a while. The problem is that depending on what I do in the
UI, it seems that the bitmap is being disposed before the picturebox has
actually displayed it and I get an exception. Is there a better way to handle
this?

Thanks
 
B

bsnguy

How obvious! That's why we have forums... I moved the dispose to just before
getting the new bitmap (with a check for it being NULL, of course!) and all
seems well, now.
 
S

Stanimir Stoyanov \(C# MVP\)

Can you tell us what software the DLL is part of? If it has a better API or
a more interactive way to stream the video instead of querying the device
and working with single frames, it would be a much better design.

Also, can you post more of your code, for example the loop that you use
(including timing, delays, etc)? This would make it easier for someone to
understand the problem and, hopefully, help.

HTH,
 
J

Jie Wang [MSFT]

Hi,

I got one more thing to add:

Since your unmanaged DLL returns a GDI bitmap handle, and in your original
code there is no indication of releasing that handle, I strongly suggest
you to add a line of DeleteObject(hBitmap) right after the
Bitmap.FromHBitmap(hBitmap). Otherwise you're very likely to have a leak.

Begin Quote: MSDN documentation:

The FromHbitmap method makes a copy of the GDI bitmap; so you can release
the incoming GDI bitmap using the GDI DeleteObject method immediately after
creating the new Image.

http://msdn.microsoft.com/en-us/library/zzxcxctz.aspx

End Quote

So the code shall looks like this:

[DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);

...

hBitmap = win32DrawImage();
theBitmap = Bitmap.FromHbitmap(hBitmap);
DeleteObject(hBitmap); // we're done with the GDI bitmap, delete it
immediately!
UpdateImageBitmapMethod(theBitmap);
this.theImage.Image = theBitmap;

Best regards,

Jie Wang ([email protected], remove 'online.')

Microsoft Online Community Support

Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/en-us/subscriptions/aa948868.aspx#notifications.

Note: MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 2 business days is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions. Issues of this
nature are best handled working with a dedicated Microsoft Support Engineer
by contacting Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/en-us/subscriptions/aa948874.aspx
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
B

bsnguy

Thanks for the additional ideas.

First, related to deleting the underlying bitmap. In the low-level Win32
code, the bitmap is reused and managed, there. This is code that's been
around for many years and is stable which is why I don't want to fiddle with
it (but I probably will have to in the coming months).

Second, this DLL is one I wrote and it's "streaming" data from custom
hardware, not a video camera. Each "frame" of data needs to be processed one
frame at a time and it's not any kind of standard video format. I get a new
frame, process that frame and then send an event to my C# program that
displays it.

Third, the proposed solution to move the dispose seems a bit fragile. What
is needed is a callback or method like is sued for the asynchronous load for
a pictureBox. In that way, the control could notify the caller when it's done
with the object. What's a bit odd is that it seems as though the
pictureBox.image call is actually doing things asynchronously, else this
would not be a problem. Is there a way to know, for sure, that the image is
done being displayed so that the data it was copying from can be discarded?
It's obvious that the call completing is not an indication that it's save to
dispose it.

Thanks for all the input,
Dave
 
J

Jie Wang [MSFT]

| First, related to deleting the underlying bitmap. In the low-level Win32
| code, the bitmap is reused and managed, there. This is code that's been
| around for many years and is stable which is why I don't want to fiddle
with
| it (but I probably will have to in the coming months).

Glad to know that. If the hBitmap will be reused, then we don't need to
delete it after creating the Bitmap object.

| Third, the proposed solution to move the dispose seems a bit fragile.
What
| is needed is a callback or method like is sued for the asynchronous load
for
| a pictureBox. In that way, the control could notify the caller when it's
done
| with the object. What's a bit odd is that it seems as though the
| pictureBox.image call is actually doing things asynchronously, else this
| would not be a problem. Is there a way to know, for sure, that the image
is
| done being displayed so that the data it was copying from can be
discarded?
| It's obvious that the call completing is not an indication that it's save
to
| dispose it.

The only time to Dispose the image is the when it is no longer needed. By
that, I mean at the time there is no reference that will use the image
again.
If the image is still be displayed in the PictureBox, then the PictureBox
holds a reference to it, when the OnPaint event happens, the PictureBox
needs the image to redraw itself.

So I think the best safe time to Dispose the old image is right after the
new image is assigned to the PictureBox.

Image old = this.theImage.Image;
this.theImage.Image = theBitmap;
if (old != null) old.Dispose();

I should have added this in my previous post.

Image.Dispose() for your reference:
http://msdn.microsoft.com/en-us/library/8th8381z.aspx

Note the Remarks section.

Hope this helps.

Best regards,

Jie Wang ([email protected], remove 'online.')

Microsoft Online Community Support

Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/en-us/subscriptions/aa948868.aspx#notifications.

Note: MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 2 business days is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions. Issues of this
nature are best handled working with a dedicated Microsoft Support Engineer
by contacting Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/en-us/subscriptions/aa948874.aspx
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
B

bsnguy

So I think the best safe time to Dispose the old image is right after the
new image is assigned to the PictureBox.

Image old = this.theImage.Image;
this.theImage.Image = theBitmap;
if (old != null) old.Dispose();


Now this is clean (and obvious, now, thanks!). Once the new image is
assigned, then we know the old one will never be used, again. Perfect.



Thank you,

Dave
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top