Microsoft MVP성태의 닷넷 이야기
.NET Framework: 302. supportedRuntime 옵션과 System.BadImageFormatException 예외 [링크 복사], [링크+제목 복사],
조회: 33336
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 
(연관된 글이 14개 있습니다.)

supportedRuntime 옵션과 System.BadImageFormatException 예외

최근에 다음과 같은 오류를 만났습니다.

badformat_appconfig_1.png

Unhandled Exception: System.BadImageFormatException: Could not load file or assembly 'ConsoleApplication1.exe' or one of its dependencies. This assembly is built by a runtime newer than the currently loaded runtime and cannot be loaded.
File name: 'ConsoleApplication1.exe'


머리로는 BadImageFormatException이 x86/x64의 불일치에서 오는 문제라고만 생각하고 있어서 제법 애를 먹었는데요. 원인은, .NET 4.0 대상으로 빌드한 응용 프로그램에 다음과 같은 supportedRuntime 정책을 적용했기 때문이었습니다.

<?xml version="1.0"?>
<configuration>
    <startup>
        <supportedRuntime version="v2.0.50727"/>
        <supportedRuntime version="v4.0.30319"/>
    </startup>
</configuration>

즉, 4.0으로 빌드한 경우 v2.0.50727 항목으로 인해 오류가 발생한 것입니다. 이를 해결하려면, 다음과 같이 순서를 바꾸는 것도 가능은 합니다.

<?xml version="1.0"?>
<configuration>
    <startup>
        <supportedRuntime version="v4.0.30319"/>
        <supportedRuntime version="v2.0.50727"/>
    </startup>
</configuration>

그렇지만, 이런 식의 해결방법은 (동작은 하지만) 잘못 판단된 것입니다. 왜냐하면, 위의 프로그램을 .NET 2.0만 설치된 환경에서 실행하면 예외가 발생하기 때문입니다. 즉, 2.0의 supportedRuntime을 두 번째 선택으로 미뤄놓은 아무런 의미가 없는 것입니다.

그렇다면, supportedRuntime이 언제 의미가 있는 것일까요?




supportedRuntime은 사실, 하위 버전으로 빌드된 어셈블리를 상위버전의 환경에서 구동할 때 호환을 위해 명시해 주는 데 의미가 있습니다. 간단하게 예를 들어볼까요?

다음과 같은 Console 응용 프로그램을 만들고,

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(Environment.Version.ToString());
    }
}

이를 .NET 2.0으로 컴파일 합니다. 이 상태에서, 아래와 같은 app.config 구성으로 .NET 2.0/4.0이 모두 설치된 컴퓨터에서 실행하면 어떤 결과가 나올까요?

<?xml version="1.0"?>
<configuration>
    <startup>
        <supportedRuntime version="v4.0.30319"/> 
        <supportedRuntime version="v2.0.50727"/>
    </startup>
</configuration>

"v4.0.30319"가 위에 있으니 Environment.Version 출력값은 (제 컴퓨터 기준으로) "4.0.30319.239"입니다. 반면, 버전 번호의 자리를 바꿔서 출력하면 이번엔 "v2.0.50727"이 위에 있으므로 (제 컴퓨터 기준으로) "2.0.50727.5448" 결괏값이 나옵니다.

정리해 보면, supportedRuntime은 하위 버전의 응용 프로그램이 어떤 .NET Framework 런타임에서 실행할지를 결정하는 옵션입니다. 따라서, 처음 이 글의 문제로 돌아가서, supportedRuntime의 순서를 바꿀 것이 아니라 해당 응용 프로그램을 .NET 2.0 대상으로 빌드하는 것이 적절한 해결책입니다. (아니면, 아예 모든 supportedRuntime 옵션을 제거하든가.)

참고로, 기타 supportedRuntime의 종류에 관해서는 예전에 정리둔 것이 있으니 한번 봐두시는 것도 좋겠습니다. ^^

app.config의 supportedRuntime 종류
; https://www.sysnet.pe.kr/2/2/178




간단한 문제를 내 볼까요? ^^ 그렇다면 .NET 2.0으로 빌드된 exe를 아무런 app.config 파일 없이 .NET 4.0만 설치된 컴퓨터에서 실행하면 어떻게 될까?

그런 경우, 다음과 같이 예외가 발생합니다.

badformat_appconfig_2.png

.NET Framework Initialization Error
Unable to find a version of the runtime to run this application.

