Dynamic DLL Loader
JSON 설정 파일을 읽어 DLL을 동적으로 로드하고 Form을 여는 프로젝트
폴더 구조
work/
├── .vscode/
│ ├── launch.json # F5 실행 설정
│ └── tasks.json # 빌드 태스크
├── build.bat # 더블클릭으로 빌드+실행
├── DynamicFormLib/ # DLL 라이브러리
│ ├── DynamicFormLib.csproj
│ ├── Form1.cs # Title, Width, Height, Message 파라미터
│ └── Form2.cs # Title, Items(string[]), SelectedIndex 파라미터
└── MainApp/ # 메인 앱
├── MainApp.csproj
├── MainForm.cs # JSON 읽기 + DLL 동적 로드
├── Program.cs
└── config.json # DLL 호출 설정
동작 원리
config.json 읽기
↓
Assembly.LoadFrom() → DLL 로드
↓
Activator.CreateInstance() → Form 인스턴스 생성
↓
리플렉션(Property.SetValue) → 파라미터 전달
↓
Form.Show() → 새 폼 열기
config.json 형식
{
"dlls": [
{
"name": "Form1",
"path": "DynamicFormLib.dll",
"typeName": "DynamicFormLib.Form1",
"parameters": [
{ "name": "Title", "type": "string", "value": "내 폼" },
{ "name": "Width", "type": "int", "value": "800" }
]
}
]
}
| 필드 | 설명 |
|---|---|
| name | DLL 표시 이름 |
| path | DLL 파일 경로 (실행파일 기준 상대경로) |
| typeName | 네임스페이스.클래스명 |
| parameters | Form Property에 전달할 파라미터 목록 |
지원 파라미터 타입
| type | 설명 | 예시 |
|---|---|---|
| string | 문자열 | "Hello" |
| int | 정수 | "800" |
| bool | 불리언 | "true" |
| double | 실수 | "3.14" |
| string[] | 문자열 배열 (쉼표 구분) | "A,B,C" |
실행 방법
VSCode
ds_dl2폴더를 VSCode로 열기F5또는Ctrl+Shift+B로 빌드 및 실행
BAT 파일
build.bat 더블클릭
명령줄
dotnet build MainApp/MainApp.csproj -c Debug
cd MainApp/bin/Debug/net10.0-windows
MainApp.exe
새로운 DLL 추가 방법
DynamicFormLib에 새 Form 클래스 생성config.json에 DLL 정보와 파라미터 추가- 빌드 후 실행
새 Form 추가 예시
namespace DynamicFormLib;
public partial class Form3 : Form
{
public string Title { get; set; } = "Form3";
public int Count { get; set; } = 0;
public Form3()
{
InitializeComponent();
}
private void InitializeComponent()
{
SuspendLayout();
// 폼 컨트롤 설정...
Text = Title;
ResumeLayout(false);
}
}
{
"name": "Form3",
"path": "DynamicFormLib.dll",
"typeName": "DynamicFormLib.Form3",
"parameters": [
{ "name": "Title", "type": "string", "value": "Form3" },
{ "name": "Count", "type": "int", "value": "10" }
]
}
핵심 API
| API | 용도 |
|---|---|
Assembly.LoadFrom(path) |
DLL 파일을 메모리에 로드 |
assembly.GetType(name) |
네임스페이스.클래스명으로 Type 조회 |
Activator.CreateInstance(type) |
Type의 인스턴스 생성 |
type.GetProperty(name) |
Property 이름으로 PropertyInfo 조회 |
prop.SetValue(instance, value) |
Property에 값 설정 |
필요 조건
- .NET 10 SDK
- VSCode (C# Dev Tools 확장 권장)
소스
MainApp/MainForm.cs
using System.Reflection;
using System.Text.Json;
namespace MainApp;
public partial class MainForm : Form
{
private ListBox dllList = new();
private Button btnLoad = new();
private Button btnRefresh = new();
private Label statusLabel = new();
private List<DllConfig> dllConfigs = new();
public MainForm()
{
InitializeComponent();
LoadJsonConfig();
}
private void InitializeComponent()
{
SuspendLayout();
Label lblTitle = new Label
{
Text = "DLL List:",
AutoSize = true,
Location = new Point(20, 20),
Font = new Font("Malgun Gothic", 10, FontStyle.Bold)
};
dllList = new ListBox
{
Location = new Point(20, 50),
Size = new Size(540, 250)
};
btnRefresh = new Button
{
Text = "Refresh",
Location = new Point(20, 320),
Size = new Size(100, 35)
};
btnRefresh.Click += BtnRefresh_Click;
btnLoad = new Button
{
Text = "Run Selected DLL",
Location = new Point(140, 320),
Size = new Size(150, 35)
};
btnLoad.Click += BtnLoad_Click;
statusLabel = new Label
{
Text = "Status: Ready",
AutoSize = true,
Location = new Point(20, 370),
ForeColor = Color.Gray
};
Controls.Add(lblTitle);
Controls.Add(dllList);
Controls.Add(btnRefresh);
Controls.Add(btnLoad);
Controls.Add(statusLabel);
Text = "Dynamic DLL Loader";
Width = 600;
Height = 430;
ResumeLayout(false);
PerformLayout();
}
private void LoadJsonConfig()
{
try
{
string jsonPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "config.json");
if (!File.Exists(jsonPath))
{
statusLabel.Text = "Status: config.json not found";
statusLabel.ForeColor = Color.Red;
return;
}
string json = File.ReadAllText(jsonPath);
var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
var config = JsonSerializer.Deserialize<ConfigRoot>(json, options);
if (config?.Dlls != null)
{
dllConfigs = config.Dlls;
RefreshDllList();
statusLabel.Text = $"Status: {dllConfigs.Count} DLL(s) loaded";
statusLabel.ForeColor = Color.Green;
}
}
catch (Exception ex)
{
statusLabel.Text = $"Status: JSON load error - {ex.Message}";
statusLabel.ForeColor = Color.Red;
}
}
private void RefreshDllList()
{
dllList.Items.Clear();
foreach (var config in dllConfigs)
{
dllList.Items.Add($"[{config.Name}] {config.TypeName}");
}
}
private void BtnRefresh_Click(object? sender, EventArgs e)
{
LoadJsonConfig();
}
private void BtnLoad_Click(object? sender, EventArgs e)
{
if (dllList.SelectedIndex < 0)
{
MessageBox.Show("Please select a DLL.", "Info", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
try
{
var selectedConfig = dllConfigs[dllList.SelectedIndex];
LoadAndShowForm(selectedConfig);
statusLabel.Text = $"Status: {selectedConfig.Name} running";
statusLabel.ForeColor = Color.Green;
}
catch (Exception ex)
{
statusLabel.Text = $"Status: DLL load error - {ex.Message}";
statusLabel.ForeColor = Color.Red;
MessageBox.Show($"Error loading DLL:\n{ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void LoadAndShowForm(DllConfig config)
{
string dllPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, config.Path);
if (!File.Exists(dllPath))
{
throw new FileNotFoundException($"DLL not found: {dllPath}");
}
Assembly assembly = Assembly.LoadFrom(dllPath);
Type? type = assembly.GetType(config.TypeName);
if (type == null)
{
throw new TypeLoadException($"Type not found: {config.TypeName}");
}
object instance = Activator.CreateInstance(type)!;
if (config.Parameters != null)
{
foreach (var param in config.Parameters)
{
PropertyInfo? prop = type.GetProperty(param.Name);
if (prop != null && prop.CanWrite)
{
object? value = ConvertParameter(param.Value, prop.PropertyType);
prop.SetValue(instance, value);
}
}
}
if (instance is Form form)
{
form.Show();
}
else
{
throw new InvalidCastException($"Instance is not a Form: {type.Name}");
}
}
private object? ConvertParameter(string value, Type targetType)
{
if (targetType == typeof(string))
return value;
if (targetType == typeof(int))
return int.Parse(value);
if (targetType == typeof(bool))
return bool.Parse(value);
if (targetType == typeof(double))
return double.Parse(value);
if (targetType == typeof(string[]))
return value.Split(',');
return Convert.ChangeType(value, targetType);
}
}
public class ConfigRoot
{
public List<DllConfig> Dlls { get; set; } = new();
}
public class DllConfig
{
public string Name { get; set; } = "";
public string Path { get; set; } = "";
public string TypeName { get; set; } = "";
public List<Parameter>? Parameters { get; set; }
}
public class Parameter
{
public string Name { get; set; } = "";
public string Type { get; set; } = "";
public string Value { get; set; } = "";
}'Software > C#' 카테고리의 다른 글
| C# ASP.NET 에서 NAS(Network Attached Storage)에 파일을 쓰는 방법 (0) | 2025.05.31 |
|---|---|
| C# DevExpress - WinForm CustomRowCellEdit (0) | 2025.02.17 |
| C# DevExpress - WinForm GridControl Button (0) | 2025.01.27 |
| C# 시작하기 - Mail Send 2 (0) | 2025.01.27 |
| C# 시작하기 - Mail Send (0) | 2025.01.27 |
