Program.cs 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. using System.IO.Compression;
  2. using System.Reflection;
  3. using System.Runtime.InteropServices;
  4. namespace AutorentSetup;
  5. internal static class Program
  6. {
  7. [STAThread]
  8. private static void Main()
  9. {
  10. ApplicationConfiguration.Initialize();
  11. Application.Run(new SetupForm());
  12. }
  13. }
  14. public sealed class SetupForm : Form
  15. {
  16. private readonly TextBox _folderBox = new()
  17. {
  18. Text = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "AutorentWinForms"),
  19. Width = 430
  20. };
  21. private readonly CheckBox _desktopShortcutBox = new()
  22. {
  23. Text = "Создать ярлык на рабочем столе",
  24. Checked = true,
  25. AutoSize = true
  26. };
  27. private readonly Button _installButton = new() { Text = "Установить", Width = 120, Height = 34 };
  28. private readonly Label _statusLabel = new() { AutoSize = true, Text = "Готово к установке." };
  29. private readonly ProgressBar _progress = new() { Width = 570, Height = 18 };
  30. public SetupForm()
  31. {
  32. Text = "Установка Автопрокат";
  33. StartPosition = FormStartPosition.CenterScreen;
  34. FormBorderStyle = FormBorderStyle.FixedDialog;
  35. MaximizeBox = false;
  36. MinimizeBox = false;
  37. ClientSize = new Size(640, 330);
  38. Font = new Font("Segoe UI", 10F);
  39. var title = new Label
  40. {
  41. Text = "Мастер установки ИС «Автопрокат»",
  42. Font = new Font("Segoe UI", 15F, FontStyle.Bold),
  43. AutoSize = true,
  44. Location = new Point(28, 24)
  45. };
  46. var description = new Label
  47. {
  48. Text = "Программа установит приложение, файл настроек БД и необходимые зависимости.",
  49. AutoSize = true,
  50. Location = new Point(31, 62)
  51. };
  52. var folderLabel = new Label
  53. {
  54. Text = "Папка установки:",
  55. AutoSize = true,
  56. Location = new Point(31, 105)
  57. };
  58. _folderBox.Location = new Point(34, 132);
  59. var browseButton = new Button
  60. {
  61. Text = "Обзор...",
  62. Width = 100,
  63. Height = 30,
  64. Location = new Point(475, 130)
  65. };
  66. browseButton.Click += (_, _) => BrowseFolder();
  67. _desktopShortcutBox.Location = new Point(34, 178);
  68. _progress.Location = new Point(34, 222);
  69. _statusLabel.Location = new Point(34, 250);
  70. _installButton.Location = new Point(365, 282);
  71. _installButton.Click += InstallButton_Click;
  72. var closeButton = new Button
  73. {
  74. Text = "Отмена",
  75. Width = 100,
  76. Height = 34,
  77. Location = new Point(475, 282)
  78. };
  79. closeButton.Click += (_, _) => Close();
  80. Controls.AddRange([
  81. title,
  82. description,
  83. folderLabel,
  84. _folderBox,
  85. browseButton,
  86. _desktopShortcutBox,
  87. _progress,
  88. _statusLabel,
  89. _installButton,
  90. closeButton
  91. ]);
  92. }
  93. private void BrowseFolder()
  94. {
  95. using var dialog = new FolderBrowserDialog
  96. {
  97. Description = "Выберите папку для установки Автопроката",
  98. UseDescriptionForTitle = true,
  99. SelectedPath = _folderBox.Text
  100. };
  101. if (dialog.ShowDialog(this) == DialogResult.OK)
  102. _folderBox.Text = dialog.SelectedPath;
  103. }
  104. private void InstallButton_Click(object? sender, EventArgs e)
  105. {
  106. Install();
  107. }
  108. private void Install()
  109. {
  110. try
  111. {
  112. _installButton.Enabled = false;
  113. _progress.Style = ProgressBarStyle.Marquee;
  114. _statusLabel.Text = "Копирование файлов...";
  115. var installPath = _folderBox.Text.Trim();
  116. if (string.IsNullOrWhiteSpace(installPath))
  117. throw new InvalidOperationException("Выберите папку установки.");
  118. Directory.CreateDirectory(installPath);
  119. ExtractApplication(installPath);
  120. EnsureSettingsFile(installPath);
  121. if (_desktopShortcutBox.Checked)
  122. CreateShortcut("Автопрокат", Path.Combine(installPath, "AutorentWinForms.exe"));
  123. _progress.Style = ProgressBarStyle.Blocks;
  124. _progress.Value = 100;
  125. _statusLabel.Text = "Установка завершена.";
  126. MessageBox.Show(
  127. "Установка завершена. Приложение можно запустить через ярлык или файл AutorentWinForms.exe.",
  128. "Автопрокат",
  129. MessageBoxButtons.OK,
  130. MessageBoxIcon.Information);
  131. _installButton.Text = "Готово";
  132. _installButton.Enabled = true;
  133. _installButton.Click -= InstallButton_Click;
  134. _installButton.Click += (_, _) => Close();
  135. }
  136. catch (Exception ex)
  137. {
  138. _progress.Style = ProgressBarStyle.Blocks;
  139. _progress.Value = 0;
  140. _statusLabel.Text = "Ошибка установки.";
  141. _installButton.Enabled = true;
  142. MessageBox.Show(ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
  143. }
  144. }
  145. private static void ExtractApplication(string installPath)
  146. {
  147. using var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("AppPackage.zip")
  148. ?? throw new InvalidOperationException("В установщик не встроен пакет приложения app.zip. Запустите scripts\\build_installer.ps1.");
  149. using var archive = new ZipArchive(stream, ZipArchiveMode.Read);
  150. foreach (var entry in archive.Entries)
  151. {
  152. var destinationPath = Path.GetFullPath(Path.Combine(installPath, entry.FullName));
  153. if (!destinationPath.StartsWith(Path.GetFullPath(installPath), StringComparison.OrdinalIgnoreCase))
  154. throw new InvalidOperationException("Некорректный путь внутри установочного пакета.");
  155. if (string.IsNullOrEmpty(entry.Name))
  156. {
  157. Directory.CreateDirectory(destinationPath);
  158. continue;
  159. }
  160. Directory.CreateDirectory(Path.GetDirectoryName(destinationPath)!);
  161. entry.ExtractToFile(destinationPath, overwrite: true);
  162. }
  163. }
  164. private static void EnsureSettingsFile(string installPath)
  165. {
  166. var settings = Path.Combine(installPath, "dbsettings.json");
  167. if (!File.Exists(settings))
  168. {
  169. File.WriteAllText(settings,
  170. """
  171. {
  172. "ConnectionString": "Host=edu-pg.itiscaf.ru;Port=5432;Database=dbwork;Username=YOUR_LOGIN;Password=YOUR_PASSWORD;Search Path=YOUR_SCHEMA,public;Pooling=true;Timeout=15;Command Timeout=30"
  173. }
  174. """);
  175. }
  176. }
  177. private static void CreateShortcut(string name, string targetPath)
  178. {
  179. var desktop = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
  180. var shortcutPath = Path.Combine(desktop, name + ".lnk");
  181. var shellType = Type.GetTypeFromProgID("WScript.Shell");
  182. if (shellType is null)
  183. return;
  184. dynamic shell = Activator.CreateInstance(shellType)!;
  185. dynamic shortcut = shell.CreateShortcut(shortcutPath);
  186. shortcut.TargetPath = targetPath;
  187. shortcut.WorkingDirectory = Path.GetDirectoryName(targetPath);
  188. shortcut.Description = "Информационная система Автопрокат";
  189. shortcut.Save();
  190. Marshal.FinalReleaseComObject(shortcut);
  191. Marshal.FinalReleaseComObject(shell);
  192. }
  193. }