diff --git a/Applications/Program.cs b/Applications/Program.cs index e879153..d041af7 100644 --- a/Applications/Program.cs +++ b/Applications/Program.cs @@ -2,24 +2,21 @@ using ICSharpCode.SharpZipLib.Zip; using Microsoft.Win32; using MySql.Data.MySqlClient; -using System; using System.Collections.Concurrent; -using System.Collections.Generic; using System.Diagnostics; -using System.IO; -using System.IO.Compression; using System.Net; using System.Net.NetworkInformation; -using System.Security.Cryptography; +using System.Net.Sockets; using System.Security.Principal; using System.ServiceProcess; using System.Text; using System.Text.Json; -using System.Xml.Linq; +using System.Text.RegularExpressions; class Program { static ConcurrentDictionary fileProcessMap = new(StringComparer.OrdinalIgnoreCase); + //[STAThread] static void Main(string[] args) { HttpListener listener = new HttpListener(); @@ -165,7 +162,7 @@ class Program File.Move(downloadedFilePath, newFilePath); Console.WriteLine($"文件已重命名为: {newFilePath}"); - + } } catch (Exception ex) @@ -194,116 +191,184 @@ class Program { Process.Start(startInfo); } - + } } else if (action == "/start") { if (path == "navicat") { - // 启动指定服务(MySQL 服务)//需要用管理员身份启动 - string serviceName = "wampmysqld"; // ← 请确认服务名 - try + int port = 6033; + + // 1. 自动搜索 MySQL bin 目录 + string[] possiblePaths = new string[] { - using (var service = new ServiceController(serviceName)) + @"C:\Program Files\MySQL\MySQL Server 5.5\bin", + @"C:\Program Files\MySQL\MySQL Server 5.6\bin", + @"C:\Program Files\MySQL\MySQL Server 5.7\bin", + @"C:\Program Files\MySQL\MySQL Server 8.0\bin", + @"C:\Program Files\MySQL\MySQL Server 8.1\bin", + @"C:\PROGRA~1\MySQL\MYSQLS~1.0\bin" + }; + string mysqlBinDir = null; + foreach (var patha in possiblePaths) + { + if (File.Exists(Path.Combine(patha, "mysqld.exe"))) { - if (service.Status != ServiceControllerStatus.Running && service.Status != ServiceControllerStatus.StartPending) - { - Console.WriteLine($"🟡 正在启动服务:{serviceName}..."); - service.Start(); - service.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromSeconds(10)); - Console.WriteLine($"✅ 服务 {serviceName} 启动成功"); - } - else - { - Console.WriteLine($"✅ 服务 {serviceName} 已在运行中"); - } + mysqlBinDir = patha; + break; } } - catch (Exception ex) - { - Console.WriteLine($"❌ 启动服务失败:{ex.Message}"); + + if (mysqlBinDir == null) { + mysqlBinDir = FindMySqlBin(); + if (mysqlBinDir == null) + { + return; + } } - // 获取当前用户的 SID - string userSid = WindowsIdentity.GetCurrent().User?.Value; - if (userSid == null) + + + // 2. 设置临时数据目录 + string tempData = @"C:\mysql_temp_data"; + string tempIni = @"C:\mysql_temp.ini"; + + int existingPid = GetProcessIdByPort(port); + if (existingPid > 0) + { + try + { + using var conn = new MySqlConnection($"server=127.0.0.1;port={port};user=root;password=;Charset=utf8mb4;"); + conn.Open(); + Console.WriteLine("已有 MySQL 正在运行,直接使用它"); + } + catch + { + + } + } + else + { + if (Directory.Exists(tempData)) + Directory.Delete(tempData, true); + Directory.CreateDirectory(tempData); + // 3. 生成临时 my.ini + using (StreamWriter writer = new StreamWriter(tempIni)) + { + writer.WriteLine("[mysqld]"); + writer.WriteLine($"datadir={tempData}"); + writer.WriteLine($"port={port}"); + writer.WriteLine("skip-networking=0"); + writer.WriteLine("skip-grant-tables=0"); + writer.WriteLine($"log-error={tempData}\\mysql.err"); + } + // 4. 初始化临时数据库 + if (!RunProcess(Path.Combine(mysqlBinDir, "mysqld.exe"), $"--defaults-file=\"{tempIni}\" --initialize-insecure")) + { + return; + } + + Console.WriteLine("已有 MySQL 正在运行,直接使用它"); + // 5. 启动临时 MySQL(WinExe 不重定向输出) + Process mysqlProcess = new Process(); + mysqlProcess.StartInfo.FileName = Path.Combine(mysqlBinDir, "mysqld.exe"); + mysqlProcess.StartInfo.Arguments = $"--defaults-file=\"{tempIni}\" --standalone --port={port}"; + mysqlProcess.StartInfo.UseShellExecute = false; + mysqlProcess.StartInfo.CreateNoWindow = true; + mysqlProcess.StartInfo.RedirectStandardOutput = true; + mysqlProcess.StartInfo.RedirectStandardError = true; + + mysqlProcess.Start(); + + mysqlProcess.BeginOutputReadLine(); + mysqlProcess.BeginErrorReadLine(); + + } + + + + + + + + // 6. 等待 MySQL 可连接(最长等待 30 秒) + string connStr = $"server=127.0.0.1;port={port};user=root;password=;Charset=utf8mb4;"; + var sw = System.Diagnostics.Stopwatch.StartNew(); + bool started = false; + while (sw.ElapsedMilliseconds < 30000) + { + try + { + using var conn = new MySql.Data.MySqlClient.MySqlConnection(connStr); + conn.Open(); + started = true; + break; + } + catch + { + System.Threading.Thread.Sleep(500); + } + } + + if (!started) { - Console.WriteLine("❌ 无法获取当前用户 SID"); return; } - string subKeyPath = $@"{userSid}\Software\PremiumSoft\Navicat\Servers\答题专用"; - Console.WriteLine("当前用户 subKeyPath" + subKeyPath); + + + + // 7 写入 Navicat 注册表 try { - // 打开HKEY_USERS根键 - using (RegistryKey baseKey = Registry.Users) + string userSid = WindowsIdentity.GetCurrent().User?.Value; + if (userSid != null) { - // 创建或打开子项,写权限需要true - using (RegistryKey key = baseKey.CreateSubKey(subKeyPath, true)) + string subKeyPath = $@"{userSid}\Software\PremiumSoft\Navicat\Servers\答题专用"; + using (var baseKey = Registry.Users) + using (var key = baseKey.CreateSubKey(subKeyPath, true)) { - if (key == null) - { - Console.WriteLine("❌ 无法创建或打开注册表项"); - return; - } - - // 写入键值示例 - key.SetValue("Host", "localhost"); - key.SetValue("Port", 6033, RegistryValueKind.DWord); + key.SetValue("Host", "127.0.0.1"); + key.SetValue("Port", port, RegistryValueKind.DWord); key.SetValue("User", "root"); - key.SetValue("Password", ""); // 注意密码如果要存可能是加密的 - // 其他必要键值写入 - Console.WriteLine("✅ 注册表写入成功"); + key.SetValue("Password", ""); } } } catch (Exception ex) { - Console.WriteLine($"❌ 写入注册表失败:{ex.Message}"); } - - // 执行数据库创建与初始化 - string connectionString = "server=localhost;port=6033;user=root;password=;charset=utf8mb4;"; - + // 8 创建数据库 + 执行 SQL try { - using (var connection = new MySqlConnection(connectionString)) + using (var conn = new MySqlConnection(connStr)) { - connection.Open(); - var createDbCmd = connection.CreateCommand(); - createDbCmd.CommandText = $"CREATE DATABASE IF NOT EXISTS `{dbName}` DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_general_ci;"; - createDbCmd.ExecuteNonQuery(); - Console.WriteLine($"✅ 数据库 {dbName} 创建成功"); + conn.Open(); + var cmd = conn.CreateCommand(); + cmd.CommandText = $"CREATE DATABASE IF NOT EXISTS `{dbName}` DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_general_ci;"; + cmd.ExecuteNonQuery(); } string sqlScript = File.ReadAllText(filepath); - - using (var dbConn = new MySqlConnection(connectionString + $"database={dbName};")) + using (var dbConn = new MySqlConnection(connStr + $"database={dbName};")) { dbConn.Open(); - var sqlStatements = SplitSqlStatements(sqlScript); - - foreach (var statement in sqlStatements) + foreach (var stmt in sqlStatements) { - if (string.IsNullOrWhiteSpace(statement)) continue; - + if (string.IsNullOrWhiteSpace(stmt)) continue; using var cmd = dbConn.CreateCommand(); - cmd.CommandText = statement.Trim(); + cmd.CommandText = stmt.Trim(); cmd.ExecuteNonQuery(); - Console.WriteLine($"执行成功:{Truncate(statement, 80)}"); } - - Console.WriteLine("✅ 所有 SQL 语句执行完成,数据库初始化成功"); } } catch (Exception ex) { - Console.WriteLine($"❌ 出错了:{ex.Message}"); } } + try { string? resolvedPath = ResolveAppPath(path); @@ -740,7 +805,8 @@ class Program if (filePath.Contains("zip")) { return true; - } else + } + else { return false; } @@ -765,7 +831,149 @@ class Program public T? data { get; set; } // 实际数据内容 public string msg { get; set; } = ""; // 消息提示 } + // 等待 MySQL 可连接 + public static bool WaitForMySql(string connStr, int timeoutSeconds) + { + var start = DateTime.Now; + while ((DateTime.Now - start).TotalSeconds < timeoutSeconds) + { + try + { + using var conn = new MySqlConnection(connStr); + conn.Open(); + return true; + } + catch + { + Thread.Sleep(1000); + } + } + return false; + } + static bool RunProcess(string fileName, string arguments, string logFile = null) + { + try + { + Process proc = new Process(); + proc.StartInfo.FileName = fileName; + proc.StartInfo.Arguments = arguments; + proc.StartInfo.UseShellExecute = false; + proc.StartInfo.RedirectStandardOutput = true; + proc.StartInfo.RedirectStandardError = true; + using (StreamWriter sw = logFile != null ? new StreamWriter(logFile, true) : null) + { + proc.OutputDataReceived += (s, e) => + { + if (!string.IsNullOrEmpty(e.Data) && sw != null) + sw.WriteLine("[OUT] " + e.Data); + }; + proc.ErrorDataReceived += (s, e) => + { + if (!string.IsNullOrEmpty(e.Data) && sw != null) + sw.WriteLine("[ERR] " + e.Data); + }; + + proc.Start(); + proc.BeginOutputReadLine(); + proc.BeginErrorReadLine(); + + proc.WaitForExit(); + return proc.ExitCode == 0; + } + } + catch (Exception ex) + { + if (logFile != null) + File.AppendAllText(logFile, "RunProcess Exception: " + ex + Environment.NewLine); + return false; + } + } + + // 以管理员身份结束进程 + static void KillProcessByPid(int pid) + { + try + { + Process p = new Process(); + p.StartInfo.FileName = "cmd.exe"; + p.StartInfo.Arguments = $"/c taskkill /PID {pid} /F"; + p.StartInfo.Verb = "runas"; // 请求管理员权限 + p.StartInfo.UseShellExecute = true; + p.Start(); + p.WaitForExit(); + } + catch (Exception ex) + { + } + } + + static int GetProcessIdByPort(int port) + { + try + { + // 调用 netstat 命令获取端口占用 + Process netstat = new Process(); + netstat.StartInfo.FileName = "netstat.exe"; + netstat.StartInfo.Arguments = "-aon"; + netstat.StartInfo.UseShellExecute = false; + netstat.StartInfo.RedirectStandardOutput = true; + netstat.StartInfo.CreateNoWindow = true; + + netstat.Start(); + string output = netstat.StandardOutput.ReadToEnd(); + netstat.WaitForExit(); + + // 正则匹配端口对应 PID + string pattern = $@"\s+TCP\s+\S+:{port}\s+\S+\s+LISTENING\s+(\d+)"; + var match = Regex.Match(output, pattern); + if (match.Success && int.TryParse(match.Groups[1].Value, out int pid)) + { + return pid; + } + } + catch + { + // 出错返回 0 + } + return 0; // 未找到占用 + } + static string FindMySqlBin() + { + string[] roots = new string[] + { + @"C:\Program Files\MySQL", + @"C:\Program Files (x86)\MySQL", + @"D:\Program Files\MySQL", + @"D:\Program Files (x86)\MySQL", + @"D:\MySQL" + }; + + foreach (var root in roots) + { + if (!Directory.Exists(root)) continue; + + try + { + var dirs = Directory.GetDirectories(root, "*", SearchOption.AllDirectories); + foreach (var dir in dirs) + { + string mysqldPath = Path.Combine(dir, "mysqld.exe"); + if (File.Exists(mysqldPath)) + { + return dir; // 找到 mysqld.exe 返回目录 + } + } + } + catch + { + // 访问被拒绝等异常直接忽略 + continue; + } + } + + return null; // 没找到 + } }