Tech Quest

Hi,

I have a C# Class Libarary which is exposed to COM. The issue is base class members are not exposed to COM.As per msdn
http://msdn2.microsoft.com/en-us/library/8877bdk6(VS.80).aspx Managed Clas hierarchies flatten out when exposed as COM objects.
Please let me know how i can resove this issue. Thanks a lot in advance

Here is the sample Application Code:
The issue is base class member properties VehicleName ,Vehicle Type are not exposed to COM

Base Class:
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Runtime.InteropServices;
  5. namespace ClassLibrary5
  6. {
  7. [Guid("99999999999A-CCCCc-ADDD-73444444E530")]
  8. public interface IVehicle
  9. {
  10. bool Start();
  11. bool Stop();
  12. string VehicleName { get; set; }
  13. string VehicleType { get; set; }
  14. }
  15. [Guid("4444444444444-1111-5555-44464445FF9")]
  16. [ClassInterface(ClassInterfaceType.None)]
  17. public abstract class Vehicle : ClassLibrary5.IVehicle
  18. {
  19. private string _VehicleName;
  20. private string _VehicleType;
  21. public string VehicleName
  22. {
  23. get
  24. {
  25. return _VehicleName;
  26. }
  27. set
  28. {
  29. _VehicleName = value;
  30. }
  31. }
  32. public string VehicleType
  33. {
  34. get
  35. {
  36. return _VehicleType;
  37. }
  38. set
  39. {
  40. _VehicleType = value;
  41. }
  42. }
  43. public abstract bool Start();
  44. public abstract bool Stop();
  45. }
  46. }

Derived class:

Code: ( text )
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Runtime.InteropServices;
  5. namespace ClassLibrary5
  6. {
  7. [Guid("00000000000-7771-8888-F8487777988")]
  8. public interface ICar : IVehicle
  9. {
  10. string CarType { get; set; }
  11. int ModelNumber { get; set; }
  12. bool Start();
  13. bool Stop();
  14. }
  15. [Guid("111111111-1234-1234-4567-C5077F131")]
  16. [ClassInterface(ClassInterfaceType.None)]
  17. public class Car : Vehicle, IVehicle, ICar
  18. {
  19. private int _ModelNumber;
  20. private string _CarType;
  21. public int ModelNumber
  22. {
  23. get
  24. {
  25. return _ModelNumber;
  26. }
  27. set
  28. {
  29. _ModelNumber = value;
  30. }
  31. }
  32. public string CarType
  33. {
  34. get
  35. {
  36. return _CarType;
  37. }
  38. set
  39. {
  40. _CarType = value;
  41. }
  42. }
  43. public override bool Start()
  44. {
  45. //Start code goes here
  46. return true;
  47. }
  48. public override bool Stop()
  49. {
  50. //stop code goes here
  51. return true;
  52. }
  53. }
  54. }
Thanks,


Re: Visual C# General COM Interop: Base class properties not exposed to COM

TaylorMichaelL

You are being misled by the documentation. If you allow the compiler to auto-generate the COM visible interface for you then it will flatten out the members when it builds the COM interface. COM only works through interfaces so the interface determines what COM sees. In your case you defined the COM visible interface. Therefore COM clients can only see the members that your COM visible interface defined. This applies to any member of your class whether it is defined within the class or inherited. For example:

[ComVisible(true)]

[Guid(...)]
public interface IFoo

{

public void Bar ( );
}

[ClassInterface(ClassInterfaceType.None)]

[ComVisible(true)]

[Guid(...)]

public class MyFoo : IFoo

{

public void Bar ( ) { } //Visible to COM

public void Bar2 ( ) { } //Not visible to COM
}

By using ClassInterface you are telling COM that you are going to determine what is (and is not) exposed to COM. This is the proper way (IMO) to do COM interop as it avoid exposing unneeded members. You can, of course, add the inherited members to your COM interface and they will get exposed to COM clients and your base class will continue to implement them.

[ComVisible(true)]

[Guid(...)]
public interface IFoo

{

public void Bar ( );

public void Bar2 ( );
}

public abstract class MyFoo : IFoo

{

public void Bar ( ) { } //Visible to COM

}

[ClassInterface(ClassInterfaceType.None)]

[ComVisible(true)]

[Guid(...)]

public class MyFoo2 : MyFoo
{

public void Bar2 () { } //Visible to COM
}

Michael Taylor - 10/4/07

http://p3net.mvps.org





Re: Visual C# General COM Interop: Base class properties not exposed to COM

Tech Quest

Hi Michael,

Thanks a lot for your quick response and explanation of what needs to be done.

