Cyberherbalist
Cyberherbalist

Reputation: 12329

Trying to build a COM Component in C# that can be referenced and used from VB5/6

I am trying to see if I can build a COM component in C# (.NET 4) which I can use from a VB5 program (cue derisive remarks) to access a web service. Following all the instructions I have been able to find on MSDN and CodeProject as follows:

I have written the following:

[Guid("7A715F02-D349-45DC-B0AE-9925FD3B943C")]
public interface ARCOM_Interface
{
    [DispId(1)]
    string GetServiceResponse();
}

[Guid("5130F041-619E-41F9-84B6-8332642228F6")
    , InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface ARCOM_Events
{
}

[Guid("0A77754F-34CF-4E0E-AAC2-85FD686758E0")
    , ClassInterface(ClassInterfaceType.None)
    , ComSourceInterfaces(typeof(ARCOM_Events))]
[ComVisible(true)]
public class ARCOM_Class : ARCOM_Interface
{
    public string GetServiceResponse()
    {
        string response = string.Empty;

        ARWebService.ARWebService svc = new ARWebService.ARWebService();

        response = svc.PingMeBack();

        return response;
    }
}

The Assembly in question is signed with a strong name and the output is registered for COM Interop. After building, I have applied RegAsm to it and generated a type library with tlbexp.exe.

In VB6, when I open the list of references from the Project properties, I can find the assembly in the list, and I can check it. I can even do the following in the VB6 code:

Private Sub HitWebService()

    Dim arcom As ARCOMObject.ARCOM_Class

    arcom. <== Intellisense doesn't sense anything!

End Sub

The Intellisense sees the ARCOMObject and the class, but nothing that is within the ARCOM_Class itself (except for the usual "GetType", "Equals" and other generic Object methods/properties). Most specifically, it does not seem to see the GetServiceResponse() method, so I can't call it.

What am I leaving out?

Upvotes: 3

Views: 2080

Answers (2)

Cyberherbalist
Cyberherbalist

Reputation: 12329

OK, I found something that unexpectedly made a difference.

Notice that the code above contains the decoration [ComVisible(true)]. Making the assembly visible to COM is of course essential. I thought that this covered it, but upon further searching I found that there is another place to mark it. If you look in the project properties, in the Application tab you will find the Assembly Information... button. Click on it and at the bottom of the dialog box you'll see a checkbox "Make assembly COM-visible". I checked it, recompiled (and re-ran tlbexp and regasm), and then found that the method GetServiceResponse() was visible.

I don't know why the make ComVisible checkbox works when setting the attribute doesn't.

Edited to add: I think I see what is up with that. The ComVisible(true) makes the class visible to COM, but not the assembly; this is why "Make assembly COM-visible" needs to be checked, because the GetServiceResponse method seems to get its COM-visibility through the ARCOM_Interface, which is not marked as ComVisible unless the assembly is as well.

Upvotes: 2

Ciaran Keating
Ciaran Keating

Reputation: 2783

I see you've worked out a way to get what you want while I was typing up this reply, but I'll continue anyway because it might tell you some stuff you don't know...

You've applied the ClassInterface(ClassInterfaceType.None) attribute to the class. This tells COM interop not to define an explicit interface for the class, and so your client must use IDispatch (late binding). This means that your client must have a-priori knowledge of the interfaces that the class implements. That is, you (the programmer) know what methods are available but tools like IntelliSense have no way of finding that information.

Just go ahead and call the method:

Dim response As String
response = arcom.GetServiceResponse

Upvotes: 2

Related Questions