Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GCHandle to get address(pointer) of .net object

I managed to get the address of a .net object by

GCHandle objHandle = GCHandle.Alloc(obj,GCHandleType.WeakTrackResurrection);
int address = GCHandle.ToIntPtr(objHandle).ToInt32();  

and I can recall the object by

Object obj = GCHandle.FromIntPtr(IntPtr(address)).Target;

Well, the purpose is to store the address in a native class and have an information of which native object is releated to which .net object.
AFAIK the address does not change because of allocing, is it true or does anyone have a better idea to serve my purpose?

Thanks

like image 376
ali_bahoo Avatar asked Nov 04 '10 13:11

ali_bahoo


3 Answers

You'll want to pin the GCHandle to stop the object moving around, as the GC moves objects around, so an unpinned pointer could become invalid. Pinning the object stops it moving:

GCHandle handle = GCHandle.Alloc(obj, GCHandleType.Pinned);
IntPtr ptr = handle.AddrOfPinnedObject();

You'll also have to free the handle when you're done:

handle.Free();
like image 179
thecoop Avatar answered Oct 20 '22 12:10

thecoop


As Tim and thecoop has pointed out, GCHandle.Alloc may prevent garbage collection but actual object address can change as GC may move object around unless you pin the object. Further, your code is using GCHandleType.WeakTrackResurrection and that would not event prevent the garbage collection. GCHandle.ToIntPtr will give address of handle that can be round-tripped over unmanaged call. Actual object address will be given by AddrOfPinnedObject method.

Said all that, IMO, your code may serve the purpose of associating .NET object with unmanaged object. This is because GCHandle.To/FromIntPtr will get back you correct GCHandle and you can reach your .NET object via it (provided its not garbage collected). IMO, it should be immaterial if actual object address had changed or not.

like image 6
VinayC Avatar answered Oct 20 '22 11:10

VinayC


What you are getting is not actually an address.

As you notice, it seems to act like an address most of the time, and you can recall the object, by using GCHandle.FromIntPtr. However, the interesting issue is that you are using GCHandleType.WeakTrackResurrection.

If your weakly referenced object gets collected (it presumably can, since it is only weakly referenced by the GCHandle), you still have the IntPtr, and you can pass it to GCHandle.FromIntPtr(). If you do so, then you get back null, assuming the IntPtr has not been recycled.

(If the IntPtr has been recycled by the CLR for some reason, then you are in trouble. I'm not sure whether this can happen.)

You are better off using either GCHandleType.Normal, or GCHandleType.Pinned (if you need to take the address of the object in unmanaged code), if you want a strong reference to the object.

(To use GCHandleType.Pinned, your object must e.g. be primitive, or have [StructLayout] attribute, or be an array of such objects.)

like image 2
Tim Lovell-Smith Avatar answered Oct 20 '22 12:10

Tim Lovell-Smith