How to wrap native array?
-
This is a native struct:
struct BufferInfo
{
void* buffers[2];
}that gets passed to this native function:
bool CreateBuffers( BufferInfo* buffersInfo );
On return from this function the
buffers
member ofbuffersInfo
points to the two halves of a double buffer, the size of which is known. I'm trying to wrap the native code with C++/CLI. I cannot usearray<Byte,2>^
to wrapvoid* buffers[2]
becausearray<>
is only for allocations in the CLR heap. Is there a way to wrap the native array and treat it like a managed one? Copying or marshaling the data in the buffers is not an option for performance reasons. -
This is a native struct:
struct BufferInfo
{
void* buffers[2];
}that gets passed to this native function:
bool CreateBuffers( BufferInfo* buffersInfo );
On return from this function the
buffers
member ofbuffersInfo
points to the two halves of a double buffer, the size of which is known. I'm trying to wrap the native code with C++/CLI. I cannot usearray<Byte,2>^
to wrapvoid* buffers[2]
becausearray<>
is only for allocations in the CLR heap. Is there a way to wrap the native array and treat it like a managed one? Copying or marshaling the data in the buffers is not an option for performance reasons.Hi, in my experience it is best to allocate a managed array, get it pinned down so the GC does not move it, fetch its pointer (IntPtr), then pass it on to the native world; that way nothing needs being copied or marshaled. I typically use an object of this class to support this process (it happens to be C# code); the C# using statement makes sure it gets disposed of as soon as appropriate:
/// /// An LP_Pinner object pins an object for as long as the LP_Pinner
/// object is alive.
///
/// /// This is the preferred use when the pointer value is not needed:
/// using (new LP_Pinner(objectThatNeedsPinning)) {
/// .. use the object here, it is pinned now ...
/// }
/// This is the preferred use when the pointer value is needed:
/// using (LP_Pinner pinning=new LP_Pinner(objectThatNeedsPinning)) {
/// IntPtr ptr=pinning.Ptr;
/// .. use the object here, it is pinned now ...
/// }
///
public class LP_Pinner : IDisposable {
private static ILP_Environment env=LP_Environment.GetEnvironment();
private GCHandle handle;
private bool disposed;
private IntPtr ptr;/// /// Creates an instance op LP\_Pinner, and pins the argument. /// /// public LP\_Pinner(object obj) { //env.log(0,"AllocPinned "+obj.GetType().Name); handle=GCHandle.Alloc(obj, GCHandleType.Pinned); ptr=handle.AddrOfPinnedObject(); } /// /// Undoes the pinning. /// ~LP\_Pinner() { Dispose(); } /// /// Disposes of the object's internal resources. /// public void Dispose() { if (!disposed) { //env.log(0,"Free"); disposed=true; handle.Free(); ptr=IntPtr.Zero; } } /// /// Returns the pointer to the pinned object. /// public IntPtr Ptr {get {return ptr;}}
}
Hope this helps. :)
Luc Pattyn
try { [Search CP Articles] [Search CP Forums] [Forum Guidelines] [My Articles] } catch { [Google] }
-
Hi, in my experience it is best to allocate a managed array, get it pinned down so the GC does not move it, fetch its pointer (IntPtr), then pass it on to the native world; that way nothing needs being copied or marshaled. I typically use an object of this class to support this process (it happens to be C# code); the C# using statement makes sure it gets disposed of as soon as appropriate:
/// /// An LP_Pinner object pins an object for as long as the LP_Pinner
/// object is alive.
///
/// /// This is the preferred use when the pointer value is not needed:
/// using (new LP_Pinner(objectThatNeedsPinning)) {
/// .. use the object here, it is pinned now ...
/// }
/// This is the preferred use when the pointer value is needed:
/// using (LP_Pinner pinning=new LP_Pinner(objectThatNeedsPinning)) {
/// IntPtr ptr=pinning.Ptr;
/// .. use the object here, it is pinned now ...
/// }
///
public class LP_Pinner : IDisposable {
private static ILP_Environment env=LP_Environment.GetEnvironment();
private GCHandle handle;
private bool disposed;
private IntPtr ptr;/// /// Creates an instance op LP\_Pinner, and pins the argument. /// /// public LP\_Pinner(object obj) { //env.log(0,"AllocPinned "+obj.GetType().Name); handle=GCHandle.Alloc(obj, GCHandleType.Pinned); ptr=handle.AddrOfPinnedObject(); } /// /// Undoes the pinning. /// ~LP\_Pinner() { Dispose(); } /// /// Disposes of the object's internal resources. /// public void Dispose() { if (!disposed) { //env.log(0,"Free"); disposed=true; handle.Free(); ptr=IntPtr.Zero; } } /// /// Returns the pointer to the pinned object. /// public IntPtr Ptr {get {return ptr;}}
}
Hope this helps. :)
Luc Pattyn
try { [Search CP Articles] [Search CP Forums] [Forum Guidelines] [My Articles] } catch { [Google] }
-
Unfortunately that is not an option. I have no control over the native code, which is an interface to an audio hardware driver that manages its own buffers.
I see no way you can have an unmanaged array being promoted to a managed one without copying it all. You can of course pass the pointer value from native to managed world, and use it there as a pointer, using unsafe code (or whatever it is called in C++/CLI) and pointer operations. But then it is not a managed object at all. :)
Luc Pattyn
try { [Search CP Articles] [Search CP Forums] [Forum Guidelines] [My Articles] } catch { [Google] }
-
I see no way you can have an unmanaged array being promoted to a managed one without copying it all. You can of course pass the pointer value from native to managed world, and use it there as a pointer, using unsafe code (or whatever it is called in C++/CLI) and pointer operations. But then it is not a managed object at all. :)
Luc Pattyn
try { [Search CP Articles] [Search CP Forums] [Forum Guidelines] [My Articles] } catch { [Google] }