views:

26

answers:

3

I'm trying to expose a C# class library via COM so that I can use it in a classic asp web site.

I've used sn - k, regasm and gacutil. About all I can do now though is echo back strings.

Methods which take Class variables as input are not working for me. ie my test method EchoPerson(Person p) which returns a string of the first and last name doesn't work. I get a runtime error 5 - Invalid procedure call or argument.

Please let me know what I am missing. Also I have no intellisence in VB. What do I need to do to get the intellisence working.

Below is my C# test code

namespace MrdcToFastCom
{

    public class Person : MrdcToFastCom.IPerson
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }


    public class ComTester : MrdcToFastCom.IComTester
    {
        public string EchoString(string s)
        {
            return ("Echo: " + s);
        }

        public string Hello()
        {
            return "Hello";
        }


        public string EchoPerson(ref Person p)
        {
            return string.Format("{0} {1}", p.FirstName, p.LastName);
        }

    }

}

and VB6 call

Private Sub btnClickMe_Click() 

    Dim ct
    Set ct = New MrdcToFastCom.ComTester

    Dim p
    Set p = New MrdcToFastCom.Person
    p.FirstName = "Joe"
    p.LastName = "Test"

    Dim s
    s = ct.EchoPerson(p) ''#Error on this line
    tbx1.Text = s


End Sub
+1  A: 

When you are using complex types in COM interfaces, you need to use structs that are attributed with [StructLayout(LayoutKind.Sequential)]. You can find more information here on MSDN: Exported Type Conversion. Since COM has to marshal the types across the boundary, you have to make sure all your types can be copied across into unmanaged land successfully. Reference types won't make it.

Garo Yeriazarian
+1  A: 
 public string EchoPerson(ref Person p)

You are getting an error because you declared the argument with the ref keyword. That's not correct, Person is already a reference type and the object that VB6 is using is a variant, not a Person. Just omit "ref". Using Option Explicit On is a good practice in VB6 btw.

You are not getting IntelliSense because you probably didn't declare the interfaces with the [InterfaceType(ComInterfaceType.InerfaceIsDual)]. Microsoft recommends against this because of the DLL Hell problems with dual interfaces. Required though to get a type library to help VB6 display the IS you want.

Hans Passant
"Option Strict On" in VB6? In VB.NET yes but not VB6 just Option Explicit
AnthonyWJones
Right, thanks for the memory jiggle.
Hans Passant
A: 

Here is the pattern you should consider using:-

[InterfaceType(ComInterfaceType.InterfaceIsDual)]
[Guid("B4CAC74B-ADE0-4ac7-AD0E-26E6439F9CF7")]
public interface _IPerson
{
    string FirstName { get; set; }     
    string LastName { get; set; }     
}

[ClassInterface(ClassInterfaceType.None)]
[Guid("A3C553DC-A348-43e4-957A-F94D23E3300E")]
public class Person :  _IPerson      
{      
    public string FirstName { get; set; }      
    public string LastName { get; set; }      
}

[InterfaceType(ComInterfaceType.InterfaceIsDual)]
[Guid("4B527235-6738-4853-BEA0-FB3087C89291")]
public interface _ComTester
{
     string EchoPerson(Person person);
}

[ClassInterface(ClassInterfaceType.None)]
[Guid("C753D72B-C802-44ae-946A-E3F6D7C5D14B")]
public class ComTester : _ComTester
{
    public string EchoPerson(Person person)
    {
        return person.FirstName + " " + person.LastName;
    }
}

This approach gives you much more control over the COM Interface exposed by the .NET components. Only the members defined by interface are exposed for consumption by COM clients.

AnthonyWJones