2013-08-11 8 views
0

CLR이 활성화 된 C++ DLL을 사용하는 C++ ActiveX 컨트롤을 호스팅하는 C# .Net 4.0 응용 프로그램이 있습니다. DLL은 OCX 용 매개 변수를로드하는 주요 기능을 가지고 있으며이 용도로 XML.Serializer를 사용합니다.Xml.Serializer C# .NET 컨트롤에서 불법 캐스트 예외 C# .Net 4.0 응용 프로그램에서 호스팅되는 ActiveX 컨트롤

이 스택은 모든 구성 요소가 MS Visual Studio .NET 2003 및 .NET 1.1에서 실행되는 C# 응용 프로그램에서 빌드 될 때 잘 작동합니다.

그러나 전체 모듈이 VS2010으로 마이그레이션되고 Application이 .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)); 

다음은 예외 문의 : ParameterModule.ParaClass.execute_DeSerialize에서

[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'. 

은() 예외가 발생했습니다.

는 'LoadNeither'컨텍스트 물결표 (~) 문자로 위치 경로를 가지고 있습니다. '기본'컨텍스트에는 전체 경로가 있습니다.

ActiveX 컨트롤의 interop DLL은 VS2010에 의해 자동 생성됩니다.

예외의 원인이 궁금합니다. 경로에서 불일치가 있습니까? 확실하지 않지만 DLL이 한 번만로드되었다고 생각합니다.

아니면 문맥의 불일치입니까? 컨텍스트가 일치하지 않기 때문에 C++ ActiveX 컨트롤과 같은 Interop 모듈의 로딩 컨텍스트를 어떻게 확인합니까? 또는 Xml.Serializer를 지정하여 기본 컨텍스트에서 직렬화 클래스를 포함하는 DLL을로드 할 수 있습니까?

나는 어디에서나 보았고 해결책을 찾지 못했습니다. 인터넷을 더 많이 빗질할수록 더 많은 일이 내게 미스테리가됩니다. 미리 감사드립니다.

답변

0

그것은 이상한,하지만이 대답은 정말이 해결 방법은 거기에 누군가가 도움이 될 수도, 모듈의 문제가 두 번로드가 해결되지 않지만 우리는 static_cast

MyClass* obj = static_cast<MyClass*>(serializer->Deserialize(reader)); 

사용하는 경우 예외가 발생하지 않았다.

1

하지만 나는 DLL 번만

아니, 두 번로드있어로드 생각합니다. 그게 문제입니다. .NET 형식의 ID는 네임 스페이스 + 형식 이름뿐 아니라로드 된 어셈블리도 포함됩니다. 이것은 DLL Hell 대응책이며 충돌하는 정의가있는 여러 DLL에서 동일한 유형을 두 번 이상로드 할 수 없도록합니다.

"LoadNeither"컨텍스트는 문제의 단서입니다. 이 어셈블리를 비정상적인 방법으로로드하고 있습니다. 그렇게하는 일반적인 방법은 Assembly.LoadFile()을 사용하는 것입니다. 아주 위험한 방법은 의도적으로과 같이 매우 특별한 경우에만 사용해야합니다. LoadFrom() 대신 항상 LoadFrom()을 사용해야하지만 가능한 경우 Load()를 사용하는 것이 좋습니다. 그리고 일반적으로 DLL을 올바른 디렉토리에 넣거나 app.exe.config 파일의 <probing> 요소를 사용하여 수행 할 수 있습니다.

버전 0.0.0.0을 얻는 것은 그리 건강하지 못하거나 [AssemblyVersion]이 .NET에서 매우 중요합니다.

+0

ParameterModule은 .Net 어셈블리가 아닙니다. CLR이 Xml.Seriliazer를 사용하도록 설정되어있는 C++입니다. – Jefraim

+0

차이점이 없으므로 C++/CLI 프로젝트에서 생성 된 혼합 모드 어셈블리는 여전히 어셈블리로드 규칙과 완전히 동일한 .NET 어셈블리입니다. 특별한 점은 고유 코드가 포함되어 있다는 것입니다. 또는 실제로/clr을 사용하여 * 모든 것을 컴파일하면 전혀 없습니다. –

+0

어셈블리 버전 관리가 직렬화 작업에 영향을 줍니까? .Net interop 서비스가 ActiveX를로드하는 방법을 잘 모르겠습니다. DLL도 DLL에 동적으로 연결되어 있기 때문에 DLL 모듈이 ActiveX로 어떻게로드되는지 알지 못합니다. Xml 직렬화 루틴은 아마도 클래스 피연산자가 들어있는 DLL 모듈을 다시로드했습니다. 이 가정은 순전히 직관적입니다. – Jefraim