성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] 제가 큰 실수를 했군요. ^^; Delegate를 통한 Bein...
[정성태] Working with Rust Libraries from C#...
[정성태] Detecting blocking calls using asyn...
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
[정성태] "props[i].GetValue(props[i])" 코드에서 ...
[정성태] 저렇게 조각 코드 말고, 실제로 재현이 되는 예제 프로젝트를 압...
글쓰기
제목
이름
암호
전자우편
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'>Assembly.Load를 이용해 GAC에 등록된 어셈블리를 로드하는 방법</h1> <p> GAC에 등록된 어셈블리를 로드하는 방법이 애매합니다. 물론 다음과 같이 하면 어셈블리 로드가 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > string assemblyName = "Microsoft.SqlServer.Types, Version=12.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91"; Assembly asm = Assembly.Load(assemblyName); </pre> <br /> 하지만 저렇게 어셈블리 이름을 완전하게 지정하는 것이 애매할 때가 있습니다. 가장 큰 문제는 Version 값인데요. 대상 PC에 어떤 버전의 어셈블리가 설치되어 있는지 확실하지 않을 때가 있습니다.<br /> <br /> 이런 경우 해결책은 2가지 정도가 있습니다.<br /> <br /> <ul> <li>Assembly.LoadWithPartialName을 이용하는 방법</li> <li>그냥 특정 버전의 어셈블리를 로컬에 복사해서 배포하는 방법</li> </ul> <br /> 첫 번째 LoadWithPartialName은 현재 <a target='tab' href='https://blog.maartenballiauw.be/post/2023/11/08/opt-in-to-experimental-apis-using-csharp-12-experimentalattribute.html'>[obsolete] 특성</a>이 적용된 상태라서 왠지 쓰기가 불안합니다. 두 번째 방법이 그나마 나은데요. 이것도 좀 그런 것이... 대상 PC의 GAC에 설치된 최신 버전의 어셈블리가 그 제품의 최신 버전과만 연동할 수 있는 경우가 가능하기 때문입니다.<br /> <br /> 방법이 없을까??? 하고 검색을 좀 해보았는데, 색다른 해결책이 하나 나왔습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Is it possible to Load an assembly from the GAC without the FullName? ; <a target='tab' href='http://stackoverflow.com/questions/6121276/is-it-possible-to-load-an-assembly-from-the-gac-without-the-fullname'>http://stackoverflow.com/questions/6121276/is-it-possible-to-load-an-assembly-from-the-gac-without-the-fullname</a> </pre> <br /> fusion.dll의 어셈블리 정보를 반환하는 IAssemblyCache.QueryAssemblyInfo 메서드를 직접 사용하는 것입니다. 위의 코드를 대략 정리해 보면 다음과 같습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > using System; using System.Reflection; using System.Runtime.InteropServices; namespace ConsoleApplication1 { class Program { [DllImport("fusion.dll")] private static extern int CreateAssemblyCache(out IAssemblyCache ppAsmCache, int reserved); static void Main(string[] args) { string gacAsmPath = GetAssemblyPath("Microsoft.SqlServer.Types"); <span style='color: blue; font-weight: bold'>Assembly sqlServerTypes = Assembly.LoadFrom(gacAsmPath);</span> } public static string GetAssemblyPath(string name) { if (name == null) { throw new ArgumentNullException("name"); } string finalName = name; AssemblyInfo aInfo = new AssemblyInfo(); aInfo.cchBuf = 1024; aInfo.currentAssemblyPath = new String('\0', aInfo.cchBuf); IAssemblyCache ac; int hr = CreateAssemblyCache(out ac, 0); if (hr >= 0) { hr = ac.QueryAssemblyInfo(0, finalName, ref aInfo); if (hr < 0) { return null; } } return aInfo.currentAssemblyPath; } } [StructLayout(LayoutKind.Sequential)] public struct AssemblyInfo { public int cbAssemblyInfo; public int assemblyFlags; public long assemblySizeInKB; [MarshalAs(UnmanagedType.LPWStr)] public string currentAssemblyPath; public int cchBuf; } [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("e707dcde-d1cd-11d2-bab9-00c04f8eceae")] public interface IAssemblyCache { void Reserved0(); [PreserveSig] int QueryAssemblyInfo(int flags, [MarshalAs(UnmanagedType.LPWStr)] string assemblyName, ref AssemblyInfo assemblyInfo); } } </pre> <br /> 그런데, 아쉽게도 GetAssemblyPath 메서드는 해당 어셈블리의 GAC 전체 경로를 반환하는 것이지, 어셈블리 이름을 반환하지는 않습니다. 그래서 Assembly.LoadFrom을 사용해야 하는데 이것도 역시 문제가 될 수 있습니다. 왜냐하면, Load와 LoadFrom의 바인딩 문맥이 다르기 때문입니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > BindingContext - Load() vs. LoadFrom() ; <a target='tab' href='https://imhumanvirus.tistory.com/186'>https://imhumanvirus.tistory.com/186</a> </pre> <br /> 약간은 불편하지만, AppDomain을 이용해 안전하게 어셈블리 이름만 구할 수도 있습니다. 즉, 다음과 같이 구현하시면 끝!<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > static void Main(string[] args) { string gacAsmPath = GetAssemblyPath("Microsoft.SqlServer.Types"); AppDomain appDomain = AppDomain.CreateDomain(Guid.NewGuid().ToString()); appDomain.SetData("asmName", gacAsmPath); appDomain.DoCallBack( () => { string asmName = AppDomain.CurrentDomain.GetData("asmName") as string; if (string.IsNullOrEmpty(asmName) == true) { return; } Assembly target = Assembly.LoadFrom(asmName); AppDomain.CurrentDomain.SetData("asmName", target.FullName); }); string assemblyName = appDomain.GetData("asmName") as string; AppDomain.Unload(appDomain); <span style='color: blue; font-weight: bold'>Assembly asm = Assembly.Load(assemblyName);</span> Console.WriteLine(assemblyName + " in " + asm.FullName); } </pre> <br /> (<a target='tab' href='http://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=856&boardid=331301885'>첨부 파일은 위의 예제를 포함</a>하고 있습니다.)<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1235
(왼쪽의 숫자를 입력해야 합니다.)