Connecting Tech Pros Worldwide Forums | Help | Site Map

Pinning Pointers with __pin in Managed C++

Hexar Anderson
Guest
 
Posts: n/a
#1: Nov 17 '05
I have two questions:
a) From documentation located at
http://msdn.microsoft.com/library/de...nsSpec_7_7.asp,
it says, "Pinning a sub-object defined in a managed object has the effect of
pinning the entire object. For example, if any element of an array is pinned,
then the whole array is also pinned. There are no extensions to the language
for declaring a pinned array. To pin an array, declare a pinning pointer to
its element type, and pin one of its elements."

My question is, does this still apply if the array is an array of reference
classes instead of value classes? Seems to me that pinning the array (by
pinning the first element of the array) would pin the array itself, and not
necessarily the actual reference class objects which are located elsewhere in
the managed heap.

b) If my assumption in (a) is correct, that means that it is harder to pin
all of the reference class elements of an array. How would you do this?
With an array of __pin pointers? Should this work?

MyObject __pin *pinners __gc[] = new MyObject*[numObjects];
vector<char*> v;
for (int i = 0; i < numObjects; i++)
{
pinners[i] = new MyObject();
v.push_back(static_cast<char*>(pinners[i]));
}
UnmanagedFunction(v);



Ronald Laeremans [MSFT]
Guest
 
Posts: n/a
#2: Nov 17 '05

re: Pinning Pointers with __pin in Managed C++


Hexar Anderson wrote:[color=blue]
> I have two questions:
> a) From documentation located at
> http://msdn.microsoft.com/library/de...nsSpec_7_7.asp,
> it says, "Pinning a sub-object defined in a managed object has the effect of
> pinning the entire object. For example, if any element of an array is pinned,
> then the whole array is also pinned. There are no extensions to the language
> for declaring a pinned array. To pin an array, declare a pinning pointer to
> its element type, and pin one of its elements."
>
> My question is, does this still apply if the array is an array of reference
> classes instead of value classes? Seems to me that pinning the array (by
> pinning the first element of the array) would pin the array itself, and not
> necessarily the actual reference class objects which are located elsewhere in
> the managed heap.
>
> b) If my assumption in (a) is correct, that means that it is harder to pin
> all of the reference class elements of an array. How would you do this?
> With an array of __pin pointers? Should this work?
>
> MyObject __pin *pinners __gc[] = new MyObject*[numObjects];
> vector<char*> v;
> for (int i = 0; i < numObjects; i++)
> {
> pinners[i] = new MyObject();
> v.push_back(static_cast<char*>(pinners[i]));
> }
> UnmanagedFunction(v);
>
>[/color]
For this situation you cannot use pinned pointers (which are only legal
on the stack) but you should use a pining handle. Create a GCHandle for
each reference, call the GCHandle Alloc member 2 parameter overload with
Pinned as the handle type. Put the handle in an array, create a second
array (of IntPTR) and put the result of calling
GCHandle::AddressOfPinnedObject into that and then you can pass that to
native code.

Note that a design that needs this probably requires rethinking since
keeping lots of pinnen objects (like an array of them) around for a long
time isn't something to do too lightly.

Ronald Laeremans
Visual C++ team

Hexar Anderson
Guest
 
Posts: n/a
#3: Nov 17 '05

re: Pinning Pointers with __pin in Managed C++


"Ronald Laeremans [MSFT]" wrote:[color=blue]
> For this situation you cannot use pinned pointers (which are only legal
> on the stack) but you should use a pinning handle. Create a GCHandle for
> each reference, call the GCHandle Alloc member 2 parameter overload with
> Pinned as the handle type. Put the handle in an array, create a second
> array (of IntPTR) and put the result of calling
> GCHandle::AddressOfPinnedObject into that and then you can pass that to
> native code.
>
> Note that a design that needs this probably requires rethinking since
> keeping lots of pinnen objects (like an array of them) around for a long
> time isn't something to do too lightly.
>
> Ronald Laeremans
> Visual C++ team[/color]

Thanks for your response. That answers the question of whether or not I can
use a __pin pointer in that way. I tried creating an array of GCHandles and
then calling GCHandle::Alloc to create the pinned handles, but it didn't
work, because I get an ArgumentException: "An instance with nonprimitive
(non-blittable) members cannot be pinned." What I'm actually trying to do is
a little more complicated, namely pin several 2D arrays of enums:

public __value enum MyEnum : unsigned char { ValueOne = 1, ValueTwo = 2};

public MyFunc()
{
Array* array __gc[] = new Array*[numObjects];
GCHandle pinners __gc[] = new GCHandle[numObjects];
vector<char*> v;
for (int i = 0; i < numObjects; i++)
{
MyEnum e __gc[,] = new MyEnum[10, 10];
array[i] = e;
pinners[i] = GCHandle::Alloc(__box(e[0, 0]), GCHandleType::Pinned);
v.push_back(static_cast<char*>(pinners[i].AddressOfPinnedObject()));
}
UnmanagedFunction(v);
// Omitted: Also call GCHandle.Free on the handles
}

I noticed also, that you cannot even create a GCHandle (pinned) on a single
enum of any kind. That seems really strange to me. Is there any way to pass
an array of 2D arrays of value-enums to unmanaged code?
Ronald Laeremans [MSFT]
Guest
 
Posts: n/a
#4: Nov 17 '05

re: Pinning Pointers with __pin in Managed C++


Hexar Anderson wrote:[color=blue]
> "Ronald Laeremans [MSFT]" wrote:
>[color=green]
>>For this situation you cannot use pinned pointers (which are only legal
>>on the stack) but you should use a pinning handle. Create a GCHandle for
>>each reference, call the GCHandle Alloc member 2 parameter overload with
>>Pinned as the handle type. Put the handle in an array, create a second
>>array (of IntPTR) and put the result of calling
>>GCHandle::AddressOfPinnedObject into that and then you can pass that to
>>native code.
>>
>>Note that a design that needs this probably requires rethinking since
>>keeping lots of pinnen objects (like an array of them) around for a long
>>time isn't something to do too lightly.
>>
>>Ronald Laeremans
>>Visual C++ team[/color]
>
>
> Thanks for your response. That answers the question of whether or not I can
> use a __pin pointer in that way. I tried creating an array of GCHandles and
> then calling GCHandle::Alloc to create the pinned handles, but it didn't
> work, because I get an ArgumentException: "An instance with nonprimitive
> (non-blittable) members cannot be pinned." What I'm actually trying to do is
> a little more complicated, namely pin several 2D arrays of enums:
>
> public __value enum MyEnum : unsigned char { ValueOne = 1, ValueTwo = 2};
>
> public MyFunc()
> {
> Array* array __gc[] = new Array*[numObjects];
> GCHandle pinners __gc[] = new GCHandle[numObjects];
> vector<char*> v;
> for (int i = 0; i < numObjects; i++)
> {
> MyEnum e __gc[,] = new MyEnum[10, 10];
> array[i] = e;
> pinners[i] = GCHandle::Alloc(__box(e[0, 0]), GCHandleType::Pinned);
> v.push_back(static_cast<char*>(pinners[i].AddressOfPinnedObject()));
> }
> UnmanagedFunction(v);
> // Omitted: Also call GCHandle.Free on the handles
> }
>
> I noticed also, that you cannot even create a GCHandle (pinned) on a single
> enum of any kind. That seems really strange to me. Is there any way to pass
> an array of 2D arrays of value-enums to unmanaged code?[/color]
You don't need to pin enums or other value types, they are always
allocated inline, for these it is enough that you pin the array
containing them.

I hope that is better news. :-)

Ronald
Closed Thread