using System; using System.IO; using System.IO.Compression; using System.Text; using System.Windows.Forms; namespace ComputerShopWpfInstaller { internal static class SetupStub { private const string AppName = "ComputerShopWpf"; private const string DisplayName = "Продажа компьютерной техники"; private static readonly byte[] Marker = Encoding.ASCII.GetBytes("CSWPF_SETUP_PAYLOAD_V1"); [STAThread] private static int Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); try { string installDir = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), AppName); DialogResult confirm = MessageBox.Show( "Будет установлено приложение \"" + DisplayName + "\".\n\nПапка установки:\n" + installDir + "\n\nПродолжить?", DisplayName + " - установщик", MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (confirm != DialogResult.Yes) { return 0; } byte[] payload = ReadPayload(); ExtractPayload(payload, installDir); CreateDesktopShortcut(installDir); DialogResult launch = MessageBox.Show( "Установка завершена.\n\nЯрлык создан на рабочем столе.\nЗапустить приложение сейчас?", DisplayName + " - установщик", MessageBoxButtons.YesNo, MessageBoxIcon.Information); if (launch == DialogResult.Yes) { System.Diagnostics.Process.Start(Path.Combine(installDir, "ComputerShopWpf.exe")); } return 0; } catch (Exception ex) { MessageBox.Show( "Не удалось выполнить установку.\n\n" + ex.Message, DisplayName + " - ошибка установки", MessageBoxButtons.OK, MessageBoxIcon.Error); return 1; } } private static byte[] ReadPayload() { byte[] exeBytes = File.ReadAllBytes(Application.ExecutablePath); int markerStart = exeBytes.Length - Marker.Length; if (markerStart <= 8 || !Matches(exeBytes, markerStart, Marker)) { throw new InvalidOperationException("В установщике не найден пакет файлов приложения."); } long payloadLength = BitConverter.ToInt64(exeBytes, markerStart - 8); if (payloadLength <= 0 || payloadLength > markerStart - 8) { throw new InvalidOperationException("Пакет файлов приложения поврежден."); } int payloadStart = markerStart - 8 - (int)payloadLength; byte[] payload = new byte[payloadLength]; Buffer.BlockCopy(exeBytes, payloadStart, payload, 0, payload.Length); return payload; } private static bool Matches(byte[] data, int start, byte[] pattern) { for (int i = 0; i < pattern.Length; i++) { if (data[start + i] != pattern[i]) { return false; } } return true; } private static void ExtractPayload(byte[] payload, string installDir) { Directory.CreateDirectory(installDir); string fullInstallDir = Path.GetFullPath(installDir); using (MemoryStream stream = new MemoryStream(payload)) using (ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Read)) { foreach (ZipArchiveEntry entry in archive.Entries) { string targetPath = Path.GetFullPath(Path.Combine(installDir, entry.FullName)); if (!targetPath.StartsWith(fullInstallDir, StringComparison.OrdinalIgnoreCase)) { throw new InvalidOperationException("Пакет содержит недопустимый путь: " + entry.FullName); } if (entry.FullName.EndsWith("/", StringComparison.Ordinal)) { Directory.CreateDirectory(targetPath); continue; } string directory = Path.GetDirectoryName(targetPath); if (!String.IsNullOrEmpty(directory)) { Directory.CreateDirectory(directory); } entry.ExtractToFile(targetPath, true); } } } private static void CreateDesktopShortcut(string installDir) { string exePath = Path.Combine(installDir, "ComputerShopWpf.exe"); string desktop = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory); CreateShortcut( Path.Combine(desktop, DisplayName + ".lnk"), exePath, installDir, DisplayName, exePath); string uninstallScript = Path.Combine(installDir, "uninstall.ps1"); if (File.Exists(uninstallScript)) { CreateShortcut( Path.Combine(desktop, DisplayName + " - удалить.lnk"), "powershell.exe", installDir, "Удалить " + DisplayName, "powershell.exe", "-NoProfile -ExecutionPolicy Bypass -File \"" + uninstallScript + "\""); } } private static void CreateShortcut( string shortcutPath, string targetPath, string workingDirectory, string description, string iconPath, string arguments = "") { Type shellType = Type.GetTypeFromProgID("WScript.Shell"); if (shellType == null) { throw new InvalidOperationException("Не удалось создать ярлык: WScript.Shell недоступен."); } object shell = Activator.CreateInstance(shellType); object shortcut = shellType.InvokeMember( "CreateShortcut", System.Reflection.BindingFlags.InvokeMethod, null, shell, new object[] { shortcutPath }); Type shortcutType = shortcut.GetType(); shortcutType.InvokeMember("TargetPath", System.Reflection.BindingFlags.SetProperty, null, shortcut, new object[] { targetPath }); shortcutType.InvokeMember("WorkingDirectory", System.Reflection.BindingFlags.SetProperty, null, shortcut, new object[] { workingDirectory }); shortcutType.InvokeMember("Description", System.Reflection.BindingFlags.SetProperty, null, shortcut, new object[] { description }); shortcutType.InvokeMember("IconLocation", System.Reflection.BindingFlags.SetProperty, null, shortcut, new object[] { iconPath }); if (!String.IsNullOrEmpty(arguments)) { shortcutType.InvokeMember("Arguments", System.Reflection.BindingFlags.SetProperty, null, shortcut, new object[] { arguments }); } shortcutType.InvokeMember("Save", System.Reflection.BindingFlags.InvokeMethod, null, shortcut, null); } } }