为什么会引发InvalidClassCast异常?

时间:2015-02-04 18:08:42

标签: .net com rcw

出于某些原因,我必须为我店提供的许多COM组件提供手动编写的运行时可调用包装器。

这是组件A的接口定义:

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

这是组件B的接口定义:

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

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

这是组件C的接口定义:

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

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

现在,以下测试程序以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;
}

为什么会这样?

编辑1:这是异常对象上的toString()的结果:

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

1 个答案:

答案 0 :(得分:0)

我们之后发现了缺少的信息,它解释了上述症状:接口的实际IDL定义。

有问题的.NET包装器不包含相应接口的所有方法,因此IDL和.NET中Sts put属性的序数索引不一样 - 即使DispId值是正确的。

我们更新了.NET包装器以完全反映IDL定义中的所有方法 - 这样每个方法与其他方法处于相同的序号索引 - 一切正常。

程序员假设方法是"偏移"根据DispId属性的值,但似乎它们是" offset"从他们在方法列表中的实际位置从头到尾。这意味着为接口提供部分包装器是不合法的 - 包装器省略了某些方法。