만약, 이 응용 프로그램을 정상적으로 구동하고 싶다면 app.config에 다음과 같은 설정을 추가해 주면 됩니다.

<?xml version="1.0"?>
<configuration>
    <startup>
        <supportedRuntime version="v4.0.30313"/>
    </startup>
</configuration>

또 다른 경우를 생각해 볼까요? .NET 1.1 exe 파일을 .NET 1.1/4.0은 설치되었지만 .NET 2.0이 설치되지 않은 컴퓨터에서 다음과 같이 2.0을 지원한다고 지정해 두면 어떻게 될까요?

<?xml version="1.0"?>
<configuration>
    <startup>
        <supportedRuntime version="v2.0.50727"/>
    </startup>
</configuration>

이런 경우에도 역시 예외가 발생하면서 실행은 안되지만, 다행히 2.0을 설치할 것인지를 물어보는 대화상자가 뜹니다.

badformat_appconfig_3.png

To run this application, you first must install one of the following versions of the .NET Framework: v2.0.50727

Would you like to download and install version v2.0.50727 of the .NET Framework now?

이번엔 닷넷 프레임워크 버전 격차를 늘려서, .NET 1.1 exe 파일을 .NET 4.0만 설치된 컴퓨터에서 다음과 같이 4.0을 지원한다고 지정해 두면 어떻게 될까요?

<?xml version="1.0"?>
<configuration>
    <startup>
        <supportedRuntime version="v4.0.30319"/>
    </startup>
</configuration>

걱정하지 마세요. ^^ (대부분의 경우) 실행이 아주 잘됩니다. 여기서 supportedRuntime을 가장 극적으로 사용할 수 있는 사례가 나옵니다. 즉, .NET 1.x/2.0/3.0/3.5/4.0에 상관없이 실행되어야 할 프로그램을 만들어야 한다면 해당 응용 프로그램은 .NET 1.1 버전으로 빌드하고 다음과 같이 supportedRuntime 목록을 구성해 주면 되는 것입니다.

<?xml version="1.0"?>
<configuration>
  <startup>
    <supportedRuntime version="v1.1.4322"/>
    <supportedRuntime version="v2.0.50727"/>
    <supportedRuntime version="v4.0.30319"/>
  </startup>
</configuration>

또는 일반적으로 최신 버전의 닷넷 프레임워크가 성능이 더 나아지기 때문에 다중 CLR이 설치된 경우에는 가장 최신의 것을 적용받도록 다음과 같이 거꾸로 순서를 지정하는 것도 좋습니다.

<?xml version="1.0"?>
<configuration>
  <startup>
    <supportedRuntime version="v4.0.30319"/>
    <supportedRuntime version="v2.0.50727"/>
    <supportedRuntime version="v1.1.4322"/>
  </startup>
</configuration>

어떤 설정이든, .NET 1.1로 빌드된 응용 프로그램은 어떤 버전의 닷넷 프레임워크라도 설치되어 있으면 정상적으로 실행이 될 것입니다.




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 6/26/2021]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 



2014-04-29 02시29분
[spowner] 항상 간지러운 곳을 긁어 주셔서 감사합니다.
[guest]
2017-01-05 05시40분
[이지영] 프로그램 실행하는데 아래 같은 CLR20r3 오류가 나와 검색 끝에 여기까지 오게 되었는데요.

혹시 아래 오류 해결 조언 좀 부탁드려도 될까요? 위에 있는 방법으로 Transistor.exe.config라는 파일을 txt로 수정해서 해봤는데 설치 메세지만 뜨고..

어떻게 해야 할지를 모르겠습니다. 넷프레임은 1.1하고 4.6.2가 설치 되어 있습니다.. 이쪽 분야에 전문가분이신 것 같은데 조언 좀 부탁드려요.


문제 서명:
  문제 이벤트 이름: CLR20r3
  문제 서명 01: Transistor.exe
  문제 서명 02: 1.0.0.0
  문제 서명 03: 53b44d4e
  문제 서명 04: MonoGame.Framework.Windows
  문제 서명 05: 2.0.0.0
  문제 서명 06: 539b9ca8
  문제 서명 07: d7d
  문제 서명 08: cf
  문제 서명 09: U5BUGYMB24YGE00VAJPF2KCRJNMKDEEE
  OS 버전: 6.1.7601.2.1.0.256.1
  로캘 ID: 1042
  추가 정보 1: 8eed
  추가 정보 2: 8eed98f8b73ca44fd30d1b635a59cc65
  추가 정보 3: ff9f
  추가 정보 4: ff9f26c412fe1114ca0cbb0f7bc711a5
