SEHException 으로 고생중이다... 2주째 인가... ㅠㅠ
예외 메시지는 다음과 같다.
이 예외의 시나리오는 우선
CSocket ← CSocketEx ← CCommandSocket 이라는 상속 구조를 가진 사용자 정의 클래스를 dll 로 만들었다.
해당 dll 을 C# 쪽에서 사용하는데 컴파일 까지는 문제가 없다. 하지만 run-time 에 위와 같은 예외가 발생한다.
dll 에 있는 CCommandSocket 을 마샬링한 클래스 객체를 생성하여 Connect 하는건 성공
또 다른 객체를 생성하여 Connect 하는 것도 성공
하지만 연결된 소켓의 연결을 해제하는 Close() 를 호출하면, 또는 해당 객체를 소멸시키기 위해 Dispose 메소드를 호출하면 그 뒤로는 예외를 발생하면서 서버로 접근이 불가능...서버에 접속하려 하면 위와 같은 예외를 발생 시키며 서버에 접근 불가능..
■ Try
1. 프로젝트 속성 변경
MFC 코드를 마샬링하여 dll 로 만들 때 프로젝트 환경 설정 옵션도 다 해주었다.. 그런데도 또 발생...
http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=51&MAEULNo=20&no=8283&ref=8283
2. Application.EnableVisualStyles() Bug
구굴링 해보니 SEHException 키워드로 검색 했을 때 제일 많은 이슈는 "Application.EnableVisualStyles()" 문제이다.
http://www.eggheadcafe.com/forumarchives/win32programmerdirectxmanaged/Oct2005/post23920195.asp
Visual Studio 2005 의 버그 라고 하는데... 내 지금 환경은 Visual Studio 2008 이다. 즉 UI 환경에서의 문제인데 혹시나 하여 WinForm 으로 테스트 하던것을 Console Application 으로 테스트 해 보았지면 역시나 문제 발생...
3. 실행 파일 폴더에 lib 파일 첨부
MFC 코드를 C++/CLI 로 마샬링 할 때는 "공용 DLL에서 MFC 사용" 을 체크 해야 한다고 한다.
혹시나 하여 생성된 dll 파일과 lib 파일을 C#쪽 실행 파일 폴더에 같이 넣어 주었다. 역시나 안됨...
4. C++/CLI 코드의 "코드 분석(정적 분석)" 실행
혹시나 하는 마음에 여기서 나오는 경고도 다 수정해 보자. 컴파일 하니 9개의 경고 메시지가 뜬다.
" warning: CA1707 : Microsoft.Naming : 'CommandSocket::ConnectServer(String^, unsigned int)' 멤버의 매개 변수 이름 '_ip'에서 밑줄을 제거하십시오. "
매개변수의 이름이 밑줄(_)로 시작하게 코딩하였는데 이 방식이 위험성이 있는가 보다. 어떤 경우인지 자세히 생각은 나지 않지만 C# 에서 매개변수가 MSIL 에는 밑줄(_) 로 붙어서 자동으로 생성되게 된다고 들은 것 같다. 메시지 내용처럼 매개 변수 이름에 밑줄(_)을 삭제하면 간단히 해결!
정적 분석 결과 중에서 디자인 경고는 MSDN 의 Design Warinings 을 참조하면 된다.
.NET Framework Design Guidlines 에 의해 경고가 되는 목록 들이다.
" warning: CA1823 : Microsoft.Performance : 'context_node_base::_Needs_Context' 필드는 사용되지 않거나 할당만 되어 있습니다. 이 필드를 사용하거나 제거하십시오. "
코드에 전용 필드가 있지만 이를 사용하는 코드 경로가 없는 경우 이 규칙이 보고됨. MSDN 에 따르면 이 경고를 표시하지 않아도 안전 하다고 한다. (Usage Warning)
" warning C4742: 'struct Define_the_symbol__ATL_MIXED::Thank_you Define_the_symbol__ATL_MIXED::clash'의 맞춤이 'stdafx.cpp'과(와) 'CliCommandSocket.cpp'에서 서로 다릅니다(4 - 1). "
" warning C4743: 'struct Define_the_symbol__ATL_MIXED::Thank_you Define_the_symbol__ATL_MIXED::clash'의 크기가 'stdafx.cpp'과(와) 'CliCommandSocket.cpp'에서 서로 다릅니다(4바이트, 1바이트). "
전체 프로그램 최적화(Whole Program Optimization) 옵션 관련 문제이다. 즉 Native Code 를 Static Library 프로젝트로 만든 후, 또 다른 프로젝트를 Mixed Mode dll 로 만들 때, 두 프로젝트의 속성에서 "전체 프로그램 최적화(Whole Program Optimization)" 옵션이 "링크 타임 코드 생성(/GL) : (Use Link Time Code Generation)" 으로 되어 있어서 그렇다. 두 프로젝트의 옵션을 "아니오" 로 선택 하면 위 경고를 없앨 수 있다.
단, 위와 같이 설정 후 컴파일 하면 다음과 같은 메시지를 볼 수 있다.
" LINK : /LTCG를 지정했지만 코드를 생성할 필요가 없습니다. 명령줄에서 /LTCG를 제거하면 링커 성능이 향상됩니다. "
오류도 아니고, 경고도 아니고 조언?! 정도. 일단 바쁘니 패스.
다른 방법으로 "#define _ATL_MIXED" 을 선언해 주어도 해결 된다고 하는데, 모든 경우에 대한 해결법은 아닌 듯 하다.
참조) Whole Program Optimization, mixed-mode and ATL_MIXED
참조) mixed mode ATL executable warnings
" warning: CA1823 : Microsoft.Performance : 'context_node_base::_Needs_Context' 필드는 사용되지 않거나 할당만 되어 있습니다. 이 필드를 사용하거나 제거하십시오.
warning: CA1812 : Microsoft.Performance : 'context_node<char const *,System::String ^>'은(는) 인스턴스화되지 않은 내부 클래스입니다. 어셈블리에서 해당 코드를 제거하십시오. 이 클래스가 정적 메서드만 포함하도록 의도된 경우에는 전용 생성자를 추가하여 컴파일러에서 기본 생성자가 생성되지 않도록 하십시오.
c:\program files\microsoft visual studio 9.0\vc\include\msclr\marshal.h(366) : warning: CA2201 : Microsoft.Usage : 'context_node<char const *,System::String ^>::context_node<char const *,System::String ^>(const char*&, String^)'이(가) 런타임에서 예약되고 관리 코드에서 발생하면 안 되는 'OutOfMemoryException' 형식의 예외를 만듭니다. 이러한 예외 인스턴스가 throw되면 다른 예외 형식을 사용하십시오. "
참 길기도 하다.. 우선 이 경고는 문자열 마샬링을 위한 #include <msclr/marshal_atl.h> 을 include 해주면 발생한다. MS 에서 문자열 마샬링을 편하게 하라고 만들어 준건데 include 하는 것 만으로도 경고를 주다니..
일단 의심되는 것은 'OutOfMemoryException" 이 발생할 수 있다는 것!
문자열 마샬링 코드를 일단 주석처리하고, #include <msclr/marshal_atl.h> 도 주석처리 해주었다. 다시 정적 분석하면 위와 같은 경고는 발생하지 않는다.
서버 접속을 위한 부분을 하드 코딩 해주었다. 그리고 다시 테스트!
아오... 빡쳐...
ConnectServer 내부적으로 CSocket 을 호출하니 아무래도 CSocket 쪽에서 뭔가 발생하는 듯 하다.
■ 결론
CSocket 사용상의 문제인 것 같습니다.... (내용을 찾다 보니 MFC 스레드에서 충돌이 일어난다는...)