C# : 실행프로그램(exe)만 있어도 BouncyCastle.CryptoExt.dll 참조 가능하도록 설정 (dll을 포함한 단일 exe배포)
이번 글에서는 실행프로그램(exe)만 있어도 dll참조하여 사용할 수 있는 dll포함 단일 exe배포방법에 대해서 공부하도록 하겠습니다. 저 같은 경우 BouncyCastle.CryptoExt.dll때문에 이번 공부를 하게 되었는데요. 다양한 방법을 정리하여 올려놓았으니 원하시는 방법으로 사용하시면 될 듯 싶습니다!
1. Assembly를 이용한 dll참조 단일 실행프로그램(exe)만들기
사용하고자하는 dll(예시 BouncyCastle.CryptoExt.dll)을 우선 프로젝트에 참조 추가합니다. 그 다음 프로그램 진입점(Program.cs)에 코드를 아래와 같이 변경합니다.
[STAThread]
static void Main()
{
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(ResolveAssembly);
Application.EnableVisualStyles();
//Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
// .NET 4.0 이상
static Assembly ResolveAssembly(object sender, ResolveEventArgs args) {
Assembly thisAssembly = Assembly.GetExecutingAssembly();
var name = args.Name.Substring(0, args.Name.IndexOf(',')) + ".dll";
var resources = thisAssembly.GetManifestResourceNames().Where(s => s.EndsWith(name));
if (resources.Count() > 0) {
string resourceName = resources.First();
using (Stream stream = thisAssembly.GetManifestResourceStream(resourceName)) {
if (stream != null) {
byte[] assembly = new byte[stream.Length];
stream.Read(assembly, 0, assembly.Length);
Console.WriteLine("Dll file load : " + resourceName);
return Assembly.Load(assembly);
}
}
}
return null;
}
// LINQ가 지원되지 않는 .NET 버전
static Assembly ResolveAssembly(object sender, ResolveEventArgs args)
{
Assembly thisAssembly = Assembly.GetExecutingAssembly();
string resourceName = null;
string fileName = args.Name.Substring(0, args.Name.IndexOf(',')) + ".dll";
foreach (string name in thisAssembly.GetManifestResourceNames())
{
if (name.EndsWith(fileName))
{
resourceName = name;
}
}
if (resourceName != null)
{
using (Stream stream = thisAssembly.GetManifestResourceStream(resourceName))
{
if (stream != null)
{
byte[] assembly = new byte[stream.Length];
stream.Read(assembly, 0, assembly.Length);
Console.WriteLine("Dll file load : " + resourceName);
return Assembly.Load(assembly);
}
}
}
return null;
}
단, 위의 소스는 exe파일과 Application이 호출하는 dll파일이 동일한 경로에 위치해 있어야 한다는 기준입니다. 만약 exe파일 경로가 아닌 다른 경로의 dll파일을 사용하고 싶은 경우 Assembly의 경로를 다르게 지정해주시면 됩니다.
Assembly thisAssembly = Assembly.GetExecutingAssembly();
string AppPath = @"특정 경로";
if (System.IO.File.Exists(String.Format("{0}{1}", AppPath, "BouncyCastle.CryptoExt.dll")))
{
thisAssembly = Assembly.LoadFile(String.Format("{0}{1}", AppPath, "BouncyCastle.CryptoExt.dll"));
}
2. EnterpriseServices Internal Publish에서 GacInstall을 이용하여 특정경로의 dll 참조걸기
[STAThread]
static void Main()
{
string AppPath = @"";
System.EnterpriseServices.Internal.Publish dllImport = new System.EnterpriseServices.Internal.Publish();
dllImport.GacInstall(String.Format("{0}{1}", AppPath, "BouncyCastle.CryptoExt.dll"));
Application.Run(new MainForm());
}
단, 위의 방법을 사용하기 위해서는 특정경로에 해당 dll이 필수로 있어야 하며, System.EnterpriseServices를 참조해야 합니다.
* GACInstall : 전역 어셈블리 캐시에 어셈블리를 설치하는 방식 GacInstall(string AsssemblyPath) : 해당 메소드를 사용하시려면 실행프로그램(exe)이 관리자 권한으로 실행되어야 합니다. 권한이 없는경우 SecurityException 오류가 발생할 수 있습니다.
* SecurityException : 호출 체인에 있는 호출자에게 비관리 코드에 액세스할 수 있는 권한이 없는 경우