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
  1. Home
  2. General Programming
  3. C#
  4. P/Invoking void * - is this the right way?

P/Invoking void * - is this the right way?

Scheduled Pinned Locked Moved C#
jsonperformancequestion
5 Posts 4 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.
  • L Offline
    L Offline
    Luca Leonardo Scorcia
    wrote on last edited by
    #1

    Hello everybody! I have this API published in a C DLL: int readValue(int objectId, int outputTypeId, void * buf); Where buf is a pointer to a buffer in memory that can be pretty much anything, depending on the outputTypeId value. In the simplest cases, it points to an int or to a float. The managed declaration I'm using is: [DllImport(ReferenceDLL)] public static extern int H5Aread(int attr_id, int mem_type_id, IntPtr buf); I have googled a lot and came out with the following solution to get the right value out of that call:

    public int GetValueInt32()
    {
    // Allocate memory
    int value = 0;
    GCHandle handleValue = GCHandle.Alloc(value, GCHandleType.Pinned);

    // Run the call
    DllImports.H5Aread(ObjectId, ImportedDataTypes.H5T_NATIVE_INT, handleValue.AddrOfPinnedObject());
    value = (int)handleValue.Target;

    handleValue.Free();

    return value;
    }

    public float GetValueFloat()
    {
    // Allocate memory
    float value = 0;
    GCHandle handleValue = GCHandle.Alloc(value, GCHandleType.Pinned);

    // Run the call
    DllImports.H5Aread(ObjectId, ImportedDataTypes.H5T_NATIVE_FLOAT, handleValue.AddrOfPinnedObject());
    value = (float) handleValue.Target;

    handleValue.Free();

    return value;
    }

    It works, but I'm a bit puzzled. According to my understanding of how GCHandle should work, it shouldn't be necessary to copy the value of handleValue.Target into value - it's just pinning the address of value to avoid moving. But if omit the copying step, value is always zero. If this is the way GCHandle is supposed to work, then why I'm passing an instance of value to GCHandle.Alloc instead of the memory size to allocate? If anyone can shed more light on this topic, I'd be really grateful. My next project is going to use a lot of P/Invokes, and I really need to understand what's going on there. Is there's a "right" way to accomplish what I'm trying to do?

    Luca The Price of Freedom is Eternal Vigilance. -- Wing Commander IV En Það Besta Sem Guð Hefur Skapað, Er Nýr Dagur. (But the best thing God has created, is a New Day.) -- Sigur Ròs - Viðrar vel til loftárása

    L L E 3 Replies Last reply
    0
    • L Luca Leonardo Scorcia

      Hello everybody! I have this API published in a C DLL: int readValue(int objectId, int outputTypeId, void * buf); Where buf is a pointer to a buffer in memory that can be pretty much anything, depending on the outputTypeId value. In the simplest cases, it points to an int or to a float. The managed declaration I'm using is: [DllImport(ReferenceDLL)] public static extern int H5Aread(int attr_id, int mem_type_id, IntPtr buf); I have googled a lot and came out with the following solution to get the right value out of that call:

      public int GetValueInt32()
      {
      // Allocate memory
      int value = 0;
      GCHandle handleValue = GCHandle.Alloc(value, GCHandleType.Pinned);

      // Run the call
      DllImports.H5Aread(ObjectId, ImportedDataTypes.H5T_NATIVE_INT, handleValue.AddrOfPinnedObject());
      value = (int)handleValue.Target;

      handleValue.Free();

      return value;
      }

      public float GetValueFloat()
      {
      // Allocate memory
      float value = 0;
      GCHandle handleValue = GCHandle.Alloc(value, GCHandleType.Pinned);

      // Run the call
      DllImports.H5Aread(ObjectId, ImportedDataTypes.H5T_NATIVE_FLOAT, handleValue.AddrOfPinnedObject());
      value = (float) handleValue.Target;

      handleValue.Free();

      return value;
      }

      It works, but I'm a bit puzzled. According to my understanding of how GCHandle should work, it shouldn't be necessary to copy the value of handleValue.Target into value - it's just pinning the address of value to avoid moving. But if omit the copying step, value is always zero. If this is the way GCHandle is supposed to work, then why I'm passing an instance of value to GCHandle.Alloc instead of the memory size to allocate? If anyone can shed more light on this topic, I'd be really grateful. My next project is going to use a lot of P/Invokes, and I really need to understand what's going on there. Is there's a "right" way to accomplish what I'm trying to do?

      Luca The Price of Freedom is Eternal Vigilance. -- Wing Commander IV En Það Besta Sem Guð Hefur Skapað, Er Nýr Dagur. (But the best thing God has created, is a New Day.) -- Sigur Ròs - Viðrar vel til loftárása

      L Offline
      L Offline
      led mike
      wrote on last edited by
      #2

      Luca Leonardo Scorcia wrote:

      Is there's a "right" way to accomplish what I'm trying to do?

      I don't know. But from my perspective as a C++ developer I would almost never use PInvoke. I would use a C++/CLI mixed mode class library project to solve all the managed-to-native issues. The resulting assembly would provide a managed class solution for use in C#. But that's me

      led mike

      1 Reply Last reply
      0
      • L Luca Leonardo Scorcia

        Hello everybody! I have this API published in a C DLL: int readValue(int objectId, int outputTypeId, void * buf); Where buf is a pointer to a buffer in memory that can be pretty much anything, depending on the outputTypeId value. In the simplest cases, it points to an int or to a float. The managed declaration I'm using is: [DllImport(ReferenceDLL)] public static extern int H5Aread(int attr_id, int mem_type_id, IntPtr buf); I have googled a lot and came out with the following solution to get the right value out of that call:

        public int GetValueInt32()
        {
        // Allocate memory
        int value = 0;
        GCHandle handleValue = GCHandle.Alloc(value, GCHandleType.Pinned);

        // Run the call
        DllImports.H5Aread(ObjectId, ImportedDataTypes.H5T_NATIVE_INT, handleValue.AddrOfPinnedObject());
        value = (int)handleValue.Target;

        handleValue.Free();

        return value;
        }

        public float GetValueFloat()
        {
        // Allocate memory
        float value = 0;
        GCHandle handleValue = GCHandle.Alloc(value, GCHandleType.Pinned);

        // Run the call
        DllImports.H5Aread(ObjectId, ImportedDataTypes.H5T_NATIVE_FLOAT, handleValue.AddrOfPinnedObject());
        value = (float) handleValue.Target;

        handleValue.Free();

        return value;
        }

        It works, but I'm a bit puzzled. According to my understanding of how GCHandle should work, it shouldn't be necessary to copy the value of handleValue.Target into value - it's just pinning the address of value to avoid moving. But if omit the copying step, value is always zero. If this is the way GCHandle is supposed to work, then why I'm passing an instance of value to GCHandle.Alloc instead of the memory size to allocate? If anyone can shed more light on this topic, I'd be really grateful. My next project is going to use a lot of P/Invokes, and I really need to understand what's going on there. Is there's a "right" way to accomplish what I'm trying to do?

        Luca The Price of Freedom is Eternal Vigilance. -- Wing Commander IV En Það Besta Sem Guð Hefur Skapað, Er Nýr Dagur. (But the best thing God has created, is a New Day.) -- Sigur Ròs - Viðrar vel til loftárása

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

        Hi Luca, I have used GCHandle many times to pass a reference type from managed C# to unmanaged C code; I never needed GCHandle.Target since my object was either an instance of a class I created, or a simple array. What really gets passed on is a memory pointer, pointing to the managed data (which got pinned down so the GC cannot move it around any more), so the unmanaged world can manipulate the data in the managed object. I assume you need GCHandle.Target to get the same result when you pass on a value type (such as the int and float in your examples); but I cannot confirm that from experience, and I have never come across any example of GCHandle.Target till now. However, when you know the argument is a value type, you can declare another prototype of your unmanaged method using the ref or out keyword, and forget all about GCHandle: reffing/outing a local value type is OK, since locals are on stack, and stack does not get moved around, so the following should work:

        [DllImport(" ... .dll")]
        public static extern void H5Aread(... , out float val);

        public int GetValueInt32(){
        int value = 0;
        DllImports.H5Aread(ObjectId, ImportedDataTypes.H5T_NATIVE_INT, out value);
        return value;}

        The hearth of the matter is you can overload the method, i.e. have multiple managed method prototypes with different parameter signatures, but all pointing to the same unmanaged function. :)

        Luc Pattyn [Forum Guidelines] [My Articles]


        This month's tips: - before you ask a question here, search CodeProject, then Google; - the quality and detail of your question reflects on the effectiveness of the help you are likely to get; - use PRE tags to preserve formatting when showing multi-line code snippets.


        L 1 Reply Last reply
        0
        • L Luca Leonardo Scorcia

          Hello everybody! I have this API published in a C DLL: int readValue(int objectId, int outputTypeId, void * buf); Where buf is a pointer to a buffer in memory that can be pretty much anything, depending on the outputTypeId value. In the simplest cases, it points to an int or to a float. The managed declaration I'm using is: [DllImport(ReferenceDLL)] public static extern int H5Aread(int attr_id, int mem_type_id, IntPtr buf); I have googled a lot and came out with the following solution to get the right value out of that call:

          public int GetValueInt32()
          {
          // Allocate memory
          int value = 0;
          GCHandle handleValue = GCHandle.Alloc(value, GCHandleType.Pinned);

          // Run the call
          DllImports.H5Aread(ObjectId, ImportedDataTypes.H5T_NATIVE_INT, handleValue.AddrOfPinnedObject());
          value = (int)handleValue.Target;

          handleValue.Free();

          return value;
          }

          public float GetValueFloat()
          {
          // Allocate memory
          float value = 0;
          GCHandle handleValue = GCHandle.Alloc(value, GCHandleType.Pinned);

          // Run the call
          DllImports.H5Aread(ObjectId, ImportedDataTypes.H5T_NATIVE_FLOAT, handleValue.AddrOfPinnedObject());
          value = (float) handleValue.Target;

          handleValue.Free();

          return value;
          }

          It works, but I'm a bit puzzled. According to my understanding of how GCHandle should work, it shouldn't be necessary to copy the value of handleValue.Target into value - it's just pinning the address of value to avoid moving. But if omit the copying step, value is always zero. If this is the way GCHandle is supposed to work, then why I'm passing an instance of value to GCHandle.Alloc instead of the memory size to allocate? If anyone can shed more light on this topic, I'd be really grateful. My next project is going to use a lot of P/Invokes, and I really need to understand what's going on there. Is there's a "right" way to accomplish what I'm trying to do?

          Luca The Price of Freedom is Eternal Vigilance. -- Wing Commander IV En Það Besta Sem Guð Hefur Skapað, Er Nýr Dagur. (But the best thing God has created, is a New Day.) -- Sigur Ròs - Viðrar vel til loftárása

          E Offline
          E Offline
          Ernest Laurentin
          wrote on last edited by
          #4

          Hi Luca, GCHandle provides direct conversion to IntPtr (use: GCHandle.ToIntPtr())

          God bless, Ernest Laurentin

          1 Reply Last reply
          0
          • L Luc Pattyn

            Hi Luca, I have used GCHandle many times to pass a reference type from managed C# to unmanaged C code; I never needed GCHandle.Target since my object was either an instance of a class I created, or a simple array. What really gets passed on is a memory pointer, pointing to the managed data (which got pinned down so the GC cannot move it around any more), so the unmanaged world can manipulate the data in the managed object. I assume you need GCHandle.Target to get the same result when you pass on a value type (such as the int and float in your examples); but I cannot confirm that from experience, and I have never come across any example of GCHandle.Target till now. However, when you know the argument is a value type, you can declare another prototype of your unmanaged method using the ref or out keyword, and forget all about GCHandle: reffing/outing a local value type is OK, since locals are on stack, and stack does not get moved around, so the following should work:

            [DllImport(" ... .dll")]
            public static extern void H5Aread(... , out float val);

            public int GetValueInt32(){
            int value = 0;
            DllImports.H5Aread(ObjectId, ImportedDataTypes.H5T_NATIVE_INT, out value);
            return value;}

            The hearth of the matter is you can overload the method, i.e. have multiple managed method prototypes with different parameter signatures, but all pointing to the same unmanaged function. :)

            Luc Pattyn [Forum Guidelines] [My Articles]


            This month's tips: - before you ask a question here, search CodeProject, then Google; - the quality and detail of your question reflects on the effectiveness of the help you are likely to get; - use PRE tags to preserve formatting when showing multi-line code snippets.


            L Offline
            L Offline
            Luca Leonardo Scorcia
            wrote on last edited by
            #5

            Whoa! This is great news! I didn't think about overloading the method! :) The distinction about value types and reference types makes sense. I'll do a few more tests in the evening to understand everything better, but your post shed much more light on this topic. Thanks a lot!

            Luca The Price of Freedom is Eternal Vigilance. -- Wing Commander IV En Það Besta Sem Guð Hefur Skapað, Er Nýr Dagur. (But the best thing God has created, is a New Day.) -- Sigur Ròs - Viðrar vel til loftárása

            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