성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] Working with Rust Libraries from C#...
[정성태] Detecting blocking calls using asyn...
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
[정성태] "props[i].GetValue(props[i])" 코드에서 ...
[정성태] 저렇게 조각 코드 말고, 실제로 재현이 되는 예제 프로젝트를 압...
[정성태] Modules 창(Ctrl+Shift+U)을 띄워서, 해당 Op...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>해당 DLL이 Managed인지 / Unmanaged인지 확인하는 방법</h1> <p> 이에 대해서 검색을 해보면, 여러 가지 방법이 나옵니다. 도구로는 corflags.exe를 이용하거나, 코드로는 PE 포맷을 분석해서 판단하는 등의 글이 나옵니다.<br /> <br /> 일단, 코드로 알아내야 하는 것이 중요한데요. 제 경우에는 Reflection을 생각해 보았습니다. 그러고 보니, 예전에도 Reflection을 이용해서 해당 DLL에 대해 Debug/Release 빌드 여부를 알아내는 방법을 소개해 드렸었는데요.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 해당 어셈블리가 Debug 빌드인지, Release 빌드인지 알아내는 방법 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/1227'>http://www.sysnet.pe.kr/2/0/1227</a> </pre> <br /> 그래서, 간단하게 다음과 같이 테스트를 해볼 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > try { return Assembly.ReflectionOnlyLoadFrom(filePath) != null; } catch { return false; } </pre> <br /> 당연히 Native DLL을 로드하는 경우는 다음과 같은 예외가 발생합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <span style='color: blue; font-weight: bold'>System.BadImageFormatException was caught</span> Message=Could not load file or assembly 'file:///D:\...\native.dll' or one of its dependencies. <span style='color: blue; font-weight: bold'>The module was expected to contain an assembly manifest.</span> Source=mscorlib FileName=file:///D:\...\ConsoleApplication1\bin\Debug\native.dll FusionLog==== Pre-bind state information === LOG: User = ... LOG: Where-ref bind. Location = D:\...\ConsoleApplication1\bin\Debug\native.dll LOG: Appbase = file:///D:/.../ConsoleApplication1/bin/Debug/ LOG: Initial PrivatePath = NULL Calling assembly : (Unknown). === LOG: This is an inspection only bind. LOG: No application configuration file found. LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v2.0.50727\config\machine.config. LOG: Attempting download of new URL file:///D:/.../ConsoleApplication1/bin/Debug/native.dll. <span style='color: blue; font-weight: bold'>ERR: Failed to complete setup of assembly (hr = 0x80131018).</span> Probing terminated. StackTrace: at System.Reflection.Assembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection) at System.Reflection.Assembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection) at System.Reflection.Assembly.InternalLoad(AssemblyName assemblyRef, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection) at System.Reflection.Assembly.InternalLoadFrom(String assemblyFile, Evidence securityEvidence, Byte[] hashValue, AssemblyHashAlgorithm hashAlgorithm, Boolean forIntrospection, StackCrawlMark& stackMark) at System.Reflection.Assembly.ReflectionOnlyLoadFrom(String assemblyFile) at ConsoleApplication1.Program.IsManaged(String filePath) in D:\...\ConsoleApplication1\Program.cs:line 27 InnerException: </pre> <br /> 이걸로 끝날까 싶었는데, 문제가 하나 있더군요. 바로, ReflectionOnlyLoadFrom 메서드를 실행하는 EXE 측의 CLR 런타임과 로드되는 DLL 측의 CLR 런타임이 다른 경우에도 예외가 발생한다는 점입니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > System.BadImageFormatException was caught Message=Could not load file or assembly 'file:///D:\...\net40.dll' or one of its dependencies. <span style='color: blue; font-weight: bold'>This assembly is built by a runtime newer than the currently loaded runtime and cannot be loaded.</span> Source=mscorlib ...[생략]... <span style='color: blue; font-weight: bold'>ERR: Failed to complete setup of assembly (hr = 0x8013101b).</span> Probing terminated. ...[생략]... </pre> <br /> 그렇다면, Managed/Unmanaged DLL을 판별하기 위해 다중으로 EXE 파일을 만들어야만 할까요? 이전에 소개해드렸던 약간의 트릭을 쓰면 ^^ 그럴 필요가 없습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 설치된 .NET 버전에 민감한 코드를 포함하는 경우, 다중으로 어셈블리를 만들어야 할까요? ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/1178'>http://www.sysnet.pe.kr/2/0/1178</a> </pre> <br /> 이를 모두 반영하면, 다음과 같이 .NET 2.0/4.0 DLL에 대해서 정상적으로 Managed 모듈임을 판명할 수 있습니다.<br /> <br /> <img onclick='toggle_img(this)' class='imgView' alt='managed_unmanaged_1.png' src='/SysWebRes/bbs/managed_unmanaged_1.png' /><br /> <br /> <a target='tab' href='http://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=713&boardid=331301885'>소스 코드는 첨부 파일에 포함</a>했으므로 참고하시고요.<br /> <br /> PE 파일 포맷을 분석하는 대신에 간단하게 여기까지 만들어보았는데, 위의 모듈에는 한 가지 단점이 있습니다. .NET Framework 4.0이 설치되지 않은 PC에 .NET 4.0 DLL이 있는 경우에는 판정이 되지 않습니다. (사실, 이 부분은 생각하기 나름입니다. .NET 4.0이 없는 환경에서는 4.0용 어셈블리는 실행되지 않으므로 Native DLL과 달리 차이가 없어 보입니다.)<br /> <br /> 어쨌든... ^^ 이 부분까지 가능하게 하려면 PE 파일 포맷을 다뤄야 합니다. 이건 나중에 시간나면 한번 더 다뤄보도록 하겠습니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 마치기 전에, .NET 2.0 실행 파일에서 CSharpCodeProvider를 이용하여 .NET 4.0 대상으로 컴파일을 강제로 하면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Dictionary<string, string> options = new Dictionary<string, string> { { "CompilerVersion", "v4.0" } }; CSharpCodeProvider provider = new CSharpCodeProvider(options); CompilerParameters compilerParams = new CompilerParameters(); compilerParams.GenerateExecutable = false; compilerParams.GenerateInMemory = true; string classText = " ...[생략]... "; CompilerResults cr = provider.CompileAssemblyFromSource(compilerParams, classText); </pre> <br /> 다음과 같은 예외가 발생합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <span style='color: blue; font-weight: bold'>Unhandled Exception: System.InvalidOperationException: Compiler executable file csc.exe cannot be found.</span> at System.CodeDom.Compiler.RedistVersionInfo.GetCompilerPath(IDictionary`2 provOptions, String compilerExecutable) at Microsoft.CSharp.CSharpCodeGenerator.FromFileBatch(CompilerParameters options, String[] fileNames) at Microsoft.CSharp.CSharpCodeGenerator.FromSourceBatch(CompilerParameters options, String[] sources) at Microsoft.CSharp.CSharpCodeGenerator.System.CodeDom.Compiler.ICodeCompiler.CompileAssemblyFromSourceBatch(CompilerParameters options, String[] sources) at System.CodeDom.Compiler.CodeDomProvider.CompileAssemblyFromSource(CompilerParameters options, String[] sources) at ClrUtility.ManagedDLL.get_Clr4Object() in D:\...\ClrUtility\ManagedDLL.cs:line 72 at ClrUtility.ManagedDLL.IsManaged(String filePath) in D:\...\ClrUtility\ManagedDLL.cs:line 29 at ConsoleApplication1.Program.Main(String[] args) in D:\...\ConsoleApplication1\Program.cs:line 17 </pre> <br /> 이전의 글 "<a target='tab' href='http://www.sysnet.pe.kr/2/0/1178'>설치된 .NET 버전에 민감한 코드를 포함하는 경우, 다중으로 어셈블리를 만들어야 할까요?</a>"에 포함된 예제에서는 .NET 4.0 실행 파일이었기 때문에 이 부분이 문제가 되지 않았는데, 이번 글에서는 .NET 2.0 실행 파일이기 때문에 .NET 4.0 컴파일을 하면 "Compiler executable file csc.exe cannot be found."라는 오류 메시지를 만나게 됩니다.<br /> <br /> 따라서 이런 경우에는 별도의 조치를 취해주어야 합니다. 즉, .NET 2.0 EXE 실행 파일로 만들되, .NET 4.0이 설치된 환경에서는 4.0 CLR 위에서 구동되도록 다음과 같이 supportedRuntime 설정을 해주어야 합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <?xml version="1.0" encoding="utf-8" ?> <configuration> <startup> <supportedRuntime version="v4.0.30319"/> <supportedRuntime version="v2.0.50727"/> </startup> </configuration> </pre> <br /> 좀 뭔가 다소 복잡한데요. 모듈을 2개로 관리하는 것이 편할지, 위와 같이 다소 복잡한 처리를 하는 것이 관리하는 데 편할지는 경중을 따져보고 선택하시면 됩니다. ^^<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1735
(왼쪽의 숫자를 입력해야 합니다.)