[OverDuePost]

While working with COM interop (VB6 client / .NET Server), our architecture team ran into some problems with returning typed arrays back to the client.  I had spent over two hours trying to get things working with the correct set of attributes, but I kept on getting “Type Mismatch” errors in VB6.  I had to leave early to meet up with my wife and Fred and Nick stayed after to help with more research.  This is our brain child:

Domain object (and interface) that is used by VB6 to populate its UI

namespace InteropLibrary
{
    
using System;
    using 
System.Runtime.InteropServices;

    
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
    [Guid(
"905816E8-9C73-42f0-A776-7117ACF633BD")]
    
public interface IPerson
    {
        [DispId(
1)]
        
string FirstName
        {
            
get;
            set;
        
}

        [DispId(
2)]
        
string LastName
        {
            
get;
            set;
        
}

        [DispId(
3)]
        
string ID
        {
            
get;
            set;
        
}
    }
}
namespace InteropLibrary
{
    
using System;
    using 
System.Runtime.InteropServices;

    
[ClassInterface(ClassInterfaceType.None),
        ComDefaultInterface(
typeof(IPerson)),
        ProgId(
"Interop.Person"),
        Guid(
"135983AB-8242-41fb-8ED8-FDE3383A2FDD"),
        Serializable]
    
public class Person : IPerson
    {
        
string firstName;
        string 
lastName;
        string 
id;

        public 
Person ()
        {
            ID 
Guid.NewGuid().ToString();
        
}

        
public string FirstName
        {
            
get return firstName}
            
set { firstName = value; }
        }

        
public string LastName
        {
            
get return lastName}
            
set { lastName = value; }
        }

        
public string ID
        {
            
get return id}
            
set { id = value; }
        }
    }
}

Server object (and interface) used by VB6 to return either a single object or an array of objects.

namespace InteropLibrary
{
    
using System;
    using 
System.Runtime.InteropServices;

    
[Guid("4E116FAC-4FBE-4952-8E08-718C38BE3F65")]
    [InterfaceType(ComInterfaceType.InterfaceIsDual)]
    
public interface IPersonService
    {
        [DispId(
1)]
        Person CreatePerson (
string firstName, string lastName);

        
[DispId(2)]
        [
return:MarshalAs(UnmanagedType.SafeArray, 
            SafeArraySubType
=VarEnum.VT_DISPATCH
            SafeArrayUserDefinedSubType
=typeof(Person))]
        Person[] CreatePeople (
int count);
    
}
}
namespace InteropLibrary
{
    
using System;
    using 
System.Runtime.InteropServices;
    
    
[Guid("BA837513-4AE9-4647-B952-CF0848BE3A9C"),
        ClassInterfaceAttribute(ClassInterfaceType.None),
        ComDefaultInterfaceAttribute(
typeof(IPersonService)),
        ProgIdAttribute(
"Interop.PersonService")]
    
public class PersonService : IPersonService
    {

        
public Person CreatePerson (string firstName, string lastName)
        {
            Person p 
= new Person();
            
p.FirstName firstName;
            
p.LastName lastName;

            return 
p;
        
}

        
public Person[] CreatePeople (int count)
        {
            Person[] p 
= new Person[count];

            for 
(int 0i < counti++)
            {
                p[i] 
= new Person();
                
p[i].FirstName i.ToString();
                
p[i].LastName i.ToString();
            
}

            
return p;
        
}
    }
}

The COM black magic that makes everything possible is in bold at the top.  Since it’s VB6, we need to make the subtype of the array to be IDispatch.  Hope this helps anyone dealing with this issue. 

This code can be found here.