Add comprehensive file management and FTP upload features

- Add tbExceptfile textbox for excluding files from processing
- Implement settings persistence with config.ini file
- Add FTP upload functionality with complete connection parameters
- Enhance file filtering logic with exception handling
- Improve UI layout with organized form design
- Add password masking for FTP credentials
- Include comprehensive error handling and user feedback

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Arin(asus)
2025-08-13 11:23:06 +09:00
parent ece077b555
commit 26e20a4ff2
2 changed files with 430 additions and 31 deletions

View File

@@ -42,89 +42,115 @@
this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.btUpdateFilelist = new System.Windows.Forms.Button();
this.tbExceptfile = new System.Windows.Forms.TextBox();
this.label5 = new System.Windows.Forms.Label();
this.grpftpinfo = new System.Windows.Forms.GroupBox();
this.tbFTPId = new System.Windows.Forms.TextBox();
this.label6 = new System.Windows.Forms.Label();
this.tbFTPServer = new System.Windows.Forms.TextBox();
this.label7 = new System.Windows.Forms.Label();
this.tbFTPPW = new System.Windows.Forms.TextBox();
this.lbpw = new System.Windows.Forms.Label();
this.tbFTPPort = new System.Windows.Forms.TextBox();
this.label8 = new System.Windows.Forms.Label();
this.chkFTPPassive = new System.Windows.Forms.CheckBox();
this.tbUploadFile = new System.Windows.Forms.Button();
this.tbFTPPath = new System.Windows.Forms.TextBox();
this.label9 = new System.Windows.Forms.Label();
this.grpftpinfo.SuspendLayout();
this.SuspendLayout();
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(33, 30);
this.label1.Location = new System.Drawing.Point(20, 20);
this.label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(36, 12);
this.label1.Size = new System.Drawing.Size(54, 18);
this.label1.TabIndex = 0;
this.label1.Text = "count";
//
// tbCount
//
this.tbCount.Location = new System.Drawing.Point(91, 25);
this.tbCount.Location = new System.Drawing.Point(100, 15);
this.tbCount.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4);
this.tbCount.Name = "tbCount";
this.tbCount.Size = new System.Drawing.Size(100, 21);
this.tbCount.Size = new System.Drawing.Size(120, 28);
this.tbCount.TabIndex = 1;
//
// btRead
//
this.btRead.Location = new System.Drawing.Point(277, 25);
this.btRead.Location = new System.Drawing.Point(450, 60);
this.btRead.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4);
this.btRead.Name = "btRead";
this.btRead.Size = new System.Drawing.Size(116, 30);
this.btRead.Size = new System.Drawing.Size(120, 35);
this.btRead.TabIndex = 2;
this.btRead.Text = "read";
this.btRead.Text = "Read INF";
this.btRead.UseVisualStyleBackColor = true;
this.btRead.Click += new System.EventHandler(this.btRead_Click);
//
// btWrite
//
this.btWrite.Location = new System.Drawing.Point(413, 21);
this.btWrite.Location = new System.Drawing.Point(580, 60);
this.btWrite.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4);
this.btWrite.Name = "btWrite";
this.btWrite.Size = new System.Drawing.Size(116, 30);
this.btWrite.Size = new System.Drawing.Size(120, 35);
this.btWrite.TabIndex = 2;
this.btWrite.Text = "write";
this.btWrite.Text = "Write INF";
this.btWrite.UseVisualStyleBackColor = true;
this.btWrite.Click += new System.EventHandler(this.btWrite_Click);
//
// tbDate
//
this.tbDate.Location = new System.Drawing.Point(91, 52);
this.tbDate.Location = new System.Drawing.Point(100, 50);
this.tbDate.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4);
this.tbDate.Name = "tbDate";
this.tbDate.Size = new System.Drawing.Size(100, 21);
this.tbDate.Size = new System.Drawing.Size(120, 28);
this.tbDate.TabIndex = 4;
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(33, 57);
this.label2.Location = new System.Drawing.Point(20, 55);
this.label2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(29, 12);
this.label2.Size = new System.Drawing.Size(43, 18);
this.label2.TabIndex = 3;
this.label2.Text = "date";
//
// tbExeFileName
//
this.tbExeFileName.Location = new System.Drawing.Point(91, 106);
this.tbExeFileName.Location = new System.Drawing.Point(100, 120);
this.tbExeFileName.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4);
this.tbExeFileName.Name = "tbExeFileName";
this.tbExeFileName.Size = new System.Drawing.Size(100, 21);
this.tbExeFileName.Size = new System.Drawing.Size(200, 28);
this.tbExeFileName.TabIndex = 8;
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(33, 111);
this.label3.Location = new System.Drawing.Point(20, 125);
this.label3.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(26, 12);
this.label3.Size = new System.Drawing.Size(38, 18);
this.label3.TabIndex = 7;
this.label3.Text = "exe";
//
// tbServerURL
//
this.tbServerURL.Location = new System.Drawing.Point(91, 79);
this.tbServerURL.Location = new System.Drawing.Point(100, 85);
this.tbServerURL.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4);
this.tbServerURL.Name = "tbServerURL";
this.tbServerURL.Size = new System.Drawing.Size(100, 21);
this.tbServerURL.Size = new System.Drawing.Size(200, 28);
this.tbServerURL.TabIndex = 6;
//
// label4
//
this.label4.AutoSize = true;
this.label4.Location = new System.Drawing.Point(33, 84);
this.label4.Location = new System.Drawing.Point(20, 90);
this.label4.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(40, 12);
this.label4.Size = new System.Drawing.Size(60, 18);
this.label4.TabIndex = 5;
this.label4.Text = "server";
//
@@ -136,9 +162,10 @@
this.listView1.FullRowSelect = true;
this.listView1.GridLines = true;
this.listView1.HideSelection = false;
this.listView1.Location = new System.Drawing.Point(47, 152);
this.listView1.Location = new System.Drawing.Point(20, 170);
this.listView1.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4);
this.listView1.Name = "listView1";
this.listView1.Size = new System.Drawing.Size(468, 178);
this.listView1.Size = new System.Drawing.Size(730, 220);
this.listView1.TabIndex = 9;
this.listView1.UseCompatibleStateImageBehavior = false;
this.listView1.View = System.Windows.Forms.View.Details;
@@ -154,19 +181,176 @@
//
// btUpdateFilelist
//
this.btUpdateFilelist.Location = new System.Drawing.Point(399, 116);
this.btUpdateFilelist.Location = new System.Drawing.Point(580, 110);
this.btUpdateFilelist.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4);
this.btUpdateFilelist.Name = "btUpdateFilelist";
this.btUpdateFilelist.Size = new System.Drawing.Size(116, 30);
this.btUpdateFilelist.Size = new System.Drawing.Size(120, 35);
this.btUpdateFilelist.TabIndex = 10;
this.btUpdateFilelist.Text = "update file list";
this.btUpdateFilelist.Text = "Update Files";
this.btUpdateFilelist.UseVisualStyleBackColor = true;
this.btUpdateFilelist.Click += new System.EventHandler(this.btUpdateFilelist_Click);
//
// tbExceptfile
//
this.tbExceptfile.Location = new System.Drawing.Point(450, 15);
this.tbExceptfile.Margin = new System.Windows.Forms.Padding(4);
this.tbExceptfile.Name = "tbExceptfile";
this.tbExceptfile.Size = new System.Drawing.Size(300, 28);
this.tbExceptfile.TabIndex = 12;
//
// label5
//
this.label5.AutoSize = true;
this.label5.Location = new System.Drawing.Point(350, 20);
this.label5.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.label5.Name = "label5";
this.label5.Size = new System.Drawing.Size(84, 18);
this.label5.TabIndex = 11;
this.label5.Text = "exceptfile";
//
// grpftpinfo
//
this.grpftpinfo.Controls.Add(this.tbFTPPath);
this.grpftpinfo.Controls.Add(this.label9);
this.grpftpinfo.Controls.Add(this.tbUploadFile);
this.grpftpinfo.Controls.Add(this.chkFTPPassive);
this.grpftpinfo.Controls.Add(this.tbFTPPort);
this.grpftpinfo.Controls.Add(this.label8);
this.grpftpinfo.Controls.Add(this.tbFTPPW);
this.grpftpinfo.Controls.Add(this.lbpw);
this.grpftpinfo.Controls.Add(this.tbFTPId);
this.grpftpinfo.Controls.Add(this.label6);
this.grpftpinfo.Controls.Add(this.tbFTPServer);
this.grpftpinfo.Controls.Add(this.label7);
this.grpftpinfo.Location = new System.Drawing.Point(20, 410);
this.grpftpinfo.Name = "grpftpinfo";
this.grpftpinfo.Size = new System.Drawing.Size(730, 150);
this.grpftpinfo.TabIndex = 13;
this.grpftpinfo.TabStop = false;
this.grpftpinfo.Text = "FTP Information";
//
// tbFTPId
//
this.tbFTPId.Location = new System.Drawing.Point(80, 60);
this.tbFTPId.Margin = new System.Windows.Forms.Padding(4);
this.tbFTPId.Name = "tbFTPId";
this.tbFTPId.Size = new System.Drawing.Size(150, 28);
this.tbFTPId.TabIndex = 8;
//
// label6
//
this.label6.AutoSize = true;
this.label6.Location = new System.Drawing.Point(15, 65);
this.label6.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.label6.Name = "label6";
this.label6.Size = new System.Drawing.Size(21, 18);
this.label6.TabIndex = 7;
this.label6.Text = "ID";
//
// tbFTPServer
//
this.tbFTPServer.Location = new System.Drawing.Point(80, 25);
this.tbFTPServer.Margin = new System.Windows.Forms.Padding(4);
this.tbFTPServer.Name = "tbFTPServer";
this.tbFTPServer.Size = new System.Drawing.Size(150, 28);
this.tbFTPServer.TabIndex = 6;
//
// label7
//
this.label7.AutoSize = true;
this.label7.Location = new System.Drawing.Point(15, 30);
this.label7.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.label7.Name = "label7";
this.label7.Size = new System.Drawing.Size(60, 18);
this.label7.TabIndex = 5;
this.label7.Text = "Server";
//
// tbFTPPW
//
this.tbFTPPW.Location = new System.Drawing.Point(290, 60);
this.tbFTPPW.Margin = new System.Windows.Forms.Padding(4);
this.tbFTPPW.Name = "tbFTPPW";
this.tbFTPPW.Size = new System.Drawing.Size(150, 28);
this.tbFTPPW.TabIndex = 10;
this.tbFTPPW.PasswordChar = '*';
//
// lbpw
//
this.lbpw.AutoSize = true;
this.lbpw.Location = new System.Drawing.Point(245, 65);
this.lbpw.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.lbpw.Name = "lbpw";
this.lbpw.Size = new System.Drawing.Size(32, 18);
this.lbpw.TabIndex = 9;
this.lbpw.Text = "PW";
//
// tbFTPPort
//
this.tbFTPPort.Location = new System.Drawing.Point(290, 25);
this.tbFTPPort.Margin = new System.Windows.Forms.Padding(4);
this.tbFTPPort.Name = "tbFTPPort";
this.tbFTPPort.Size = new System.Drawing.Size(80, 28);
this.tbFTPPort.TabIndex = 12;
this.tbFTPPort.Text = "21";
//
// label8
//
this.label8.AutoSize = true;
this.label8.Location = new System.Drawing.Point(245, 30);
this.label8.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.label8.Name = "label8";
this.label8.Size = new System.Drawing.Size(40, 18);
this.label8.TabIndex = 11;
this.label8.Text = "Port";
//
// chkFTPPassive
//
this.chkFTPPassive.AutoSize = true;
this.chkFTPPassive.Location = new System.Drawing.Point(460, 25);
this.chkFTPPassive.Name = "chkFTPPassive";
this.chkFTPPassive.Size = new System.Drawing.Size(150, 22);
this.chkFTPPassive.TabIndex = 13;
this.chkFTPPassive.Text = "Passive Mode";
this.chkFTPPassive.UseVisualStyleBackColor = true;
//
// tbUploadFile
//
this.tbUploadFile.Location = new System.Drawing.Point(460, 55);
this.tbUploadFile.Margin = new System.Windows.Forms.Padding(4);
this.tbUploadFile.Name = "tbUploadFile";
this.tbUploadFile.Size = new System.Drawing.Size(150, 70);
this.tbUploadFile.TabIndex = 14;
this.tbUploadFile.Text = "Upload Files";
this.tbUploadFile.UseVisualStyleBackColor = true;
this.tbUploadFile.Click += new System.EventHandler(this.tbUploadFile_Click);
//
// tbFTPPath
//
this.tbFTPPath.Location = new System.Drawing.Point(100, 95);
this.tbFTPPath.Margin = new System.Windows.Forms.Padding(4);
this.tbFTPPath.Name = "tbFTPPath";
this.tbFTPPath.Size = new System.Drawing.Size(340, 28);
this.tbFTPPath.TabIndex = 16;
this.tbFTPPath.Text = "/home/ftpgloria/unimarc";
//
// label9
//
this.label9.AutoSize = true;
this.label9.Location = new System.Drawing.Point(15, 100);
this.label9.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.label9.Name = "label9";
this.label9.Size = new System.Drawing.Size(82, 18);
this.label9.TabIndex = 15;
this.label9.Text = "Root Path";
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 12F);
this.AutoScaleDimensions = new System.Drawing.SizeF(10F, 18F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 450);
this.ClientSize = new System.Drawing.Size(780, 580);
this.Controls.Add(this.grpftpinfo);
this.Controls.Add(this.tbExceptfile);
this.Controls.Add(this.label5);
this.Controls.Add(this.btUpdateFilelist);
this.Controls.Add(this.listView1);
this.Controls.Add(this.tbExeFileName);
@@ -179,8 +363,11 @@
this.Controls.Add(this.btRead);
this.Controls.Add(this.tbCount);
this.Controls.Add(this.label1);
this.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4);
this.Name = "Form1";
this.Text = "Form1";
this.grpftpinfo.ResumeLayout(false);
this.grpftpinfo.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
@@ -202,6 +389,21 @@
private System.Windows.Forms.ColumnHeader columnHeader1;
private System.Windows.Forms.ColumnHeader columnHeader2;
private System.Windows.Forms.Button btUpdateFilelist;
private System.Windows.Forms.TextBox tbExceptfile;
private System.Windows.Forms.Label label5;
private System.Windows.Forms.GroupBox grpftpinfo;
private System.Windows.Forms.TextBox tbFTPId;
private System.Windows.Forms.Label label6;
private System.Windows.Forms.TextBox tbFTPServer;
private System.Windows.Forms.Label label7;
private System.Windows.Forms.TextBox tbFTPPort;
private System.Windows.Forms.Label label8;
private System.Windows.Forms.TextBox tbFTPPW;
private System.Windows.Forms.Label lbpw;
private System.Windows.Forms.CheckBox chkFTPPassive;
private System.Windows.Forms.Button tbUploadFile;
private System.Windows.Forms.TextBox tbFTPPath;
private System.Windows.Forms.Label label9;
}
}