As per your clarifications, i understand that we need to add the base class properties to the derived class interface to make it exposed to com.

Please consider the following points/questions:
1) In the below example eventhough the ICar interface inherits from IVechicle interface why do we need to add the base class properties to ICar interface
2) I have some 10 derived classe which is inherited from the the same base class, do i need to add the all the base class properties to all
the 10 derived class interfaces to make the properties visible

//Base class Vehicle has two properties vehicleName and vehicleType
public class Vehicle//Base class
{
int vehicleName;
int vehicleType;
public VehcileName //Not exposed to COM
{
get{}
set{}
}
public VehcileType //Not exposed to COM
{
get{}
set{}
}
public int start()
public int stop()
}

//Derived class inherits Vehicle
public class Car:Vehicle,ICar //inherits vehicle class
{
public int carType
public int CarNumber
public int start()
public int stop()
}

//Derived class inherits Vehicle
public class Bus : Vehicle,IBus //inherits vehicle class
{
int busType
int NumberofSeats
int start()
int stop()
}

//Base class interface
public interface IVehicle
{
public VehcileName{get;set;}
public VehcileType{get;set;}
}
public int start()
public int stop()
}

//Car Interface which inherits from IVehicle
public interface ICar:IVehicle //inherits IVehicle
{
int carType
int carNumber
int vehcileType//base class properties added to derived class as this is not exposed
int VehcileName//base class properties added to derived class as this is not exposed
}


Thanks a lot in advance for you kind help.





Re: Visual C# General COM Interop: Base class properties not exposed to COM

TaylorMichaelL

Just so we're clear on everything to this point let me lay out a few "rules" that are followed for COM.

  1. COM only deals with interfaces. Base/derived classes have no meaning or functionality in COM. Inheritance is not applicable either.
  2. In COM interfaces can inherit from one another. However the .NET implementation that exposes the .NET interface to COM does not support inheritance. Therefore you must replicate any interface members in a base interface to the derived interface.
  3. Moving members between a base and derived class will have no impact on what is visible to COM.
  4. When you explicitly define a COM interface to be exposed (like I recommend and how you've done) then you are completely responsible for determing what does and does not get exposed to COM. The compiler will not use reflection or anything else to determine what should be exposed.
  5. All COM classes have a single, default interface. This is the interface that is normally used for an object. A COM class can expose other interfaces but the COM client must then query for the interface. In .NET the first COM-visible interface is used as the default interface for a COM class. The ordering changed between v1.x and v2.

For the following discussions I'm going to leave off the various attributes that are normally applied. To clarify point 2 imagine the following:

Code Block

public interface IFoo

{

public void FooMethod();
}

public interface IFoo2 : IFoo

{

public void FooMethodEx();
}

public class FooClass : IFoo2

{

public void FooMethod ( ) { }

public void FooMethodEx ( ) { }
}

Because of how the .NET interop works only the IFoo2 explicit members are visible in COM. The interop code does not look at base interface types when building the exposed COM interface. Therefore IFoo2 must also include all members of IFoo when defining the interface. This is one of the big reasons why you should isolate your COM-visible types from .NET types. If you try to do this:

Code Block

public interface IFoo2 : IFoo
{

public void FooMethodEx ( );

//IFoo members

public void FooMethod ( );
}

Then now COM will see the IFoo and IFoo2 members but .NET will get ambiguity errors because FooMethod is defined in two different interfaces. The additional problem though is that if the COM client queries for IFoo then it'll fail because FooClass only implements IFoo2 as far as COM is concerned. The most practical approach is to define each COM interface separately (without inheritance) and then have the COM class implement each of the interfaces explicitly.

Note that the above only applies to COM interfaces that you define within .NET and expose to the outside world. If you are implementing a COM interface in .NET that was defined in unmanaged code (say IShellView2) then you won't be reregistering the COM interface so the unmanaged inheritance will work for it. You still have to break up the interface in the .NET code but the COM client will work correctly (at least I believe so, you'd have to try it to verify).

On point 5, in v2 the basic rule is that the first COM-visible interface found in a class'es inheritance list is used as the default interface. If you derive from a base class that also has a COM visible interface then the rules get messier. I think it still defaults to the derived-class'es first visible interface but I'm not 100% sure. There is a new attribute that you can apply to a COM class to explicitly identify the default interface. If you have a base class and COM visible interface on the same type then consider using the attribute to avoid confusion.

Now on to your question. Remember that COM is interface based. Whether you implement the interface member in a base or derived class is irrelevant so we'll move away from the entire base/derived class discussion. Instead focus on how the interfaces are defined.

