views:

551

answers:

6

I am using some unmanaged code that is returning pointers (IntPtr) to large image objects. I use the references but after I am finished with the images, I need to free that memory referenced by the pointers. Currently, the only thing that frees the memory is to shutdown my entire app. I need to be able to free that memory from inside my application.

Here is the call to that allocates the memory. hbitmap is the pointer that is returned and needs to be deallocated.

[DllImport("twain_32.dll", EntryPoint = "#1")]
public static extern TwainResult DsImageTransfer(
    [In, Out] Identity origin, [In] Identity dest, DataGroup dg, 
    DataArgumentType dat, Message msg, ref IntPtr hbitmap);
+5  A: 

You need to use the specific memory allocator mechanism that was used to allocate the memory in the first place.

So, if you were using COM and the IMalloc interface to allocate the memory, then you have to pass the IntPtr back to the Free method on that implementation in order to free the memory allocated.

If you are indeed using the COM allocator that is returned by a call to CoGetMalloc, then you can call the static FreeCoTaskMem method on the Marshal class.

The Marshal class also has a method for freeing memory that is allocated through a call to LocalAlloc called FreeHGlobal.

However, and this is a common case, if the memory was allocated by the new operator in C++, or a call to malloc in C, then you have to expose a function in unmanaged code through interop which will free the memory appropriately.

In the case of C++, you would expose a function that takes a pointer and simply calls delete on that pointer. In the case of malloc, you would create a function that takes a pointer, and calls free on that pointer.

In specific regards to your question, it would seem that DsImageTransfer is a vendor-specific API (one that doesn't have much discoverability on the web either, I'm afraid), so more information is needed about that specific API function and how it allocates memory. Just knowing the handle type (an HBITMAP in this case) doesn't give any indication as to how it's allocated. It can be allocated with all the mechanisms mentioned above.

Assuming it is creating the HBITMAP using GDI Object api functions (specifically, the CreateBitmap function), then you could use the DeleteObject function to release the handle (as per the documentation page for the GDI Object api functions).

casperOne
+2  A: 

It depends. Do you have any documentation (or source code) for the native functions you are calling?

Native code doesn't have a single deallocation function. This is one of the great advantages of the CLR.

If I was a betting man, I'd go for GlobalFree. But it's not going to be much fun trying various APIs until your code stops crashing.

Daniel Earwicker
Whaddaya know, I guessed right!
Daniel Earwicker
+2  A: 

That would depend on how that memory was allocated. The Marshal class has methods for deallocating memory allocated through the common interop allocation patterns, like FreeCoTaskMem. If the unmanaged code uses a non Interop compatible way of allocating, then you cannot interop with it.

Updated

If I would venture a guess, the function #1 you invoke in twain_32.dll is the DS_ENTRY function in a TWAIN provider. The Twain specifications call out the memory resource management protocol:

Memory Management in TWAIN 2.0 and Higher
TWAIN requires Applications and Sources to manage each other’s memory. The chief problem is guaranteeing agreement on the API’s to use. TWAIN 2.0 introduces four new functions that are obtained from the Source Manager through DAT_ENTRYPOINT.

TW_HANDLE PASCAL DSM_MemAllocate (TW_UINT32)
PASCAL DSM_MemFree (TW_HANDLE)
TW_MEMREF PASCAL DSM_MemLock(TW_HANDLE)
void PASCAL DSM_MemUnlock(TW_HANDLE)

These functions correspond to the WIN32 Global Memory functions mentioned in previous versions of the TWAIN Specification: GlobalAlloc, GlobalFree, GlobalLock, GlobalUnlock
On MacOS/X these functions call NewPtrClear and DisposePtr. The lock and unlock functions are no-ops, but they still must be called. TWAIN 2.0 compliant Applications and Sources must use these calls on all platforms (Windows, MacOS/X and Linux). The Source Manager takes the responsibility to make sure that all components are using the same memory management API’s.

So to free resources you're supposed to call DSM_MemFree, which supposedly on Win32 platforms would be implemented through GlobalFree, or Marshal.FreeHGlobal.

Since this is mostly speculation on my part, you better validate with the specs of the specific TWAIN implementation you use.

Remus Rusanu
GlobalFree worked for me. Thank you!
Dave
+1  A: 

Please show your unmanaged code. There are different ways to allocate memory in unmanaged land, and you must use the correct corresponding means of deallocating. You will probably end up implementing a Finalizer and IDisposable, and implementing the Dispose pattern as described here: http://www.codeproject.com/KB/cs/idisposable.aspx

JMarsch
You can only call the native deallocation function from a finalizer if the native deallocation system is thread safe. It's better to avoid writing a finalizer if at all possible.
Daniel Earwicker
@Earwicker: I hadn't considered non-threadsafe deallocations -- to be honest, I didn't consider that there were unsafe deallocation calls. In fact, what would that mean to writing threaded code in .Net (if the underlying native calls rely upon non-threadsafe deallocators)?
JMarsch
The well-defined Microsoft APIs for allocation/deallocation of memory are thread safe these days (prior to VS 2005 there was an option to use non-thread-safe version of `malloc`/`free`, however). But anyone can write a native library that exposes a similar interface, where a pointer is returned by an "allocate" function and must later be passed back to a "free" function. They could be doing absolutely anything behind the scenes, without appropriate locking. You don't know unless you know the internals of the library. So I was thinking here about some random 3rd party native library.
Daniel Earwicker
@Earwicker -- I understand where you're coming from now. That's a really good point. Thank you for clearing it up for me.
JMarsch
BTW, COM is an example of this - most COM objects are not particularly thread-safe: you have to call `Release` on the same thread as you created and used the object. So the RCW has a finalizer that only posts a "please Release this object" message to the thread on which the object was created, i.e. it marshals the `Release` call onto the correct thread. So background threads that create such COM objects have to be STA threads (to enable this behaviour) and they also have to regularly pump messages.
Daniel Earwicker
A: 

Perhaps you could try creating a Bitmap object from hBitmap and then disposing it.

Bitmap bitmap = Bitmap.FromHBitmap(hBitmap);
bitmap.Dispose();
Zach Johnson
A: 

As everyone else is pointing out, It dpends on how it was allocated. However, if it really is a Win32 hbitmap, then you deallocate it with the Win32 "DeleteObject" function.

danbystrom