using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Net; using System.Reflection.Emit; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.Diagnostics; using System.IO; using Newtonsoft.Json; using System.Security.Cryptography; using System.Net.Http; using Microsoft.Win32; using System.Security.Policy; using System.Runtime.InteropServices; namespace StudioClient { public partial class Form1 : Form { static string serverUrl = "http://xr.flexing.ai:3030/XR_Server/"; static string appName_Studio = "Studio"; static string appName_StudioTwin = "StudioTwin"; static string appName_StudioSimulator = "StudioSimulator"; static string setupFileTag = "Setup.exe"; static readonly HttpClient httpClient = new HttpClient(); [DllImport("user32.dll", CharSet = CharSet.Auto)] public static extern uint RegisterWindowMessage(string lpString); private uint installCompleteMsg; private uint uninstallCompleteMsg; public Form1() { InitializeComponent(); Initialize(); } void Initialize() { installCompleteMsg = RegisterWindowMessage($@"INSTALL_COMPLETE"); uninstallCompleteMsg = RegisterWindowMessage($@"UNINSTALL_COMPLETE"); string installPath; installPath = GetInstalledPathFromRegistry(appName_Studio); if (!string.IsNullOrWhiteSpace(installPath) && Directory.Exists(installPath)) { SetButtonState(true, StudioInstallButton, StudioCheckButton, StudioDeleteButton); } else { SetButtonState(false, StudioInstallButton, StudioCheckButton, StudioDeleteButton); } } void SetButtonState(bool isInstallComplete, Button installButton, Button checkButton, Button deleteButton) { if (isInstallComplete) { installButton.Text = "실행"; checkButton.Visible = true; checkButton.Enabled = true; deleteButton.Visible = true; deleteButton.Enabled = true; } else { installButton.Text = "설치"; checkButton.Visible = false; checkButton.Enabled = false; deleteButton.Visible = false; deleteButton.Enabled = false; } } private async void StudioInstallButton_Click(object sender, EventArgs e) { await OnClickButton(appName_Studio); } private async void StudioTwinInstallButton_Click(object sender, EventArgs e) { //await InstallApp(serverUrl, appName_StudioTwin); } private async void StudioSimulatorInstallButton_Click(object sender, EventArgs e) { } private async void StudioCheckButton_Click(object sender, EventArgs e) { } private async void StudioDeleteButton_Click(object sender, EventArgs e) { await UninstallApp(appName_Studio); } private async void StudioTwinDeleteButton_Click(object sender, EventArgs e) { } private async void StudioSimulatorDeleteButton_Click(object sender, EventArgs e) { } private async void WriteText(string text) { label1.Text = text; } private async Task OnClickButton(string appName) { string appUrl = Path.Combine(serverUrl, appName); // 이미 Setup으로 설치를 진행했는지 체크 string installPath = GetInstalledPathFromRegistry(appName); string exeFilePath; if (!string.IsNullOrWhiteSpace(installPath) && Directory.Exists(installPath)) // 이미 설치 되있으면 경로에서 exe파일 실행 { WriteText("런처 실행"); exeFilePath = Directory.GetFiles(installPath, "*.exe", SearchOption.TopDirectoryOnly) .FirstOrDefault(file => !Path.GetFileName(file).Equals("unins000.exe", StringComparison.OrdinalIgnoreCase) && Path.GetFileName(file).IndexOf("Launcher", StringComparison.OrdinalIgnoreCase) >= 0); if (string.IsNullOrEmpty(exeFilePath)) { WriteText("❌ 설치 경로에 실행할 수 있는 런처의 exe 파일이 없습니다."); return; } StartExecutableFile(exeFilePath, installPath); } else // 설치 안되있으면 Setup 다운받고 Setup 실행 { WriteText("설치 진행중"); // Setup 파일이 이미 있으면 삭제하고 서버에서 새로 다운로드 string setupFileName = appName + setupFileTag; if (File.Exists(setupFileName)) { File.Delete(setupFileName); } string setupFileUrl = Path.Combine(appUrl, setupFileName); await DownloadFile(setupFileUrl, ProgressBar); string currentDir = AppContext.BaseDirectory; exeFilePath = Path.Combine(currentDir, setupFileName); StartExecutableFile(exeFilePath, currentDir); } } private string GetInstalledPathFromRegistry(string appName) { try { using (RegistryKey key = Registry.CurrentUser.OpenSubKey($@"Software\UVC\{appName}")) { if (key != null) { return key.GetValue("InstallPath") as string ?? ""; } } } catch (Exception ex) { WriteText($"❌ 레지스트리 읽기 실패 ({appName}): {ex.Message}"); } return ""; } private async Task DownloadFile(string url, ProgressBar progressBar) { try { string currentDir = AppContext.BaseDirectory; string fileName = Path.GetFileName(new Uri(url).LocalPath); string fullPath = Path.Combine(currentDir, fileName); using (var response = await httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead)) { response.EnsureSuccessStatusCode(); long? totalBytes = response.Content.Headers.ContentLength; if (totalBytes == null) { WriteText("❌ 파일 크기를 알 수 없습니다."); return; } using (var contentStream = await response.Content.ReadAsStreamAsync()) using (var fileStream = new FileStream(fullPath, FileMode.Create, FileAccess.Write, FileShare.None)) { progressBar.Invoke((MethodInvoker)(() => { progressBar.Minimum = 0; progressBar.Maximum = 100; progressBar.Value = 0; })); byte[] buffer = new byte[81920]; // 80KB 버퍼 long totalRead = 0; int bytesRead; while ((bytesRead = await contentStream.ReadAsync(buffer, 0, buffer.Length)) > 0) { await fileStream.WriteAsync(buffer, 0, bytesRead); totalRead += bytesRead; int progress = (int)((totalRead * 100) / totalBytes.Value); progressBar.Invoke((MethodInvoker)(() => { progressBar.Value = Math.Min(progress, 100); })); } WriteText("✅ 다운로드 완료!"); } } } catch (Exception ex) { WriteText($"❌ 다운로드 실패: {ex.Message}"); } } private void StartExecutableFile(string exeFilePath, string workingDirectory) { ProcessStartInfo startInfo = new ProcessStartInfo { FileName = exeFilePath, WorkingDirectory = workingDirectory, UseShellExecute = true // Windows에서 기본 프로그램으로 실행 }; Process.Start(startInfo); } private async Task UninstallApp(string appName) { string appUrl = Path.Combine(serverUrl, appName); // 설치가 이미 되어있는지 체크 string installPath = GetInstalledPathFromRegistry(appName); string exeFilePath; if (!string.IsNullOrWhiteSpace(installPath) && Directory.Exists(installPath)) // 설치 되있으면 경로에서 Uninstaller 실행 { exeFilePath = Directory.GetFiles(installPath, "unins000.exe", SearchOption.TopDirectoryOnly).FirstOrDefault(); if (string.IsNullOrEmpty(exeFilePath)) { WriteText("❌ 설치 경로에 실행할 수 있는 unins000.exe 파일이 없습니다."); return; } WriteText("Uninstaller 실행"); StartExecutableFile(exeFilePath, installPath); } else { WriteText("❌ 설치된 경로가 없습니다."); } } // Install / Uninstall 완료 시 protected override void WndProc(ref Message m) { if (m.Msg == installCompleteMsg) { SetButtonState(true, StudioInstallButton, StudioCheckButton, StudioDeleteButton); } else if (m.Msg == uninstallCompleteMsg) { SetButtonState(false, StudioInstallButton, StudioCheckButton, StudioDeleteButton); } base.WndProc(ref m); } } }