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

554 lines
20 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 System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.NetworkInformation;
using System.Security.Cryptography;
using System.Security.Principal;
using System.ServiceProcess;
using System.Text.Json;
using System.Xml.Linq;
using Applications;
using Microsoft.Win32;
using MySql.Data.MySqlClient;
class Program
{
static ConcurrentDictionary<string, int> fileProcessMap = new(StringComparer.OrdinalIgnoreCase);
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");
// 处理预检请求
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 ip = context.Request.QueryString["ip"];
string action = context.Request.Url.AbsolutePath.ToLower();
string responseMessage = "";
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根据需要
};
// 检测一下端口是否被占用48080
if (!IsPortInUse(48082))
{
Process.Start(startInfo);
}
}
}
else if (action == "/start")
{
if (path == "navicat")
{
// 启动指定服务MySQL 服务)//需要用管理员身份启动
string serviceName = "wampmysqld"; // ← 请确认服务名
try
{
using (var service = new ServiceController(serviceName))
{
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} 已在运行中");
}
}
}
catch (Exception ex)
{
Console.WriteLine($"❌ 启动服务失败:{ex.Message}");
}
// 获取当前用户的 SID
string userSid = WindowsIdentity.GetCurrent().User?.Value;
if (userSid == null)
{
Console.WriteLine("❌ 无法获取当前用户 SID");
return;
}
string subKeyPath = $@"{userSid}\Software\PremiumSoft\Navicat\Servers\答题专用";
Console.WriteLine("当前用户 subKeyPath" + subKeyPath);
try
{
// 打开HKEY_USERS根键
using (RegistryKey baseKey = Registry.Users)
{
// 创建或打开子项写权限需要true
using (RegistryKey key = baseKey.CreateSubKey(subKeyPath, true))
{
if (key == null)
{
Console.WriteLine("❌ 无法创建或打开注册表项");
return;
}
// 写入键值示例
key.SetValue("Host", "localhost");
key.SetValue("Port", 6033, RegistryValueKind.DWord);
key.SetValue("User", "root");
key.SetValue("Password", ""); // 注意密码如果要存可能是加密的
// 其他必要键值写入
Console.WriteLine("✅ 注册表写入成功");
}
}
}
catch (Exception ex)
{
Console.WriteLine($"❌ 写入注册表失败:{ex.Message}");
}
// 执行数据库创建与初始化
string connectionString = "server=localhost;port=6033;user=root;password=;charset=utf8mb4;";
try
{
using (var connection = new MySqlConnection(connectionString))
{
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} 创建成功");
}
string sqlScript = File.ReadAllText(filepath);
using (var dbConn = new MySqlConnection(connectionString + $"database={dbName};"))
{
dbConn.Open();
var sqlStatements = SplitSqlStatements(sqlScript);
foreach (var statement in sqlStatements)
{
if (string.IsNullOrWhiteSpace(statement)) continue;
using var cmd = dbConn.CreateCommand();
cmd.CommandText = statement.Trim();
cmd.ExecuteNonQuery();
Console.WriteLine($"执行成功:{Truncate(statement, 80)}");
}
Console.WriteLine("✅ 所有 SQL 语句执行完成,数据库初始化成功");
}
}
catch (Exception ex)
{
Console.WriteLine($"❌ 出错了:{ex.Message}");
}
}
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"; // ← 替换成你的接口地址
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();
}
}
}
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(int port)
{
IPGlobalProperties ipGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();
TcpConnectionInformation[] tcpConnInfoArray = ipGlobalProperties.GetActiveTcpConnections();
foreach (TcpConnectionInformation tcpi in tcpConnInfoArray)
{
if (tcpi.LocalEndPoint.Port == port)
{
return true; // 端口被占用
}
}
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; } = ""; // 消息提示
}
}