.netcomrcw

Why would this raise an InvalidClassCast exception?


For certain reasons, I must provide manually written runtime callable wrappers for a number of COM components offered by my shop.

This is the interface definition for component A:

[ComImport, Guid("02922621-2EAE-4442-8A0A-C1C3CD886027")]
public interface IProdistLogging
{
  [DispId(1000)]
  IProdistLoggingHierarchy CreateHierarchy ([MarshalAs(UnmanagedType.BStr)] string type, object configuration);
}

This is the interface definition for component B:

[ComImport, Guid("8D841E5C-F25B-4C12-B03A-70A899B3A32E")]
public interface ISts
{
  [DispId(1001)]
  IProdistLoggingHierarchy Logging { get; set; }

  [DispId(1000)]
  IStsSession CreateSession ();
}

This is the interface definition for component C:

[ComImport, Guid("13385FC6-2618-4830-A3A9-703398AA5A0B")]
public interface IStsRsfn
{
  [DispId(1000)]
  ISts Sts { get; set; }

  [DispId(1010)]
  IStsRsfnSession CreateSession();
}

Now, the following test program terminates with an InvalidCastException:

public static void Main (string[] args)
{
  IProdistLogging logging = (IProdistLogging)System.Activator.CreateInstance(Type.GetTypeFromProgID("prodist.logging.Logging.5.4"));
  IProdistLoggingHierarchy loggingHierarchy = logging.CreateHierarchy("log4cxx", null);
  ISts sts = (ISts)System.Activator.CreateInstance(Type.GetTypeFromProgID("prodist.sts.Sts.5.4"));
  sts.Logging = loggingHierarchy;
  IStsRsfn rsfn = (IStsRsfn)System.Activator.CreateInstance(Type.GetTypeFromProgID("prodist.sts.rsfn.StsRsfn.5.4"));

  // The following statement raises an InvalidCastException
  // with message "Specified cast is not valid"
  rsfn.Sts = sts;

  IStsRsfnSession session = rsfn.CreateSession();
  return;
}

Why would this be?

Edit 1: this is the result of toString() on the exception object:

System.InvalidCastException: Specified cast is not valid.
   at prodist.sts.rsfn.IStsRsfn.set_Sts(ISts value)
   at sandbox.Program.Main(String[] args) in (...)

Solution

  • We have since discovered the missing information which explains the above symptoms: the actual IDL definition for the interface.

    The problematic .NET wrapper did not include all methods of the corresponding interface, such that the ordinal index for the Sts put property in IDL and .NET was not the same -- even though the DispId value is correct.

    After we updated the .NET wrapper to completely reflect all methods from the IDL definition -- such that each method was at the same ordinal index as the other -- everything worked.

    The programmer assumed that methods were "offset" according with the value of the DispId attribute, but it seems they are "offset" by their actual position in the list of methods from first to last. This implies it is not lawful to provider partial wrappers for interfaces -- wrappers which omit certain methods.