Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
CODE PROJECT For Those Who Code
  • Home
  • Articles
  • FAQ
Community
  1. Home
  2. General Programming
  3. Managed C++/CLI
  4. How to wrap native array?

How to wrap native array?

Scheduled Pinned Locked Moved Managed C++/CLI
c++dotnetdata-structuresperformancetutorial
5 Posts 2 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    mid 5741
    wrote on last edited by
    #1

    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 of buffersInfo 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 use array<Byte,2>^ to wrap void* buffers[2] because array<> 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.

    L 1 Reply Last reply
    0
    • M mid 5741

      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 of buffersInfo 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 use array<Byte,2>^ to wrap void* buffers[2] because array<> 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.

      L Offline
      L Offline
      Luc Pattyn
      wrote on last edited by
      #2

      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] }


      M 1 Reply Last reply
      0
      • L Luc Pattyn

        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] }


        M Offline
        M Offline
        mid 5741
        wrote on last edited by
        #3

        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.

        L 1 Reply Last reply
        0
        • M mid 5741

          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.

          L Offline
          L Offline
          Luc Pattyn
          wrote on last edited by
          #4

          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] }


          M 1 Reply Last reply
          0
          • L Luc Pattyn

            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] }


            M Offline
            M Offline
            mid 5741
            wrote on last edited by
            #5

            OK. Thanks for your input. I'm going to see if a managed class with a private void* member can use an indexed property to give access to the bytes in the buffer and not affect performance.

            1 Reply Last reply
            0
            Reply
            • Reply as topic
            Log in to reply
            • Oldest to Newest
            • Newest to Oldest
            • Most Votes


            • Login

            • Don't have an account? Register

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • World
            • Users
            • Groups