weird GCHandle behavior

  • Thread starter Thread starter XYZ
  • Start date Start date
X

XYZ

I need to pass the address of a variableto some win32 API functions like
RTLMoveMemory

I noticed some weird behavior when pinning objects and using the handle's
pointer to write data to the memory location.

it seems as if after pinning an object the memory and the object are not
updated at the same time anymore


let's say I have this code:

Dim c As Integer

Dim s As String = ""

Dim s2 As String = ""

Dim b(5) As Byte

Dim gh1 As System.Runtime.InteropServices.GCHandle =
System.Runtime.InteropServices.GCHandle.Alloc(c,
Runtime.InteropServices.GCHandleType.Pinned)

Dim gh2 As System.Runtime.InteropServices.GCHandle =
System.Runtime.InteropServices.GCHandle.Alloc(s,
Runtime.InteropServices.GCHandleType.Pinned)

Dim gh3 As System.Runtime.InteropServices.GCHandle =
System.Runtime.InteropServices.GCHandle.Alloc(b,
Runtime.InteropServices.GCHandleType.Pinned)

c = 5

gh1.Target = 100

I made gh1 a handle to "c" and pinned "c". now the value of c and the value
of the target of gh1 in memory change independently. If I copy something to
the location pointed by gh1.addressofpinnedobject, "c" will not change.



s = "allo"

gh2.Target = "hello"

again, no change in "s"



s2 = "will it work?"

Dim gh4 As System.Runtime.InteropServices.GCHandle =
System.Runtime.InteropServices.GCHandle.Alloc(s2,
Runtime.InteropServices.GCHandleType.Pinned)

the order of operations also matters. If I pin S2 before assigning the
string to it, gh4.target is an empty string

if I pin it after assigning a string, gh4.target will say "will it work?"
but any further changes to S2 will not change the string in memory



CopyMemory(gh2.AddrOfPinnedObject().ToInt32, gh4.AddrOfPinnedObject.ToInt32,
s2.Length)

after this call, gh2.target will show "will ", I assume because the original
string was only 5 characters long

but S is still unchanged

HOWEVER, the following code:

b(0) = 100

will immediately affect gh3.target and if I copy something to
gh3.addressofpinnedobject then array "b" will change right away



what is going on? I thought that if I "pin" an object using a handle,
gchandle.addressofpinnedobject will be a pointer to my variable and changing
the memory value at the pointer will change my variable as well

this only works if the pinned object is an array, otherwise I can change the
value in memory (using the pointer from the handle) but my local var doesn't
change value. why?
 
XYZ said:
I need to pass the address of a variableto some win32 API functions like
RTLMoveMemory

I noticed some weird behavior when pinning objects and using the handle's
pointer to write data to the memory location.

I would never change a string's data using unmanaged code because it can
lead to misbehaving code. Strings in .NET are immutable and thus should not
be manipulated, because otherwise it is not guaranteed that all the string
object's methods and properties still work as specified.

You can either pass a 'String' variable 'ByVal' when using VB.NET's
'Declare' statement, or you can use a 'StringBuilder' object.
 
c = 5
gh1.Target = 100


I made gh1 a handle to "c" and pinned "c". now the value of c and the value
of the target of gh1 in memory change independently. If I copy something to
the location pointed by gh1.addressofpinnedobject, "c" will not change.

No, since GCHandle.Alloc takes an Object parameter, you end up pinning
a boxed copy of c. You can't pin c since it's stack allocated.

Assigning 100 to Target just creates a new boxed Integer, it doesn't
affect the original object.

s = "allo"

gh2.Target = "hello"


again, no change in "s"


Of course not, you're just reassigning the Target reference to another
object. If we forget about GCHandle for a while and just look at
regular variables, you have the same situation

s = "allo"
Dim target As String = s
target = hello"

' now target is "hello" but s remains unchanged as "allo"

what is going on? I thought that if I "pin" an object using a handle,
gchandle.addressofpinnedobject will be a pointer to my variable and changing
the memory value at the pointer will change my variable as well

Right, but you're not "changing the memory value at the pointer" by
reassigning Target. And if you change a boxed copy of a value type,
you have to unbox it to see the changes.



Mattias
 
Herfried K. Wagner said:
I would never change a string's data using unmanaged code because it can
lead to misbehaving code. Strings in .NET are immutable and thus should
not be manipulated, because otherwise it is not guaranteed that all the
string object's methods and properties still work as specified.

what does "immutable" mean?

finally I'm saving the string as a byte array and reconstructing the class
from it, so this is not an issue
 
Mattias Sjögren said:
No, since GCHandle.Alloc takes an Object parameter, you end up pinning
a boxed copy of c. You can't pin c since it's stack allocated.

aaargh! I forgot about that, obviously if it's on the stack it can't be in
the general memory

so, what happens then? does this call to alloc actually allocate space in
memory?


what is a "boxed copy" ?
 
so, what happens then? does this call to alloc actually allocate space in
memory?

The boxing of the integer will allocate an object on the heap, and a
reference to that is passed to Alloc.

what is a "boxed copy" ?

Boxing is basically a way to embed a value type value in a heap
allocated object. You can read more about boxing in the documentation.

The "box" object contains a copy of the value, so there's no
connection back to the original value. Changing the boxed object will
not affect the original.



Mattias
 
XYZ said:
is there a list of classes/objects that are immutable, and those that
aren't?

Most classes are not immutable. The documentation of the string class
clearly states that this class' instances are immutable. I doubt that there
is an overview over immutable classes.
 
Back
Top