Problem with Array from C# to COM

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

    Problem with Array from C# to COM

    Hi,

    i have a problem with a Type Library, which is written in C++.
    I am developing an application in C#.NET and have to use functions from
    this COM-Type Library. When I use these functions in the "old" VB it
    works but not in .NET. I think it is a problem with marshalling but I
    could not find a solution yet.

    First I included the Type Library in VS.NET 2003. Other functions of
    the TL work so the reference to the Lib must be correct.

    Here the piece of code in C#.NET:

    app = new nwApplication() ;
    int[] id = new int[2];
    id[0] = 1;
    id[1] = 2;

    broadcast = app.get_broadca st(id);

    app is an Application-Object of the Library. The array id has two
    numbers. The get_broadcast method needs this array as parameter and
    returns a broadcast-object.

    Here is the PROBLEM. I seems that the get_broadcast method does not get
    the content of the array correctly.

    I tried it in VB like this:

    Dim app, broadcast, id
    id = Array(1,2)
    Set app = CreateObject("N wLib.nwApplicat ion")
    Set broadcast = app.get_broadca st(id)

    This works correctly.

    When I look for the get_broadcast message in the object browser the
    definition is like this:
    nwApplication.g et_broadcast(ob ject)

    When i compile my project, VS.NET creates a Interop.nw.dll. I
    disassembled it to IL and looked for the definitions of the method. It
    was like this:

    ......... get_broadcast(o bject marshal( struct) Value)....

    Is it possible that the array in C# is not correctly marshalled?

    Has anyone an idea where the problem could be? Thanks very much!

    Peter

  • Clive Dixon

    #2
    Re: Problem with Array from C# to COM

    It sounds likely that the array is not being correctly marshalled. For the
    C# code you are using, you may have to modify your interop assembly usiing
    ildasm, a text editor, and ilasm to compile back. The marshalling in the IL
    may have to be changed to something like

    marshal(int32[])

    or even

    marshal(safearr ay int32)

    However I don't know what the method definition looks like in your TLB. The
    marshalling specified in the interop dll may well be correct but what you
    are trying to do in your C# is incorrect. (I don't know what the VB Array
    operation does.)

    "mupe" <p.mueller@eise nmann.de> wrote in message
    news:1138026398 .937069.58280@f 14g2000cwb.goog legroups.com...[color=blue]
    > Hi,
    >
    > i have a problem with a Type Library, which is written in C++.
    > I am developing an application in C#.NET and have to use functions from
    > this COM-Type Library. When I use these functions in the "old" VB it
    > works but not in .NET. I think it is a problem with marshalling but I
    > could not find a solution yet.
    >
    > First I included the Type Library in VS.NET 2003. Other functions of
    > the TL work so the reference to the Lib must be correct.
    >
    > Here the piece of code in C#.NET:
    >
    > app = new nwApplication() ;
    > int[] id = new int[2];
    > id[0] = 1;
    > id[1] = 2;
    >
    > broadcast = app.get_broadca st(id);
    >
    > app is an Application-Object of the Library. The array id has two
    > numbers. The get_broadcast method needs this array as parameter and
    > returns a broadcast-object.
    >
    > Here is the PROBLEM. I seems that the get_broadcast method does not get
    > the content of the array correctly.
    >
    > I tried it in VB like this:
    >
    > Dim app, broadcast, id
    > id = Array(1,2)
    > Set app = CreateObject("N wLib.nwApplicat ion")
    > Set broadcast = app.get_broadca st(id)
    >
    > This works correctly.
    >
    > When I look for the get_broadcast message in the object browser the
    > definition is like this:
    > nwApplication.g et_broadcast(ob ject)
    >
    > When i compile my project, VS.NET creates a Interop.nw.dll. I
    > disassembled it to IL and looked for the definitions of the method. It
    > was like this:
    >
    > ......... get_broadcast(o bject marshal( struct) Value)....
    >
    > Is it possible that the array in C# is not correctly marshalled?
    >
    > Has anyone an idea where the problem could be? Thanks very much!
    >
    > Peter
    >[/color]


    Comment

    • Clive Dixon

      #3
      Re: Problem with Array from C# to COM

      ....I'm also slightly surprised that the IL doesn't mark the parameter with
      [in] (unless you missed that out).

      Can you supply the method signature in the type library and the full method
      definition in IL?

      "mupe" <p.mueller@eise nmann.de> wrote in message
      news:1138026398 .937069.58280@f 14g2000cwb.goog legroups.com...[color=blue]
      > Hi,
      >
      > i have a problem with a Type Library, which is written in C++.
      > I am developing an application in C#.NET and have to use functions from
      > this COM-Type Library. When I use these functions in the "old" VB it
      > works but not in .NET. I think it is a problem with marshalling but I
      > could not find a solution yet.
      >
      > First I included the Type Library in VS.NET 2003. Other functions of
      > the TL work so the reference to the Lib must be correct.
      >
      > Here the piece of code in C#.NET:
      >
      > app = new nwApplication() ;
      > int[] id = new int[2];
      > id[0] = 1;
      > id[1] = 2;
      >
      > broadcast = app.get_broadca st(id);
      >
      > app is an Application-Object of the Library. The array id has two
      > numbers. The get_broadcast method needs this array as parameter and
      > returns a broadcast-object.
      >
      > Here is the PROBLEM. I seems that the get_broadcast method does not get
      > the content of the array correctly.
      >
      > I tried it in VB like this:
      >
      > Dim app, broadcast, id
      > id = Array(1,2)
      > Set app = CreateObject("N wLib.nwApplicat ion")
      > Set broadcast = app.get_broadca st(id)
      >
      > This works correctly.
      >
      > When I look for the get_broadcast message in the object browser the
      > definition is like this:
      > nwApplication.g et_broadcast(ob ject)
      >
      > When i compile my project, VS.NET creates a Interop.nw.dll. I
      > disassembled it to IL and looked for the definitions of the method. It
      > was like this:
      >
      > ......... get_broadcast(o bject marshal( struct) Value)....
      >
      > Is it possible that the array in C# is not correctly marshalled?
      >
      > Has anyone an idea where the problem could be? Thanks very much!
      >
      > Peter
      >[/color]


      Comment

      • mupe

        #4
        Re: Problem with Array from C# to COM

        Hi,

        yes i will post the code tomorrow when I am back in office.

        I already disassembled the assembly to IL and then I tried to recompile
        it but that did not work.
        So I disassembled it and recompiled it without any changes but then I
        got an error message
        that an entry point was not found and the dll was not created. I will
        post the exact error message tomorrow.

        Thanks so long.

        Comment

        • Vlad P

          #5
          RE: Problem with Array from C# to COM

          I don’t know what is the problem but as far as you received the
          [nwApplication.g et_broadcast(ob ject)]
          Object that means you receive the address of the array object and you just
          need to work out the indexes/values of your object?

          If I missed your point ignore the message.

          Vlad P

          "mupe" wrote:
          [color=blue]
          > Hi,
          >
          > i have a problem with a Type Library, which is written in C++.
          > I am developing an application in C#.NET and have to use functions from
          > this COM-Type Library. When I use these functions in the "old" VB it
          > works but not in .NET. I think it is a problem with marshalling but I
          > could not find a solution yet.
          >
          > First I included the Type Library in VS.NET 2003. Other functions of
          > the TL work so the reference to the Lib must be correct.
          >
          > Here the piece of code in C#.NET:
          >
          > app = new nwApplication() ;
          > int[] id = new int[2];
          > id[0] = 1;
          > id[1] = 2;
          >
          > broadcast = app.get_broadca st(id);
          >
          > app is an Application-Object of the Library. The array id has two
          > numbers. The get_broadcast method needs this array as parameter and
          > returns a broadcast-object.
          >
          > Here is the PROBLEM. I seems that the get_broadcast method does not get
          > the content of the array correctly.
          >
          > I tried it in VB like this:
          >
          > Dim app, broadcast, id
          > id = Array(1,2)
          > Set app = CreateObject("N wLib.nwApplicat ion")
          > Set broadcast = app.get_broadca st(id)
          >
          > This works correctly.
          >
          > When I look for the get_broadcast message in the object browser the
          > definition is like this:
          > nwApplication.g et_broadcast(ob ject)
          >
          > When i compile my project, VS.NET creates a Interop.nw.dll. I
          > disassembled it to IL and looked for the definitions of the method. It
          > was like this:
          >
          > ......... get_broadcast(o bject marshal( struct) Value)....
          >
          > Is it possible that the array in C# is not correctly marshalled?
          >
          > Has anyone an idea where the problem could be? Thanks very much!
          >
          > Peter
          >
          >[/color]

          Comment

          • mupe

            #6
            Re: Problem with Array from C# to COM

            @Vlad P: No, the object I get back from the method needs the value of
            the array for internal use. And because of the object´s behaviour I
            think that it does not get the value of the array correctly.

            @Clive Dixon: Recompilation with ilasm now works. I forgot some options
            yesterday. Here I have the pieces of IL code I found in the nw.il after
            disassembling it from Interop.Nw.dll. The names of methods could be
            different to those I posted yesterday but nwBroadcast is the object I
            get back from the method get_nwBroadcast ().

            .method public hidebysig newslot specialname virtual
            instance class nwLib.nwBroadca st
            marshal( interface)
            get_nwBroadcast (object marshal( struct) Value) runtime
            managed internalcall
            {
            .custom instance void
            [mscorlib]System.Runtime. InteropServices .DispIdAttribut e::.ctor(int32)
            = ( 01 00 0F 00 00 00 00 00 )
            .override nwLib.InwApplic ation::get_nwBr oadcast
            } // end of method nwApplicationCl ass::get_nwBroa dcast

            ....

            .property class nwLib.nwBroadca st
            nwBroadcast(obj ect)
            {
            .custom instance void
            [mscorlib]System.Runtime. InteropServices .DispIdAttribut e::.ctor(int32)
            = ( 01 00 0F 00 00 00 00 00 )
            .get instance class nwLib.nwBroadca st
            nwLib.nwApplica tionClass::get_ nwBroadcast(obj ect)
            } // end of property nwApplicationCl ass::nwBroadcas t

            ....

            .method public hidebysig newslot specialname abstract virtual
            instance class nwLib.nwBroadca st
            marshal( interface)
            get_nwBroadcast (object marshal( struct) Value) runtime
            managed internalcall
            {
            .custom instance void
            [mscorlib]System.Runtime. InteropServices .DispIdAttribut e::.ctor(int32)
            = ( 01 00 0F 00 00 00 00 00 )
            } // end of method InwApplication: :get_nwBroadcas t

            ....

            .property class nwLib.nwBroadca st
            nwBroadcast(obj ect)
            {
            .custom instance void
            [mscorlib]System.Runtime. InteropServices .DispIdAttribut e::.ctor(int32)
            = ( 01 00 0F 00 00 00 00 00 )
            .get instance class nwLib.nwBroadca st
            nwLib.InwApplic ation::get_nwBr oadcast(object)
            } // end of property InwApplication: :nwBroadcast

            Thats all I found to this method.

            In another method I get back an object which I cast to System.Array in
            my C#-Code. I found in IL code that this is also marshalled as struct.
            But that works without any problems?! Here the code:

            .method public hidebysig newslot abstract virtual
            instance object
            marshal( struct)
            ScanNet([in] int32 lngStartID,
            [in] int32 lngEndID) runtime managed internalcall
            {
            .custom instance void
            [mscorlib]System.Runtime. InteropServices .DispIdAttribut e::.ctor(int32)
            = ( 01 00 03 00 00 00 00 00 )
            } // end of method InwNetwork::Sca nNet


            I also tried marshal( int32[]) like you told me yesterday but that did
            not work. I got an error message: "parameter #1 can not be marshalled.
            Invalid managed/unmanaged type combination (the object class has to be
            combined with Interface, IUnknown, IDispatch, AsAny or Struct."

            I hope you can help me with the code above. Thanks in advance!

            Peter

            Comment

            • mupe

              #7
              Re: Problem with Array from C# to COM

              I viewed the Type Lib in the C++ TypeLib Viewer and there it looked
              likes this:

              [id(0x0000000f), propget, helpstring("pro perty nwBroadcast")]
              HRESULT nwBroadcast(
              VARIANT Value,
              [out, retval] InwBroadcast** pVal);

              Since my last entry I tried more things but nothing works....

              Comment

              • Clive Dixon

                #8
                Re: Problem with Array from C# to COM

                Seems odd that the System.Array to VARIANT (IL 'struct') marshalling happens
                one way but not the other.

                Next up, I would suggest you try manually marshalling the array to VARIANT
                before you pass it, using Marshal.GetNati veVariantForObj ect.

                You will first need to allocate some memory for the out VARIANT using
                Marshal.AllocCo TaskMem. I don't immediately see a way of allocating the
                exact size for a VARIANT in C# so you'll probably have to try giving it a
                "sufficient ly large" amount (from memory a VARIANT is 16 bytes, but don't
                quote me on that).

                "mupe" <p.mueller@eise nmann.de> wrote in message
                news:1138095798 .732965.6420@o1 3g2000cwo.googl egroups.com...
                @Vlad P: No, the object I get back from the method needs the value of
                the array for internal use. And because of the object´s behaviour I
                think that it does not get the value of the array correctly.

                @Clive Dixon: Recompilation with ilasm now works. I forgot some options
                yesterday. Here I have the pieces of IL code I found in the nw.il after
                disassembling it from Interop.Nw.dll. The names of methods could be
                different to those I posted yesterday but nwBroadcast is the object I
                get back from the method get_nwBroadcast ().

                .method public hidebysig newslot specialname virtual
                instance class nwLib.nwBroadca st
                marshal( interface)
                get_nwBroadcast (object marshal( struct) Value) runtime
                managed internalcall
                {
                .custom instance void
                [mscorlib]System.Runtime. InteropServices .DispIdAttribut e::.ctor(int32)
                = ( 01 00 0F 00 00 00 00 00 )
                .override nwLib.InwApplic ation::get_nwBr oadcast
                } // end of method nwApplicationCl ass::get_nwBroa dcast

                ....

                .property class nwLib.nwBroadca st
                nwBroadcast(obj ect)
                {
                .custom instance void
                [mscorlib]System.Runtime. InteropServices .DispIdAttribut e::.ctor(int32)
                = ( 01 00 0F 00 00 00 00 00 )
                .get instance class nwLib.nwBroadca st
                nwLib.nwApplica tionClass::get_ nwBroadcast(obj ect)
                } // end of property nwApplicationCl ass::nwBroadcas t

                ....

                .method public hidebysig newslot specialname abstract virtual
                instance class nwLib.nwBroadca st
                marshal( interface)
                get_nwBroadcast (object marshal( struct) Value) runtime
                managed internalcall
                {
                .custom instance void
                [mscorlib]System.Runtime. InteropServices .DispIdAttribut e::.ctor(int32)
                = ( 01 00 0F 00 00 00 00 00 )
                } // end of method InwApplication: :get_nwBroadcas t

                ....

                .property class nwLib.nwBroadca st
                nwBroadcast(obj ect)
                {
                .custom instance void
                [mscorlib]System.Runtime. InteropServices .DispIdAttribut e::.ctor(int32)
                = ( 01 00 0F 00 00 00 00 00 )
                .get instance class nwLib.nwBroadca st
                nwLib.InwApplic ation::get_nwBr oadcast(object)
                } // end of property InwApplication: :nwBroadcast

                Thats all I found to this method.

                In another method I get back an object which I cast to System.Array in
                my C#-Code. I found in IL code that this is also marshalled as struct.
                But that works without any problems?! Here the code:

                .method public hidebysig newslot abstract virtual
                instance object
                marshal( struct)
                ScanNet([in] int32 lngStartID,
                [in] int32 lngEndID) runtime managed internalcall
                {
                .custom instance void
                [mscorlib]System.Runtime. InteropServices .DispIdAttribut e::.ctor(int32)
                = ( 01 00 03 00 00 00 00 00 )
                } // end of method InwNetwork::Sca nNet


                I also tried marshal( int32[]) like you told me yesterday but that did
                not work. I got an error message: "parameter #1 can not be marshalled.
                Invalid managed/unmanaged type combination (the object class has to be
                combined with Interface, IUnknown, IDispatch, AsAny or Struct."

                I hope you can help me with the code above. Thanks in advance!

                Peter


                Comment

                • mupe

                  #9
                  Re: Problem with Array from C# to COM

                  This is the code I tried:

                  IntPtr mem;

                  int[] appId = new int[2];
                  appId[0] = 1;
                  appId[1] = 2;

                  mem = Marshal.AllocCo TaskMem(64); // also tried 32.....

                  Marshal.GetNati veVariantForObj ect(appId, mem);

                  nwBroad = nwApp.get_nwBro adcast(mem);

                  It does not work. It has the same effect like using appId directly as
                  parameter......

                  Do I have to edit the IL code for this too??

                  Thanks.

                  Comment

                  • mupe

                    #10
                    Re: Problem with Array from C# to COM

                    Today I tried something new. I wrote a VB6-DLL as "debug layer" which
                    gets the array as parameter. This dll hands the array over to the
                    getBroadcast method (in VB6 the whole thing works, so I chose VB6). I
                    returned the array from the dll back to my c# application and I got the
                    array with the correct numbers in it... but...
                    ....if I hand over the array without doing anything other it does not
                    work.
                    If I define a new array in the dll and copy the content of the array I
                    get as parameter into that new array, it works! So it has something to
                    do with marshaling. The numbers in the parameter array are correct. If
                    I view them in debug mode they are of type Variant/Integer.
                    The new array i define is also Variant/Integer so I do not see any
                    difference?!?

                    Comment

                    Working...