 |
 | Pinning copy of the structure Lesheniuk | 6:04 2 Mar '07 |
|
 |
try this at the end of code
Console.WriteLine(ts.a);
and you'll see that you pin wrong object.
Actually in this line
pin.ManagedObject = ts;
a copy of the structure is created and passed as value to the property.
And even if you'd use directly
GCHandle.Alloc(ts, GSHandleType.Pinned)
then a copy of the struct would be created, boxed in object, passed to the Alloc method, and handle to this box-object would be returned.
|
|
|
|
 |
|
 |
Lesheniuk wrote: a copy of the structure is created and passed as value to the property.
That's correct. To acquire the current state of the managed object, you have to do:
ts = pin.ManangedObject; Console.WriteLine(ts.a);
But that's the way structures work, they're not passed by reference.
for example:
... Change(ts); Console.WriteLine(ts.a); ...
public static void Change(TestStruct ts) { ts.a = 3; }
Does not change the caller's value to 3.
Marc
Thyme In The CountryInteracxPeople are just notoriously impossible. --DavidCrow There's NO excuse for not commenting your code. -- John Simmons / outlaw programmer People who say that they will refactor their code later to make it "good" don't understand refactoring, nor the art and craft of programming. -- Josh Smith
|
|
|
|
 |
 | fixed statement rvpilot | 11:48 13 Feb '07 |
|
 |
I am currently using c# and an unmanaged DLL that need structs and byte buffers passing to them (FTDI's D2XX.DLL USB API), and I suspect that it may be the reason for some recent unpredictable behaviour !!
How does your helper compare to the 'fixed (...) { ... }' statement and in what situation would you use one instead of the other ?
Regards, Simon.
|
|
|
|
 |
|
 |
rvpilot wrote: How does your helper compare to the 'fixed (...) { ... }' statement and in what situation would you use one instead of the other ?
That's a good question and I should have addressed it in the article. The "fixed" statement is useful when you are pinning something for the lifetime of the code within the "fixed" block. My pinned object is useful especially in a threaded scenario when you read or write some data asynchronously and later come back and work with the data or write out more data.
So, basically, anytime you need an object pinned beyond the lifetime of a "fixed" block, would be when to use a different mechanism, such as the PinnedObject to pin the object.
Marc
Thyme In The CountryPeople are just notoriously impossible. --DavidCrow There's NO excuse for not commenting your code. -- John Simmons / outlaw programmer People who say that they will refactor their code later to make it "good" don't understand refactoring, nor the art and craft of programming. -- Josh Smith
|
|
|
|
 |
|
 |
Thanks Marc,
Sounds like your PinnedObject is the way to go for my app !!
Simon
|
|
|
|
 |
 | Testing Luc Pattyn | 13:07 12 Feb '07 |
|
 |
Hi Marc,
it's me again. I forgot to ask: how do you test such a feature, i.e. how can you be sure the object really got pinned (inside my using block) or no longer is pinned (outside my using block) ?
It is clear if pinning is required, but not applied, and the object got moved, all kinds of things may happen, but can we make an object move on purpose in such a way that it will actually change position (unless pinned) ??
Greetings,
Luc Pattyn
|
|
|
|
 |
|
 |
Luc Pattyn wrote: but can we make an object move on purpose in such a way that it will actually change position (unless pinned) ??
I experienced this with the USB stuff I was using, and it was very predictable. However, I never tried reducing it down to a repeatable test case. You'd have to do a bunch of allocations to fragment the heap and then force garbage collection, I imagine.
Marc
Thyme In The CountryPeople are just notoriously impossible. --DavidCrow There's NO excuse for not commenting your code. -- John Simmons / outlaw programmer People who say that they will refactor their code later to make it "good" don't understand refactoring, nor the art and craft of programming. -- Josh Smith
|
|
|
|
 |
 | My .NET 1.1 approach, without generics Luc Pattyn | 12:27 12 Feb '07 |
|
 |
Hi Marc,
your article got me thinking. I had a simple scheme where I pass an object (typically a byte array) to the constructor of an LP_Pinning object. I did not implement the equivalent of your ManangedObject property, but then I also never needed it since I always use the using(...) pattern.
So now I tested my approach for other things, and it seems to accept a struct of bittable things (say ints); of course it rejects some others when GCHandle.Alloc complains with "Object contains non-primitive or non-blittable data."
So here is my entire class, please feel free to comment on it:
using System; using System.Runtime.InteropServices; // GCHandle
namespace LP_Core { /// <summary> /// An LP_Pinning instance pins an object for as long as it is alive. /// </summary> /// <remarks> /// This is the preferred use when the pointer value is not needed: /// using (new LP_Pinning(objectThatNeedsPinning)) { /// .. use the object here, it is pinned now ... /// } /// This is the preferred use when the pointer value is needed: /// using (LP_Pinning pinning=new LP_Pinning(objectThatNeedsPinning)) { /// IntPtr ptr=pinning.Ptr; /// .. use the object here, it is pinned now ... /// } /// </remarks> public class LP_Pinning : IDisposable { private GCHandle handle; private bool disposed; private IntPtr ptr;
/// <summary> /// Creates an instance op LP_Pinning, and pins the argument. /// </summary> /// <param name="obj"></param> public LP_Pinning(object obj) { handle=GCHandle.Alloc(obj, GCHandleType.Pinned); ptr=handle.AddrOfPinnedObject(); }
/// <summary> /// Undoes the pinning. /// </summary> ~LP_Pinning() { Dispose(); }
public void Dispose() { if (!disposed) { disposed=true; handle.Free(); ptr=IntPtr.Zero; } }
/// <summary> /// Returns the pointer to the pinned object. /// </summary> public IntPtr Ptr {get {return ptr;}} } }
Regards, Luc Pattyn
|
|
|
|
 |