Assuming that IVehicle and ICar are COM visible then you must replicate the members of IVehicle in ICar in order for COM to see the vehicle members in ICar (as you have done). The .NET interop does not support interface inheritance of COM interfaces.

As for the base/derived classes it doesn't matter where you implement the interface members. You can implement some in a base class and some in derived if you want. Here is an example:

Code Block

public interface IVehicle //COM visible
{
public int VehicleType { get; }

public string VehicleName { get; set; }
}

public interface ICar //: IVehicle - COM visible
{
public int CarType { get; set; }

//IVehicle

public int VehicleType { get; }

public string VehicleName { get; set; }
}

public abstract class VehicleBase : IVehicle //Not COM visible since it can't be created
{

public virtual int VehicleType { get ; set; }

public virtual string VehicleName { get; set; }
}

public class Car : VehicleBase, ICar, IVehicle //COM Visible

{

//ICar members

//IVehicle members
}


A few notes. Since I believe in segregating COM visible stuff from .NET stuff (so you can remove it later) I would not be using any of COM visible interfaces in .NET code. As a result I throw out most .NET guidelines as far as design goes. In the above code I could have used inheritance but, since COM won't see it, there is no benefit.

Next note. Car derives from VehicleBase so I get the default impl of IVehicle. However so that COM clients can query for either ICar or IVehicle I have to include these interfaces in my inheritance list. COM clients will see the Car class as implementing both interfaces even though, internally, I had to replicate the members. Some of the interface members are implemented in the derived class while others are implemented in the base class.

Final note. Explicit interface implementations, rather than public, are a good choice here to keep the .NET member list clean. .NET clients don't care about the ICar, IVehicle stuff so don't bother showing it to them.

Michael Taylor - 10/4/07

http://p3net.mvps.org





Re: Visual C# General COM Interop: Base class properties not exposed to COM

Tech Quest

Hi Michael,

Thanks a lot for your valuable time and detailed explanation of COM Interfaces.

I will try to implement the stuff you have mentioned. Also let me know what other steps do you follow for segregating COM visible stuff from .NET stuff.

Please let me know the links where i can find more documention on these topics.

Thanks,





Re: Visual C# General COM Interop: Base class properties not exposed to COM

TaylorMichaelL

The best place to learn about COM interop is at MSDN: http://msdn2.microsoft.com/en-us/library/zsfww439(vs.80).aspx It covers most of the information you'll need.

Michael Taylor - 10/4/07

http://p3net.mvps.org





Re: Visual C# General COM Interop: Base class properties not exposed to COM

Tech Quest

Hi Michael,

I have futher questions regarding ComInterop

1) Exposing enumerations to COM
Following enum is exposed to com

Code Block

Guid(""),ComVisible(true)]
public enum Colors{ RED= 0, BLUE= 1, TWO = 2, THREE = 3, FOUR = 4 }


  1. The issue is when i use the enum colors in the Com the enum members are prefixed with enum name as Colors_RED, Colors_BLUE any idea on why enum name is prefixed to its members
  2. To make the enum comvisible adding Guid is just enough or is there any other steps that i need to follow
2)Overloaded function:
If i have an overloaded method Add then it will be exposed to com as Add, Add_1, and Add_2
is there any solution to overcome this (MSDN http://msdn2.microsoft.com/en-us/library/8877bdk6(VS.80).aspx suggests to have different names but in my case i cant have different names)

3) What is the the best design guidline: Setting the ComVisible attribute of entire asembly to true and turnoff the
attribute when it is not required v/s turning of the comvisible atrribute at assembly level and turning it on when ever required.


Thanks a lot in advance,




Re: Visual C# General COM Interop: Base class properties not exposed to COM

TaylorMichaelL

1) The enumeration is correct. Unlike C#, languages that support enumerations often require them to be globally unique (like early versions of C++). Therefore the exporter prefixes each enumeration member with the name of the enumerated type. You can see this same behavior if you browse through the framework enumerations that were exposed to COM.

2) Most languages do not support overloading. COM does not support it at all. Each exposed member of an interface must have a unique name. Therefore the exporter converts the other overloads to unique names. There is no workaround for this as COM doesn't support overloading.

The attribute ComAliasName can be used to rename certain aspects of COM-visible types but I don't know if it will work in this case. You could try applying it to the enumeration members. For the overloads you can try it as well but you can't reuse an existing name so the names still have to be unique.

Michael Taylor - 10/6/07

http://p3net.mvps.org





Re: Visual C# General COM Interop: Base class properties not exposed to COM

Tech Quest

Hi Michael,


Thanks a lot for all help.

Thanks and Regards,