Calling C++ function from C#

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • cozumeldiver@comcast.net

    Calling C++ function from C#

    I need to call the below function from a C# application. Having
    problems converting it to C#. I think the BOOLs are just integers in
    C#. I have tried char[] and string for the PAWDOBJKEY. I always get
    "ERROR_BAD_PARA M" for a return value.

    SHORT APIENTRY AwdApiInsertIte mKey(
    HWND hwndContainer,
    PAWDOBJKEY pAwdObjParentKe y,
    PAWDOBJKEY pAwdObjKey,
    BOOL fUpdateCount,
    BOOL fLockFlag,
    PVOID pReserved);

    Parameters
    hwndContainer: A handle to the container in which you want to
    insert an item.
    pAwdObjParentKe y: A pointer to the key of an existing parent of
    the item to be inserted. If NULL, the item is inserted at the root.
    pAwdObjKey: A pointer to the key of the item to insert. A view
    call is made to get all the needed information to insert the item.
    fUpdateCount: This parameter is ignored.
    fLockFlag: Specifies whether or not to lock the object on
    insertion. True=Lock False=Don’t Lock.
    pReserved: Reserved for future use; it should be NULL.
    =============== ==
    AWDOBJKEY
    Data that uniquely defines an AWD object. This data
    distinguishes the object from other objects of the same type.
    Typedef struct awdobjkey
    {
    CHAR crdattim [26];
    CHAR recordcd;
    CHAR crnode[2];
    } AWDOBJKEY, *PAWDOBJKEY;

    ==============
  • Pavel Minaev

    #2
    Re: Calling C++ function from C#

    On Aug 19, 6:10 pm, cozumeldi...@co mcast.net wrote:
    I need to call the below function from a C# application. Having
    problems converting it to C#. I think the BOOLs are just integers in
    C#.
    It will work, but you can also use "bool" just fine - it maps to 4-
    byte WinAPI-style BOOL by default.
    I have tried char[] and string for the PAWDOBJKEY. I always get
    "ERROR_BAD_PARA M" for a return value.
    >
        SHORT APIENTRY AwdApiInsertIte mKey(
                         HWND hwndContainer,
                         PAWDOBJKEY pAwdObjParentKe y,
                         PAWDOBJKEY pAwdObjKey,
                         BOOL fUpdateCount,
                         BOOL fLockFlag,
                         PVOID pReserved);
    >
        Parameters
          hwndContainer:    A handle to the container in which you want to
    insert an item.
          pAwdObjParentKe y: A pointer to the key of an existing parent of
    the item to be inserted. If NULL, the item is inserted at the root.
          pAwdObjKey:       A pointer to the key of the item to insert. A view
    call is made to get all the needed information to insert the item.
          fUpdateCount:     This parameter is ignored.
          fLockFlag:                Specifies whether or not to lock the object on
    insertion. True=Lock False=Don’t Lock.
          pReserved:                Reserved for futureuse; it should be NULL.
      =============== ==
        AWDOBJKEY
          Data that uniquely defines an AWD object. This data
    distinguishes the object from other objects of the same type.
          Typedef struct awdobjkey
                {
                  CHAR crdattim [26];
                  CHAR recordcd;
                  CHAR crnode[2];
                } AWDOBJKEY, *PAWDOBJKEY;
    I don't see why you should use char[] or string for AWDOBJKEY, since
    it's a struct. So you need to create a corresponding C# struct:

    [StructLayout(La youtKind.Sequen tial, CharSet=CharSet .Ansi)]
    struct ADWOBJKEY
    {
    [MarshalAs(Unman agedType.ByValT Str, SizeConst=26)]
    string crdattim;

    char recordcd;

    [MarshalAs(Unman agedType.ByValT Str, SizeConst=2)]
    string crnode;
    }

    And then PAWDOBJKEY is just a pointer, which (if you want to avoid
    pointers in C#) translates to a "ref" argument of the method:

    short AwdApiInsertIte mKey(
                        IntPtr hwndContainer,
                         ref AWDOBJKEY pAwdObjParentKe y,
                         ref AWDOBJKEY pAwdObjKey,
                         bool fUpdateCount,
                         bool fLockFlag,
                         IntPtr pReserved);

    Depending on whether the C++ code also includes some #pragma pack
    directives (or is compiled with the corresponding compiler options),
    you might also need to set StructLayoutAtt ribute.Size on the struct
    declaration.

    Comment

    • cozumeldiver@comcast.net

      #3
      Re: Calling C++ function from C#

      Thank you for your reply. Your code almost does the trick. I can do a
      trace on the C++ function and it looks to me that when the C++
      function get the data it is a little off. I am sending
      "2008-06-13-03.54.36.420704 " for the crdattim, 'T' for the recordcd
      and "01" for the crnode. The first trace below is from another
      application that calls this function, the second from my app. Looks
      like the last character in the 2 strings is messed up. the last
      character of the 1st string is a "0" and the last character of the
      second string is a "."

      Any ideas?

      Good call:
      DATA: 56 bytes
      56 49 45 57 41 43 42 4C 30 30 31 38 58 58 58 58
      <VIEWACBL0018XX XX>
      58 58 58 58 30 30 30 30 30 31 4C 32 30 30 38 2D <XXXX000001L200 8-
      >
      30 36 2D 31 33 2D 30 33 2E 35 34 2E 33 36 2E 34 <06-13-03.54.36.4>
      32 30 37 30 34 54 30 31
      <20704T01 >

      Bad call:
      DATA: 56 bytes
      56 49 45 57 41 43 42 4C 30 30 31 38 58 58 58 58
      <VIEWACBL0018XX XX>
      58 58 58 58 30 30 30 30 30 31 52 32 30 30 38 2D <XXXX000001R200 8-
      >
      30 36 2D 31 33 2D 30 33 2E 35 34 2E 33 36 2E 34 <06-13-03.54.36.4>
      32 30 37 30 30 54 30 00
      <20700T0. >

      Comment

      • Pavel Minaev

        #4
        Re: Calling C++ function from C#

        On Aug 22, 12:42 am, cozumeldi...@co mcast.net wrote:
        Thank you for your reply. Your code almost does the trick. I can do a
        trace on the C++ function and it looks to me that when the C++
        function get the data it is a little off. I am sending
        "2008-06-13-03.54.36.420704 " for the crdattim, 'T' for  the recordcd
        and "01" for the crnode
        Oh, so those strings are fixed length and not null-terminated (since
        you are passing 2 chars to a char[2], which leaves no space for a
        terminating '\0').

        . The first trace below is from another
        application that calls this function, the second from my app. Looks
        like the last character in the 2 strings is messed up. the last
        character of the 1st string is a "0" and the last character of the
        second string is a "."
        .NET assumed C-style null-terminated strings, and therefore replaced
        the last character with '\0' for both strings (a single char was
        marshalled fine because it's not a string).
        Unfortunately, it means that you cannot use string marshalling (it
        always assumes null terminator), and will have to work directly with
        byte arrays. So:

        [StructLayout(La youtKind.Sequen tial, CharSet=CharSet .Ansi)]
        struct ADWOBJKEY
        {
        [MarshalAs(Unman agedType.ByValA rray, SizeConst=26)]
        byte[] crdattim;

        char recordcd;

        [MarshalAs(Unman agedType.ByValA rray, SizeConst=2)]
        byte[] crnode;
        }

        To convert .NET strings to byte arrays and back, you use
        Encoding.GetByt es() and Encoding.GetStr ing() methods. The default
        system encoding is Encoding.Defaul t (it will be the same as using
        CharSet.Ansi in earlier declarations).

        Comment

        • cozumeldiver@comcast.net

          #5
          Re: Calling C++ function from C#

          Thank you very much. It now works. You are a genius.

          On Aug 22, 1:23 am, Pavel Minaev <int...@gmail.c omwrote:
          On Aug 22, 12:42 am, cozumeldi...@co mcast.net wrote:
          >
          Thank you for your reply. Your code almost does the trick. I can do a
          trace on theC++function and it looks to me that when theC++
          function get the data it is a little off. I am sending
          "2008-06-13-03.54.36.420704 " for the crdattim, 'T' for the recordcd
          and "01" for the crnode
          >
          Oh, so those strings are fixed length and not null-terminated (since
          you are passing 2 chars to a char[2], which leaves no space for a
          terminating '\0').
          >
          . The first trace below is from another
          >
          application that calls this function, the second from my app. Looks
          like the last character in the 2 strings is messed up. the last
          character of the 1st string is a "0" and the last character of the
          second string is a "."
          >
          .NET assumed C-style null-terminated strings, and therefore replaced
          the last character with '\0' for both strings (a single char was
          marshalled fine because it's not a string).
          Unfortunately, it means that you cannot use string marshalling (it
          always assumes null terminator), and will have to work directly with
          byte arrays. So:
          >
          [StructLayout(La youtKind.Sequen tial, CharSet=CharSet .Ansi)]structADWOBJKEY
          {
          [MarshalAs(Unman agedType.ByValA rray, SizeConst=26)]
          byte[] crdattim;
          >
          char recordcd;
          >
          [MarshalAs(Unman agedType.ByValA rray, SizeConst=2)]
          byte[] crnode;
          >
          }
          >
          To convert .NET strings to byte arrays and back, you use
          Encoding.GetByt es() and Encoding.GetStr ing() methods. The default
          system encoding is Encoding.Defaul t (it will be the same as using
          CharSet.Ansi in earlier declarations).

          Comment

          Working...