Files

1115 lines
40 KiB
C#
Raw Permalink Normal View History

using Applications;
using ICSharpCode.SharpZipLib.Zip;
using Microsoft.Win32;
using MySql.Data.MySqlClient;
2025-06-27 11:51:40 +08:00
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;
2025-06-27 11:51:40 +08:00
using System.Text.Json;
using System.Text.RegularExpressions;
2025-06-27 11:51:40 +08:00
class Program
{
static ConcurrentDictionary<string, int> fileProcessMap = new(StringComparer.OrdinalIgnoreCase);
//[STAThread]
2025-06-27 11:51:40 +08:00
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");
2025-06-27 11:51:40 +08:00
// 处理预检请求
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"];
2025-06-27 11:51:40 +08:00
string ip = context.Request.QueryString["ip"];
2025-08-07 15:38:23 +08:00
// 方案ID
string taskId = context.Request.QueryString["taskId"];
2025-06-27 11:51:40 +08:00
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
{
//ip = "www.hblk.top:48080";
// 如果带有端口号(即含冒号)就去掉冒号及后面内容
if (ip.Contains(":"))
{
ip = ip.Split(':')[0];
}
Console.WriteLine(ip);
string dbUser = "root"; // ✅ 你的数据库账号
string dbPass = "root"; // ✅ 你的数据库密码
var startInfo = new ProcessStartInfo
{
FileName = exePath,
WorkingDirectory = workingDirectory, // 必须!
Arguments = $"-jar \"{exePath}\" " +
$"--spring.datasource.url=\"jdbc:mysql://{ip}:3306/pc-exam?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true\" " +
$"--spring.datasource.username={dbUser} " +
$"--spring.datasource.password={dbPass}",
UseShellExecute = true, // 或 false根据需要
Verb = "runas" // 指定管理员运行
};
// 检测一下端口是否被占用48082
if (!IsPortInUse("judgement"))
{
Process.Start(startInfo);
}
}
}
else if (action == "/start")
2025-06-27 11:51:40 +08:00
{
if (path == "navicat")
{
int port = 48086;
// 1. 自动搜索 MySQL bin 目录
string[] possiblePaths = new string[]
2025-06-27 11:51:40 +08:00
{
@"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")))
2025-06-27 11:51:40 +08:00
{
mysqlBinDir = patha;
break;
2025-06-27 11:51:40 +08:00
}
}
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)
2025-06-27 11:51:40 +08:00
{
try
{
using var conn = new MySql.Data.MySqlClient.MySqlConnection(connStr);
conn.Open();
started = true;
break;
}
catch
{
System.Threading.Thread.Sleep(500);
}
2025-06-27 11:51:40 +08:00
}
if (!started)
2025-06-27 11:51:40 +08:00
{
return;
}
// 7 写入 Navicat 注册表
2025-06-27 11:51:40 +08:00
try
{
string userSid = WindowsIdentity.GetCurrent().User?.Value;
if (userSid != null)
2025-06-27 11:51:40 +08:00
{
string subKeyPath = $@"{userSid}\Software\PremiumSoft\Navicat\Servers\答题专用";
using (var baseKey = Registry.Users)
using (var key = baseKey.CreateSubKey(subKeyPath, true))
2025-06-27 11:51:40 +08:00
{
key.SetValue("Host", "127.0.0.1");
key.SetValue("Port", port, RegistryValueKind.DWord);
2025-06-27 11:51:40 +08:00
key.SetValue("User", "root");
key.SetValue("Password", "");
2025-06-27 11:51:40 +08:00
}
}
}
catch (Exception ex)
{
}
// 8 创建数据库 + 执行 SQL
2025-06-27 11:51:40 +08:00
try
{
using (var conn = new MySqlConnection(connStr))
2025-06-27 11:51:40 +08:00
{
conn.Open();
var cmd = conn.CreateCommand();
cmd.CommandText = $"CREATE DATABASE IF NOT EXISTS `{dbName}` DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_general_ci;";
cmd.ExecuteNonQuery();
2025-06-27 11:51:40 +08:00
}
string sqlScript = File.ReadAllText(filepath);
using (var dbConn = new MySqlConnection(connStr + $"database={dbName};"))
2025-06-27 11:51:40 +08:00
{
dbConn.Open();
var sqlStatements = SplitSqlStatements(sqlScript);
foreach (var stmt in sqlStatements)
2025-06-27 11:51:40 +08:00
{
if (string.IsNullOrWhiteSpace(stmt)) continue;
2025-06-27 11:51:40 +08:00
using var cmd = dbConn.CreateCommand();
cmd.CommandText = stmt.Trim();
2025-06-27 11:51:40 +08:00
cmd.ExecuteNonQuery();
}
}
}
catch (Exception ex)
{
}
}
2025-06-27 11:51:40 +08:00
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;
}
}
// 停止软件
2025-06-27 11:51:40 +08:00
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.";
}
}
// 检测学生端环境
2025-06-27 11:51:40 +08:00
else if (action == "/check")
{
Console.WriteLine("check");
string apiUrl;
if (ip.Contains(":"))
{
// 已包含端口号或域名带端口
apiUrl = $"http://{ip}/admin-api/exam/app/getAppCheckList/{taskId}";
}
else
{
// 未包含端口号
apiUrl = $"http://{ip}:48080/admin-api/exam/app/getAppCheckList/{taskId}";
}
2025-06-27 11:51:40 +08:00
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 == "/white")
{
Console.WriteLine("check111");
string apiUrl;
if (ip.Contains(":"))
{
// 已包含端口号或域名带端口
apiUrl = $"http://{ip}/admin-api/exam/param/getAppWhiteList/{taskId}";
}
else
{
// 未包含端口号
apiUrl = $"http://{ip}:48080/admin-api/exam/param/getAppWhiteList/{taskId}";
}
Console.WriteLine(apiUrl);
List<String> softwareList = await FetchSoftwareWhiteListFromApi(apiUrl);
List<string> result = new List<string>();
// 将 result 转换为 JSON 并返回
responseMessage = JsonSerializer.Serialize(softwareList);
2025-06-27 11:51:40 +08:00
}
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
2025-08-25 19:02:18 +08:00
// 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();
// }
// }
2025-06-27 11:51:40 +08:00
}
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 async Task<List<String>> FetchSoftwareWhiteListFromApi(string url)
{
try
{
using HttpClient client = new();
var response = await client.GetStringAsync(url);
var apiResponse = JsonSerializer.Deserialize<ApiWhiteResponse>(response);
if (apiResponse != null && apiResponse.code == 0)
{
// 如果 code 为 0说明数据有效返回 softwareList
return apiResponse.data ?? new List<String>();
}
else
{
// Console.WriteLine($"API error: {apiResponse?.msg}");
return new List<String>();
}
}
catch (Exception ex)
{
// Console.WriteLine("获取接口数据失败: " + ex.Message);
return new List<String>();
}
}
2025-06-27 11:51:40 +08:00
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);
}
2025-06-27 11:51:40 +08:00
// 写入文件内容
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;
}
}
2025-06-27 11:51:40 +08:00
// 获取当前登录用户 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();
2025-06-27 11:51:40 +08:00
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;
//}
2025-06-27 11:51:40 +08:00
}