[guest]
2017-01-06 12시35분
CLR20r3 문제는 해당 프로그램을 만든 개발자도 해결하기 힘든 문제에 속합니다. 외부 개발자의 경우 어찌어찌 문제의 원인은 파악할 수 있어도 그렇다고 해결할 수 있는 것은 아닙니다. 경우에 따라 소스 코드를 변경해야 하기 때문인데요. 따라서 이런 문제는 Transistor.exe를 개발한 측에 물어보는 것이 가장 좋습니다.
정성태
2017-01-06 05시01분
[이지영] 아주 해결하기 어려운 문제인가 보군요. 조언 정말 감사합니다.
[guest]
2017-01-09 05시38분
[정환나라] // 이지영 //
.Net Framework를 4.0이나 2.0을 추가로 설치해 보세요.
[guest]

... 166  167  168  169  170  171  172  173  [174]  175  176  177  178  179  180  ...
NoWriterDateCnt.TitleFile(s)
652정성태1/22/200922778.NET Framework: 121. WPF - PrintTicket provider failed to bind to printer.
651정성태1/20/200920050.NET Framework: 120. 타입이 다른 배열끼리의 변환
650정성태1/19/200931806COM 개체 관련: 21. C/C++ 프로젝트에 /clr 옵션 적용으로 인한 COM 개체 사용 오류
649정성태1/18/200929382Windows: 38. Q1U UMPC에 Windows 7 베타 설치하기
648정성태1/18/200928094Windows: 37. Windows PE를 USB 메모리에 적용
647정성태1/18/200938231Windows: 36. Windows PE ISO 이미지 만들기 [1]
646정성태1/18/200931158디버깅 기술: 23. COMPLUS_ZapDisable - JIT 최적화 코드 생성 제어 [1]
645정성태1/11/200929960Windows: 35. 서명되지 않은 드라이버 로딩 방법
644정성태1/11/200921063Windows: 34. VPC 설치 후기 [2]
643정성태1/10/200926501Windows: 33. Windows 7 베타와 VMA 충돌 [1]
642정성태1/8/200925216개발 환경 구성: 34. Sysinternals의 모든 툴을 한번에 업데이트 하는 방법 [1]
641정성태1/7/200922363기타: 27. D820 - A09 바이오스 업데이트 프로그램 패치 [2]
640정성태1/4/200924009Team Foundation Server: 29. ClickOnce 응용 프로그램 배포를 Team Build에 추가.
639정성태1/4/200922017Team Foundation Server: 28. PFX 코드 서명을 포함한 프로젝트의 팀 빌드 실패 - MSB4018
638정성태1/3/200925079.NET Framework: 119. WPF - 의존 속성 정의에서 XamlParseException 발생하는 예 [2]
637정성태1/1/200927282기타: 26. 2008년 인기 순위 정리
636정성태12/31/200822407.NET Framework: 118. 2진 검색을 이용한 리스트 정렬 삽입파일 다운로드1
635정성태12/29/200824966오류 유형: 66. 파일 암호화 오류 - Recovery policy configured for this system contains invalid recovery certificate
634정성태12/29/200839336기타: 25. 가상 키보드 관련 정리 [4]
633정성태12/20/200824840기타: 24. RMClock for x64 [2]
632정성태12/19/200833480기타: 23. D820 - 배터리 없이 바이오스 업데이트 방법 [2]파일 다운로드1
631정성태12/10/200842127VC++: 36. Detours 라이브러리를 이용한 Win32 API - Sleep 호출 가로채기 [3]
630정성태12/9/200822925.NET Framework: 117. WPF - TreeView에서 항목이 펼쳐질 때 Cursors.Wait 사용파일 다운로드1
629정성태12/7/200832085.NET Framework: 116. 소켓 연결 시간 제한
628정성태12/6/200820999.NET Framework: 115. Marshal 타입 관련 2가지 자원 해제 메서드파일 다운로드1
627정성태12/6/200823382VS.NET IDE: 58. VS.NET IDE 팁 - 커서 위치 이동 [1]
... 166  167  168  169  170  171  172  173  [174]  175  176  177  178  179  180  ...