在C#.Net 4.0应用程序中托管的C ++ ActiveX控件中的Xml.Serializer非法转换异常

时间:2013-08-11 13:42:24

标签: c# c++ activex interopservices

我有一个C#.Net 4.0应用程序,它使用启用了CLR的C ++ DLL来托管C ++ ActiveX控件。 DLL具有加载OCX参数的主要功能,并使用XML.Serializer实现此目的。

当所有组件都在MS Visual Studio .Net 2003和.Net 1.1中运行的C#应用​​程序中构建时,此堆栈工作正常。

但是,当整个模块迁移到VS2010并将应用程序迁移到.Net 4.0时,由于上下文不匹配,我得到了可怕的Xml.Serializer非法转换异常。

例外情况发生在第4行:

FileStream* fs = __gcnew FileStream( filename, FileMode::Open );
XmlReader* reader = __gcnew XmlTextReader( fs );
XmlSerializer* serializer = __gcnew XmlSerializer( __typeof(MyClass) );
MyClass* obj = __try_cast<MyClass*>(serializer->Deserialize(reader)); 

这是异常声明:

[A]MyClass cannot be cast to [B]MyClass.
Type A originates from 'ParameterModule, Version=0.0.0.0, Culture=neutral,      PublicKeyToken=null' in the context 'Default'
at location 'C:\path\to\module\ParameterModule.dll'.
Type B originates from 'ParameterModule, Version=0.0.0.0, Culture=neutral,  PublicKeyToken=null' in the context 'LoadNeither'
at location 'C:\path\to\modu~\ParameterModule.dll'. 

在ParameterModule.ParaClass.execute_DeSerialize() 抛出异常。

请注意,'LoadNeither'上下文的位置路径包含代字号(〜)字符。 “默认”上下文具有完整路径。

ActiveX控件的互操作DLL由VS2010自动生成。

我想知道导致异常的原因。 这是路径中的不匹配吗?我不确定,但我认为DLL只加载了一次。

或者是背景中的不匹配? 如果是由于上下文不匹配,我们如何确保Interop模块的加载上下文,如C ++ ActiveX控件? 或者,我们可以指定Xml.Serializer来加载包含Default上下文中的序列化类的DLL吗?

我到处寻找,我找不到解决方案。我梳理互联网的次数越多,这对我来说就越神秘。提前谢谢。

2 个答案:

答案 0 :(得分:1)

  

但我认为DLL只加载了一次

不,它装了两次。这就是问题,.NET类型的标识不仅仅是命名空间+类型名称,它还包括从中加载的程序集。它是一个DLL Hell对策,它确保您不能从具有冲突定义的不同DLL中多次加载相同的类型。

“LoadNeither”上下文是您问题的提示。你以某种方式加载这个组件。这样做的常用方法是使用Assembly.LoadFile(),这是一种非常危险的方法,只应在故意不希望类型匹配的特殊情况下使用。你应该总是使用LoadFrom(),但是如果可以的话,真的很喜欢Load()。通常可以将DLL放在正确的目录中,或者使用app.exe.config文件中的<probing>元素。

获得版本0.0.0.0不是很健康btw,[AssemblyVersion]在.NET中是一个非常大的问题。

答案 1 :(得分:0)

这很奇怪,但是当我们使用static_cast

时没有发生异常
MyClass* obj = static_cast<MyClass*>(serializer->Deserialize(reader)); 

虽然这个答案并没有真正解决模块被加载两次的问题,但这种解决方法可能会帮助那些人。