exporting function with parm pointer to struct

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

    exporting function with parm pointer to struct

    I'm exporting (with DllImport) a C-style function with this syntax:

    int z9indqry (4_PARM *parm);

    4_PARM is a structure declared in a proprietary header file that cannot be
    included in my project (due to C# limits).

    What would be the other best way to do this? I would like to be able to use
    the original struct because these structs have over 40 members each and
    there are several more Structs similar to 4_PARM. Also, they are modified by
    the company every two months so I'd need to compare and modify my C# structs
    everytime they change the h structs.
    I'm not going to use wrappers because the dll function calls are working
    well when the parms are simple data types (int, char, string, etc...). I
    just need a way to be able to call these specialized structs.

    Thanks again.

    P.S. - I'm pretty sure this is the last question I have regarding unmanaged
    code :-))


  • Nicholas Paldino [.NET/C# MVP]

    #2
    Re: exporting function with parm pointer to struct

    Angel,

    If your structures are really that flexible, then I would recommend that
    you not use a pointer to the struct, but rather, a pointer to void in the
    declaration. This will prevent you from having to recompile, as well as
    redefine the C# code (at least for the declaration).

    Also, it would imply that you need a better design that is more
    flexible, IMO. Changing the structure every two months is very time
    consuming. It might make sense to have a keyed collection of some kind to
    use.

    That being said, with what you have now, you will have to declare the
    structure in C#. You will want it to have the same layout in memory as the
    structure in C# (remember longs in C are ints in C#, etc, etc). Also, you
    will want to adorn the structure with the StructLayout attribute, passing
    LayoutKind.Sequ ential to the constructor.

    Hope this helps.


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

    "Angel" <none> wrote in message
    news:%235%23Z0o SAEHA.2308@tk2m sftngp13.phx.gb l...[color=blue]
    > I'm exporting (with DllImport) a C-style function with this syntax:
    >
    > int z9indqry (4_PARM *parm);
    >
    > 4_PARM is a structure declared in a proprietary header file that cannot be
    > included in my project (due to C# limits).
    >
    > What would be the other best way to do this? I would like to be able to[/color]
    use[color=blue]
    > the original struct because these structs have over 40 members each and
    > there are several more Structs similar to 4_PARM. Also, they are modified[/color]
    by[color=blue]
    > the company every two months so I'd need to compare and modify my C#[/color]
    structs[color=blue]
    > everytime they change the h structs.
    > I'm not going to use wrappers because the dll function calls are working
    > well when the parms are simple data types (int, char, string, etc...). I
    > just need a way to be able to call these specialized structs.
    >
    > Thanks again.
    >
    > P.S. - I'm pretty sure this is the last question I have regarding[/color]
    unmanaged[color=blue]
    > code :-))
    >
    >[/color]


    Comment

    • Angel

      #3
      Re: exporting function with parm pointer to struct

      Thanks for the post.

      I did what you suggested but I still get "This type can not be marshaled as
      a structure field" when I call the function. This is my initial code:

      [DllImport("C:\\ zm7\\Developm\\ DLL\\ZIP4_W32.D LL")]
      public static extern int z9indqry(4_PARM parm);
      public static void getParms ()
      {
      int i;
      Zip4_parm parm = new Zip4_parm();
      i = z9indqry(parm); // Error: "This type can not be marshaled as a
      structure field"
      // IntPtr buffer = Marshal.AllocCo TaskMem( Marshal.SizeOf( parm ));
      }
      What can this error mean?
      Also, I'm trying to delare some const vars from the initial H file (eg.
      #define Z4_INVADDR 10) but adding it to the cs file that contains the
      structs generates error "Expected class, delegate, enum, interface, or
      struct".

      Any help would be appreciated.

      "Nicholas Paldino [.NET/C# MVP]" <mvp@spam.guard .caspershouse.c om> wrote in
      message news:#9XbMLTAEH A.580@TK2MSFTNG P11.phx.gbl...[color=blue]
      > Angel,
      >
      > If your structures are really that flexible, then I would recommend[/color]
      that[color=blue]
      > you not use a pointer to the struct, but rather, a pointer to void in the
      > declaration. This will prevent you from having to recompile, as well as
      > redefine the C# code (at least for the declaration).
      >
      > Also, it would imply that you need a better design that is more
      > flexible, IMO. Changing the structure every two months is very time
      > consuming. It might make sense to have a keyed collection of some kind to
      > use.
      >
      > That being said, with what you have now, you will have to declare the
      > structure in C#. You will want it to have the same layout in memory as[/color]
      the[color=blue]
      > structure in C# (remember longs in C are ints in C#, etc, etc). Also, you
      > will want to adorn the structure with the StructLayout attribute, passing
      > LayoutKind.Sequ ential to the constructor.
      >
      > Hope this helps.
      >
      >
      > --
      > - Nicholas Paldino [.NET/C# MVP]
      > - mvp@spam.guard. caspershouse.co m
      >
      > "Angel" <none> wrote in message
      > news:%235%23Z0o SAEHA.2308@tk2m sftngp13.phx.gb l...[color=green]
      > > I'm exporting (with DllImport) a C-style function with this syntax:
      > >
      > > int z9indqry (4_PARM *parm);
      > >
      > > 4_PARM is a structure declared in a proprietary header file that cannot[/color][/color]
      be[color=blue][color=green]
      > > included in my project (due to C# limits).
      > >
      > > What would be the other best way to do this? I would like to be able to[/color]
      > use[color=green]
      > > the original struct because these structs have over 40 members each and
      > > there are several more Structs similar to 4_PARM. Also, they are[/color][/color]
      modified[color=blue]
      > by[color=green]
      > > the company every two months so I'd need to compare and modify my C#[/color]
      > structs[color=green]
      > > everytime they change the h structs.
      > > I'm not going to use wrappers because the dll function calls are working
      > > well when the parms are simple data types (int, char, string, etc...).[/color][/color]
      I[color=blue][color=green]
      > > just need a way to be able to call these specialized structs.
      > >
      > > Thanks again.
      > >
      > > P.S. - I'm pretty sure this is the last question I have regarding[/color]
      > unmanaged[color=green]
      > > code :-))
      > >
      > >[/color]
      >
      >[/color]


      Comment

      • Jeffrey Tan[MSFT]

        #4
        Re: exporting function with parm pointer to struct


        Hi Angel,

        Thank you for posting in the community!

        I am confused by your code. In your function declaration:
        public static extern int z9indqry(4_PARM parm)
        It needs 4_PARM structure, but you construct a Zip4_parm, then pass it to
        z9indqry.

        What is "Zip4_parm" ?

        I think the most recommanded way is do the marshaling and declaration in C#
        for your 4_PARM structure. Then use it as:
        public static extern int z9indqry(ref 4_PARM parm)

        If you still do not want to declare the structure. Just as Nicholas said,
        you may use IntPtr, which you need to read and write the structure memory
        all by yourself(Which is not recommanded)
        Below is the steps:

        1). Initialize a byte[] which is the same length as the structure.
        2). Initilize the structure byte[] array(Do some write to this byte[] array)
        3). Use Marshal.AllocCo TaskMem() to alloc a structure size in unmanaged
        memory
        4). Use Marshal.Copy(By te[], Int32, IntPtr, Int32) to copy the managed
        byte[] array to the unmanaged memory.
        5). Use the function like this: public static extern int z9indqry(ref
        IntPtr parm)

        =============== =============== =============
        Please apply my suggestion above and let me know if it helps resolve your
        problem.

        Thank you for your patience and cooperation. If you have any questions or
        concerns, please feel free to post it in the group. I am standing by to be
        of assistance.

        Best regards,
        Jeffrey Tan
        Microsoft Online Partner Support
        Get Secure! - www.microsoft.com/security
        This posting is provided "as is" with no warranties and confers no rights.

        Comment

        • Angel

          #5
          Re: exporting function with parm pointer to struct

          Thanks for your help. Instead of recreating the C-style struct as a C#
          struct, I decided to use it as a class. I think that it's at least
          communicating with the dll. This is how my class looks like:

          [StructLayout(La youtKind.Sequen tial, CharSet=CharSet .Ansi) ]
          public class city
          {
          public city()
          {
          }
          //[MarshalAs(Unman agedType.LPStr)]
          [MarshalAs( UnmanagedType.B yValArray, SizeConst=5 )]
          public char detail_code;
          public char[] zip_code;
          public char[] city_key;
          public char zip_class_code;
          public char[] city_name;
          }

          The original:
          typedef struct
          {
          char detail_code;
          char zip_code[5+1];
          char city_key[6+1];
          char zip_class_code;
          char city_name[28+1];
          } CITY_REC;


          When I invoke the function, I receive the error: "Can not marshal field
          detail_code of type ZM7.city: Invalid managed/unmanaged type combination
          (chars must be paired with U1 or U2)". At least the error specifies a field
          (detail_code) inside the class, which I think may be a good sign.

          What could it be?

          Thanks.



          """Jeffrey Tan[MSFT]""" <v-jetan@online.mi crosoft.com> wrote in message
          news:oT1Gl9bAEH A.2340@cpmsftng xa06.phx.gbl...[color=blue]
          >
          > Hi Angel,
          >
          > Thank you for posting in the community!
          >
          > I am confused by your code. In your function declaration:
          > public static extern int z9indqry(4_PARM parm)
          > It needs 4_PARM structure, but you construct a Zip4_parm, then pass it to
          > z9indqry.
          >
          > What is "Zip4_parm" ?
          >
          > I think the most recommanded way is do the marshaling and declaration in[/color]
          C#[color=blue]
          > for your 4_PARM structure. Then use it as:
          > public static extern int z9indqry(ref 4_PARM parm)
          >
          > If you still do not want to declare the structure. Just as Nicholas said,
          > you may use IntPtr, which you need to read and write the structure memory
          > all by yourself(Which is not recommanded)
          > Below is the steps:
          >
          > 1). Initialize a byte[] which is the same length as the structure.
          > 2). Initilize the structure byte[] array(Do some write to this byte[][/color]
          array)[color=blue]
          > 3). Use Marshal.AllocCo TaskMem() to alloc a structure size in unmanaged
          > memory
          > 4). Use Marshal.Copy(By te[], Int32, IntPtr, Int32) to copy the managed
          > byte[] array to the unmanaged memory.
          > 5). Use the function like this: public static extern int z9indqry(ref
          > IntPtr parm)
          >
          > =============== =============== =============
          > Please apply my suggestion above and let me know if it helps resolve your
          > problem.
          >
          > Thank you for your patience and cooperation. If you have any questions or
          > concerns, please feel free to post it in the group. I am standing by to be
          > of assistance.
          >
          > Best regards,
          > Jeffrey Tan
          > Microsoft Online Partner Support
          > Get Secure! - www.microsoft.com/security
          > This posting is provided "as is" with no warranties and confers no rights.
          >[/color]


          Comment

          • Dmitry Kostenko

            #6
            Re: exporting function with parm pointer to struct

            Hi, Angel ;)

            Try the following

            [StructLayout(La youtKind.Sequen tial, CharSet=CharSet .Ansi) ]
            public class city
            {
            public city()
            {
            }
            [MarshalAs(Unman agedType.U1)]
            public char detail_code;
            [MarshalAs( UnmanagedType.B yValArray, SizeConst=5 )]
            public char[] zip_code;
            [MarshalAs( UnmanagedType.B yValArray, SizeConst=6 )]
            public char[] city_key;
            [MarshalAs(Unman agedType.U1)]
            public char zip_class_code;
            [MarshalAs( UnmanagedType.B yValArray, SizeConst=29 )]
            public char[] city_name;
            }

            You should marshal 'char' as 'UnmanagedType. U1' which means C 'char' and
            'char[]' as 'UnmanagedType. ByValArray, SizeConst=size' which means C 'char[size]'.

            Also you may need to compile C structure with '#pragma pack push(1)' to remove data alignment.

            Angel wrote:
            [color=blue]
            > Thanks for your help. Instead of recreating the C-style struct as a C#
            > struct, I decided to use it as a class. I think that it's at least
            > communicating with the dll. This is how my class looks like:
            >
            > [StructLayout(La youtKind.Sequen tial, CharSet=CharSet .Ansi) ]
            > public class city
            > {
            > public city()
            > {
            > }
            > //[MarshalAs(Unman agedType.LPStr)]
            > [MarshalAs( UnmanagedType.B yValArray, SizeConst=5 )]
            > public char detail_code;
            > public char[] zip_code;
            > public char[] city_key;
            > public char zip_class_code;
            > public char[] city_name;
            > }
            >
            > The original:
            > typedef struct
            > {
            > char detail_code;
            > char zip_code[5+1];
            > char city_key[6+1];
            > char zip_class_code;
            > char city_name[28+1];
            > } CITY_REC;
            >
            >
            > When I invoke the function, I receive the error: "Can not marshal field
            > detail_code of type ZM7.city: Invalid managed/unmanaged type combination
            > (chars must be paired with U1 or U2)". At least the error specifies a field
            > (detail_code) inside the class, which I think may be a good sign.
            >
            > What could it be?
            >
            > Thanks.
            >
            >
            >
            > """Jeffrey Tan[MSFT]""" <v-jetan@online.mi crosoft.com> wrote in message
            > news:oT1Gl9bAEH A.2340@cpmsftng xa06.phx.gbl...
            >[color=green]
            >>Hi Angel,
            >>
            >>Thank you for posting in the community!
            >>
            >>I am confused by your code. In your function declaration:
            >>public static extern int z9indqry(4_PARM parm)
            >>It needs 4_PARM structure, but you construct a Zip4_parm, then pass it to
            >>z9indqry.
            >>
            >>What is "Zip4_parm" ?
            >>
            >>I think the most recommanded way is do the marshaling and declaration in[/color]
            >
            > C#
            >[color=green]
            >>for your 4_PARM structure. Then use it as:
            >>public static extern int z9indqry(ref 4_PARM parm)
            >>
            >>If you still do not want to declare the structure. Just as Nicholas said,
            >>you may use IntPtr, which you need to read and write the structure memory
            >>all by yourself(Which is not recommanded)
            >>Below is the steps:
            >>
            >>1). Initialize a byte[] which is the same length as the structure.
            >>2). Initilize the structure byte[] array(Do some write to this byte[][/color]
            >
            > array)
            >[color=green]
            >>3). Use Marshal.AllocCo TaskMem() to alloc a structure size in unmanaged
            >>memory
            >>4). Use Marshal.Copy(By te[], Int32, IntPtr, Int32) to copy the managed
            >>byte[] array to the unmanaged memory.
            >>5). Use the function like this: public static extern int z9indqry(ref
            >>IntPtr parm)
            >>[/color][/color]

            --
            With best regards :)
            Dmitry Kostenko

            Comment

            • Jeffrey Tan[MSFT]

              #7
              Re: exporting function with parm pointer to struct


              Hi Angel,

              Please apply Dmitry's suggestion to see if resolve your problem. Thanks

              Best regards,
              Jeffrey Tan
              Microsoft Online Partner Support
              Get Secure! - www.microsoft.com/security
              This posting is provided "as is" with no warranties and confers no rights.

              Comment

              Working...