Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C#
  4. COM/C# datatype mismatch

COM/C# datatype mismatch

Scheduled Pinned Locked Moved C#
csharphelpcssvisual-studiocom
14 Posts 2 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • K KingTermite

    I have a C# com object that I'm creating which I'm testing in a VB environment. This COM object is also calling other COM objects which were written in VB. I have a VB COM object with a method who's signature looks like this: Public Function MyFunction(varNames() As String) As String() I'm trying to send in a string array when calling this guy in my C# code like this: string[] sNames = { "ProjectName" }; // 1 element array COMInt.ComClass oCDS = new COMInt.ComClass(); sValues = oCDS.MyFunction(ref sNames); I get type mismatch on the "ref sNames". This is just one of many combinations I've tried, but have not quite figured out the correct type match. Here is the error I receive in VS.Net: D:\CSS\Dev\ProjName\ProjClass.cs(255): The best overloaded method match for 'COMInt.ComClass.MyFunction(ref System.Array)' has some invalid arguments Can anybody help me out and explain this? P.S. Sorry for all the "MyFunction" and "ProjClass", etc.... but this is at work and I could get in trouble just for posting the names of things (they are VERY picky).


    There are only 10 types of people in this world....those that understand binary, and those that do not.

    H Offline
    H Offline
    Heath Stewart
    wrote on last edited by
    #2

    Check the signature of MyFunction. If it doesn't have a ref or out keyword before the param, don't use either ref or out to call the method. Strings in .NET (as well as most other classes) are already reference Types, so you rarely need to use ref or out (sometimes it's necessary, like for pointers to pointers, but it's typically only necessary for value types).

    Microsoft MVP, Visual C# My Articles

    K 1 Reply Last reply
    0
    • H Heath Stewart

      Check the signature of MyFunction. If it doesn't have a ref or out keyword before the param, don't use either ref or out to call the method. Strings in .NET (as well as most other classes) are already reference Types, so you rarely need to use ref or out (sometimes it's necessary, like for pointers to pointers, but it's typically only necessary for value types).

      Microsoft MVP, Visual C# My Articles

      K Offline
      K Offline
      KingTermite
      wrote on last edited by
      #3

      Yeah, I know what you're saying. The signature was the first code section/line. I tried it first without the ref, assuming that was the correct way (most of my experience being a C programmer). That just gave me the same error. This one shows up too: D:\CSS\Dev\ProjName\ClassName.cs(255): Argument '1': cannot convert from 'string[]' to 'ref System.Array'. BTW...also to note, the new C# must match the existing VB signature because that is a long time used COM object so interface can't change.


      There are only 10 types of people in this world....those that understand binary, and those that do not.

      H 1 Reply Last reply
      0
      • K KingTermite

        Yeah, I know what you're saying. The signature was the first code section/line. I tried it first without the ref, assuming that was the correct way (most of my experience being a C programmer). That just gave me the same error. This one shows up too: D:\CSS\Dev\ProjName\ClassName.cs(255): Argument '1': cannot convert from 'string[]' to 'ref System.Array'. BTW...also to note, the new C# must match the existing VB signature because that is a long time used COM object so interface can't change.


        There are only 10 types of people in this world....those that understand binary, and those that do not.

        H Offline
        H Offline
        Heath Stewart
        wrote on last edited by
        #4

        No, what was the signature in the CCW (the interop assembly) that was generated from the VB COM object? Did it use a ref? The original error message you got indicates that it does not.

        Microsoft MVP, Visual C# My Articles

        K 1 Reply Last reply
        0
        • H Heath Stewart

          No, what was the signature in the CCW (the interop assembly) that was generated from the VB COM object? Did it use a ref? The original error message you got indicates that it does not.

          Microsoft MVP, Visual C# My Articles

          K Offline
          K Offline
          KingTermite
          wrote on last edited by
          #5

          Oh...sorry..I got ya now. And no, it didn't use ref, I didn't think it did. I was only trying that after it didn't work originally without the ref thinking maybe I needed that to send it in. This is the interop assembly (the type lib you mean I hope...this is my first taste in COM). SAFEARRAY(BSTR) MyFunction([in, out] SAFEARRAY(BSTR)* varNames);


          There are only 10 types of people in this world....those that understand binary, and those that do not.

          H 1 Reply Last reply
          0
          • K KingTermite

            Oh...sorry..I got ya now. And no, it didn't use ref, I didn't think it did. I was only trying that after it didn't work originally without the ref thinking maybe I needed that to send it in. This is the interop assembly (the type lib you mean I hope...this is my first taste in COM). SAFEARRAY(BSTR) MyFunction([in, out] SAFEARRAY(BSTR)* varNames);


            There are only 10 types of people in this world....those that understand binary, and those that do not.

            H Offline
            H Offline
            Heath Stewart
            wrote on last edited by
            #6

            No, the assembly generated after running tlbimp.exe on the typelib, or using VS.NET to do the same. Judging by the method declaration, though, you should end up with something like the following:

            void MyFunction(
            [MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VarEnum.VT_BSTR)]
            string[] varNames,
            [MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VarEnum.VT_BSTR), Out]
            string[] retVal);

            Microsoft MVP, Visual C# My Articles

            K 1 Reply Last reply
            0
            • H Heath Stewart

              No, the assembly generated after running tlbimp.exe on the typelib, or using VS.NET to do the same. Judging by the method declaration, though, you should end up with something like the following:

              void MyFunction(
              [MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VarEnum.VT_BSTR)]
              string[] varNames,
              [MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VarEnum.VT_BSTR), Out]
              string[] retVal);

              Microsoft MVP, Visual C# My Articles

              K Offline
              K Offline
              KingTermite
              wrote on last edited by
              #7

              Sorry...I'm lost. I found the command line version of the tlbimp.exe but didn't have much success. I ran it on the vb COM dll (it was created such that type library is built in I'm told), and it created an "imported" version of the dll in the program files\common files\....1033\nt directory. When I tried viewing that type library it couldn't load it. I don't see the option to do what you are saying VS.Net. If you (or anybody) and just mention that a bit more, I'd appreciate it. I have to run now, but I'll check again 1st thing in am. Thanks for all your help so far. :)


              There are only 10 types of people in this world....those that understand binary, and those that do not.

              H 1 Reply Last reply
              0
              • K KingTermite

                Sorry...I'm lost. I found the command line version of the tlbimp.exe but didn't have much success. I ran it on the vb COM dll (it was created such that type library is built in I'm told), and it created an "imported" version of the dll in the program files\common files\....1033\nt directory. When I tried viewing that type library it couldn't load it. I don't see the option to do what you are saying VS.Net. If you (or anybody) and just mention that a bit more, I'd appreciate it. I have to run now, but I'll check again 1st thing in am. Thanks for all your help so far. :)


                There are only 10 types of people in this world....those that understand binary, and those that do not.

                H Offline
                H Offline
                Heath Stewart
                wrote on last edited by
                #8

                You can't just use a COM control from .NET - a wrapper, or Runtime Callable Wrapper (RCW), has to be created first. This wrapper is in an COM interop assembly. You use tlbimp.exe to create a COM interop assembly and reference that assembly in your project. If you don't, you have to resort to many excrutiatingly painful methods of redefining interfaces and creating instances of COM objects at runtime and you don't get any marshaling or Type safety for free. You definitley DO NOT want to do it this way, and it's recommended that you don't. For more information on creating interop assemblies, please read Exposing COM Components to the .NET Framework[^].

                Microsoft MVP, Visual C# My Articles

                K 1 Reply Last reply
                0
                • H Heath Stewart

                  You can't just use a COM control from .NET - a wrapper, or Runtime Callable Wrapper (RCW), has to be created first. This wrapper is in an COM interop assembly. You use tlbimp.exe to create a COM interop assembly and reference that assembly in your project. If you don't, you have to resort to many excrutiatingly painful methods of redefining interfaces and creating instances of COM objects at runtime and you don't get any marshaling or Type safety for free. You definitley DO NOT want to do it this way, and it's recommended that you don't. For more information on creating interop assemblies, please read Exposing COM Components to the .NET Framework[^].

                  Microsoft MVP, Visual C# My Articles

                  K Offline
                  K Offline
                  KingTermite
                  wrote on last edited by
                  #9

                  According to that link (and another article I've found), when you add the COM reference to the project in VS.Net, it automatically converts it for you so that you are "on the same page". Anyway....I found the assembly info you were talking about....I had to use a VS.Net command line tool called ildasm (which I didn't know about before). But anyway...here it the info it generates: .method public hidebysig newslot virtual instance string[] marshal( safearray bstr) MyFunction([in][out] string[]& marshal( safearray bstr) varNames) runtime managed internalcall { .custom instance void [mscorlib]System.Runtime.InteropServices.DispIdAttribute::.ctor(int32) = ( 01 00 15 00 03 60 00 00 ) // .....`.. .override COMInterface._COMClass::MyFunction } // end of method COMClass::MyFunction I'm still trying to match the C# datatype for the argument for that VB6 COM function.


                  There are only 10 types of people in this world....those that understand binary, and those that do not.

                  H 1 Reply Last reply
                  0
                  • K KingTermite

                    According to that link (and another article I've found), when you add the COM reference to the project in VS.Net, it automatically converts it for you so that you are "on the same page". Anyway....I found the assembly info you were talking about....I had to use a VS.Net command line tool called ildasm (which I didn't know about before). But anyway...here it the info it generates: .method public hidebysig newslot virtual instance string[] marshal( safearray bstr) MyFunction([in][out] string[]& marshal( safearray bstr) varNames) runtime managed internalcall { .custom instance void [mscorlib]System.Runtime.InteropServices.DispIdAttribute::.ctor(int32) = ( 01 00 15 00 03 60 00 00 ) // .....`.. .override COMInterface._COMClass::MyFunction } // end of method COMClass::MyFunction I'm still trying to match the C# datatype for the argument for that VB6 COM function.


                    There are only 10 types of people in this world....those that understand binary, and those that do not.

                    H Offline
                    H Offline
                    Heath Stewart
                    wrote on last edited by
                    #10

                    Yes, VS.NET does create the interop assembly but you never said you added such a COM reference and I've learned to assume nothing in this forum. After all, you did give the VB6 method signature and said you were trying to call it. The data type (not C#, but .NET) is a String[] array, as well as is the return value, just as I mentioned previously. The param indeed takes a ref as designated by the address operator, &. More easily, however, would've been to look at the signature that IntelliSense returned, which would've shows the method signature as it is declared. It should look something like this:

                    string[] MyFunction(ref string[] varNames);

                    When you call it, you must pass an initialized array:

                    string[] varNames = new string[] {"One", "Two" };
                    string[] retNames = obj.MyFunction(ref varNames);

                    Microsoft MVP, Visual C# My Articles

                    K 1 Reply Last reply
                    0
                    • H Heath Stewart

                      Yes, VS.NET does create the interop assembly but you never said you added such a COM reference and I've learned to assume nothing in this forum. After all, you did give the VB6 method signature and said you were trying to call it. The data type (not C#, but .NET) is a String[] array, as well as is the return value, just as I mentioned previously. The param indeed takes a ref as designated by the address operator, &. More easily, however, would've been to look at the signature that IntelliSense returned, which would've shows the method signature as it is declared. It should look something like this:

                      string[] MyFunction(ref string[] varNames);

                      When you call it, you must pass an initialized array:

                      string[] varNames = new string[] {"One", "Two" };
                      string[] retNames = obj.MyFunction(ref varNames);

                      Microsoft MVP, Visual C# My Articles

                      K Offline
                      K Offline
                      KingTermite
                      wrote on last edited by
                      #11

                      Heath Stewart wrote: Yes, VS.NET does create the interop assembly but you never said you added such a COM reference and I've learned to assume nothing in this forum. After all, you did give the VB6 method signature and said you were trying to call it. The data type (not C#, but .NET) is a String[] array, as well as is the return value, just as I mentioned previously. The param indeed takes a ref as designated by the address operator, &. More easily, however, would've been to look at the signature that IntelliSense returned, which would've shows the method signature as it is declared. It should look something like this: Yes...you are right...sorry ".Net", not C#. ;) Sorry I didn't mention the reference...this is my 1st time playing with COM and that is the only way I knew how to do it. So I just assumed that was assumed. If that makes sense. Thanks for your answer, but if you go back to my original post, you'll see from my code examples that was exactly where I started. So...full circle?


                      There are only 10 types of people in this world....those that understand binary, and those that do not.

                      H 1 Reply Last reply
                      0
                      • K KingTermite

                        Heath Stewart wrote: Yes, VS.NET does create the interop assembly but you never said you added such a COM reference and I've learned to assume nothing in this forum. After all, you did give the VB6 method signature and said you were trying to call it. The data type (not C#, but .NET) is a String[] array, as well as is the return value, just as I mentioned previously. The param indeed takes a ref as designated by the address operator, &. More easily, however, would've been to look at the signature that IntelliSense returned, which would've shows the method signature as it is declared. It should look something like this: Yes...you are right...sorry ".Net", not C#. ;) Sorry I didn't mention the reference...this is my 1st time playing with COM and that is the only way I knew how to do it. So I just assumed that was assumed. If that makes sense. Thanks for your answer, but if you go back to my original post, you'll see from my code examples that was exactly where I started. So...full circle?


                        There are only 10 types of people in this world....those that understand binary, and those that do not.

                        H Offline
                        H Offline
                        Heath Stewart
                        wrote on last edited by
                        #12

                        I suppose we have. Is there any possibility you can send me the VB COM library? I don't need the source. If you have configured CodeProject to send email when someone replies to you, my email address will be above.

                        Microsoft MVP, Visual C# My Articles

                        K 1 Reply Last reply
                        0
                        • H Heath Stewart

                          I suppose we have. Is there any possibility you can send me the VB COM library? I don't need the source. If you have configured CodeProject to send email when someone replies to you, my email address will be above.

                          Microsoft MVP, Visual C# My Articles

                          K Offline
                          K Offline
                          KingTermite
                          wrote on last edited by
                          #13

                          Thanks for the offer. It is sent.


                          There are only 10 types of people in this world....those that understand binary, and those that do not.

                          1 Reply Last reply
                          0
                          • K KingTermite

                            I have a C# com object that I'm creating which I'm testing in a VB environment. This COM object is also calling other COM objects which were written in VB. I have a VB COM object with a method who's signature looks like this: Public Function MyFunction(varNames() As String) As String() I'm trying to send in a string array when calling this guy in my C# code like this: string[] sNames = { "ProjectName" }; // 1 element array COMInt.ComClass oCDS = new COMInt.ComClass(); sValues = oCDS.MyFunction(ref sNames); I get type mismatch on the "ref sNames". This is just one of many combinations I've tried, but have not quite figured out the correct type match. Here is the error I receive in VS.Net: D:\CSS\Dev\ProjName\ProjClass.cs(255): The best overloaded method match for 'COMInt.ComClass.MyFunction(ref System.Array)' has some invalid arguments Can anybody help me out and explain this? P.S. Sorry for all the "MyFunction" and "ProjClass", etc.... but this is at work and I could get in trouble just for posting the names of things (they are VERY picky).


                            There are only 10 types of people in this world....those that understand binary, and those that do not.

                            K Offline
                            K Offline
                            KingTermite
                            wrote on last edited by
                            #14

                            Ok...I got it (what a pain)! I want to post the answer here for posterity in case somebody else has a similar problem in the future. For the record, I found the answer in a book a co-worker lent me (COM and .NET Interoperability by Andrew Troelsen). The VB function signature:

                            Public Function MyFunction(varNames() As String) As String()
                            

                            showed up as this in the assembly like this:

                            .method public hidebysig newslot virtual 
                            instance string[] 
                            marshal( safearray bstr) 
                            MyFunction([in][out] string[]& marshal( safearray bstr) varNames) runtime managed internalcall
                            {
                            .custom instance void [mscorlib]System.Runtime.InteropServices.DispIdAttribute::.ctor(int32) = ( 01 00 15 00 03 60 00 00 ) // .....`..
                            .override COMInterface._COMClass::MyFunction 
                            } // end of method COMClass::MyFunction
                            

                            The problem was this assembly (and intellisense) was telling it it had to be a safearray and apparently it just wouldn't take a string[]! Not even if it was instantiated on initializaation like:

                            string[] varNames = new string[] {"One", "Two" };
                            

                            The intellisense was telling me it had to be a "System.Array", not a string[]! What needs to be done is not a "cast", but intantiating a System.Array and set it equal to the string array that was initialized and then pass in the ref to that array. This was the way to get it working was:

                            COMInterface.COMObj oCOMObject = new COMInterface.COMObj();
                            			
                            string[] sNames = new string[] { "ProjectName" }; // 1 element array
                            System.Array oTemp = sNames;
                            string[] sValues = new string[1];
                            System.Array oTempVals = sValues;
                            oTempVals = oCOMObject.TheCOMFunction( ref oTemp );
                            

                            It wasn't intuitive....but now, in retrospect, it makes sense. Apparently you have to use the "System.Array" type for the "safearray" that it expects in the assembly, and since it doens't like you to cast it from string[] to System.Array, you have to just create an instance and set it equal.


                            There are only 10 types of people in this world....those that understand binary, and those that do not.

                            1 Reply Last reply
                            0
                            Reply
                            • Reply as topic
                            Log in to reply
                            • Oldest to Newest
                            • Newest to Oldest
                            • Most Votes


                            • Login

                            • Don't have an account? Register

                            • Login or register to search.
                            • First post
                              Last post
                            0
                            • Categories
                            • Recent
                            • Tags
                            • Popular
                            • World
                            • Users
                            • Groups