Delete a file in Finalizer

R

Richard Arthur

This is a weird problem.

1) I use MediaDet to save a bitmap in a temporary file.
2) I create a bitmap using that temporary file's name.
3) I use the bitmap.
4) I want to destroy the file when the process exits, but I am having
trouble
I have written a Finalizer on the object that actually generates the
bitmaps, as well as implementing IDisposable. The finalizer gets called, I
then call Dispose on each of the bitmaps it the object has created, and then
I call File.Delete() to delete the file used to create the bitmap.

If I call Dispose explicitly on the object in a form's Dispose method, this
works fine. If I close it in the event handler for the "Close" event, it
works fine, but if I let the garbage collector Finalize the object itself,
then this does not delete the files. It throws an IOException (which I
catch), saying that the object is in use by another process.

How can I make this object so that it cleans itself up properly? It is
going to be used by other people, so I do not want to give them too much
documentation overhead.

Richard Arthur
 
A

Andreas Huber

Richard said:
This is a weird problem.

1) I use MediaDet to save a bitmap in a temporary file.
2) I create a bitmap using that temporary file's name.
3) I use the bitmap.
4) I want to destroy the file when the process exits, but I am having
trouble
I have written a Finalizer on the object that actually generates
the bitmaps, as well as implementing IDisposable. The finalizer gets
called, I then call Dispose on each of the bitmaps it the object has
created, and then I call File.Delete() to delete the file used to
create the bitmap.

If I call Dispose explicitly on the object in a form's Dispose
method, this works fine. If I close it in the event handler for the
"Close" event, it works fine, but if I let the garbage collector
Finalize the object itself, then this does not delete the files. It
throws an IOException (which I catch), saying that the object is in
use by another process.

Your problem stems from the fact that finalizers of no longer accessible
objects are called in arbitrary order. You have three objects: One of your
class, the Bitmap object and a FileStream object. As soon as the an object
of your class goes out of scope, all 3 objects become garbage. Two of these
objects have finalizers. These can be called in the correct order (finalizer
of FileStream first, finalizer of your object second) or the other way
round, which leads to the problem you're observing.
How can I make this object so that it cleans itself up properly? It
is going to be used by other people, so I do not want to give them
too much documentation overhead.

With the design you're describing there simply is no way to achieve what
you're after. You cannot reliably expose the same object (the file) to the
effects of more than one finalizer when correctness depends on their
execution order. There is a similar problem in the .NET framework with
FileStream and StreamWriter objects, both of which have finalizers. When you
forget to call Dispose() on the StreamWriter object and let it go out of
scope, data in its buffer is not written into the FileStream and is simply
lost.

If you have enough memory I would suggest to use MemoryStream instead of a
FileStream.

Regards,

Andreas
 
R

Richard Arthur

Andreas,

There is only 1 way that I can see to implement if the way you suggest.
The function that gives me the Bitmap data requests a reference to a byte.
(ref byte). I need to pass it a null for that parameter so that it will
tell me how space I need to allocate. How do I pass a null in for that
parameter? If I can do that, I can call that routine, get the size, and
then allocate a byte array that is large enough for the data. I then can
pass into that same spot a pointer to the first element in that array,
create a MemoryStream around that byte array, and then create the Bitmap.

Thanks,

Richard Arthur

is if I can pass a null into the function
 
A

Andreas Huber

Richard said:
Andreas,

There is only 1 way that I can see to implement if the way you
suggest.
The function that gives me the Bitmap data requests a reference to a
byte. (ref byte). I need to pass it a null for that parameter so
that it will tell me how space I need to allocate. How do I pass a
null in for that parameter?

Have you tried to pass null for that parameter? I don't see any reason why
it should not work...

Regards,

Andreas
 
R

Richard Arthur

The C# compiler complains because the definition of the method says "ref
byte", and since bytes are primitive types, they cannot be null. If I could
change the way the parameter is defined, then I could pass in a null.
 
A

Andreas Huber

Richard Arthur said:
The C# compiler complains because the definition of the method says "ref
byte", and since bytes are primitive types, they cannot be null. If I could
change the way the parameter is defined, then I could pass in a null.

Sorry, I misread your previous post. I though that parameter was a ref
byte[]. What is the meaning of that parameter anyway? If there is no
other way to get at the size of the bitmap, it seems the interface is
either badly designed, badly documented or both.

Regards,

Andreas
 
R

Richard Arthur

This is the description of the method I am trying to use in the MediaDet
object. It is not documented very well.

ms-help://MS.VSCC.2003/MS.DirectX9.1033/DirectX9_c/directX/htm/getbitmapbits
methodmediaobject.htm

This is the MediaDet object in DirectX that exposes that method.

ms-help://MS.VSCC.2003/MS.DirectX9.1033/DirectX9_c/directX/htm/mediadetobjec
t.htm

ref byte is supposed to be a pointer to a byte array, but it is not exposed
very well. If the code knows the correllation between Media Types and bytes
used per pixel, and knows how much of a BitmapHeader will be tacked onto the
data, maybe the data can be allocated correctly.


Andreas Huber said:
"Richard Arthur" <[email protected]> wrote in message
The C# compiler complains because the definition of the method says "ref
byte", and since bytes are primitive types, they cannot be null. If I could
change the way the parameter is defined, then I could pass in a null.

Sorry, I misread your previous post. I though that parameter was a ref
byte[]. What is the meaning of that parameter anyway? If there is no
other way to get at the size of the bitmap, it seems the interface is
either badly designed, badly documented or both.

Regards,

Andreas
 
A

Andreas Huber

Richard Arthur said:
This is the description of the method I am trying to use in the MediaDet
object. It is not documented very well.

ms-help://MS.VSCC.2003/MS.DirectX9.1033/DirectX9_c/directX/htm/getbitmapbits
methodmediaobject.htm

The docs aren't very helpful...
This is the MediaDet object in DirectX that exposes that method.

ms-help://MS.VSCC.2003/MS.DirectX9.1033/DirectX9_c/directX/htm/mediadetobjec
t.htm

ref byte is supposed to be a pointer to a byte array, but it is not exposed
very well. If the code knows the correllation between Media Types and bytes
used per pixel, and knows how much of a BitmapHeader will be tacked onto the
data, maybe the data can be allocated correctly.

Sorry, I can't help you here. The C# version of the interface seems to
be flawed. I don't see any way how you could pass in null for the
pBuffer parameter. Maybe there is a way with unsafe code.
Another way to make it work is to use a buffer that is always large
enough and copy the contents after calling the function (I assume the
function also returns the number of bytes written to the buffer).
Although this is less efficient than necessary it should be much more
efficient than the version using an external file...

Regards,

Andreas
 
R

Richard Arthur

Thanks anyway. It looks like I will just use the write-to-file method to
create the image, and then read it in. cleaning up as many of the tmeporary
files as I can, but leaving any extras there.
Richard
 

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