?
Solved

GCHandle question

Posted on 2005-04-14
6
Medium Priority
?
650 Views
Last Modified: 2012-08-14
I have the following :

int MyInt = 100;

GCHandle gch = GCHandle.Alloc( MyInt, GCHandleType.Pinned );

If i print GCHandle.Target i get 100. Now, if i do :

Myint = 200;

And i print GCHandle.Target i still get 100. Is this normal ?
I thought GCHandle gives me a stable pointer to the object (MyInt).
But it seems as if it copies MyInt somewhere and returns a pointer to the copy.

I am calling a function in an unmanaged DLL that requires a pointer to an int.
This pointer must remain stable for the lifetime of my app since it's value is updated
thru other calls to the DLL. This means that I have to do MyInt = GCHandle.Target to
get the new value every time I call a DLL function that modifies the pointer value.

Is this the only way of getting a stable pointer (no GC and no moving) ?







0
Comment
Question by:drinkwater
6 Comments
 
LVL 7

Expert Comment

by:Ceiled
ID: 13786459
The reason your integer gets "copied" somewhere else and then written to is because int is a value type. When you cast a value type to "object," the value gets boxed (that is, copied to a new location on the stack). But don't be discouraged -- once pinned, boxed values *can* be modified, you just have to know how to do it. Here's a sample:

      GCHandle h = GCHandle.Alloc(100, GCHandleType.Pinned);
      Console.WriteLine(Marshal.ReadInt32(h.AddrOfPinnedObject()));
      Marshal.WriteInt32(h.AddrOfPinnedObject(), 500);
      Console.WriteLine(Marshal.ReadInt32(h.AddrOfPinnedObject()));

All that needs to be done differently is using the Marshal class to set the value, because C# doesn't actually have any syntax for doing what you're trying to do. Note also that you can just look at h.Target to get the value, but it's going to be slightly less efficient because under the covers, it will go to the location on the heap where the int was boxed before, pull the integer out, then box it again. Using Marshal.ReadByte() will return the int directly on the stack, avoiding the extra boxing operation.

Don't forget to Free() the handle when you're done with it (or those four bytes will never be deallocated), and you should be good. Hope this helps.
0
 
LVL 7

Expert Comment

by:Ceiled
ID: 13786462
Er...the parentheses on "the value gets boxed" should read "that is, copied to a new location on the HEAP," not the stack. Sorry for the confusion.
0
 

Author Comment

by:drinkwater
ID: 13787990
Aha, so that's what boxing is ! My main concern is that the pointer never move or be garbage collected. The Int example is just one case. But I have other cases where I need a pointer to a buffer (again must not move or be GC). If I use Marshal.AllocHGlobal which returns an IntPtr - can I be sure that it will never move or be GC ? Remember I am passing
the pointer to an unmanaged DLL which stores the pointer and uses that pointer in other calls to the DLL
0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
LVL 7

Accepted Solution

by:
Ceiled earned 2000 total points
ID: 13788375
Yes, the pointers returned from AllocHGlobal() are guaranteed to stay in place. Things that you pin by creating a GCHandle are also guaranteed not to be moved out from under you -- which one you use depends on your needs. If all you want is a buffer where managed APIs can store and retrieve data, go ahead and use AllocHGlobal(). If you want an object that can be passed back and forth between managed and unmanaged code and used intuitively in both contexts, use GCHandle. Make sure to remember to call GCHandle.Free() or FreeHGlobal() when you're done with it, though.
0
 
LVL 48

Expert Comment

by:AlexFM
ID: 13788395
Result of Marshal.AllocHGlobal is pointer to unmanaged memory block which is not subject of garbage collecting and will never be moved.
IntPtr structure itself, however, can be moved by GC, but it's value remains the same and memory block pointed by it will not be moved.
0
 

Expert Comment

by:landerson999
ID: 22160990
Hey Ceiled, dont want to highjack a questino, although this one has been answered, and experts-exchange don't have the ideas to put in a request member to view your question button, so I hope you could take a look over at http://www.experts-exchange.com/Programming/Languages/.NET/Visual_Basic.NET/Q_23595254.html as I have a similar problem using the gchandle, which isn't quite working out...
0

Featured Post

How to Use the Help Bell

Need to boost the visibility of your question for solutions? Use the Experts Exchange Help Bell to confirm priority levels and contact subject-matter experts for question attention.  Check out this how-to article for more information.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

In order to hide the "ugly" records selectors (triangles) in the rowheaders, here are some suggestions. Microsoft doesn't have a direct method/property to do it. You can only hide the rowheader column. First solution, the easy way The first sol…
Calculating holidays and working days is a function that is often needed yet it is not one found within the Framework. This article presents one approach to building a working-day calculator for use in .NET.
In a question here at Experts Exchange (https://www.experts-exchange.com/questions/29062564/Adobe-acrobat-reader-DC.html), a member asked how to create a signature in Adobe Acrobat Reader DC (the free Reader product, not the paid, full Acrobat produ…
Is your OST file inaccessible, Need to transfer OST file from one computer to another? Want to convert OST file to PST? If the answer to any of the above question is yes, then look no further. With the help of Stellar OST to PST Converter, you can e…
Suggested Courses

839 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question