Calling a C function from C# with struct' as a parameter.

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Treadstone

    Calling a C function from C# with struct' as a parameter.

    Hi,

    Being a newbie to C# and having worked with C all the way, I am stuck
    with an interop problem.

    I have a DLL exporting certain functions (and written in C).
    The signature of 1 such function is as follows:

    extern "C"
    {
    __declspec(dlle xport) int EnumerateDevice (DEVICE **DeviceList);
    }

    struct DEVICE
    {
    int DeviceNo;
    DEVICE *next;
    };

    I need to call this function from my C# code. How do I go about doing
    this? I went through some interop samples but most of them use basic
    data types (int and char) as parameters in their examples.

    Any code sample in this regard would be useful.

    Thanks in advance.

    Regards,
    Treadstone

  • Christof Nordiek

    #2
    Re: Calling a C function from C# with struct' as a parameter.

    "Treadstone " <u.bhargav@gmai l.comschrieb im Newsbeitrag
    news:1191835812 .718931.174920@ o80g2000hse.goo glegroups.com.. .
    Hi,
    >
    Being a newbie to C# and having worked with C all the way, I am stuck
    with an interop problem.
    >
    I have a DLL exporting certain functions (and written in C).
    The signature of 1 such function is as follows:
    >
    Do you know this link:


    It doesn't contain your method, but has some examples, of Marshalling
    structs witch P/Invoke.

    HTH
    Christof

    Comment

    • Nicholas Paldino [.NET/C# MVP]

      #3
      Re: Calling a C function from C# with struct' as a parameter.

      Treadstone,

      First, you are going to have to define the structure:

      [StructLayout(La youtKind.Sequen tial)]
      public struct Device
      {
      public int DeviceNo;
      public IntPtr Next;
      }

      You use an IntPtr for the Next parameter because you are going to
      marshal it manually when you need it. Then, you define your API like this:

      [DllImport("dlln ame.dll")]
      static int EnumerateDevice (ref IntPtr DeviceList);

      You would then call the api passing an IntPtr to your method. When you
      get it back, you would call the static PtrToStructure method on the Marshal
      class to get an instance of the Device structure back. You would also need
      to do this for next item in the list, as pointed out by the Next field on
      the structure.

      Finally, you will probably have to deallocate the memory allocated by
      the call to EnumerateDevice , as well as all the items pointed to by the Next
      field in each of the structures in the enumeration.


      --
      - Nicholas Paldino [.NET/C# MVP]
      - mvp@spam.guard. caspershouse.co m



      "Treadstone " <u.bhargav@gmai l.comwrote in message
      news:1191835812 .718931.174920@ o80g2000hse.goo glegroups.com.. .
      Hi,
      >
      Being a newbie to C# and having worked with C all the way, I am stuck
      with an interop problem.
      >
      I have a DLL exporting certain functions (and written in C).
      The signature of 1 such function is as follows:
      >
      extern "C"
      {
      __declspec(dlle xport) int EnumerateDevice (DEVICE **DeviceList);
      }
      >
      struct DEVICE
      {
      int DeviceNo;
      DEVICE *next;
      };
      >
      I need to call this function from my C# code. How do I go about doing
      this? I went through some interop samples but most of them use basic
      data types (int and char) as parameters in their examples.
      >
      Any code sample in this regard would be useful.
      >
      Thanks in advance.
      >
      Regards,
      Treadstone
      >

      Comment

      • Treadstone

        #4
        Re: Calling a C function from C# with struct' as a parameter.

        Nicholas,

        I defined the structure in the manner suggested by you, along with the
        DllImport declaration.
        However, the moment I called either Marshal.AllocCo TaskMem or
        Marshal.AllocHG lobal or Marshal.PtrToSt ructure, I am getting a
        System.NotSuppo rted exception.

        My code inside my function is as follows:

        //BEGINNING OF CODE SNIPPET

        IntPtr DeviceList = IntPtr.Zero;
        DEVICE device = new DEVICE( ); //The DEVICE structure has been defined
        already.

        Marshal.AllocHG lobal(Marshal.S izeOf(device); //This gives me a
        System.NotSuppo rtedException

        //My function call
        iReturnValue = EnumerateDevice (ref DeviceList);

        Marshal.PtrToSt ructure(DeviceL ist, device) //If I do not invoke the
        Marshal.AllocHG lobal call, then
        the //
        System.NotSuppo rtedException occurs here.

        //END OF CODE SNIPPET

        I tried the Marshal.PtrToSt ructure with all possible combinations of
        the overloaded methods, but ended up with the same result.
        Am I making some mistake while calling the methods of Marshal (such as
        AllocHGlobal/ AllocCoTaskMem/PtrToStrucuture )? Or does it have
        something to do with the version of VS2005?

        Thanks in Advance.

        Christof: Thanks for the pointer to the website. It has been of great
        help to me.

        Regards,
        Treadstone

        Comment

        • mh

          #5
          Re: Calling a C function from C# with struct' as a parameter.


          Marshal.Structu reToPtr(device, DeviceList, true);
          iReturnValue = EnumerateDevice (ref DeviceList);
          DEVICE retdevice = (DEVICE)Marshal .PtrToStructure (DeviceList,
          typeof(DEVICE))

          MH

          On Oct 8, 10:18 pm, Treadstone <u.bhar...@gmai l.comwrote:
          Nicholas,
          >
          I defined the structure in the manner suggested by you, along with the
          DllImport declaration.
          However, the moment I called either Marshal.AllocCo TaskMem or
          Marshal.AllocHG lobal or Marshal.PtrToSt ructure, I am getting a
          System.NotSuppo rted exception.
          >
          My code inside my function is as follows:
          >
          //BEGINNING OF CODE SNIPPET
          >
          IntPtr DeviceList = IntPtr.Zero;
          DEVICE device = new DEVICE( ); //The DEVICE structure has been defined
          already.
          >
          Marshal.AllocHG lobal(Marshal.S izeOf(device); //This gives me a
          System.NotSuppo rtedException
          >
          //My function call
          iReturnValue = EnumerateDevice (ref DeviceList);
          >
          Marshal.PtrToSt ructure(DeviceL ist, device) //If I do not invoke the
          Marshal.AllocHG lobal call, then
          the //
          System.NotSuppo rtedException occurs here.
          >
          //END OF CODE SNIPPET
          >
          I tried the Marshal.PtrToSt ructure with all possible combinations of
          the overloaded methods, but ended up with the same result.
          Am I making some mistake while calling the methods of Marshal (such as
          AllocHGlobal/ AllocCoTaskMem/PtrToStrucuture )? Or does it have
          something to do with the version of VS2005?
          >
          Thanks in Advance.
          >
          Christof: Thanks for the pointer to the website. It has been of great
          help to me.
          >
          Regards,
          Treadstone

          Comment

          • Treadstone

            #6
            Re: Calling a C function from C# with struct' as a parameter.


            MH,

            Tried that as well. Still the same result.
            I'm getting a System.NotSuppo rtedException in the first statement
            itself:

            Marshal.Structu reToPtr(device, DeviceList, true); //This method
            throws an exception.

            Tried with various permutations and combinations as well but in vain.

            Thanks in advance.

            Regards,
            Treadstone

            Comment

            • mh

              #7
              Re: Calling a C function from C# with struct' as a parameter.

              Add a constructor to the the DEVICE structure to initialize the
              variables.


              [System.Runtime. InteropServices .StructLayout(S ystem.Runtime.I nteropServices. LayoutKind.Sequ ential)]
              public struct DEVICE
              {
              public int DeviceNo;
              public IntPtr Next;
              public DEVICE(int _DeviceNo, IntPtr _Next)
              {
              DeviceNo = _DeviceNo;
              Next = _Next;
              }
              }

              //This part works without throwing any exceptions

              DEVICE device = new DEVICE(0 , IntPtr.Zero);
              IntPtr DeviceList = Marshal.AllocHG lobal(Marshal.S izeOf(device));
              Marshal.Structu reToPtr(device, DeviceList, true);
              //..

              MH


              On Oct 11, 7:11 am, Treadstone <u.bhar...@gmai l.comwrote:
              MH,
              >
              Tried that as well. Still the same result.
              I'm getting a System.NotSuppo rtedException in the first statement
              itself:
              >
              Marshal.Structu reToPtr(device, DeviceList, true); //This method
              throws an exception.
              >
              Tried with various permutations and combinations as well but in vain.
              >
              Thanks in advance.
              >
              Regards,
              Treadstone

              Comment

              • Treadstone

                #8
                Re: Calling a C function from C# with struct' as a parameter.

                MH,

                Thanks a ton. That worked. But the addition of another variable into
                the structure saw to it that my woes did not end.
                A variable of type string was added into the structure.

                My new structure in my C Dll is as follows:

                struct DEVICE
                {
                int DeviceNo;
                string DeviceName;
                DEVICE *next;
                }
                >From few of the interop articles that I went through, I understood
                that a string has to be declared as an IntPtr.
                So, in my C# code, here are the modifications I made:

                public struct DEVICE
                {
                public int DeviceNo;
                public IntPtr DeviceName;
                public IntPtr Next;
                }

                // In my code.
                DEVICE device = new DEVICE( );
                IntPtr DeviceList = Marshal.AllocHG lobal(Marshal.S izeOf(device));
                device.DeviceNa me = Marshal.AllocHG lobal(256);

                //My function call
                iReturnValue = EnumerateDevice (ref DeviceList); // The EnumerateDevice
                returns all the device names in range.
                DEVICE retdevice = (DEVICE)Marshal .PtrToStructure (DeviceList,
                typeof(DEVICE)) ;

                //Here I am trying to access the DeviceName that is returned by the
                EnumerateDevice Function.
                string MyString = Marshal.PtrToSt ringUni(device. DeviceName); //code
                fails here.

                The moment I try something like this, the active sync connection to my
                mobile (on which the application is running) breaks down.

                Am I doing some elementary mistake here?

                Thanks in advance.

                Regards,
                Treadstone.




                Comment

                • mh

                  #9
                  Re: Calling a C function from C# with struct' as a parameter.

                  If possible, try to redefine DeviceName as char* or wchar* rather than
                  string in the C dll. In most cases .NET can not handle C/C++ strings
                  properly or not at all. Also depending on the DeviceName (ANSI/W) data
                  type, you need to use either PtrToStringUni or PtrToStringAnsi
                  versions.

                  struct DEVICE
                  {
                  int DeviceNo;
                  char *DeviceName; //wchar*
                  DEVICE *next;
                  }

                  MH

                  On Oct 15, 4:28 am, Treadstone <u.bhar...@gmai l.comwrote:
                  MH,
                  >
                  Thanks a ton. That worked. But the addition of another variable into
                  the structure saw to it that my woes did not end.
                  A variable of type string was added into the structure.
                  >
                  My new structure in my C Dll is as follows:
                  >
                  struct DEVICE
                  {
                  int DeviceNo;
                  string DeviceName;
                  DEVICE *next;
                  >
                  }
                  From few of the interop articles that I went through, I understood
                  >
                  that a string has to be declared as an IntPtr.
                  So, in my C# code, here are the modifications I made:
                  >
                  public struct DEVICE
                  {
                  public int DeviceNo;
                  public IntPtr DeviceName;
                  public IntPtr Next;
                  >
                  }
                  >
                  // In my code.
                  DEVICE device = new DEVICE( );
                  IntPtr DeviceList = Marshal.AllocHG lobal(Marshal.S izeOf(device));
                  device.DeviceNa me = Marshal.AllocHG lobal(256);
                  >
                  //My function call
                  iReturnValue = EnumerateDevice (ref DeviceList); // The EnumerateDevice
                  returns all the device names in range.
                  DEVICE retdevice = (DEVICE)Marshal .PtrToStructure (DeviceList,
                  typeof(DEVICE)) ;
                  >
                  //Here I am trying to access the DeviceName that is returned by the
                  EnumerateDevice Function.
                  string MyString = Marshal.PtrToSt ringUni(device. DeviceName); //code
                  fails here.
                  >
                  The moment I try something like this, the active sync connection to my
                  mobile (on which the application is running) breaks down.
                  >
                  Am I doing some elementary mistake here?
                  >
                  Thanks in advance.
                  >
                  Regards,
                  Treadstone.

                  Comment

                  • Treadstone

                    #10
                    Re: Calling a C function from C# with struct' as a parameter.


                    MH,

                    Tried that as well. (Changing the data type to char* / wchar*). :(
                    Also, tried using the PtrToStringUni and PtrToStringBSTR
                    (PtrToStringAns i isn't suppported with Compact Framework, I presume).

                    Each time I use the PtrToStringUni method, the application hangs and
                    the connection to my device is broken. It doesn't even throw an
                    exception.

                    Thanks.
                    Treadstone.

                    Comment

                    • mh

                      #11
                      Re: Calling a C function from C# with struct' as a parameter.

                      How are you allocating the string in the C dll? Are you using
                      SysAllocString, GlobalAlloc, malloc, ...?

                      MH

                      On Oct 15, 6:07 am, Treadstone <u.bhar...@gmai l.comwrote:
                      MH,
                      >
                      Tried that as well. (Changing the data type to char* / wchar*). :(
                      Also, tried using the PtrToStringUni and PtrToStringBSTR
                      (PtrToStringAns i isn't suppported with Compact Framework, I presume).
                      >
                      Each time I use the PtrToStringUni method, the application hangs and
                      the connection to my device is broken. It doesn't even throw an
                      exception.
                      >
                      Thanks.
                      Treadstone.

                      Comment

                      • Treadstone

                        #12
                        Re: Calling a C function from C# with struct' as a parameter.

                        In the C Dll, the memory has been allocated for the structure by using
                        'new'.
                        The code in the C Dll is as follows:

                        __declspec(dlle xport) int EnumeratDevice( DEVICE **DeviceList,in t
                        *pNum)
                        {
                        DEVICE *BTDevicesList = NULL;
                        DEVICE *BTSpecificDevi ce = NULL;
                        DEVICE *BTDevice = NULL;

                        BTDevice = new DEVICE;

                        //Enumerate BT devices here.
                        ....
                        ....
                        BTDevicesList = BTDevice;

                        *DeviceList = BTDevicesList;
                        return SUCCESS;
                        }

                        But, does the manner in which the memory is allocated make an impact
                        on the marshalling?

                        -Treadstone.

                        Comment

                        • Willy Denoyette [MVP]

                          #13
                          Re: Calling a C function from C# with struct' as a parameter.

                          "Treadstone " <u.bhargav@gmai l.comwrote in message
                          news:1192507297 .078826.202940@ i38g2000prf.goo glegroups.com.. .
                          In the C Dll, the memory has been allocated for the structure by using
                          'new'.
                          The code in the C Dll is as follows:
                          >
                          __declspec(dlle xport) int EnumeratDevice( DEVICE **DeviceList,in t
                          *pNum)
                          {
                          DEVICE *BTDevicesList = NULL;
                          DEVICE *BTSpecificDevi ce = NULL;
                          DEVICE *BTDevice = NULL;
                          >
                          BTDevice = new DEVICE;
                          >
                          //Enumerate BT devices here.
                          ....
                          ....
                          BTDevicesList = BTDevice;
                          >
                          *DeviceList = BTDevicesList;
                          return SUCCESS;
                          }
                          >
                          But, does the manner in which the memory is allocated make an impact
                          on the marshalling?
                          >
                          -Treadstone.
                          >

                          This doesn't show us how your C string looks like, if this is a non-Unicode
                          build, the string will be an ANSI string, as you are marshaling the IntPtr
                          as pointing to a Unicode string, this will fail.

                          Willy.

                          Comment

                          • Treadstone

                            #14
                            Re: Calling a C function from C# with struct' as a parameter.

                            Willy, MH,

                            It finally worked. I changed the struct definition in my C# code and
                            it looked something like this:
                            [StructLayout(La youtKind.Sequen tial, CharSet=CharSet .Unicode)]
                            struct DEVICE {
                            public int DeviceNo;
                            [MarshalAs(Unman agedType.ByValT Str, SizeConst=256)] public string
                            DeviceName;
                            public IntPtr Next;
                            }

                            And in the function, the Marshal.PtrToSt ructure method succeeded and I
                            could access DEVICE.DeviceNa me.
                            I dint have to do anything else after that.

                            If someone else has a similar problem (strings within structures),
                            this link might provide some useful pointers.
                            Review the default marshalling behavior for strings in interfaces, platform invoke, structures, & fixed-length string buffers in .NET.


                            Willy, MH thanks a lot for all the help.

                            Regards,
                            Treadstone.

                            Comment

                            Working...