View File

@@ -9,6 +9,7 @@ using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.Text.RegularExpressions;
using System.Net;
namespace UpdateInfoMaker
{
@@ -17,10 +18,12 @@ namespace UpdateInfoMaker
private string currentIniPath = "";
private Dictionary<string, Dictionary<string, string>> iniData = new Dictionary<string, Dictionary<string, string>>();
private List<string> fileList = new List<string>();
private string configFilePath = Path.Combine(Application.StartupPath, "config.ini");
public Form1()
{
InitializeComponent();
LoadSettings();
}
private void btRead_Click(object sender, EventArgs e)
@@ -65,6 +68,7 @@ namespace UpdateInfoMaker
string folderPath = Path.GetDirectoryName(currentIniPath);
UpdateFileList(folderPath);
UpdateFileListView();
SaveSettings();
}
private void ReadIniFile(string filePath)
@@ -214,7 +218,10 @@ namespace UpdateInfoMaker
if (!Directory.Exists(folderPath))
return;
string[] extensions = { "*.exe", "*.dll", "*.xml", "*.config" };
string[] extensions = { "*.inf","*.exe", "*.dll", "*.xml", "*.config" };
// 제외할 파일 목록 가져오기
HashSet<string> exceptFiles = GetExceptFiles();
foreach (string extension in extensions)
{
@@ -222,9 +229,14 @@ namespace UpdateInfoMaker
foreach (string file in files)
{
string fileName = Path.GetFileName(file);
// 제외 파일 목록에 없는 경우에만 추가
if (!exceptFiles.Contains(fileName))
{
fileList.Add($"\\{fileName}");
}
}
}
// 파일 개수 업데이트
if (!iniData.ContainsKey("files"))
@@ -271,5 +283,190 @@ namespace UpdateInfoMaker
return $"{len:0.##} {sizes[order]}";
}
private HashSet<string> GetExceptFiles()
{
var exceptFiles = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
if (!string.IsNullOrWhiteSpace(tbExceptfile.Text))
{
string[] files = tbExceptfile.Text.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
foreach (string file in files)
{
exceptFiles.Add(file.Trim());
}
}
return exceptFiles;
}
private void LoadSettings()
{
try
{
if (File.Exists(configFilePath))
{
string[] lines = File.ReadAllLines(configFilePath, Encoding.Default);
foreach (string line in lines)
{
if (line.StartsWith("exceptfiles="))
{
tbExceptfile.Text = line.Substring("exceptfiles=".Length);
break;
}
}
}
else
{
// 기본값 설정
tbExceptfile.Text = "Factory_Client.exe";
SaveSettings();
}
}
catch (Exception ex)
{
MessageBox.Show($"설정 파일 로드 중 오류가 발생했습니다: {ex.Message}", "오류", MessageBoxButtons.OK, MessageBoxIcon.Error);
tbExceptfile.Text = "Factory_Client.exe";
}
}
private void SaveSettings()
{
try
{
string[] lines = { $"exceptfiles={tbExceptfile.Text}" };
File.WriteAllLines(configFilePath, lines, Encoding.Default);
}
catch (Exception ex)
{
MessageBox.Show($"설정 파일 저장 중 오류가 발생했습니다: {ex.Message}", "오류", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void tbUploadFile_Click(object sender, EventArgs e)
{
//파일목록의 파일을 지정된 FTP정보를 가지고 업로드해야함
UploadFilesToFTP();
}
private void UploadFilesToFTP()
{
// FTP 정보 유효성 검사
if (string.IsNullOrWhiteSpace(tbFTPServer.Text) ||
string.IsNullOrWhiteSpace(tbFTPId.Text) ||
string.IsNullOrWhiteSpace(tbFTPPW.Text))
{
MessageBox.Show("FTP 서버, 아이디, 패스워드를 모두 입력해주세요.", "알림", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
if (fileList.Count == 0)
{
MessageBox.Show("업로드할 파일이 없습니다. 먼저 파일 목록을 업데이트해주세요.", "알림", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
if (string.IsNullOrEmpty(currentIniPath))
{
MessageBox.Show("먼저 INF 파일을 읽어주세요.", "알림", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
try
{
string sourceFolder = Path.GetDirectoryName(currentIniPath);
string ftpServer = tbFTPServer.Text.Trim();
string ftpUser = tbFTPId.Text.Trim();
string ftpPassword = tbFTPPW.Text.Trim();
string ftpPath = tbFTPPath.Text.Trim();
int ftpPort = 21;
if (!int.TryParse(tbFTPPort.Text, out ftpPort))
{
ftpPort = 21;
}
int successCount = 0;
int failCount = 0;
var failedFiles = new List<string>();
foreach (string file in fileList)
{
string fileName = file.TrimStart('\\');
string localFilePath = Path.Combine(sourceFolder, fileName);
if (!File.Exists(localFilePath))
{
failedFiles.Add($"{fileName} (파일 없음)");
failCount++;
continue;
}
try
{
// FTP URI 생성
string ftpUri;
if (ftpPath.EndsWith("/"))
ftpUri = $"ftp://{ftpServer}:{ftpPort}{ftpPath}{fileName}";
else
ftpUri = $"ftp://{ftpServer}:{ftpPort}{ftpPath}/{fileName}";
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(ftpUri);
request.Method = WebRequestMethods.Ftp.UploadFile;
request.Credentials = new NetworkCredential(ftpUser, ftpPassword);
request.UsePassive = chkFTPPassive.Checked;
request.UseBinary = true;
request.KeepAlive = false;
// 파일 업로드
using (FileStream fileStream = new FileStream(localFilePath, FileMode.Open, FileAccess.Read))
using (Stream ftpStream = request.GetRequestStream())
{
byte[] buffer = new byte[10240];
int read;
while ((read = fileStream.Read(buffer, 0, buffer.Length)) > 0)
{
ftpStream.Write(buffer, 0, read);
}
}
// 응답 확인
using (FtpWebResponse response = (FtpWebResponse)request.GetResponse())
{
if (response.StatusCode == FtpStatusCode.ClosingData ||
response.StatusCode == FtpStatusCode.FileActionOK)
{
successCount++;
}
else
{
failedFiles.Add($"{fileName} (상태: {response.StatusDescription})");
failCount++;
}
}
}
catch (Exception ex)
{
failedFiles.Add($"{fileName} ({ex.Message})");
failCount++;
}
}
// 결과 메시지 표시
string resultMessage = $"업로드 완료\n\n성공: {successCount}개\n실패: {failCount}개";
if (failedFiles.Count > 0)
{
resultMessage += "\n\n실패한 파일들:\n" + string.Join("\n", failedFiles);
}
MessageBox.Show(resultMessage, "FTP 업로드 결과", MessageBoxButtons.OK,
failCount > 0 ? MessageBoxIcon.Warning : MessageBoxIcon.Information);
}
catch (Exception ex)
{
MessageBox.Show($"FTP 업로드 중 오류가 발생했습니다: {ex.Message}", "오류", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
}