Problem Sending VB6 Byte Array to C#...help?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • intrepid_dw@hotmail.com

    Problem Sending VB6 Byte Array to C#...help?

    Hello, all.

    I've created a C# dll that contains, among other things, two functions
    dealing with byte arrays. The first is a function that returns a byte
    array, and the other is intended to receive a byte array as one of its
    parameters. The project is marked for COM interop, and that all
    proceeds normally.

    When I reference the type library in the VB6 project, and write the
    code to call the function that returns the byte array, it works
    perfectly. However, when I write the code to call the method that
    expects the byte arrary as a parameter, VB informs me that "Function is
    marked restricted, or uses a type not supported by Automation." The
    Object Browser shows the library AND the method with its (correct)
    parameter list.

    The latter portion of the warning didn't ring entirely true to me,
    because I had returned a byte array with no problem. It occurred to me
    there might be a problem on the outbound side.

    As a test, I built a quick-and-dirty VB6 COM DLL with a method that
    expected a byte array, and the OLEView utility for that DLL showed the
    TLB for that method showed this signature:

    VB6 dummy COM DLL method:
    HRESULT TestMethod( [in] SAFEARRAY(unsig ned char)* parm,
    [out, retval] BSTR* pRetVal);

    However, when I looked at the IDL for the Interop assembly of my C#
    code, the Byte array parameter signature was as follows:

    C# class method w/System.Byte[] as parameter
    HRESULT MyMethod( [in] SAFEARRAY(unsig ned char) FileContent,
    [in] BSTR FileComment,
    [out, retval] BSTR* pRetVal);

    Note the difference in the signatures for the first parameter; the
    first is [in] SAFEARRAY(unsig ned char)*, but the latter is only [in]
    SAFEARRAY(unsig ned char). Why the difference?? Each is expecting the
    same thing.

    My initial thought was that this, perhaps, was a bug in the IDL/TLB
    generation code from C#, but that seemed unlikely (?). Can anyone else
    offer any suggestions or help?

    Ultimately, I really just need to pass a byte array from VB6 to C#, so
    I figure someone is bound to have done that before. If anyone has any
    suggestions, I'd be appreciative.

    Thanks,
    David

    ps Please reply to group; email herein is long since dead.

  • Kevin Spencer

    #2
    Re: Problem Sending VB6 Byte Array to C#...help?

    > Note the difference in the signatures for the first parameter; the[color=blue]
    > first is [in] SAFEARRAY(unsig ned char)*, but the latter is only [in]
    > SAFEARRAY(unsig ned char). Why the difference?? Each is expecting the
    > same thing.[/color]

    Not exactly the same thing. The one that works is looking for a pointer to a
    byte array. The second is looking for a byte array.

    It sounds like you need to build a COM interop wrapper for the VB6 DLL.

    --
    HTH,

    Kevin Spencer
    Microsoft MVP
    ..Net Developer
    Ambiguity has a certain quality to it.

    <intrepid_dw@ho tmail.com> wrote in message
    news:1128529797 .819522.233220@ z14g2000cwz.goo glegroups.com.. .[color=blue]
    > Hello, all.
    >
    > I've created a C# dll that contains, among other things, two functions
    > dealing with byte arrays. The first is a function that returns a byte
    > array, and the other is intended to receive a byte array as one of its
    > parameters. The project is marked for COM interop, and that all
    > proceeds normally.
    >
    > When I reference the type library in the VB6 project, and write the
    > code to call the function that returns the byte array, it works
    > perfectly. However, when I write the code to call the method that
    > expects the byte arrary as a parameter, VB informs me that "Function is
    > marked restricted, or uses a type not supported by Automation." The
    > Object Browser shows the library AND the method with its (correct)
    > parameter list.
    >
    > The latter portion of the warning didn't ring entirely true to me,
    > because I had returned a byte array with no problem. It occurred to me
    > there might be a problem on the outbound side.
    >
    > As a test, I built a quick-and-dirty VB6 COM DLL with a method that
    > expected a byte array, and the OLEView utility for that DLL showed the
    > TLB for that method showed this signature:
    >
    > VB6 dummy COM DLL method:
    > HRESULT TestMethod( [in] SAFEARRAY(unsig ned char)* parm,
    > [out, retval] BSTR* pRetVal);
    >
    > However, when I looked at the IDL for the Interop assembly of my C#
    > code, the Byte array parameter signature was as follows:
    >
    > C# class method w/System.Byte[] as parameter
    > HRESULT MyMethod( [in] SAFEARRAY(unsig ned char) FileContent,
    > [in] BSTR FileComment,
    > [out, retval] BSTR* pRetVal);
    >
    > Note the difference in the signatures for the first parameter; the
    > first is [in] SAFEARRAY(unsig ned char)*, but the latter is only [in]
    > SAFEARRAY(unsig ned char). Why the difference?? Each is expecting the
    > same thing.
    >
    > My initial thought was that this, perhaps, was a bug in the IDL/TLB
    > generation code from C#, but that seemed unlikely (?). Can anyone else
    > offer any suggestions or help?
    >
    > Ultimately, I really just need to pass a byte array from VB6 to C#, so
    > I figure someone is bound to have done that before. If anyone has any
    > suggestions, I'd be appreciative.
    >
    > Thanks,
    > David
    >
    > ps Please reply to group; email herein is long since dead.
    >[/color]


    Comment

    • intrepid_dw@hotmail.com

      #3
      Re: Problem Sending VB6 Byte Array to C#...help?

      Kevin:

      Thanks for your help.

      I reread my original post, and realized it was a bit muddled. My
      apologies for not making it more clear. There are three pieces of code
      involved; A C# Interop DLL, a "client" VB6 application that will use
      the C# interop assembly, and then a throwaway "test" VB6 COM DLL
      created only to test how the type library
      records the parameters in the method signatures.

      My expectation was that the Interop assembly would create a type
      library expecting a **pointer** to a SAFEARRAY of unsigned characters,
      but it didn't; it was just the SAFEARRAY. I didn't think that seemed
      right, so I built a "test" VB6 COM DLL to test what IT would generate
      for a byte array in the type library method signatures.

      See the declarations below:

      // C# decl in interop assembly, no pointer...
      // TLB generates [in] SAFEARRAY(unsig ned char) FileContent
      public string MyMethod(System .Byte[] FileContent,
      String FileComment)


      // VB6 "dummy" declaration to compare type library signatures
      // TLB has *pointer* reference, eg
      // this one generates [in] SAFEARRAY(unsig ned char)* parm
      public function TestMethod(parm () as byte) as String

      Sure enough, my prediction was right; the VB6 COM DLL type library
      wanted a *pointer* to a SAFEARRAY of unsigned chars, and hence my
      question. If two different methods in two different DLL's are both
      exposing a COM interface, and each is expecting a byte array, why
      wouldn't the type library for *both* expect a pointer to a SAFEARRAY of
      unsigned chars? It would seem to me the type library signatures should
      match, and they don't.

      Is that explanation any better? I'm sure I'm overlooking something
      obvious, just not sure what it is.

      Thanks again for your help,
      David


      Kevin Spencer wrote:[color=blue][color=green]
      > > Note the difference in the signatures for the first parameter; the
      > > first is [in] SAFEARRAY(unsig ned char)*, but the latter is only [in]
      > > SAFEARRAY(unsig ned char). Why the difference?? Each is expecting the
      > > same thing.[/color]
      >
      > Not exactly the same thing. The one that works is looking for a pointer to a
      > byte array. The second is looking for a byte array.
      >
      > It sounds like you need to build a COM interop wrapper for the VB6 DLL.
      >
      > --
      > HTH,
      >
      > Kevin Spencer
      > Microsoft MVP
      > .Net Developer
      > Ambiguity has a certain quality to it.
      >
      > <intrepid_dw@ho tmail.com> wrote in message
      > news:1128529797 .819522.233220@ z14g2000cwz.goo glegroups.com.. .[color=green]
      > > Hello, all.
      > >
      > > I've created a C# dll that contains, among other things, two functions
      > > dealing with byte arrays. The first is a function that returns a byte
      > > array, and the other is intended to receive a byte array as one of its
      > > parameters. The project is marked for COM interop, and that all
      > > proceeds normally.
      > >
      > > When I reference the type library in the VB6 project, and write the
      > > code to call the function that returns the byte array, it works
      > > perfectly. However, when I write the code to call the method that
      > > expects the byte arrary as a parameter, VB informs me that "Function is
      > > marked restricted, or uses a type not supported by Automation." The
      > > Object Browser shows the library AND the method with its (correct)
      > > parameter list.
      > >
      > > The latter portion of the warning didn't ring entirely true to me,
      > > because I had returned a byte array with no problem. It occurred to me
      > > there might be a problem on the outbound side.
      > >
      > > As a test, I built a quick-and-dirty VB6 COM DLL with a method that
      > > expected a byte array, and the OLEView utility for that DLL showed the
      > > TLB for that method showed this signature:
      > >
      > > VB6 dummy COM DLL method:
      > > HRESULT TestMethod( [in] SAFEARRAY(unsig ned char)* parm,
      > > [out, retval] BSTR* pRetVal);
      > >
      > > However, when I looked at the IDL for the Interop assembly of my C#
      > > code, the Byte array parameter signature was as follows:
      > >
      > > C# class method w/System.Byte[] as parameter
      > > HRESULT MyMethod( [in] SAFEARRAY(unsig ned char) FileContent,
      > > [in] BSTR FileComment,
      > > [out, retval] BSTR* pRetVal);
      > >
      > > Note the difference in the signatures for the first parameter; the
      > > first is [in] SAFEARRAY(unsig ned char)*, but the latter is only [in]
      > > SAFEARRAY(unsig ned char). Why the difference?? Each is expecting the
      > > same thing.
      > >
      > > My initial thought was that this, perhaps, was a bug in the IDL/TLB
      > > generation code from C#, but that seemed unlikely (?). Can anyone else
      > > offer any suggestions or help?
      > >
      > > Ultimately, I really just need to pass a byte array from VB6 to C#, so
      > > I figure someone is bound to have done that before. If anyone has any
      > > suggestions, I'd be appreciative.
      > >
      > > Thanks,
      > > David
      > >
      > > ps Please reply to group; email herein is long since dead.
      > >[/color][/color]

      Comment

      • Kevin Spencer

        #4
        Re: Problem Sending VB6 Byte Array to C#...help?

        Well, David, I'm still a bit confused. You have a VB6 COM DLL, and an
        Interop .Net class that interoperates with it, and which was generated by a
        tool. So far so good? Now, here it starts to get fuzzy. You are now working
        with the Interop assembly, and not directly with the COM DLL, correct? So,
        you call a method in the Interop DLL that returns a byte array, and you get
        one back. Am I still on the right track? But you call a method in the
        Interop that is supposed to take byte array as a parameter, and it fails
        because the Interop DLL is expecting a pointer to a byte array? Now, this is
        where it starts to get really fuzzy. First, I can't imagine a managed
        Interop DLL that would be expecting a pointer. Still, I suppose it's
        possible. Second, you say you created ANOTHER VB6 COM DLL and compared its
        type library reference to the type library reference in the Interop, and
        they didn't match? Well, why should they? First, the second COM DLL is not
        the one the Interop is working with. You would have to create another
        Interop for that DLL and compare IT to the type library in the second COM
        DLL.

        So, at this point, being thoroughly fuddled, I can mention only that the
        tools for creating COM Interop assemblies don't always work correctly
        straight out of the box, and you may need to tweak the Interop assembly. But
        as confused as I am, I can only guess.

        --
        HTH,

        Kevin Spencer
        Microsoft MVP
        ..Net Developer
        Ambiguity has a certain quality to it.

        <intrepid_dw@ho tmail.com> wrote in message
        news:1128606377 .756303.35250@z 14g2000cwz.goog legroups.com...[color=blue]
        > Kevin:
        >
        > Thanks for your help.
        >
        > I reread my original post, and realized it was a bit muddled. My
        > apologies for not making it more clear. There are three pieces of code
        > involved; A C# Interop DLL, a "client" VB6 application that will use
        > the C# interop assembly, and then a throwaway "test" VB6 COM DLL
        > created only to test how the type library
        > records the parameters in the method signatures.
        >
        > My expectation was that the Interop assembly would create a type
        > library expecting a **pointer** to a SAFEARRAY of unsigned characters,
        > but it didn't; it was just the SAFEARRAY. I didn't think that seemed
        > right, so I built a "test" VB6 COM DLL to test what IT would generate
        > for a byte array in the type library method signatures.
        >
        > See the declarations below:
        >
        > // C# decl in interop assembly, no pointer...
        > // TLB generates [in] SAFEARRAY(unsig ned char) FileContent
        > public string MyMethod(System .Byte[] FileContent,
        > String FileComment)
        >
        >
        > // VB6 "dummy" declaration to compare type library signatures
        > // TLB has *pointer* reference, eg
        > // this one generates [in] SAFEARRAY(unsig ned char)* parm
        > public function TestMethod(parm () as byte) as String
        >
        > Sure enough, my prediction was right; the VB6 COM DLL type library
        > wanted a *pointer* to a SAFEARRAY of unsigned chars, and hence my
        > question. If two different methods in two different DLL's are both
        > exposing a COM interface, and each is expecting a byte array, why
        > wouldn't the type library for *both* expect a pointer to a SAFEARRAY of
        > unsigned chars? It would seem to me the type library signatures should
        > match, and they don't.
        >
        > Is that explanation any better? I'm sure I'm overlooking something
        > obvious, just not sure what it is.
        >
        > Thanks again for your help,
        > David
        >
        >
        > Kevin Spencer wrote:[color=green][color=darkred]
        >> > Note the difference in the signatures for the first parameter; the
        >> > first is [in] SAFEARRAY(unsig ned char)*, but the latter is only [in]
        >> > SAFEARRAY(unsig ned char). Why the difference?? Each is expecting the
        >> > same thing.[/color]
        >>
        >> Not exactly the same thing. The one that works is looking for a pointer
        >> to a
        >> byte array. The second is looking for a byte array.
        >>
        >> It sounds like you need to build a COM interop wrapper for the VB6 DLL.
        >>
        >> --
        >> HTH,
        >>
        >> Kevin Spencer
        >> Microsoft MVP
        >> .Net Developer
        >> Ambiguity has a certain quality to it.
        >>
        >> <intrepid_dw@ho tmail.com> wrote in message
        >> news:1128529797 .819522.233220@ z14g2000cwz.goo glegroups.com.. .[color=darkred]
        >> > Hello, all.
        >> >
        >> > I've created a C# dll that contains, among other things, two functions
        >> > dealing with byte arrays. The first is a function that returns a byte
        >> > array, and the other is intended to receive a byte array as one of its
        >> > parameters. The project is marked for COM interop, and that all
        >> > proceeds normally.
        >> >
        >> > When I reference the type library in the VB6 project, and write the
        >> > code to call the function that returns the byte array, it works
        >> > perfectly. However, when I write the code to call the method that
        >> > expects the byte arrary as a parameter, VB informs me that "Function is
        >> > marked restricted, or uses a type not supported by Automation." The
        >> > Object Browser shows the library AND the method with its (correct)
        >> > parameter list.
        >> >
        >> > The latter portion of the warning didn't ring entirely true to me,
        >> > because I had returned a byte array with no problem. It occurred to me
        >> > there might be a problem on the outbound side.
        >> >
        >> > As a test, I built a quick-and-dirty VB6 COM DLL with a method that
        >> > expected a byte array, and the OLEView utility for that DLL showed the
        >> > TLB for that method showed this signature:
        >> >
        >> > VB6 dummy COM DLL method:
        >> > HRESULT TestMethod( [in] SAFEARRAY(unsig ned char)* parm,
        >> > [out, retval] BSTR* pRetVal);
        >> >
        >> > However, when I looked at the IDL for the Interop assembly of my C#
        >> > code, the Byte array parameter signature was as follows:
        >> >
        >> > C# class method w/System.Byte[] as parameter
        >> > HRESULT MyMethod( [in] SAFEARRAY(unsig ned char) FileContent,
        >> > [in] BSTR FileComment,
        >> > [out, retval] BSTR* pRetVal);
        >> >
        >> > Note the difference in the signatures for the first parameter; the
        >> > first is [in] SAFEARRAY(unsig ned char)*, but the latter is only [in]
        >> > SAFEARRAY(unsig ned char). Why the difference?? Each is expecting the
        >> > same thing.
        >> >
        >> > My initial thought was that this, perhaps, was a bug in the IDL/TLB
        >> > generation code from C#, but that seemed unlikely (?). Can anyone else
        >> > offer any suggestions or help?
        >> >
        >> > Ultimately, I really just need to pass a byte array from VB6 to C#, so
        >> > I figure someone is bound to have done that before. If anyone has any
        >> > suggestions, I'd be appreciative.
        >> >
        >> > Thanks,
        >> > David
        >> >
        >> > ps Please reply to group; email herein is long since dead.
        >> >[/color][/color]
        >[/color]


        Comment

        • intrepid_dw@hotmail.com

          #5
          Re: Problem Sending VB6 Byte Array to C#...help?

          I'm sorry, Kevin. Bear with me. I really don't mean to confuse you :)

          First, the C# DLL has two methods; one returns a byte array, one
          requires a byte array as a parameter. A VB6 client needs to talk to
          each of these methods, so I mark the C# DLL for COM Interop. So far, so
          good.

          Next, I fire up VB6 and include a reference to the .tlb from the
          interop assembly. So far, so good.

          Now, I write code to call the interop methods from VB6. When I call the
          method that returns the array of bytes, it works. When I call the
          method that requires a byte array as a parameter, I get a compile-time
          error saying "Function marked as restricted or uses an automation type
          not supported in Visual Basic."

          I discard the first possibility (marked as limited). I don't understand
          the second possibility, because if I can get an array of bytes from an
          Interop assembly, why shouldn't I be able to send one? So, I suspect
          it's some sort of type problem I don't understand or see.

          Now, I examine the TLB of the Interop assembly, and the method that's
          giving me problems has the byte array parameter declared as a
          SAFEARRAY(unsig ned char) - NOT a pointer.

          Not recognizing the type problem, I opt to just try some research
          separately. I wanted to see what the declaration for a byte array
          parameter would look like in the type library for a COM DLL written
          from a different source - eg, VB6. SO I did; I wrote a throwaway VB6
          DLL, and declared a function with a byte array as a parameter. I
          observed the type library for this DLL, and noticed that parameter is
          declared as a POINTER to a SAFEARRAY(unsig ned char).

          My confusion is that, while I fully understand the DLL's are coming
          from diffrent sources, each is exposing a COM interface to receive the
          same kind of data - an array of bytes (SAFEARRAY). On that basis, I
          would expect COM to force both sides (COM Interop from .NET or VB6 COM
          DLL) to generate a consistent declaration for the same data type, but
          it didn't. One COM DLL wants a *pointer* to SAFEARRAY, while the other
          wants JUST a SAFEARRAY. I was just trying to understand why they were
          different. If you're passing a variant array to a COM server,
          regardless of whether that COM server originates in an interop DLL or
          VB6, it would seem as though you should pass it the same way. It seems
          to me that one of these ways will end up being wrong.

          If that doesn't help explain my situation, it's my fault, and I
          appreciate your attempt nonetheless.

          -David

          Kevin Spencer wrote:[color=blue]
          > Well, David, I'm still a bit confused. You have a VB6 COM DLL, and an
          > Interop .Net class that interoperates with it, and which was generated by a
          > tool. So far so good? Now, here it starts to get fuzzy. You are now working
          > with the Interop assembly, and not directly with the COM DLL, correct? So,
          > you call a method in the Interop DLL that returns a byte array, and you get
          > one back. Am I still on the right track? But you call a method in the
          > Interop that is supposed to take byte array as a parameter, and it fails
          > because the Interop DLL is expecting a pointer to a byte array? Now, this is
          > where it starts to get really fuzzy. First, I can't imagine a managed
          > Interop DLL that would be expecting a pointer. Still, I suppose it's
          > possible. Second, you say you created ANOTHER VB6 COM DLL and compared its
          > type library reference to the type library reference in the Interop, and
          > they didn't match? Well, why should they? First, the second COM DLL is not
          > the one the Interop is working with. You would have to create another
          > Interop for that DLL and compare IT to the type library in the second COM
          > DLL.
          >
          > So, at this point, being thoroughly fuddled, I can mention only that the
          > tools for creating COM Interop assemblies don't always work correctly
          > straight out of the box, and you may need to tweak the Interop assembly. But
          > as confused as I am, I can only guess.
          >
          > --
          > HTH,
          >
          > Kevin Spencer
          > Microsoft MVP
          > .Net Developer
          > Ambiguity has a certain quality to it.
          >[/color]

          Comment

          • Willy Denoyette [MVP]

            #6
            Re: Problem Sending VB6 Byte Array to C#...help?

            Following C# method signatures:

            byte[] RetArr();

            void GetArr(byte[] aParam1);

            should translate into:

            HRESULT RetArr([out, retval] SAFEARRAY(unsig ned char)* pRetVal);

            HRESULT GetArr([in] SAFEARRAY(unsig ned char) aParam1);



            in your typelib generated by regasm.exe. Are you sure you didn't pass the
            arg by ref?

            void GetArr(ref byte[] aParam1);

            Willy.

            <intrepid_dw@ho tmail.com> wrote in message
            news:1128630177 .547790.18020@g 43g2000cwa.goog legroups.com...
            [color=blue]
            > I'm sorry, Kevin. Bear with me. I really don't mean to confuse you :)
            >
            > First, the C# DLL has two methods; one returns a byte array, one
            > requires a byte array as a parameter. A VB6 client needs to talk to
            > each of these methods, so I mark the C# DLL for COM Interop. So far, so
            > good.
            >
            > Next, I fire up VB6 and include a reference to the .tlb from the
            > interop assembly. So far, so good.
            >
            > Now, I write code to call the interop methods from VB6. When I call the
            > method that returns the array of bytes, it works. When I call the
            > method that requires a byte array as a parameter, I get a compile-time
            > error saying "Function marked as restricted or uses an automation type
            > not supported in Visual Basic."
            >
            > I discard the first possibility (marked as limited). I don't understand
            > the second possibility, because if I can get an array of bytes from an
            > Interop assembly, why shouldn't I be able to send one? So, I suspect
            > it's some sort of type problem I don't understand or see.
            >
            > Now, I examine the TLB of the Interop assembly, and the method that's
            > giving me problems has the byte array parameter declared as a
            > SAFEARRAY(unsig ned char) - NOT a pointer.
            >
            > Not recognizing the type problem, I opt to just try some research
            > separately. I wanted to see what the declaration for a byte array
            > parameter would look like in the type library for a COM DLL written
            > from a different source - eg, VB6. SO I did; I wrote a throwaway VB6
            > DLL, and declared a function with a byte array as a parameter. I
            > observed the type library for this DLL, and noticed that parameter is
            > declared as a POINTER to a SAFEARRAY(unsig ned char).
            >
            > My confusion is that, while I fully understand the DLL's are coming
            > from diffrent sources, each is exposing a COM interface to receive the
            > same kind of data - an array of bytes (SAFEARRAY). On that basis, I
            > would expect COM to force both sides (COM Interop from .NET or VB6 COM
            > DLL) to generate a consistent declaration for the same data type, but
            > it didn't. One COM DLL wants a *pointer* to SAFEARRAY, while the other
            > wants JUST a SAFEARRAY. I was just trying to understand why they were
            > different. If you're passing a variant array to a COM server,
            > regardless of whether that COM server originates in an interop DLL or
            > VB6, it would seem as though you should pass it the same way. It seems
            > to me that one of these ways will end up being wrong.
            >
            > If that doesn't help explain my situation, it's my fault, and I
            > appreciate your attempt nonetheless.
            >
            > -David
            >
            > Kevin Spencer wrote:[color=green]
            >> Well, David, I'm still a bit confused. You have a VB6 COM DLL, and an
            >> Interop .Net class that interoperates with it, and which was generated by
            >> a
            >> tool. So far so good? Now, here it starts to get fuzzy. You are now
            >> working
            >> with the Interop assembly, and not directly with the COM DLL, correct?
            >> So,
            >> you call a method in the Interop DLL that returns a byte array, and you
            >> get
            >> one back. Am I still on the right track? But you call a method in the
            >> Interop that is supposed to take byte array as a parameter, and it fails
            >> because the Interop DLL is expecting a pointer to a byte array? Now, this
            >> is
            >> where it starts to get really fuzzy. First, I can't imagine a managed
            >> Interop DLL that would be expecting a pointer. Still, I suppose it's
            >> possible. Second, you say you created ANOTHER VB6 COM DLL and compared
            >> its
            >> type library reference to the type library reference in the Interop, and
            >> they didn't match? Well, why should they? First, the second COM DLL is
            >> not
            >> the one the Interop is working with. You would have to create another
            >> Interop for that DLL and compare IT to the type library in the second COM
            >> DLL.
            >>
            >> So, at this point, being thoroughly fuddled, I can mention only that the
            >> tools for creating COM Interop assemblies don't always work correctly
            >> straight out of the box, and you may need to tweak the Interop assembly.
            >> But
            >> as confused as I am, I can only guess.
            >>
            >> --
            >> HTH,
            >>
            >> Kevin Spencer
            >> Microsoft MVP
            >> .Net Developer
            >> Ambiguity has a certain quality to it.
            >>[/color]
            >[/color]


            Comment

            • Kevin Spencer

              #7
              Re: Problem Sending VB6 Byte Array to C#...help?

              Don't worry about it, David. I've been a bit overworked lately. Just
              finished a deadline and am getting ready to get some rest now! So, it could
              be me!

              Here's the problem I'm having with your methodology: You created a second
              COM DLL to test against. Now, you claim that it has the same parameter type
              as the first, but you don't seem to understand the difference between a
              pointer to an array and an array. At least you haven't specifically said
              that the first VB COM DLL most definitely takes a pointer to an array rather
              than an array as a parameter. Since you've created a second VB6 COM DLL, I
              can't be sure whether or not the method you defined in the second indeed
              matches the signature of the method defined in the first. In other words,
              this whole second DLL you created has done nothing but muddy the waters with
              unreliable data. Unless you can tell me that you're absolutely certain that
              both methods have the exact same signature, no test with the second VB6 DLL
              will yield meaningful results.

              The difference between an array of bytes and a pointer to an array of bytes
              may not seem like much in VB, where everything is a variant, but it is
              highly significant in the strongly-typed world of .Net. The difference is
              the difference between my house, and the address of my house. Now, I might
              say that I live at 13 Mockingbird Lane, but I don't really. I live in the
              house that is located at the address of 13 Mockingbird Lane. The address is
              merely a locator for my house. Let's say that I hired a mover and had my
              entire house moved to another location. I would still live in my house, but
              it would no longer be at 13 Mockingbird Lane.

              In .Net, everything is really a pointer, underneath the hood. When you
              create an instance of a string, for example, you are creating a pointer to
              an immutable array of char. If you change the string, you aren't really
              changing the string at all. You are creating a new string somewhere else in
              memory, and moving the pointer with it. The pointer still has the same name,
              and is a pointer to a string, but not a pointer to the SAME string.

              So, if you pass an array, you are passing the array itself. When you pass a
              pointer to an array, you are passing the address in memory of the array. A
              pointer is a number (offset in memory). An array is a group of numbers. Not
              the same thing at all.

              And, as I mentioned earlier, in my last post, you can't always rely on the
              ..Net tools to write your Interop assemblies exactly correctly, for a number
              of reasons.

              What you need to do is to find out (from the original VB6 COM DLL) what data
              type it is expecting, and make sure that your Interop assembly is passing
              that exact data type to it. This may require some tweaking of the Interop
              assembly.

              --
              HTH,

              Kevin Spencer
              Microsoft MVP
              ..Net Developer
              Ambiguity has a certain quality to it.


              <intrepid_dw@ho tmail.com> wrote in message
              news:1128630177 .547790.18020@g 43g2000cwa.goog legroups.com...[color=blue]
              > I'm sorry, Kevin. Bear with me. I really don't mean to confuse you :)
              >
              > First, the C# DLL has two methods; one returns a byte array, one
              > requires a byte array as a parameter. A VB6 client needs to talk to
              > each of these methods, so I mark the C# DLL for COM Interop. So far, so
              > good.
              >
              > Next, I fire up VB6 and include a reference to the .tlb from the
              > interop assembly. So far, so good.
              >
              > Now, I write code to call the interop methods from VB6. When I call the
              > method that returns the array of bytes, it works. When I call the
              > method that requires a byte array as a parameter, I get a compile-time
              > error saying "Function marked as restricted or uses an automation type
              > not supported in Visual Basic."
              >
              > I discard the first possibility (marked as limited). I don't understand
              > the second possibility, because if I can get an array of bytes from an
              > Interop assembly, why shouldn't I be able to send one? So, I suspect
              > it's some sort of type problem I don't understand or see.
              >
              > Now, I examine the TLB of the Interop assembly, and the method that's
              > giving me problems has the byte array parameter declared as a
              > SAFEARRAY(unsig ned char) - NOT a pointer.
              >
              > Not recognizing the type problem, I opt to just try some research
              > separately. I wanted to see what the declaration for a byte array
              > parameter would look like in the type library for a COM DLL written
              > from a different source - eg, VB6. SO I did; I wrote a throwaway VB6
              > DLL, and declared a function with a byte array as a parameter. I
              > observed the type library for this DLL, and noticed that parameter is
              > declared as a POINTER to a SAFEARRAY(unsig ned char).
              >
              > My confusion is that, while I fully understand the DLL's are coming
              > from diffrent sources, each is exposing a COM interface to receive the
              > same kind of data - an array of bytes (SAFEARRAY). On that basis, I
              > would expect COM to force both sides (COM Interop from .NET or VB6 COM
              > DLL) to generate a consistent declaration for the same data type, but
              > it didn't. One COM DLL wants a *pointer* to SAFEARRAY, while the other
              > wants JUST a SAFEARRAY. I was just trying to understand why they were
              > different. If you're passing a variant array to a COM server,
              > regardless of whether that COM server originates in an interop DLL or
              > VB6, it would seem as though you should pass it the same way. It seems
              > to me that one of these ways will end up being wrong.
              >
              > If that doesn't help explain my situation, it's my fault, and I
              > appreciate your attempt nonetheless.
              >
              > -David
              >
              > Kevin Spencer wrote:[color=green]
              >> Well, David, I'm still a bit confused. You have a VB6 COM DLL, and an
              >> Interop .Net class that interoperates with it, and which was generated by
              >> a
              >> tool. So far so good? Now, here it starts to get fuzzy. You are now
              >> working
              >> with the Interop assembly, and not directly with the COM DLL, correct?
              >> So,
              >> you call a method in the Interop DLL that returns a byte array, and you
              >> get
              >> one back. Am I still on the right track? But you call a method in the
              >> Interop that is supposed to take byte array as a parameter, and it fails
              >> because the Interop DLL is expecting a pointer to a byte array? Now, this
              >> is
              >> where it starts to get really fuzzy. First, I can't imagine a managed
              >> Interop DLL that would be expecting a pointer. Still, I suppose it's
              >> possible. Second, you say you created ANOTHER VB6 COM DLL and compared
              >> its
              >> type library reference to the type library reference in the Interop, and
              >> they didn't match? Well, why should they? First, the second COM DLL is
              >> not
              >> the one the Interop is working with. You would have to create another
              >> Interop for that DLL and compare IT to the type library in the second COM
              >> DLL.
              >>
              >> So, at this point, being thoroughly fuddled, I can mention only that the
              >> tools for creating COM Interop assemblies don't always work correctly
              >> straight out of the box, and you may need to tweak the Interop assembly.
              >> But
              >> as confused as I am, I can only guess.
              >>
              >> --
              >> HTH,
              >>
              >> Kevin Spencer
              >> Microsoft MVP
              >> .Net Developer
              >> Ambiguity has a certain quality to it.
              >>[/color]
              >[/color]


              Comment

              • intrepid_dw@hotmail.com

                #8
                Re: Problem Sending VB6 Byte Array to C#...help?

                Kevin:

                Thanks again. I greatly appreciate the effort.

                Please know that I understand the difference between pointers to arrays
                and arrays and the like...I've been hacking around in all these things
                for longer than I care to mention, from C to C++ and VB6 and .NET and
                too many others, and have tried to mentor many a coworker on them over
                the years :). This is just a very narrow problem tied to this
                particular interop situation that made me wonder about typelib
                generation for COM Interop DLL's.

                I'm pretty sure that, based on your response, that I'm just doing a
                lousy job of explaining my problem - and that's entirely my fault. I'm
                more than a bit embarrassed to think how dense you must think I am to
                have had to explain pointers...<gul p>....

                Let me reset things a bit, along with some updated info. First, let me
                offer that I fixed the original problem of VB6 complaining about the
                "automation type unsupported by Visual Basic." In fixing *that*
                problem, it ALSO fixed the way .NET generated the type library for the
                Interop assembly. Those issues dovetail in a way that probably explains
                the whole problem better than I have so far.

                Here's how I got there. In thinking about the typelib for the COM
                interop method, I realized what VB was complaining about; it
                essentially saw a declaration requesting that a SafeArray be passed
                ByVal, which almost certainly scrambled VB's brain. It can only pass
                them by reference. That implies that the method signature needed to be
                SAFEARRAY(unsig ned char)*. I needed a "control" to verify the theory,
                and that led me to building the throwaway VB dll that expected a byte
                array parameter so I could inspect *its* type library...Sure enough,
                the type library for a VB6 DLL expecting a byte array parameter ends up
                looking like

                HRESULT MyFunction([in, out] SAFEARRAY(unsig ned char)* MyArray);

                WIth that in hand, that led me to the fix on the .NET side.......

                The fix was to change the method parameter signature in the C# Interop
                DLL from "byte[]" to "ref byte[]". This had the downstream effect of
                changing the method signature in the COM type library to
                SAFEARRAY(unsig ned char)*, which is *precisely* what I expected/needed.
                When I call the function from VB, it now works perfectly.

                A different way of seeing my problem can be illustrated in the
                following C# example:

                void SomeMethod(Syst em.Byte[] lotsabytes, ref byte[] morebytes);

                If marked for COM Interop, the type library for SomeMethod will look
                something like:

                HRESULT SomeMethod([in] SAFEARRAY(unsig ned char) lotsabytes, [in]
                SAFEARRAY(unsig ned char)* morebytes)

                VB can't pass an array by value, as implied by the first declaration,
                but it can pass the array by reference. The latter declaration is
                consistent with how .NET writes the COM Interop type library for a
                function *returning* a byte array, but not for a *parameter*. That's
                what had me puzzled; declarations for the same type were being written
                two different ways. Changing the declaration of the array to "ref"
                resolved the problem, and everything now works the way I
                intended/expected.

                I realize you're probably tired of my rambling explanations, but
                hopefully THIS version of the explanation was an approach from a
                different angle that clarified what I was trying to do. I appreciate
                your patient and polite help nonetheless, and I hope you don't think
                I'm a *complete* idiot. :)

                David

                Comment

                • intrepid_dw@hotmail.com

                  #9
                  Re: Problem Sending VB6 Byte Array to C#...help?

                  Hi, Willy.

                  I just saw your post, right after I'd finished a rather lengthy reply
                  to Kevin's last message.

                  You're absolutely right - the typelibs for the methods you describe are
                  exactly what I'm seeing. For VB to send a byte array, which will
                  necessarily be by reference, the parameter for your "GetArr" sample
                  would have to be SAFEARRAY(unsig ned char)* aParam1.

                  I changed the delcaration in my C# method to ref byte[], and that
                  solved the problem. The typelib now matches what I would expect for a
                  byte array, and the resultant C# DLL interops with VB6 perfectly.

                  Thanks for your willingness to help.

                  David

                  Comment

                  Working...