Files
pengchen-exam-java-applicat…/Applications/Program.cs

1035 lines
38 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Applications;
using ICSharpCode.SharpZipLib.Zip;
using Microsoft.Win32;
using MySql.Data.MySqlClient;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Security.Principal;
using System.ServiceProcess;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
class Program
{
static ConcurrentDictionary<string, int> fileProcessMap = new(StringComparer.OrdinalIgnoreCase);
//[STAThread]
static void Main(string[] args)
{
HttpListener listener = new HttpListener();
listener.Prefixes.Add("http://localhost:48081/");
listener.Start();
// Console.WriteLine("Listening on http://localhost:48081/");
while (true)
{
var context = listener.GetContext();
ThreadPool.QueueUserWorkItem(_ => HandleRequestAsync(context));
}
}
static async Task HandleRequestAsync(HttpListenerContext context)
{
// 添加 CORS 响应头
context.Response.AddHeader("Access-Control-Allow-Origin", "*");
context.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
context.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, tenant-id");
// 处理预检请求
if (context.Request.HttpMethod == "OPTIONS")
{
context.Response.StatusCode = (int)HttpStatusCode.OK;
context.Response.Close();
return;
}
string path = context.Request.QueryString["path"];
string dbName = context.Request.QueryString["dbName"];
string filepath = context.Request.QueryString["filepath"];
string fileToOpen = context.Request.QueryString["file"];
string openType = context.Request.QueryString["type"];
string exePath = context.Request.QueryString["exepath"];
string workingDirectory = context.Request.QueryString["workingdirectory"];
// 生成文件夹
string folderPath = context.Request.QueryString["folderPath"];
// 文件URL
string filesurl = context.Request.QueryString["filesurl"];
// 文件名称
string desiredFileName = context.Request.QueryString["filename"];
// 需要被打包的 源目录路径
string sourceDir = context.Request.QueryString["sourceDir"];
string ip = context.Request.QueryString["ip"];
// 方案ID
string taskId = context.Request.QueryString["taskId"];
string action = context.Request.Url.AbsolutePath.ToLower();
string responseMessage = "";
// 压缩文件方法
if (action == "/zipfiles")
{
try
{
if (!Directory.Exists(sourceDir))
{
throw new DirectoryNotFoundException("源目录不存在!");
}
// 构造ZIP文件路径同级目录同名.zip
string parentDir = Directory.GetParent(sourceDir).FullName;
string folderName = new DirectoryInfo(sourceDir).Name;
string outputZipPath = Path.Combine(parentDir, $"{folderName}.zip");
// 如果ZIP已存在先删除可选
if (File.Exists(outputZipPath))
{
File.Delete(outputZipPath);
}
// 使用SharpZipLib打包
using (var zipStream = new ZipOutputStream(File.Create(outputZipPath)))
{
zipStream.SetLevel(5); // 压缩级别 (0-9)
foreach (var file in Directory.GetFiles(sourceDir, "*", SearchOption.AllDirectories))
{
string relativePath = file.Substring(sourceDir.Length + 1);
var entry = new ZipEntry(relativePath)
{
DateTime = File.GetLastWriteTime(file),
IsUnicodeText = true
};
// 保留文件属性(隐藏、只读等)
var fileAttributes = File.GetAttributes(file);
entry.ExternalFileAttributes = (int)fileAttributes << 16;
zipStream.PutNextEntry(entry);
using (var fileStream = File.OpenRead(file))
{
fileStream.CopyTo(zipStream);
}
zipStream.CloseEntry();
}
}
// 返回ZIP文件的绝对路径
responseMessage = Path.GetFullPath(outputZipPath);
}
catch (Exception ex)
{
throw new Exception($"压缩失败: {ex.Message}");
}
}
// 下载文件方法
if (action == "/downloadfiles")
{
try
{
string downloadedFilePath = await DownloadFileAsync(filesurl, folderPath);
Console.WriteLine($"文件已下载到: {downloadedFilePath}");
if (IsZipFile(downloadedFilePath))
{
Console.WriteLine("检测到ZIP文件开始解压...");
string extractPath = Path.Combine(folderPath, Path.GetFileNameWithoutExtension(downloadedFilePath));
//System.IO.Compression.ZipFile.ExtractToDirectory(downloadedFilePath, folderPath);
UnzipWithChineseNames(downloadedFilePath, folderPath);
Console.WriteLine($"解压完成,文件保存在: {extractPath}");
// 删除原ZIP文件
File.Delete(downloadedFilePath);
Console.WriteLine("已删除原ZIP文件");
}
else
{
Console.WriteLine("文件不是ZIP格式保留原文件");
// 获取原文件扩展名
string originalExtension = Path.GetExtension(downloadedFilePath);
// 构建新文件名(保留原扩展名)
string newFileName = $"{desiredFileName}{originalExtension}";
string newFilePath = Path.Combine(folderPath, newFileName);
// 如果目标文件已存在,先删除
if (File.Exists(newFilePath))
{
File.Delete(newFilePath);
}
File.Move(downloadedFilePath, newFilePath);
Console.WriteLine($"文件已重命名为: {newFilePath}");
}
}
catch (Exception ex)
{
Console.WriteLine($"操作失败: {ex.Message}");
}
}
// 获取学生端本地的IPV4地址
if (action == "/getipv4address") {
Console.WriteLine("获取IPV4");
responseMessage = Dns.GetHostEntry(Dns.GetHostName())
.AddressList
.FirstOrDefault(ip => ip.AddressFamily == AddressFamily.InterNetwork)
?.ToString() ?? "未找到IPv4地址";
}
// 打开本地判分的JAVA环境
if (action == "/openjudgement")
{
string relativePath = "";
if (openType == "1")
{
string exeName = exePath;
relativePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, exeName);
}
else
{
var startInfo = new ProcessStartInfo
{
FileName = exePath,
WorkingDirectory = workingDirectory, // 必须!
UseShellExecute = true, // 或 false根据需要
Verb = "runas" // 指定管理员运行
};
// 检测一下端口是否被占用48082
if (!IsPortInUse("judgement"))
{
Process.Start(startInfo);
}
}
}
else if (action == "/start")
{
if (path == "navicat")
{
int port = 48086;
// 1. 自动搜索 MySQL bin 目录
string[] possiblePaths = new string[]
{
@"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")))
{
mysqlBinDir = patha;
break;
}
}
if (mysqlBinDir == null) {
mysqlBinDir = FindMySqlBin();
if (mysqlBinDir == null)
{
return;
}
}
// 2. 设置临时数据目录
string tempData = @"D:\mysql_temp_data";
string tempIni = @"D:\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();
}
catch
{
}
}
else
{
try
{
if (Directory.Exists(tempData))
Directory.Delete(tempData, true);
Directory.CreateDirectory(tempData);
// 如果已有 ini 文件,先删掉
if (File.Exists(tempIni))
{
File.Delete(tempIni);
}
// 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");
}
}
catch (Exception ex)
{
}
// 4. 初始化临时数据库
if (!RunProcess(Path.Combine(mysqlBinDir, "mysqld.exe"), $"--defaults-file=\"{tempIni}\" --initialize-insecure"))
{
return;
}
// 5. 启动临时 MySQLWinExe 不重定向输出)
Process mysqlProcess = new Process();
mysqlProcess.StartInfo.FileName = Path.Combine(mysqlBinDir, "mysqld.exe");
mysqlProcess.StartInfo.Arguments = $"--defaults-file=\"{tempIni}\" --standalone --port={port}";
// 必须 false 才能重定向输出和隐藏窗口
mysqlProcess.StartInfo.UseShellExecute = false;
mysqlProcess.StartInfo.CreateNoWindow = true;
// 重定向输出
mysqlProcess.StartInfo.RedirectStandardOutput = true;
mysqlProcess.StartInfo.RedirectStandardError = true;
// 捕获输出
mysqlProcess.OutputDataReceived += (s, e) => { if (e.Data != null) Console.WriteLine("[MySQL] " + e.Data); };
mysqlProcess.ErrorDataReceived += (s, e) => { if (e.Data != null) Console.WriteLine("[MySQL-ERR] " + e.Data); };
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)
{
return;
}
// 7 写入 Navicat 注册表
try
{
string userSid = WindowsIdentity.GetCurrent().User?.Value;
if (userSid != null)
{
string subKeyPath = $@"{userSid}\Software\PremiumSoft\Navicat\Servers\答题专用";
using (var baseKey = Registry.Users)
using (var key = baseKey.CreateSubKey(subKeyPath, true))
{
key.SetValue("Host", "127.0.0.1");
key.SetValue("Port", port, RegistryValueKind.DWord);
key.SetValue("User", "root");
key.SetValue("Password", "");
}
}
}
catch (Exception ex)
{
}
// 8 创建数据库 + 执行 SQL
try
{
using (var conn = new MySqlConnection(connStr))
{
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(connStr + $"database={dbName};"))
{
dbConn.Open();
var sqlStatements = SplitSqlStatements(sqlScript);
foreach (var stmt in sqlStatements)
{
if (string.IsNullOrWhiteSpace(stmt)) continue;
using var cmd = dbConn.CreateCommand();
cmd.CommandText = stmt.Trim();
cmd.ExecuteNonQuery();
}
}
}
catch (Exception ex)
{
}
}
try
{
string? resolvedPath = ResolveAppPath(path);
if (!string.IsNullOrEmpty(resolvedPath) && File.Exists(resolvedPath))
{
ProcessStartInfo psi = new ProcessStartInfo
{
FileName = resolvedPath,
Arguments = string.IsNullOrEmpty(fileToOpen) ? "" : $"\"{fileToOpen}\"",
UseShellExecute = true
};
var process = Process.Start(psi);
if (process != null)
{
if (!string.IsNullOrEmpty(fileToOpen))
{
fileProcessMap[fileToOpen] = process.Id;
responseMessage = $"Started {resolvedPath} with {fileToOpen}";
}
else
{
responseMessage = $"Started {resolvedPath} (no file)";
}
}
else
{
responseMessage = "Failed to start process.";
}
}
else if (!string.IsNullOrEmpty(fileToOpen) && File.Exists(fileToOpen))
{
// 使用默认程序打开文件
ProcessStartInfo psi = new ProcessStartInfo
{
FileName = fileToOpen,
UseShellExecute = true
};
var process = Process.Start(psi);
if (process != null)
{
fileProcessMap[fileToOpen] = process.Id;
responseMessage = $"Opened {fileToOpen} with default program (PID: {process.Id})";
}
else
{
responseMessage = $"Failed to open {fileToOpen}.";
}
}
else
{
responseMessage = "Missing or invalid 'path' or 'file'.";
}
}
catch (Exception ex)
{
responseMessage = "Error: " + ex.Message;
}
}
// 停止软件
else if (action == "/stop")
{
if (!string.IsNullOrEmpty(fileToOpen))
{
if (fileProcessMap.TryRemove(fileToOpen, out int pid))
{
try
{
var proc = Process.GetProcessById(pid);
proc.Kill();
responseMessage = $"Stopped process for file: {fileToOpen} (PID: {pid})";
}
catch (Exception ex)
{
responseMessage = $"Failed to stop process: {ex.Message}";
}
}
else
{
responseMessage = $"No tracked process for file: {fileToOpen}";
}
}
else
{
responseMessage = "Missing 'file' parameter.";
}
}
// 检测学生端环境
else if (action == "/check")
{
string apiUrl = "http://" + ip + ":48080/admin-api/exam/app/getAppCheckList/" + taskId; // ← 替换成你的接口地址
List<AppCheck> softwareList = await FetchSoftwareListFromApi(apiUrl);
List<string> result = new List<string>();
foreach (AppCheck softwareLine in softwareList)
{
var keywords = softwareLine.appName;
string? resolvedPath = ResolveAppPath(keywords);
if (!string.IsNullOrEmpty(resolvedPath) && File.Exists(resolvedPath))
{
result.Add(keywords + ":True");
}
else
{
result.Add(keywords + ":False");
}
}
// 将 result 转换为 JSON 并返回
responseMessage = JsonSerializer.Serialize(result);
}
else if (action == "/closeapps")
{
foreach (var proc in Process.GetProcesses())
{
try
{
// 主窗口句柄不为 0表示是一个窗口程序用户级应用
if (proc.MainWindowHandle != IntPtr.Zero &&
proc.SessionId != 0 &&
proc.Responding)
{
Console.WriteLine($"App: {proc.ProcessName} (PID: {proc.Id}) - Title: {proc.MainWindowTitle}");
if (!proc.MainWindowTitle.Contains("ExamStudent") && !proc.MainWindowTitle.Contains("Applications"))
{
var procs = Process.GetProcessById(proc.Id);
procs.Kill();
}
}
// 关闭临时 MySQL只关掉端口 48086
// if (proc.ProcessName.Equals("mysqld", StringComparison.OrdinalIgnoreCase))
// {
// string cmdLine = GetCommandLine(proc);
// if (!string.IsNullOrEmpty(cmdLine) && cmdLine.Contains("--port=48086"))
// {
// Console.WriteLine($"Closing temporary MySQL (PID: {proc.Id}) on port 48086");
// proc.Kill();
// }
// }
}
catch
{
// 一些系统进程可能抛异常,忽略
}
}
}
else if (action == "/allapps")
{
List<string> result = new List<string>();
foreach (var proc in Process.GetProcesses())
{
try
{
// 主窗口句柄不为 0表示是一个窗口程序用户级应用
if (proc.MainWindowHandle != IntPtr.Zero &&
proc.SessionId != 0 &&
proc.Responding)
{
Console.WriteLine($"App: {proc.ProcessName} (PID: {proc.Id}) - Title: {proc.MainWindowTitle}");
result.Add(proc.ProcessName);
}
}
catch
{
// 一些系统进程可能抛异常,忽略
}
}
responseMessage = JsonSerializer.Serialize(result);
}
try
{
context.Response.ContentType = "text/plain";
context.Response.ContentEncoding = System.Text.Encoding.UTF8;
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(CreateJsonResponse(200, responseMessage, "") ?? "No response");
context.Response.ContentLength64 = buffer.Length;
await context.Response.OutputStream.WriteAsync(buffer, 0, buffer.Length);
}
catch (Exception ex)
{
Console.WriteLine("Response write error: " + ex.Message);
}
finally
{
context.Response.OutputStream.Close();
}
}
static string? ResolveAppPath(string appName)
{
var fromReg = FindInRegistry(appName);
if (!string.IsNullOrEmpty(fromReg)) return fromReg;
return null;
}
static string? FindInRegistry(string exeName)
{
using var regKey = Registry.ClassesRoot.OpenSubKey("Applications");
if (regKey != null)
{
// 获取所有子项
foreach (var subKeyName in regKey.GetSubKeyNames())
{
// 打开每个应用程序子键
using var appKey = regKey.OpenSubKey(subKeyName);
if (appKey != null)
{
// 查看是否有 "shell\open\command" 子键,这里存储着启动路径
using var commandKey = appKey.OpenSubKey(@"shell\open\command");
if (commandKey != null)
{
var commandValue = commandKey.GetValue("") as string;
if (commandValue != null)
{
if (subKeyName.IndexOf(exeName, StringComparison.OrdinalIgnoreCase) >= 0)
{
return commandValue.Split('"')[1];
}
}
}
}
}
}
return null;
}
static async Task<List<AppCheck>> FetchSoftwareListFromApi(string url)
{
try
{
using HttpClient client = new();
var response = await client.GetStringAsync(url);
var apiResponse = JsonSerializer.Deserialize<ApiResponse>(response);
if (apiResponse != null && apiResponse.code == 0)
{
// 如果 code 为 0说明数据有效返回 softwareList
return apiResponse.data ?? new List<AppCheck>();
}
else
{
// Console.WriteLine($"API error: {apiResponse?.msg}");
return new List<AppCheck>();
}
}
catch (Exception ex)
{
// Console.WriteLine("获取接口数据失败: " + ex.Message);
return new List<AppCheck>();
}
}
static string CreateJsonResponse<T>(int code, T data, string msg)
{
var response = new StandardResponse<T>
{
code = code,
data = data,
msg = msg
};
return JsonSerializer.Serialize(response);
}
static string Truncate(string value, int maxLength)
{
if (string.IsNullOrEmpty(value)) return value;
return value.Length <= maxLength ? value : value.Substring(0, maxLength) + "...";
}
static List<string> SplitSqlStatements(string sqlScript)
{
var statements = new List<string>();
string delimiter = ";";
int pos = 0, lastPos = 0, length = sqlScript.Length;
while (pos < length)
{
if (MatchKeyword(sqlScript, pos, "DELIMITER"))
{
string prevSegment = sqlScript.Substring(lastPos, pos - lastPos);
var prevStatements = SplitByDelimiter(prevSegment, delimiter);
statements.AddRange(prevStatements);
int delimStart = pos + "DELIMITER".Length;
while (delimStart < length && char.IsWhiteSpace(sqlScript[delimStart])) delimStart++;
int delimEnd = delimStart;
while (delimEnd < length && !char.IsWhiteSpace(sqlScript[delimEnd]) && sqlScript[delimEnd] != '\r' && sqlScript[delimEnd] != '\n') delimEnd++;
delimiter = sqlScript.Substring(delimStart, delimEnd - delimStart);
pos = delimEnd;
while (pos < length && sqlScript[pos] != '\n') pos++;
pos++;
lastPos = pos;
}
else
{
pos++;
}
}
if (lastPos < length)
{
string lastSegment = sqlScript.Substring(lastPos);
var lastStatements = SplitByDelimiter(lastSegment, delimiter);
statements.AddRange(lastStatements);
}
return statements;
}
static bool MatchKeyword(string text, int pos, string keyword)
{
if (pos + keyword.Length > text.Length) return false;
var segment = text.Substring(pos, keyword.Length);
return string.Equals(segment, keyword, StringComparison.OrdinalIgnoreCase);
}
static List<string> SplitByDelimiter(string sql, string delimiter)
{
var list = new List<string>();
int start = 0, idx;
while ((idx = sql.IndexOf(delimiter, start, StringComparison.Ordinal)) >= 0)
{
list.Add(sql.Substring(start, idx - start));
start = idx + delimiter.Length;
}
if (start < sql.Length)
list.Add(sql.Substring(start));
return list;
}
public static bool IsPortInUse(string name)
{
foreach (var proc in Process.GetProcesses())
{
try
{
// 主窗口句柄不为 0表示是一个窗口程序用户级应用
if (proc.SessionId != 0 &&
proc.Responding)
{
if (proc.ProcessName.Contains(name))
{
var procs = Process.GetProcessById(proc.Id);
return true;
}
}
}
catch
{
// 一些系统进程可能抛异常,忽略
}
}
return false; // 端口可用
}
/// <summary>
/// 解压ZIP文件并保留中文文件名
/// </summary>
/// <param name="zipFilePath">ZIP文件路径</param>
/// <param name="outputFolder">解压目标文件夹</param>
public static void UnzipWithChineseNames(string zipFilePath, string outputFolder)
{
// ✅ 注册编码提供程序(仅.NET Core / .NET 5 + 需要)
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
// ✅ 设置 GBK 编码(或 UTF-8
ZipStrings.CodePage = Encoding.GetEncoding("GBK").CodePage; // 或 936 / UTF8
if (!Directory.Exists(outputFolder))
Directory.CreateDirectory(outputFolder);
using (var fs = File.OpenRead(zipFilePath))
using (var zipInputStream = new ZipInputStream(fs))
{
ZipEntry entry;
while ((entry = zipInputStream.GetNextEntry()) != null)
{
// 处理路径(统一替换路径分隔符为当前系统的分隔符)
string entryName = entry.Name.Replace('/', Path.DirectorySeparatorChar);
string fullPath = Path.Combine(outputFolder, entryName);
if (entry.IsDirectory)
{
// 如果是目录,确保创建该目录
if (!Directory.Exists(fullPath))
{
Directory.CreateDirectory(fullPath);
// 设置目录的修改时间(可选)
Directory.SetLastWriteTime(fullPath, entry.DateTime);
}
}
else
{
// 如果是文件,确保父目录存在
string directoryName = Path.GetDirectoryName(fullPath);
if (!string.IsNullOrEmpty(directoryName) && !Directory.Exists(directoryName))
{
Directory.CreateDirectory(directoryName);
}
// 写入文件内容
using (var streamWriter = File.Create(fullPath))
{
byte[] buffer = new byte[4096];
int size;
while ((size = zipInputStream.Read(buffer, 0, buffer.Length)) > 0)
{
streamWriter.Write(buffer, 0, size);
}
}
// 设置文件的修改时间
File.SetLastWriteTime(fullPath, entry.DateTime);
}
}
}
}
static async Task<string> DownloadFileAsync(string url, string saveDir)
{
using (var httpClient = new HttpClient())
{
// 确保目录存在
Directory.CreateDirectory(saveDir);
// 从URL获取文件名
Uri uri = new Uri(url);
string fileName = Path.GetFileName(uri.LocalPath);
if (string.IsNullOrEmpty(fileName))
{
fileName = $"downloaded_{DateTime.Now:yyyyMMddHHmmss}";
}
string fullPath = Path.Combine(saveDir, fileName);
// 下载文件
var response = await httpClient.GetAsync(url);
response.EnsureSuccessStatusCode();
using (var fileStream = File.Create(fullPath))
{
await response.Content.CopyToAsync(fileStream);
}
return fullPath;
}
}
// 检查文件是否是ZIP格式
static bool IsZipFile(string filePath)
{
try
{
if (filePath.Contains("zip"))
{
return true;
}
else
{
return false;
}
}
catch
{
return false;
}
}
// 获取当前登录用户 SID
static string GetCurrentUserSid()
{
var sid = System.Security.Principal.WindowsIdentity.GetCurrent().User?.ToString();
if (sid == null) throw new Exception("无法获取当前用户 SID");
return $"HKEY_USERS\\{sid}";
}
class StandardResponse<T>
{
public int code { get; set; } // 0 表示成功,其他表示失败
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; // 没找到
}
// 获取进程命令行,需要添加 System.Management 引用
//public static string GetCommandLine(Process process)
//{
// try
// {
// using (var searcher = new System.Management.ManagementObjectSearcher(
// "SELECT CommandLine FROM Win32_Process WHERE ProcessId = " + process.Id))
// {
// foreach (var obj in searcher.Get())
// {
// return obj["CommandLine"]?.ToString();
// }
// }
// }
// catch
// {
// return null;
// }
// return null;
//}
}